...
1 package cview
2
3 import "sync"
4
5
6
7
8 type Focusable interface {
9 HasFocus() bool
10 }
11
12 type focusElement struct {
13 primitive Primitive
14 disabled bool
15 }
16
17
18 type FocusManager struct {
19 elements []*focusElement
20
21 focused int
22 wrapAround bool
23
24 setFocus func(p Primitive)
25
26 sync.RWMutex
27 }
28
29
30 func NewFocusManager(setFocus func(p Primitive)) *FocusManager {
31 return &FocusManager{setFocus: setFocus}
32 }
33
34
35
36
37
38
39 func (f *FocusManager) SetWrapAround(wrapAround bool) {
40 f.Lock()
41 defer f.Unlock()
42
43 f.wrapAround = wrapAround
44 }
45
46
47 func (f *FocusManager) Add(p ...Primitive) {
48 f.Lock()
49 defer f.Unlock()
50
51 for _, primitive := range p {
52 f.elements = append(f.elements, &focusElement{primitive: primitive})
53 }
54 }
55
56
57 func (f *FocusManager) AddAt(index int, p Primitive) {
58 f.Lock()
59 defer f.Unlock()
60
61 if index < 0 || index > len(f.elements) {
62 panic("index out of range")
63 }
64
65 element := &focusElement{primitive: p}
66
67 if index == len(f.elements) {
68 f.elements = append(f.elements, element)
69 return
70 }
71 f.elements = append(f.elements[:index+1], f.elements[index:]...)
72 f.elements[index] = element
73 }
74
75
76 func (f *FocusManager) Focus(p Primitive) {
77 f.Lock()
78 defer f.Unlock()
79
80 for i, element := range f.elements {
81 if p == element.primitive && !element.disabled {
82 f.focused = i
83 break
84 }
85 }
86 f.setFocus(f.elements[f.focused].primitive)
87 }
88
89
90 func (f *FocusManager) FocusPrevious() {
91 f.Lock()
92 defer f.Unlock()
93
94 f.focused--
95 f.updateFocusIndex(true)
96 f.setFocus(f.elements[f.focused].primitive)
97 }
98
99
100 func (f *FocusManager) FocusNext() {
101 f.Lock()
102 defer f.Unlock()
103
104 f.focused++
105 f.updateFocusIndex(false)
106 f.setFocus(f.elements[f.focused].primitive)
107 }
108
109
110 func (f *FocusManager) FocusAt(index int) {
111 f.Lock()
112 defer f.Unlock()
113
114 f.focused = index
115 f.setFocus(f.elements[f.focused].primitive)
116 }
117
118
119 func (f *FocusManager) GetFocusIndex() int {
120 f.Lock()
121 defer f.Unlock()
122
123 return f.focused
124 }
125
126
127 func (f *FocusManager) GetFocusedPrimitive() Primitive {
128 f.Lock()
129 defer f.Unlock()
130
131 return f.elements[f.focused].primitive
132 }
133
134 func (f *FocusManager) updateFocusIndex(decreasing bool) {
135 for i := 0; i < len(f.elements); i++ {
136 if f.focused < 0 {
137 if f.wrapAround {
138 f.focused = len(f.elements) - 1
139 } else {
140 f.focused = 0
141 }
142 } else if f.focused >= len(f.elements) {
143 if f.wrapAround {
144 f.focused = 0
145 } else {
146 f.focused = len(f.elements) - 1
147 }
148 }
149
150 item := f.elements[f.focused]
151 if !item.disabled {
152 break
153 }
154
155 if decreasing {
156 f.focused--
157 } else {
158 f.focused++
159 }
160 }
161 }
162
163
164 func (f *FocusManager) Transform(tr Transformation) {
165 var decreasing bool
166 switch tr {
167 case TransformFirstItem:
168 f.focused = 0
169 decreasing = true
170 case TransformLastItem:
171 f.focused = len(f.elements) - 1
172 case TransformPreviousItem:
173 f.focused--
174 decreasing = true
175 case TransformNextItem:
176 f.focused++
177 }
178 f.updateFocusIndex(decreasing)
179 }
180
View as plain text