My mirror of the Barnard terminal client for Mumble.
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

153 lines
2.8 KiB

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