Files
barnard/uiterm/ui.go
2014-12-04 17:08:26 -04:00

171 lines
3.1 KiB
Go

package uiterm
import (
"github.com/nsf/termbox-go"
)
type LayoutFunc func(ui *Ui, width, height int)
type KeyListener func(ui *Ui, key Key)
type UiManager interface {
OnUiInitialize(ui *Ui)
OnUiResize(ui *Ui, width, height int)
}
type Ui struct {
close chan bool
manager UiManager
elements map[string]*uiElement
activeElement *uiElement
keyListeners map[Key][]KeyListener
fg Attribute
bg Attribute
}
type uiElement struct {
X0, Y0, X1, Y1 int
View View
}
func New(manager UiManager) *Ui {
ui := &Ui{
close: make(chan bool, 10),
elements: make(map[string]*uiElement),
manager: manager,
keyListeners: make(map[Key][]KeyListener),
}
return ui
}
func (ui *Ui) Close() {
if termbox.IsInit {
ui.close <- true
}
}
func (ui *Ui) Refresh() {
if termbox.IsInit {
termbox.Clear(termbox.Attribute(ui.fg), termbox.Attribute(ui.bg))
termbox.HideCursor()
for _, element := range ui.elements {
element.View.Draw(ui)
}
termbox.Flush()
}
}
func (ui *Ui) Active() View {
return ui.activeElement.View
}
func (ui *Ui) SetActive(name string) {
element, _ := ui.elements[name]
if ui.activeElement != nil {
ui.activeElement.View.SetActive(ui, false)
}
ui.activeElement = element
if element != nil {
element.View.SetActive(ui, true)
}
ui.Refresh()
}
func (ui *Ui) SetClear(fg, bg Attribute) {
ui.fg = fg
ui.bg = bg
}
func (ui *Ui) Run() error {
if termbox.IsInit {
return nil
}
if err := termbox.Init(); err != nil {
return nil
}
defer termbox.Close()
termbox.SetInputMode(termbox.InputAlt)
events := make(chan termbox.Event)
go func() {
for {
events <- termbox.PollEvent()
}
}()
ui.manager.OnUiInitialize(ui)
width, height := termbox.Size()
ui.manager.OnUiResize(ui, width, height)
ui.Refresh()
for {
select {
case <-ui.close:
return nil
case event := <-events:
switch event.Type {
case termbox.EventResize:
ui.manager.OnUiResize(ui, event.Width, event.Height)
ui.Refresh()
case termbox.EventKey:
if event.Ch != 0 {
ui.onCharacterEvent(event.Ch)
} else {
ui.onKeyEvent(Modifier(event.Mod), Key(event.Key))
}
}
}
}
}
func (ui *Ui) onCharacterEvent(ch rune) {
if ui.activeElement != nil {
ui.activeElement.View.CharacterEvent(ui, ch)
}
}
func (ui *Ui) onKeyEvent(mod Modifier, key Key) {
if ui.keyListeners[key] != nil {
for _, listener := range ui.keyListeners[key] {
listener(ui, key)
}
}
if ui.activeElement != nil {
ui.activeElement.View.KeyEvent(ui, mod, key)
}
}
func (ui *Ui) SetView(name string, x0, y0, x1, y1 int, view View) {
if element, ok := ui.elements[name]; ok {
element.X0 = x0
element.Y0 = y0
element.X1 = x1
element.Y1 = y1
view = element.View
} else {
ui.elements[name] = &uiElement{
X0: x0,
Y0: y0,
X1: x1,
Y1: y1,
View: view,
}
}
view.SetBounds(ui, x0, y0, x1, y1)
}
func (ui *Ui) View(name string) View {
if element, ok := ui.elements[name]; !ok {
return nil
} else {
return element.View
}
}
func (ui *Ui) AddKeyListener(listener KeyListener, key Key) {
ui.keyListeners[key] = append(ui.keyListeners[key], listener)
}