My mirror of the Barnard terminal client for Mumble.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

149 行
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. }