-
Notifications
You must be signed in to change notification settings - Fork 0
/
mainmenu.go
148 lines (127 loc) · 3.75 KB
/
mainmenu.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package main
import (
gc "github.com/rthornton128/goncurses"
)
const (
// MenuWindowWidth represents the width of the menu window in characters
MenuWindowWidth = 55
// MenuWindowHeight represents the height of the menu window in characters
MenuWindowHeight = 10
menuTitle = "Main Menu"
menuMark = " => "
menuMarkEmpty = " "
menuItemOffset = 5
menuContentTopOffset = 3
)
// Menu is an interface for interaction with Menu type
type Menu interface {
HandleInput() bool
Free()
Refresh()
init(stdscr *gc.Window, items []*MenuItem)
}
// MenuItemHandlerFunction represents an action point on the particular menu item
type MenuItemHandlerFunction func() bool
// MenuWindow contains all of the ncurses main-menu realted stuff
type MenuWindow struct {
window *gc.Window
items []*MenuItem
currentItemIndex int
}
// MenuItem describes the title description and functionality of the menu item
type MenuItem struct {
MenuItemTitle string
MenuItemDescription string
MenuItemHandler MenuItemHandlerFunction
}
func (item *MenuItem) String() string {
return item.MenuItemTitle + "\t" + item.MenuItemDescription
}
// NewMenuItem creates new menu item with specified title, description and handler
func NewMenuItem(title string, description string, handler MenuItemHandlerFunction) *MenuItem {
return &MenuItem{
MenuItemTitle: title,
MenuItemDescription: description,
MenuItemHandler: handler,
}
}
// HandleInput obtains the user input and executes actions based on it.
func (m *MenuWindow) HandleInput() bool {
gc.Update()
ch := m.window.GetChar()
switch ch {
case gc.KEY_DOWN:
m.moveCaretDown()
case gc.KEY_UP:
m.moveCaretUp()
case gc.KEY_RETURN:
return m.executeCurrentHandler()
default:
break
}
m.Refresh()
return true
}
func (m *MenuWindow) moveCaretDown() {
if m.currentItemIndex == len(m.items)-1 {
m.currentItemIndex = 0
} else {
m.currentItemIndex++
}
}
func (m *MenuWindow) moveCaretUp() {
if m.currentItemIndex == 0 {
m.currentItemIndex = len(m.items) - 1
} else {
m.currentItemIndex--
}
}
func (m *MenuWindow) getCurrentItem() *MenuItem {
return m.items[m.currentItemIndex]
}
func (m *MenuWindow) executeCurrentHandler() bool {
return m.getCurrentItem().MenuItemHandler()
}
func (m *MenuWindow) init(stdscr *gc.Window, items []*MenuItem) {
maxY, maxX := stdscr.MaxYX()
gc.InitPair(1, gc.C_RED, gc.C_BLACK)
m.currentItemIndex = 0
m.items = items
m.window = createMenuWindow(stdscr, items, maxX, maxY)
m.window.Refresh()
}
// Refresh performs redrawing of the menu window contents
func (m *MenuWindow) Refresh() {
for idx, item := range m.items {
if idx == m.currentItemIndex {
m.window.MovePrint(idx+menuContentTopOffset, 1, menuMark)
} else {
m.window.MovePrint(idx+menuContentTopOffset, 1, menuMarkEmpty)
}
m.window.MovePrint(idx+menuContentTopOffset, menuItemOffset, item.String())
}
m.window.Refresh()
}
// Free erase the content of the window from the screen and frees the memory, allocated for it.
func (m *MenuWindow) Free() {
m.window.Erase()
m.window.Delete()
}
func createMenuWindow(stdscr *gc.Window, items []*MenuItem, maxX int, maxY int) *gc.Window {
wnd := stdscr.Derived(MenuWindowHeight, MenuWindowWidth, maxY/2-5, maxX/2-30)
wnd.Keypad(true)
wnd.Box(0, 0)
wnd.ColorOn(1)
wnd.MovePrint(1, (MenuWindowWidth/2)-(len(menuTitle)/2), menuTitle)
wnd.ColorOff(1)
wnd.MoveAddChar(2, 0, gc.ACS_LTEE)
wnd.HLine(2, 1, gc.ACS_HLINE, MenuWindowWidth-2)
wnd.MoveAddChar(2, MenuWindowWidth-1, gc.ACS_RTEE)
return wnd
}
// NewMenu creates new instance of main menu nested in specified Window with specified option items
func NewMenu(stdscr *gc.Window, items []*MenuItem) Menu {
menu := new(MenuWindow)
menu.init(stdscr, items)
return menu
}