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ů.

150 řádky
2.7 KiB

  1. package uiterm
  2. import (
  3. "strings"
  4. "github.com/nsf/termbox-go"
  5. )
  6. type TreeItem interface {
  7. TreeItemStyle(fg, bg Attribute, active bool) (Attribute, Attribute)
  8. String() string
  9. }
  10. type renderedTreeItem struct {
  11. //String string
  12. Level int
  13. Item TreeItem
  14. }
  15. type Tree struct {
  16. Fg Attribute
  17. Bg Attribute
  18. Generator func(item TreeItem) []TreeItem
  19. Listener func(ui *Ui, tree *Tree, item TreeItem)
  20. lines []renderedTreeItem
  21. activeLine int
  22. ui *Ui
  23. active bool
  24. x0, y0, x1, y1 int
  25. }
  26. func bounded(i, lower, upper int) int {
  27. if i < lower {
  28. return lower
  29. }
  30. if i > upper {
  31. return upper
  32. }
  33. return i
  34. }
  35. func (t *Tree) uiInitialize(ui *Ui) {
  36. t.ui = ui
  37. }
  38. func (t *Tree) uiSetActive(active bool) {
  39. t.active = active
  40. t.uiDraw()
  41. }
  42. func (t *Tree) uiSetBounds(x0, y0, x1, y1 int) {
  43. t.x0 = x0
  44. t.y0 = y0
  45. t.x1 = x1
  46. t.y1 = y1
  47. t.uiDraw()
  48. }
  49. func (t *Tree) Rebuild() {
  50. if t.Generator == nil {
  51. t.lines = []renderedTreeItem{}
  52. return
  53. }
  54. lines := []renderedTreeItem{}
  55. for _, item := range t.Generator(nil) {
  56. children := t.rebuild_rec(item, 0)
  57. if children != nil {
  58. lines = append(lines, children...)
  59. }
  60. }
  61. t.lines = lines
  62. t.activeLine = bounded(t.activeLine, 0, len(t.lines)-1)
  63. t.uiDraw()
  64. }
  65. func (t *Tree) rebuild_rec(parent TreeItem, level int) []renderedTreeItem {
  66. if parent == nil {
  67. return nil
  68. }
  69. lines := []renderedTreeItem{
  70. renderedTreeItem{
  71. Level: level,
  72. Item: parent,
  73. },
  74. }
  75. for _, item := range t.Generator(parent) {
  76. children := t.rebuild_rec(item, level+1)
  77. if children != nil {
  78. lines = append(lines, children...)
  79. }
  80. }
  81. return lines
  82. }
  83. func (t *Tree) uiDraw() {
  84. t.ui.beginDraw()
  85. defer t.ui.endDraw()
  86. if t.lines == nil {
  87. t.Rebuild()
  88. }
  89. line := 0
  90. for y := t.y0; y < t.y1; y++ {
  91. var reader *strings.Reader
  92. var item TreeItem
  93. level := 0
  94. if line < len(t.lines) {
  95. item = t.lines[line].Item
  96. level = t.lines[line].Level
  97. reader = strings.NewReader(item.String())
  98. }
  99. for x := t.x0; x < t.x1; x++ {
  100. var chr rune = ' '
  101. fg := t.Fg
  102. bg := t.Bg
  103. dx := x - t.x0
  104. dy := y - t.y0
  105. if reader != nil && level*2 <= dx {
  106. if ch, _, err := reader.ReadRune(); err == nil {
  107. chr = ch
  108. fg, bg = item.TreeItemStyle(fg, bg, t.active && t.activeLine == dy)
  109. }
  110. }
  111. termbox.SetCell(x, y, chr, termbox.Attribute(fg), termbox.Attribute(bg))
  112. }
  113. line++
  114. }
  115. }
  116. func (t *Tree) uiKeyEvent(mod Modifier, key Key) {
  117. switch key {
  118. case KeyArrowUp:
  119. t.activeLine = bounded(t.activeLine-1, 0, len(t.lines)-1)
  120. case KeyArrowDown:
  121. t.activeLine = bounded(t.activeLine+1, 0, len(t.lines)-1)
  122. case KeyEnter:
  123. if t.Listener != nil && t.activeLine >= 0 && t.activeLine < len(t.lines) {
  124. t.Listener(t.ui, t, t.lines[t.activeLine].Item)
  125. }
  126. }
  127. t.uiDraw()
  128. }
  129. func (t *Tree) uiCharacterEvent(ch rune) {
  130. }