1 package cview
2
3 import (
4 "sync"
5
6 "github.com/gdamore/tcell/v2"
7 )
8
9
10 type panel struct {
11 Name string
12 Item Primitive
13 Resize bool
14 Visible bool
15 }
16
17
18
19
20 type Panels struct {
21 *Box
22
23
24 panels []*panel
25
26
27
28 setFocus func(p Primitive)
29
30
31
32 changed func()
33
34 sync.RWMutex
35 }
36
37
38 func NewPanels() *Panels {
39 p := &Panels{
40 Box: NewBox(),
41 }
42 p.focus = p
43 return p
44 }
45
46
47
48 func (p *Panels) SetChangedFunc(handler func()) {
49 p.Lock()
50 defer p.Unlock()
51
52 p.changed = handler
53 }
54
55
56 func (p *Panels) GetPanelCount() int {
57 p.RLock()
58 defer p.RUnlock()
59
60 return len(p.panels)
61 }
62
63
64
65
66
67
68
69
70
71
72 func (p *Panels) AddPanel(name string, item Primitive, resize, visible bool) {
73 hasFocus := p.HasFocus()
74
75 p.Lock()
76 defer p.Unlock()
77
78 var added bool
79 for i, pg := range p.panels {
80 if pg.Name == name {
81 p.panels[i] = &panel{Item: item, Name: name, Resize: resize, Visible: visible}
82 added = true
83 break
84 }
85 }
86 if !added {
87 p.panels = append(p.panels, &panel{Item: item, Name: name, Resize: resize, Visible: visible})
88 }
89 if p.changed != nil {
90 p.Unlock()
91 p.changed()
92 p.Lock()
93 }
94 if hasFocus {
95 p.Unlock()
96 p.Focus(p.setFocus)
97 p.Lock()
98 }
99 }
100
101
102
103 func (p *Panels) RemovePanel(name string) {
104 hasFocus := p.HasFocus()
105
106 p.Lock()
107 defer p.Unlock()
108
109 var isVisible bool
110 for index, panel := range p.panels {
111 if panel.Name == name {
112 isVisible = panel.Visible
113 p.panels = append(p.panels[:index], p.panels[index+1:]...)
114 if panel.Visible && p.changed != nil {
115 p.Unlock()
116 p.changed()
117 p.Lock()
118 }
119 break
120 }
121 }
122 if isVisible {
123 for index, panel := range p.panels {
124 if index < len(p.panels)-1 {
125 if panel.Visible {
126 break
127 }
128 } else {
129 panel.Visible = true
130 }
131 }
132 }
133 if hasFocus {
134 p.Unlock()
135 p.Focus(p.setFocus)
136 p.Lock()
137 }
138 }
139
140
141 func (p *Panels) HasPanel(name string) bool {
142 p.RLock()
143 defer p.RUnlock()
144
145 for _, panel := range p.panels {
146 if panel.Name == name {
147 return true
148 }
149 }
150 return false
151 }
152
153
154
155 func (p *Panels) ShowPanel(name string) {
156 hasFocus := p.HasFocus()
157
158 p.Lock()
159 defer p.Unlock()
160
161 for _, panel := range p.panels {
162 if panel.Name == name {
163 panel.Visible = true
164 if p.changed != nil {
165 p.Unlock()
166 p.changed()
167 p.Lock()
168 }
169 break
170 }
171 }
172 if hasFocus {
173 p.Unlock()
174 p.Focus(p.setFocus)
175 p.Lock()
176 }
177 }
178
179
180 func (p *Panels) HidePanel(name string) {
181 hasFocus := p.HasFocus()
182
183 p.Lock()
184 defer p.Unlock()
185
186 for _, panel := range p.panels {
187 if panel.Name == name {
188 panel.Visible = false
189 if p.changed != nil {
190 p.Unlock()
191 p.changed()
192 p.Lock()
193 }
194 break
195 }
196 }
197 if hasFocus {
198 p.Unlock()
199 p.Focus(p.setFocus)
200 p.Lock()
201 }
202 }
203
204
205
206 func (p *Panels) SetCurrentPanel(name string) {
207 hasFocus := p.HasFocus()
208
209 p.Lock()
210 defer p.Unlock()
211
212 for _, panel := range p.panels {
213 if panel.Name == name {
214 panel.Visible = true
215 } else {
216 panel.Visible = false
217 }
218 }
219 if p.changed != nil {
220 p.Unlock()
221 p.changed()
222 p.Lock()
223 }
224 if hasFocus {
225 p.Unlock()
226 p.Focus(p.setFocus)
227 p.Lock()
228 }
229 }
230
231
232
233
234 func (p *Panels) SendToFront(name string) {
235 hasFocus := p.HasFocus()
236
237 p.Lock()
238 defer p.Unlock()
239
240 for index, panel := range p.panels {
241 if panel.Name == name {
242 if index < len(p.panels)-1 {
243 p.panels = append(append(p.panels[:index], p.panels[index+1:]...), panel)
244 }
245 if panel.Visible && p.changed != nil {
246 p.Unlock()
247 p.changed()
248 p.Lock()
249 }
250 break
251 }
252 }
253 if hasFocus {
254 p.Unlock()
255 p.Focus(p.setFocus)
256 p.Lock()
257 }
258 }
259
260
261
262
263 func (p *Panels) SendToBack(name string) {
264 hasFocus := p.HasFocus()
265
266 p.Lock()
267 defer p.Unlock()
268
269 for index, pg := range p.panels {
270 if pg.Name == name {
271 if index > 0 {
272 p.panels = append(append([]*panel{pg}, p.panels[:index]...), p.panels[index+1:]...)
273 }
274 if pg.Visible && p.changed != nil {
275 p.Unlock()
276 p.changed()
277 p.Lock()
278 }
279 break
280 }
281 }
282 if hasFocus {
283 p.Unlock()
284 p.Focus(p.setFocus)
285 p.Lock()
286 }
287 }
288
289
290
291 func (p *Panels) GetFrontPanel() (name string, item Primitive) {
292 p.RLock()
293 defer p.RUnlock()
294
295 for index := len(p.panels) - 1; index >= 0; index-- {
296 if p.panels[index].Visible {
297 return p.panels[index].Name, p.panels[index].Item
298 }
299 }
300 return
301 }
302
303
304 func (p *Panels) HasFocus() bool {
305 p.RLock()
306 defer p.RUnlock()
307
308 for _, panel := range p.panels {
309 if panel.Item.GetFocusable().HasFocus() {
310 return true
311 }
312 }
313 return false
314 }
315
316
317 func (p *Panels) Focus(delegate func(p Primitive)) {
318 p.Lock()
319 defer p.Unlock()
320
321 if delegate == nil {
322 return
323 }
324 p.setFocus = delegate
325 var topItem Primitive
326 for _, panel := range p.panels {
327 if panel.Visible {
328 topItem = panel.Item
329 }
330 }
331 if topItem != nil {
332 p.Unlock()
333 delegate(topItem)
334 p.Lock()
335 }
336 }
337
338
339 func (p *Panels) Draw(screen tcell.Screen) {
340 if !p.GetVisible() {
341 return
342 }
343
344 p.Box.Draw(screen)
345
346 p.Lock()
347 defer p.Unlock()
348
349 x, y, width, height := p.GetInnerRect()
350
351 for _, panel := range p.panels {
352 if !panel.Visible {
353 continue
354 }
355 if panel.Resize {
356 panel.Item.SetRect(x, y, width, height)
357 }
358 panel.Item.Draw(screen)
359 }
360 }
361
362
363 func (p *Panels) MouseHandler() func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
364 return p.WrapMouseHandler(func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
365 if !p.InRect(event.Position()) {
366 return false, nil
367 }
368
369
370 for index := len(p.panels) - 1; index >= 0; index-- {
371 panel := p.panels[index]
372 if panel.Visible {
373 consumed, capture = panel.Item.MouseHandler()(action, event, setFocus)
374 if consumed {
375 return
376 }
377 }
378 }
379
380 return
381 })
382 }
383
384
385 type page = panel
386
387
388
389
390
391 type Pages struct {
392 *Panels
393 }
394
395
396
397
398
399 func NewPages() *Pages {
400 return &Pages{NewPanels()}
401 }
402
403
404 func (p *Pages) GetPageCount() int {
405 return p.GetPanelCount()
406 }
407
408
409 func (p *Pages) AddPage(name string, item Primitive, resize, visible bool) {
410 p.AddPanel(name, item, resize, visible)
411 }
412
413
414 func (p *Pages) AddAndSwitchToPage(name string, item Primitive, resize bool) {
415 p.AddPanel(name, item, resize, true)
416 p.SetCurrentPanel(name)
417 }
418
419
420 func (p *Pages) RemovePage(name string) {
421 p.RemovePanel(name)
422 }
423
424
425 func (p *Pages) HasPage(name string) bool {
426 return p.HasPanel(name)
427 }
428
429
430 func (p *Pages) ShowPage(name string) {
431 p.ShowPanel(name)
432 }
433
434
435 func (p *Pages) HidePage(name string) {
436 p.HidePanel(name)
437 }
438
439
440
441 func (p *Pages) SwitchToPage(name string) {
442 p.SetCurrentPanel(name)
443 }
444
445
446 func (p *Pages) GetFrontPage() (name string, item Primitive) {
447 return p.GetFrontPanel()
448 }
449
View as plain text