]> git.0d.be Git - barnard.git/blob - uiterm/ui.go
uiterm: make View interface methods private
[barnard.git] / uiterm / ui.go
1 package uiterm
2
3 import (
4         "github.com/nsf/termbox-go"
5 )
6
7 type LayoutFunc func(ui *Ui, width, height int)
8
9 type KeyListener func(ui *Ui, key Key)
10
11 type UiManager interface {
12         OnUiInitialize(ui *Ui)
13         OnUiResize(ui *Ui, width, height int)
14 }
15
16 type Ui struct {
17         close   chan bool
18         manager UiManager
19
20         elements      map[string]*uiElement
21         activeElement *uiElement
22
23         keyListeners map[Key][]KeyListener
24
25         fg Attribute
26         bg Attribute
27 }
28
29 type uiElement struct {
30         X0, Y0, X1, Y1 int
31         View           View
32 }
33
34 func New(manager UiManager) *Ui {
35         ui := &Ui{
36                 close:        make(chan bool, 10),
37                 elements:     make(map[string]*uiElement),
38                 manager:      manager,
39                 keyListeners: make(map[Key][]KeyListener),
40         }
41         return ui
42 }
43
44 func (ui *Ui) Close() {
45         if termbox.IsInit {
46                 ui.close <- true
47         }
48 }
49
50 func (ui *Ui) Refresh() {
51         if termbox.IsInit {
52                 termbox.Clear(termbox.Attribute(ui.fg), termbox.Attribute(ui.bg))
53                 termbox.HideCursor()
54                 for _, element := range ui.elements {
55                         element.View.draw(ui)
56                 }
57                 termbox.Flush()
58         }
59 }
60
61 func (ui *Ui) Active() View {
62         return ui.activeElement.View
63 }
64
65 func (ui *Ui) SetActive(name string) {
66         element, _ := ui.elements[name]
67         if ui.activeElement != nil {
68                 ui.activeElement.View.setActive(ui, false)
69         }
70         ui.activeElement = element
71         if element != nil {
72                 element.View.setActive(ui, true)
73         }
74         ui.Refresh()
75 }
76
77 func (ui *Ui) SetClear(fg, bg Attribute) {
78         ui.fg = fg
79         ui.bg = bg
80 }
81
82 func (ui *Ui) Run() error {
83         if termbox.IsInit {
84                 return nil
85         }
86         if err := termbox.Init(); err != nil {
87                 return nil
88         }
89         defer termbox.Close()
90         termbox.SetInputMode(termbox.InputAlt)
91
92         events := make(chan termbox.Event)
93         go func() {
94                 for {
95                         events <- termbox.PollEvent()
96                 }
97         }()
98
99         ui.manager.OnUiInitialize(ui)
100         width, height := termbox.Size()
101         ui.manager.OnUiResize(ui, width, height)
102         ui.Refresh()
103
104         for {
105                 select {
106                 case <-ui.close:
107                         return nil
108                 case event := <-events:
109                         switch event.Type {
110                         case termbox.EventResize:
111                                 ui.manager.OnUiResize(ui, event.Width, event.Height)
112                                 ui.Refresh()
113                         case termbox.EventKey:
114                                 if event.Ch != 0 {
115                                         ui.onCharacterEvent(event.Ch)
116                                 } else {
117                                         ui.onKeyEvent(Modifier(event.Mod), Key(event.Key))
118                                 }
119                         }
120                 }
121         }
122 }
123
124 func (ui *Ui) onCharacterEvent(ch rune) {
125         if ui.activeElement != nil {
126                 ui.activeElement.View.characterEvent(ui, ch)
127         }
128 }
129
130 func (ui *Ui) onKeyEvent(mod Modifier, key Key) {
131         if ui.keyListeners[key] != nil {
132                 for _, listener := range ui.keyListeners[key] {
133                         listener(ui, key)
134                 }
135         }
136         if ui.activeElement != nil {
137                 ui.activeElement.View.keyEvent(ui, mod, key)
138         }
139 }
140
141 func (ui *Ui) SetView(name string, x0, y0, x1, y1 int, view View) {
142         if element, ok := ui.elements[name]; ok {
143                 element.X0 = x0
144                 element.Y0 = y0
145                 element.X1 = x1
146                 element.Y1 = y1
147                 view = element.View
148         } else {
149                 ui.elements[name] = &uiElement{
150                         X0:   x0,
151                         Y0:   y0,
152                         X1:   x1,
153                         Y1:   y1,
154                         View: view,
155                 }
156         }
157         view.setBounds(ui, x0, y0, x1, y1)
158 }
159
160 func (ui *Ui) View(name string) View {
161         if element, ok := ui.elements[name]; !ok {
162                 return nil
163         } else {
164                 return element.View
165         }
166 }
167
168 func (ui *Ui) AddKeyListener(listener KeyListener, key Key) {
169         ui.keyListeners[key] = append(ui.keyListeners[key], listener)
170 }