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.

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