]> git.0d.be Git - barnard.git/blob - uiterm/tree.go
uiterm: prefix View methods with ui
[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(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 TreeFunc func(item TreeItem) []TreeItem
21 type TreeListener func(ui *Ui, tree *Tree, item TreeItem)
22
23 type Tree struct {
24         Fg        Attribute
25         Bg        Attribute
26         Generator TreeFunc
27         Listener  TreeListener
28
29         lines          []renderedTreeItem
30         activeLine     int
31
32         ui *Ui
33         active         bool
34         x0, y0, x1, y1 int
35 }
36
37 func bounded(i, lower, upper int) int {
38         if i < lower {
39                 return lower
40         }
41         if i > upper {
42                 return upper
43         }
44         return i
45 }
46
47 func (t *Tree) uiInitialize(ui *Ui) {
48         t.ui = ui
49 }
50
51 func (t *Tree) uiSetActive(active bool) {
52         t.active = active
53 }
54
55 func (t *Tree) uiSetBounds(x0, y0, x1, y1 int) {
56         t.x0 = x0
57         t.y0 = y0
58         t.x1 = x1
59         t.y1 = y1
60 }
61
62 func (t *Tree) Rebuild() {
63         if t.Generator == nil {
64                 t.lines = []renderedTreeItem{}
65                 return
66         }
67
68         lines := []renderedTreeItem{}
69         for _, item := range t.Generator(nil) {
70                 children := t.rebuild_rec(item, 0)
71                 if children != nil {
72                         lines = append(lines, children...)
73                 }
74         }
75         t.lines = lines
76         t.activeLine = bounded(t.activeLine, 0, len(t.lines)-1)
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         if t.lines == nil {
100                 t.Rebuild()
101         }
102
103         line := 0
104         for y := t.y0; y < t.y1; y++ {
105                 var reader *strings.Reader
106                 var item TreeItem
107                 level := 0
108                 if line < len(t.lines) {
109                         item = t.lines[line].Item
110                         level = t.lines[line].Level
111                         reader = strings.NewReader(item.String())
112                 }
113                 for x := t.x0; x < t.x1; x++ {
114                         var chr rune = ' '
115                         fg := t.Fg
116                         bg := t.Bg
117                         dx := x - t.x0
118                         dy := y - t.y0
119                         if reader != nil && level*2 <= dx {
120                                 if ch, _, err := reader.ReadRune(); err == nil {
121                                         chr = ch
122                                         fg, bg = item.TreeItemStyle(t.active && t.activeLine == dy)
123                                 }
124                         }
125                         termbox.SetCell(x, y, chr, termbox.Attribute(fg), termbox.Attribute(bg))
126                 }
127                 line++
128         }
129 }
130
131 func (t *Tree) uiKeyEvent(mod Modifier, key Key) {
132         switch key {
133         case KeyArrowUp:
134                 t.activeLine = bounded(t.activeLine-1, 0, len(t.lines)-1)
135         case KeyArrowDown:
136                 t.activeLine = bounded(t.activeLine+1, 0, len(t.lines)-1)
137         case KeyEnter:
138                 if t.Listener != nil && t.activeLine >= 0 && t.activeLine < len(t.lines) {
139                         t.Listener(t.ui, t, t.lines[t.activeLine].Item)
140                 }
141         }
142         t.ui.Refresh()
143 }
144
145 func (t *Tree) uiCharacterEvent(ch rune) {
146 }