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.

141 lines
2.7 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. active bool
  25. x0, y0, x1, y1 int
  26. }
  27. func bounded(i, lower, upper int) int {
  28. if i < lower {
  29. return lower
  30. }
  31. if i > upper {
  32. return upper
  33. }
  34. return i
  35. }
  36. func (t *Tree) SetBounds(ui *Ui, x0, y0, x1, y1 int) {
  37. t.x0 = x0
  38. t.y0 = y0
  39. t.x1 = x1
  40. t.y1 = y1
  41. }
  42. func (t *Tree) Rebuild() {
  43. if t.Generator == nil {
  44. t.lines = []renderedTreeItem{}
  45. return
  46. }
  47. lines := []renderedTreeItem{}
  48. for _, item := range t.Generator(nil) {
  49. children := t.rebuild_rec(item, 0)
  50. if children != nil {
  51. lines = append(lines, children...)
  52. }
  53. }
  54. t.lines = lines
  55. t.activeLine = bounded(t.activeLine, 0, len(t.lines)-1)
  56. }
  57. func (t *Tree) rebuild_rec(parent TreeItem, level int) []renderedTreeItem {
  58. if parent == nil {
  59. return nil
  60. }
  61. lines := []renderedTreeItem{
  62. renderedTreeItem{
  63. Level: level,
  64. Item: parent,
  65. },
  66. }
  67. for _, item := range t.Generator(parent) {
  68. children := t.rebuild_rec(item, level+1)
  69. if children != nil {
  70. lines = append(lines, children...)
  71. }
  72. }
  73. return lines
  74. }
  75. func (t *Tree) Draw(ui *Ui) {
  76. if t.lines == nil {
  77. t.Rebuild()
  78. }
  79. line := 0
  80. for y := t.y0; y < t.y1; y++ {
  81. var reader *strings.Reader
  82. var item TreeItem
  83. level := 0
  84. if line < len(t.lines) {
  85. item = t.lines[line].Item
  86. level = t.lines[line].Level
  87. reader = strings.NewReader(item.String())
  88. }
  89. for x := t.x0; x < t.x1; x++ {
  90. var chr rune = ' '
  91. fg := t.Fg
  92. bg := t.Bg
  93. dx := x - t.x0
  94. dy := y - t.y0
  95. if reader != nil && level*2 <= dx {
  96. if ch, _, err := reader.ReadRune(); err == nil {
  97. chr = ch
  98. fg, bg = item.TreeItemStyle(t.active && t.activeLine == dy)
  99. }
  100. }
  101. termbox.SetCell(x, y, chr, termbox.Attribute(fg), termbox.Attribute(bg))
  102. }
  103. line++
  104. }
  105. }
  106. func (t *Tree) SetActive(ui *Ui, active bool) {
  107. t.active = active
  108. }
  109. func (t *Tree) KeyEvent(ui *Ui, mod Modifier, key Key) {
  110. switch key {
  111. case KeyArrowUp:
  112. t.activeLine = bounded(t.activeLine-1, 0, len(t.lines)-1)
  113. case KeyArrowDown:
  114. t.activeLine = bounded(t.activeLine+1, 0, len(t.lines)-1)
  115. case KeyEnter:
  116. if t.Listener != nil && t.activeLine >= 0 && t.activeLine < len(t.lines) {
  117. t.Listener(ui, t, t.lines[t.activeLine].Item)
  118. }
  119. }
  120. ui.Refresh()
  121. }
  122. func (t *Tree) CharacterEvent(ui *Ui, ch rune) {
  123. }