My mirror of the Barnard terminal client for Mumble.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

176 řádky
3.3 KiB

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