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.

tree.go 2.7 KiB

il y a 10 ans
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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. }