My mirror of the Barnard terminal client for Mumble.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ui.go 3.0 KiB

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