]> git.0d.be Git - barnard.git/blob - uiterm/ui.go
uiterm: remove LayoutFunc, remove InputFunc type
[barnard.git] / uiterm / ui.go
1 package uiterm
2
3 import (
4         "errors"
5
6         "github.com/nsf/termbox-go"
7 )
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         Fg Attribute
18         Bg Attribute
19
20         close   chan bool
21         manager UiManager
22
23         elements      map[string]*uiElement
24         activeElement *uiElement
25
26         keyListeners map[Key][]KeyListener
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()
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(false)
69         }
70         ui.activeElement = element
71         if element != nil {
72                 element.View.setActive(true)
73         }
74         ui.Refresh()
75 }
76
77 func (ui *Ui) Run() error {
78         if termbox.IsInit {
79                 return nil
80         }
81         if err := termbox.Init(); err != nil {
82                 return nil
83         }
84         defer termbox.Close()
85         termbox.SetInputMode(termbox.InputAlt)
86
87         events := make(chan termbox.Event)
88         go func() {
89                 for {
90                         events <- termbox.PollEvent()
91                 }
92         }()
93
94         ui.manager.OnUiInitialize(ui)
95         width, height := termbox.Size()
96         ui.manager.OnUiResize(ui, width, height)
97         ui.Refresh()
98
99         for {
100                 select {
101                 case <-ui.close:
102                         return nil
103                 case event := <-events:
104                         switch event.Type {
105                         case termbox.EventResize:
106                                 ui.manager.OnUiResize(ui, event.Width, event.Height)
107                                 ui.Refresh()
108                         case termbox.EventKey:
109                                 if event.Ch != 0 {
110                                         ui.onCharacterEvent(event.Ch)
111                                 } else {
112                                         ui.onKeyEvent(Modifier(event.Mod), Key(event.Key))
113                                 }
114                         }
115                 }
116         }
117 }
118
119 func (ui *Ui) onCharacterEvent(ch rune) {
120         if ui.activeElement != nil {
121                 ui.activeElement.View.characterEvent(ch)
122         }
123 }
124
125 func (ui *Ui) onKeyEvent(mod Modifier, key Key) {
126         if ui.keyListeners[key] != nil {
127                 for _, listener := range ui.keyListeners[key] {
128                         listener(ui, key)
129                 }
130         }
131         if ui.activeElement != nil {
132                 ui.activeElement.View.keyEvent(mod, key)
133         }
134 }
135
136 func (ui *Ui) Add(name string, view View) error {
137         if _, ok := ui.elements[name]; ok {
138                 return errors.New("view already exists")
139         }
140         ui.elements[name] = &uiElement{
141                 View: view,
142         }
143         view.uiInitialize(ui)
144         return nil
145 }
146
147 func (ui *Ui) SetBounds(name string, x0, y0, x1, y1 int) error {
148         element, ok := ui.elements[name]
149         if !ok {
150                 return errors.New("view cannot be found")
151         }
152         element.X0 = x0
153         element.Y0 = y0
154         element.X1 = x1
155         element.Y1 = y1
156         element.View.setBounds(x0, y0, x1, y1)
157         return nil
158 }
159
160 func (ui *Ui) AddKeyListener(listener KeyListener, key Key) {
161         ui.keyListeners[key] = append(ui.keyListeners[key], listener)
162 }