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