My mirror of the Barnard terminal client for Mumble.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

149 lignes
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, 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. }