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