1 package tview
2
3 import (
4 "strings"
5
6 "github.com/gdamore/tcell/v2"
7 "github.com/rivo/uniseg"
8 )
9
10
11
12
13
14 type Checkbox struct {
15 *Box
16
17
18 disabled bool
19
20
21 checked bool
22
23
24 label string
25
26
27
28 labelWidth int
29
30
31 labelColor tcell.Color
32
33
34 fieldBackgroundColor tcell.Color
35
36
37 fieldTextColor tcell.Color
38
39
40 checkedString string
41
42
43
44 changed func(checked bool)
45
46
47
48
49 done func(tcell.Key)
50
51
52
53 finished func(tcell.Key)
54 }
55
56
57 func NewCheckbox() *Checkbox {
58 return &Checkbox{
59 Box: NewBox(),
60 labelColor: Styles.SecondaryTextColor,
61 fieldBackgroundColor: Styles.ContrastBackgroundColor,
62 fieldTextColor: Styles.PrimaryTextColor,
63 checkedString: "X",
64 }
65 }
66
67
68
69 func (c *Checkbox) SetChecked(checked bool) *Checkbox {
70 if c.checked != checked {
71 if c.changed != nil {
72 c.changed(checked)
73 }
74 c.checked = checked
75 }
76 return c
77 }
78
79
80 func (c *Checkbox) IsChecked() bool {
81 return c.checked
82 }
83
84
85 func (c *Checkbox) SetLabel(label string) *Checkbox {
86 c.label = label
87 return c
88 }
89
90
91 func (c *Checkbox) GetLabel() string {
92 return c.label
93 }
94
95
96
97 func (c *Checkbox) SetLabelWidth(width int) *Checkbox {
98 c.labelWidth = width
99 return c
100 }
101
102
103 func (c *Checkbox) SetLabelColor(color tcell.Color) *Checkbox {
104 c.labelColor = color
105 return c
106 }
107
108
109 func (c *Checkbox) SetFieldBackgroundColor(color tcell.Color) *Checkbox {
110 c.fieldBackgroundColor = color
111 return c
112 }
113
114
115 func (c *Checkbox) SetFieldTextColor(color tcell.Color) *Checkbox {
116 c.fieldTextColor = color
117 return c
118 }
119
120
121
122 func (c *Checkbox) SetCheckedString(checked string) *Checkbox {
123 c.checkedString = checked
124 return c
125 }
126
127
128 func (c *Checkbox) SetFormAttributes(labelWidth int, labelColor, bgColor, fieldTextColor, fieldBgColor tcell.Color) FormItem {
129 c.labelWidth = labelWidth
130 c.labelColor = labelColor
131 c.backgroundColor = bgColor
132 c.fieldTextColor = fieldTextColor
133 c.fieldBackgroundColor = fieldBgColor
134 return c
135 }
136
137
138 func (c *Checkbox) GetFieldWidth() int {
139 return 1
140 }
141
142
143 func (c *Checkbox) GetFieldHeight() int {
144 return 1
145 }
146
147
148 func (c *Checkbox) SetDisabled(disabled bool) FormItem {
149 c.disabled = disabled
150 if c.finished != nil {
151 c.finished(-1)
152 }
153 return c
154 }
155
156
157
158 func (c *Checkbox) SetChangedFunc(handler func(checked bool)) *Checkbox {
159 c.changed = handler
160 return c
161 }
162
163
164
165
166
167
168
169
170 func (c *Checkbox) SetDoneFunc(handler func(key tcell.Key)) *Checkbox {
171 c.done = handler
172 return c
173 }
174
175
176 func (c *Checkbox) SetFinishedFunc(handler func(key tcell.Key)) FormItem {
177 c.finished = handler
178 return c
179 }
180
181
182 func (c *Checkbox) Focus(delegate func(p Primitive)) {
183
184
185 if c.finished != nil && c.disabled {
186 c.finished(-1)
187 return
188 }
189
190 c.Box.Focus(delegate)
191 }
192
193
194 func (c *Checkbox) Draw(screen tcell.Screen) {
195 c.Box.DrawForSubclass(screen, c)
196
197
198 x, y, width, height := c.GetInnerRect()
199 rightLimit := x + width
200 if height < 1 || rightLimit <= x {
201 return
202 }
203
204
205 if c.labelWidth > 0 {
206 labelWidth := c.labelWidth
207 if labelWidth > width {
208 labelWidth = width
209 }
210 Print(screen, c.label, x, y, labelWidth, AlignLeft, c.labelColor)
211 x += labelWidth
212 } else {
213 _, drawnWidth := Print(screen, c.label, x, y, width, AlignLeft, c.labelColor)
214 x += drawnWidth
215 }
216
217
218 fieldBackgroundColor := c.fieldBackgroundColor
219 if c.disabled {
220 fieldBackgroundColor = c.backgroundColor
221 }
222 fieldStyle := tcell.StyleDefault.Background(fieldBackgroundColor).Foreground(c.fieldTextColor)
223 if c.HasFocus() {
224 fieldStyle = fieldStyle.Background(c.fieldTextColor).Foreground(fieldBackgroundColor)
225 }
226 checkboxWidth := uniseg.StringWidth(c.checkedString)
227 checkedString := c.checkedString
228 if !c.checked {
229 checkedString = strings.Repeat(" ", checkboxWidth)
230 }
231 printWithStyle(screen, checkedString, x, y, 0, checkboxWidth, AlignLeft, fieldStyle, false)
232 }
233
234
235 func (c *Checkbox) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
236 return c.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
237 if c.disabled {
238 return
239 }
240
241
242 switch key := event.Key(); key {
243 case tcell.KeyRune, tcell.KeyEnter:
244 if key == tcell.KeyRune && event.Rune() != ' ' {
245 break
246 }
247 c.checked = !c.checked
248 if c.changed != nil {
249 c.changed(c.checked)
250 }
251 case tcell.KeyTab, tcell.KeyBacktab, tcell.KeyEscape:
252 if c.done != nil {
253 c.done(key)
254 }
255 if c.finished != nil {
256 c.finished(key)
257 }
258 }
259 })
260 }
261
262
263 func (c *Checkbox) MouseHandler() func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
264 return c.WrapMouseHandler(func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
265 if c.disabled {
266 return false, nil
267 }
268
269 x, y := event.Position()
270 _, rectY, _, _ := c.GetInnerRect()
271 if !c.InRect(x, y) {
272 return false, nil
273 }
274
275
276 if y == rectY {
277 if action == MouseLeftDown {
278 setFocus(c)
279 consumed = true
280 } else if action == MouseLeftClick {
281 c.checked = !c.checked
282 if c.changed != nil {
283 c.changed(c.checked)
284 }
285 consumed = true
286 }
287 }
288
289 return
290 })
291 }
292
View as plain text