forked from jojomi/gonsole
-
Notifications
You must be signed in to change notification settings - Fork 4
/
basewindow.go
150 lines (127 loc) · 3.28 KB
/
basewindow.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
149
150
package gonsole
import "github.com/nsf/termbox-go"
// Window is the top-level struct in gonsole library.
type BaseWindow struct {
BaseElement
BaseContainer
app *App
focusedControl Control
onClose func()
}
func (win *BaseWindow) Init(app *App, id string) {
win.app = app
win.BaseElement.Init(win, nil, id, "window")
}
func (win *BaseWindow) App() *App {
return win.app
}
func (win *BaseWindow) Focused() bool {
aw := win.app.activeWindow()
if aw != nil {
if win.ID() == aw.ID() {
return true
}
}
return false
}
func (win *BaseWindow) Focus() {
win.app.moveWindowToTop(win)
}
func (win *BaseWindow) FocusedControl() Control {
return win.focusedControl
}
func (win *BaseWindow) FocusControl(control Control) {
for _, loopFC := range win.ChildrenDeep() {
if loopFC.ID() == control.ID() {
win.focusedControl = loopFC
return
}
}
}
func (win *BaseWindow) Close() {
win.App().removeWindow(win)
win.App().Redraw()
}
func (win *BaseWindow) OnClose(handler func()) {
win.onClose = handler
}
func (win *BaseWindow) moveFocus(num int) {
focusControls := win.getFocusableControls()
if len(focusControls) == 0 {
return
}
currentFocusControl := win.FocusedControl()
// get focus index
index := -1
for i, loopFC := range focusControls {
if loopFC.ID() == currentFocusControl.ID() {
index = i
}
}
newIndex := (index + num + len(focusControls)) % len(focusControls)
if index == -1 {
newIndex = 0
}
newFocusControl := focusControls[newIndex]
win.FocusControl(newFocusControl)
// update focus, mark dirty
currentFocusControl.SetDirty(true)
newFocusControl.SetDirty(true)
}
func (win *BaseWindow) getFocusableControls() []Control {
// TODO order by tabIndex and filter non-focussable controls
focusControls := []Control{}
for _, control := range win.ChildrenDeep() {
if control.Focusable() {
focusControls = append(focusControls, control)
}
}
return focusControls
}
// return true if event was parsed and should not continue bubbling up
func (win *BaseWindow) ParseEvent(ev *termbox.Event) (handled, repaint bool) {
// TODO window level event parsing, support tabbing for changing focus
// dispatch event to currently focussed control
if win.FocusedControl() != nil {
handled, repaint = win.FocusedControl().ParseEvent(ev)
if handled {
return handled, repaint
}
}
// focus navigation events
// catch tab key if the focussed control did not need it
// catch arrow keys if the focussed control did not need them
if ev.Type == termbox.EventKey {
switch ev.Key {
case termbox.KeyTab:
win.moveFocus(1)
return true, true
case termbox.KeyArrowDown, termbox.KeyArrowRight:
win.moveFocus(1)
return true, true
case termbox.KeyArrowUp, termbox.KeyArrowLeft:
win.moveFocus(-1)
return true, true
}
}
return false, false
}
func (win *BaseWindow) Repaint() {
if !win.Dirty() {
return
}
prefix := ""
if win.Focused() {
prefix = "focused."
}
win.drawBox(prefix)
win.BaseContainer.RepaintChildren()
// draw title
if win.Title() != "" {
if win.BorderType() == LineNone {
win.SetPadding(win.Padding().Plus(Sides{Top: 1}))
}
fg, bg := win.Theme().ColorTermbox(prefix+"title.fg"), win.Theme().ColorTermbox(prefix+"title.bg")
DrawTextSimple(" "+win.Title()+" ", false, win.BorderBox().Minus(Sides{Left: 2}), fg, bg)
}
}