]> git.0d.be Git - barnard.git/blob - uiterm/ui.go
uiterm: change Ui.Active to return View name
[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         Name           string
31         X0, Y0, X1, Y1 int
32         View           View
33 }
34
35 func New(manager UiManager) *Ui {
36         ui := &Ui{
37                 close:        make(chan bool, 10),
38                 elements:     make(map[string]*uiElement),
39                 manager:      manager,
40                 keyListeners: make(map[Key][]KeyListener),
41         }
42         return ui
43 }
44
45 func (ui *Ui) Close() {
46         if termbox.IsInit {
47                 ui.close <- true
48         }
49 }
50
51 func (ui *Ui) Refresh() {
52         if termbox.IsInit {
53                 termbox.Clear(termbox.Attribute(ui.Fg), termbox.Attribute(ui.Bg))
54                 termbox.HideCursor()
55                 for _, element := range ui.elements {
56                         element.View.uiDraw()
57                 }
58                 termbox.Flush()
59         }
60 }
61
62 func (ui *Ui) Active() string {
63         return ui.activeElement.Name
64 }
65
66 func (ui *Ui) SetActive(name string) {
67         element, _ := ui.elements[name]
68         if ui.activeElement != nil {
69                 ui.activeElement.View.uiSetActive(false)
70         }
71         ui.activeElement = element
72         if element != nil {
73                 element.View.uiSetActive(true)
74         }
75         ui.Refresh()
76 }
77
78 func (ui *Ui) Run() error {
79         if termbox.IsInit {
80                 return nil
81         }
82         if err := termbox.Init(); err != nil {
83                 return nil
84         }
85         defer termbox.Close()
86         termbox.SetInputMode(termbox.InputAlt)
87
88         events := make(chan termbox.Event)
89         go func() {
90                 for {
91                         events <- termbox.PollEvent()
92                 }
93         }()
94
95         ui.manager.OnUiInitialize(ui)
96         width, height := termbox.Size()
97         ui.manager.OnUiResize(ui, width, height)
98         ui.Refresh()
99
100         for {
101                 select {
102                 case <-ui.close:
103                         return nil
104                 case event := <-events:
105                         switch event.Type {
106                         case termbox.EventResize:
107                                 ui.manager.OnUiResize(ui, event.Width, event.Height)
108                                 ui.Refresh()
109                         case termbox.EventKey:
110                                 if event.Ch != 0 {
111                                         ui.onCharacterEvent(event.Ch)
112                                 } else {
113                                         ui.onKeyEvent(Modifier(event.Mod), Key(event.Key))
114                                 }
115                         }
116                 }
117         }
118 }
119
120 func (ui *Ui) onCharacterEvent(ch rune) {
121         if ui.activeElement != nil {
122                 ui.activeElement.View.uiCharacterEvent(ch)
123         }
124 }
125
126 func (ui *Ui) onKeyEvent(mod Modifier, key Key) {
127         if ui.keyListeners[key] != nil {
128                 for _, listener := range ui.keyListeners[key] {
129                         listener(ui, key)
130                 }
131         }
132         if ui.activeElement != nil {
133                 ui.activeElement.View.uiKeyEvent(mod, key)
134         }
135 }
136
137 func (ui *Ui) Add(name string, view View) error {
138         if _, ok := ui.elements[name]; ok {
139                 return errors.New("view already exists")
140         }
141         ui.elements[name] = &uiElement{
142                 Name: name,
143                 View: view,
144         }
145         view.uiInitialize(ui)
146         return nil
147 }
148
149 func (ui *Ui) SetBounds(name string, x0, y0, x1, y1 int) error {
150         element, ok := ui.elements[name]
151         if !ok {
152                 return errors.New("view does not exist")
153         }
154         element.X0, element.Y0, element.X1, element.Y1 = x0, y0, x1, y1
155         element.View.uiSetBounds(x0, y0, x1, y1)
156         return nil
157 }
158
159 func (ui *Ui) AddKeyListener(listener KeyListener, key Key) {
160         ui.keyListeners[key] = append(ui.keyListeners[key], listener)
161 }