7 "github.com/nsf/termbox-go"
10 type KeyListener func(ui *Ui, key Key)
12 type UiManager interface {
13 OnUiInitialize(ui *Ui)
14 OnUiResize(ui *Ui, width, height int)
24 elements map[string]*uiElement
25 activeElement *uiElement
27 keyListeners map[Key][]KeyListener
30 type uiElement struct {
36 func New(manager UiManager) *Ui {
38 close: make(chan bool, 10),
39 elements: make(map[string]*uiElement),
41 keyListeners: make(map[Key][]KeyListener),
46 func (ui *Ui) Close() {
52 func (ui *Ui) Refresh() {
57 termbox.Clear(termbox.Attribute(ui.Fg), termbox.Attribute(ui.Bg))
59 for _, element := range ui.elements {
65 func (ui *Ui) beginDraw() {
66 atomic.AddInt32(&ui.drawCount, 1)
69 func (ui *Ui) endDraw() {
70 if count := atomic.AddInt32(&ui.drawCount, -1); count == 0 {
75 func (ui *Ui) Active() string {
76 return ui.activeElement.Name
79 func (ui *Ui) SetActive(name string) {
80 element, _ := ui.elements[name]
81 if ui.activeElement != nil {
82 ui.activeElement.View.uiSetActive(false)
84 ui.activeElement = element
86 element.View.uiSetActive(true)
91 func (ui *Ui) Run() error {
95 if err := termbox.Init(); err != nil {
99 termbox.SetInputMode(termbox.InputAlt)
101 events := make(chan termbox.Event)
104 events <- termbox.PollEvent()
108 ui.manager.OnUiInitialize(ui)
109 width, height := termbox.Size()
110 ui.manager.OnUiResize(ui, width, height)
117 case event := <-events:
119 case termbox.EventResize:
120 ui.manager.OnUiResize(ui, event.Width, event.Height)
122 case termbox.EventKey:
124 ui.onCharacterEvent(event.Ch)
126 ui.onKeyEvent(Modifier(event.Mod), Key(event.Key))
133 func (ui *Ui) onCharacterEvent(ch rune) {
134 if ui.activeElement != nil {
135 ui.activeElement.View.uiCharacterEvent(ch)
139 func (ui *Ui) onKeyEvent(mod Modifier, key Key) {
140 if ui.keyListeners[key] != nil {
141 for _, listener := range ui.keyListeners[key] {
145 if ui.activeElement != nil {
146 ui.activeElement.View.uiKeyEvent(mod, key)
150 func (ui *Ui) Add(name string, view View) error {
151 if _, ok := ui.elements[name]; ok {
152 return errors.New("view already exists")
154 ui.elements[name] = &uiElement{
158 view.uiInitialize(ui)
162 func (ui *Ui) SetBounds(name string, x0, y0, x1, y1 int) error {
163 element, ok := ui.elements[name]
165 return errors.New("view does not exist")
167 element.X0, element.Y0, element.X1, element.Y1 = x0, y0, x1, y1
168 element.View.uiSetBounds(x0, y0, x1, y1)
172 func (ui *Ui) AddKeyListener(listener KeyListener, key Key) {
173 ui.keyListeners[key] = append(ui.keyListeners[key], listener)