]> git.lizzy.rs Git - micro.git/blob - cmd/micro/split_tree.go
e34c37f1335865b1d146557afd922c1a61da94b2
[micro.git] / cmd / micro / split_tree.go
1 package main
2
3 // SplitType specifies whether a split is horizontal or vertical
4 type SplitType bool
5
6 const (
7         // VerticalSplit type
8         VerticalSplit = false
9         // HorizontalSplit type
10         HorizontalSplit = true
11 )
12
13 // A Node on the split tree
14 type Node interface {
15         VSplit(buf *Buffer, splitIndex int)
16         HSplit(buf *Buffer, splitIndex int)
17         String() string
18 }
19
20 // A LeafNode is an actual split so it contains a view
21 type LeafNode struct {
22         view *View
23
24         parent *SplitTree
25 }
26
27 // NewLeafNode returns a new leaf node containing the given view
28 func NewLeafNode(v *View, parent *SplitTree) *LeafNode {
29         n := new(LeafNode)
30         n.view = v
31         n.view.splitNode = n
32         n.parent = parent
33         return n
34 }
35
36 // A SplitTree is a Node itself and it contains other nodes
37 type SplitTree struct {
38         kind SplitType
39
40         parent   *SplitTree
41         children []Node
42
43         x int
44         y int
45
46         width      int
47         height     int
48         lockWidth  bool
49         lockHeight bool
50
51         tabNum int
52 }
53
54 // VSplit creates a vertical split
55 func (l *LeafNode) VSplit(buf *Buffer, splitIndex int) {
56         if splitIndex < 0 {
57                 splitIndex = 0
58         }
59
60         tab := tabs[l.parent.tabNum]
61         if l.parent.kind == VerticalSplit {
62                 if splitIndex > len(l.parent.children) {
63                         splitIndex = len(l.parent.children)
64                 }
65
66                 newView := NewView(buf)
67                 newView.TabNum = l.parent.tabNum
68
69                 l.parent.children = append(l.parent.children, nil)
70                 copy(l.parent.children[splitIndex+1:], l.parent.children[splitIndex:])
71                 l.parent.children[splitIndex] = NewLeafNode(newView, l.parent)
72
73                 tab.Views = append(tab.Views, nil)
74                 copy(tab.Views[splitIndex+1:], tab.Views[splitIndex:])
75                 tab.Views[splitIndex] = newView
76
77                 tab.CurView = splitIndex
78         } else {
79                 if splitIndex > 1 {
80                         splitIndex = 1
81                 }
82
83                 s := new(SplitTree)
84                 s.kind = VerticalSplit
85                 s.parent = l.parent
86                 s.tabNum = l.parent.tabNum
87                 newView := NewView(buf)
88                 newView.TabNum = l.parent.tabNum
89                 if splitIndex == 1 {
90                         s.children = []Node{l, NewLeafNode(newView, s)}
91                 } else {
92                         s.children = []Node{NewLeafNode(newView, s), l}
93                 }
94                 l.parent.children[search(l.parent.children, l)] = s
95                 l.parent = s
96
97                 tab.Views = append(tab.Views, nil)
98                 copy(tab.Views[splitIndex+1:], tab.Views[splitIndex:])
99                 tab.Views[splitIndex] = newView
100
101                 tab.CurView = splitIndex
102         }
103
104         tab.Resize()
105 }
106
107 // HSplit creates a horizontal split
108 func (l *LeafNode) HSplit(buf *Buffer, splitIndex int) {
109         if splitIndex < 0 {
110                 splitIndex = 0
111         }
112
113         tab := tabs[l.parent.tabNum]
114         if l.parent.kind == HorizontalSplit {
115                 if splitIndex > len(l.parent.children) {
116                         splitIndex = len(l.parent.children)
117                 }
118
119                 newView := NewView(buf)
120                 newView.TabNum = l.parent.tabNum
121
122                 l.parent.children = append(l.parent.children, nil)
123                 copy(l.parent.children[splitIndex+1:], l.parent.children[splitIndex:])
124                 l.parent.children[splitIndex] = NewLeafNode(newView, l.parent)
125
126                 tab.Views = append(tab.Views, nil)
127                 copy(tab.Views[splitIndex+1:], tab.Views[splitIndex:])
128                 tab.Views[splitIndex] = newView
129
130                 tab.CurView = splitIndex
131         } else {
132                 if splitIndex > 1 {
133                         splitIndex = 1
134                 }
135
136                 s := new(SplitTree)
137                 s.kind = HorizontalSplit
138                 s.tabNum = l.parent.tabNum
139                 s.parent = l.parent
140                 newView := NewView(buf)
141                 newView.TabNum = l.parent.tabNum
142                 newView.Num = len(tab.Views)
143                 if splitIndex == 1 {
144                         s.children = []Node{l, NewLeafNode(newView, s)}
145                 } else {
146                         s.children = []Node{NewLeafNode(newView, s), l}
147                 }
148                 l.parent.children[search(l.parent.children, l)] = s
149                 l.parent = s
150
151                 tab.Views = append(tab.Views, nil)
152                 copy(tab.Views[splitIndex+1:], tab.Views[splitIndex:])
153                 tab.Views[splitIndex] = newView
154
155                 tab.CurView = splitIndex
156         }
157
158         tab.Resize()
159 }
160
161 // Delete deletes a split
162 func (l *LeafNode) Delete() {
163         i := search(l.parent.children, l)
164
165         copy(l.parent.children[i:], l.parent.children[i+1:])
166         l.parent.children[len(l.parent.children)-1] = nil
167         l.parent.children = l.parent.children[:len(l.parent.children)-1]
168
169         tab := tabs[l.parent.tabNum]
170         j := findView(tab.Views, l.view)
171         copy(tab.Views[j:], tab.Views[j+1:])
172         tab.Views[len(tab.Views)-1] = nil // or the zero value of T
173         tab.Views = tab.Views[:len(tab.Views)-1]
174
175         for i, v := range tab.Views {
176                 v.Num = i
177         }
178         if tab.CurView > 0 {
179                 tab.CurView--
180         }
181 }
182
183 // Cleanup rearranges all the parents after a split has been deleted
184 func (s *SplitTree) Cleanup() {
185         for i, node := range s.children {
186                 if n, ok := node.(*SplitTree); ok {
187                         if len(n.children) == 1 {
188                                 if child, ok := n.children[0].(*LeafNode); ok {
189                                         s.children[i] = child
190                                         child.parent = s
191                                         continue
192                                 }
193                         }
194                         n.Cleanup()
195                 }
196         }
197 }
198
199 // ResizeSplits resizes all the splits correctly
200 func (s *SplitTree) ResizeSplits() {
201         lockedWidth := 0
202         lockedHeight := 0
203         lockedChildren := 0
204         for _, node := range s.children {
205                 if n, ok := node.(*LeafNode); ok {
206                         if s.kind == VerticalSplit {
207                                 if n.view.LockWidth {
208                                         lockedWidth += n.view.Width
209                                         lockedChildren++
210                                 }
211                         } else {
212                                 if n.view.LockHeight {
213                                         lockedHeight += n.view.Height
214                                         lockedChildren++
215                                 }
216                         }
217                 } else if n, ok := node.(*SplitTree); ok {
218                         if s.kind == VerticalSplit {
219                                 if n.lockWidth {
220                                         lockedWidth += n.width
221                                         lockedChildren++
222                                 }
223                         } else {
224                                 if n.lockHeight {
225                                         lockedHeight += n.height
226                                         lockedChildren++
227                                 }
228                         }
229                 }
230         }
231         x, y := 0, 0
232         for _, node := range s.children {
233                 if n, ok := node.(*LeafNode); ok {
234                         if s.kind == VerticalSplit {
235                                 if !n.view.LockWidth {
236                                         n.view.Width = (s.width - lockedWidth) / (len(s.children) - lockedChildren)
237                                 }
238                                 n.view.Height = s.height
239
240                                 n.view.x = s.x + x
241                                 n.view.y = s.y
242                                 x += n.view.Width
243                         } else {
244                                 if !n.view.LockHeight {
245                                         n.view.Height = (s.height - lockedHeight) / (len(s.children) - lockedChildren)
246                                 }
247                                 n.view.Width = s.width
248
249                                 n.view.y = s.y + y
250                                 n.view.x = s.x
251                                 y += n.view.Height
252                         }
253                         if n.view.Buf.Settings["statusline"].(bool) {
254                                 n.view.Height--
255                         }
256
257                         n.view.ToggleTabbar()
258                 } else if n, ok := node.(*SplitTree); ok {
259                         if s.kind == VerticalSplit {
260                                 if !n.lockWidth {
261                                         n.width = (s.width - lockedWidth) / (len(s.children) - lockedChildren)
262                                 }
263                                 n.height = s.height
264
265                                 n.x = s.x + x
266                                 n.y = s.y
267                                 x += n.width
268                         } else {
269                                 if !n.lockHeight {
270                                         n.height = (s.height - lockedHeight) / (len(s.children) - lockedChildren)
271                                 }
272                                 n.width = s.width
273
274                                 n.y = s.y + y
275                                 n.x = s.x
276                                 y += n.height
277                         }
278                         n.ResizeSplits()
279                 }
280         }
281 }
282
283 func (l *LeafNode) String() string {
284         return l.view.Buf.GetName()
285 }
286
287 func search(haystack []Node, needle Node) int {
288         for i, x := range haystack {
289                 if x == needle {
290                         return i
291                 }
292         }
293         return 0
294 }
295
296 func findView(haystack []*View, needle *View) int {
297         for i, x := range haystack {
298                 if x == needle {
299                         return i
300                 }
301         }
302         return 0
303 }
304
305 // VSplit is here just to make SplitTree fit the Node interface
306 func (s *SplitTree) VSplit(buf *Buffer, splitIndex int) {}
307
308 // HSplit is here just to make SplitTree fit the Node interface
309 func (s *SplitTree) HSplit(buf *Buffer, splitIndex int) {}
310
311 func (s *SplitTree) String() string {
312         str := "["
313         for _, child := range s.children {
314                 str += child.String() + ", "
315         }
316         return str + "]"
317 }