makepad_widgets/
check_box.rs

1use {
2    crate::{
3        makepad_derive_widget::*,
4        makepad_draw::*,
5        widget::*,
6    }
7};
8
9live_design!{
10    link widgets;
11    use link::theme::*;
12    use makepad_draw::shader::std::*;
13    
14    pub DrawCheckBox = {{DrawCheckBox}} {}
15    pub CheckBoxBase = {{CheckBox}} {}
16    
17    pub CheckBox = <CheckBoxBase> {
18        width: Fit, height: Fit,
19        padding: <THEME_MSPACE_2> {}
20        align: { x: 0., y: 0. }
21        
22        label_walk: {
23            width: Fit, height: Fit,
24            margin: <THEME_MSPACE_H_1> { left: 13. }
25        }
26        
27        draw_bg: {
28            instance disabled: 0.0,
29            instance down: 0.0,
30
31            uniform size: 14.0;
32
33            uniform border_size: (THEME_BEVELING)
34            uniform border_radius: (THEME_CORNER_RADIUS)
35
36            uniform color_dither: 1.0
37
38            uniform color: (THEME_COLOR_INSET)
39            uniform color_hover: (THEME_COLOR_INSET_HOVER)
40            uniform color_down: (THEME_COLOR_INSET_DOWN)
41            uniform color_active: (THEME_COLOR_INSET_ACTIVE)
42            uniform color_focus: (THEME_COLOR_INSET_FOCUS)
43            uniform color_disabled: (THEME_COLOR_INSET_DISABLED)
44
45            uniform border_color_1: (THEME_COLOR_BEVEL_INSET_2)
46            uniform border_color_1_hover: (THEME_COLOR_BEVEL_INSET_2_HOVER)
47            uniform border_color_1_down: (THEME_COLOR_BEVEL_INSET_2_DOWN)
48            uniform border_color_1_active: (THEME_COLOR_BEVEL_INSET_2_ACTIVE)
49            uniform border_color_1_focus: (THEME_COLOR_BEVEL_INSET_2_FOCUS)
50            uniform border_color_1_disabled: (THEME_COLOR_BEVEL_INSET_2_DISABLED)
51
52            uniform border_color_2: (THEME_COLOR_BEVEL_INSET_1)
53            uniform border_color_2_hover: (THEME_COLOR_BEVEL_INSET_1_HOVER)
54            uniform border_color_2_down: (THEME_COLOR_BEVEL_INSET_1_DOWN)
55            uniform border_color_2_active: (THEME_COLOR_BEVEL_INSET_1_ACTIVE)
56            uniform border_color_2_focus: (THEME_COLOR_BEVEL_INSET_1_FOCUS)
57            uniform border_color_2_disabled: (THEME_COLOR_BEVEL_INSET_1_DISABLED)
58
59            uniform mark_size: 0.65
60            uniform mark_color: (THEME_COLOR_U_HIDDEN)
61            uniform mark_color_hover: (THEME_COLOR_U_HIDDEN)
62            uniform mark_color_down: (THEME_COLOR_U_HIDDEN)
63            uniform mark_color_active: (THEME_COLOR_MARK_ACTIVE)
64            uniform mark_color_active_hover: (THEME_COLOR_MARK_ACTIVE_HOVER)
65            uniform mark_color_focus: (THEME_COLOR_MARK_FOCUS)
66            uniform mark_color_disabled: (THEME_COLOR_MARK_DISABLED)
67
68            fn pixel(self) -> vec4 {
69                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
70                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
71
72                let sz_px = self.size;
73                let sz_inner_px = sz_px - self.border_size * 2.;
74                let shift_px = vec2(0, 0)
75                let center_px = vec2(
76                    sz_px * 0.5,
77                    self.rect_size.y * 0.5
78                )
79                
80                let offset_px = vec2(
81                    shift_px.x,
82                    shift_px.y + center_px.y - sz_px * 0.5
83                )
84
85                let offset_uv = vec2(
86                    offset_px.x / self.rect_size.x,
87                    offset_px.y / self.rect_size.y
88                )
89
90                let border_sz_uv = vec2(
91                    self.border_size / self.rect_size.x,
92                    self.border_size / self.rect_size.y
93                )
94
95                let scale_factor_border = vec2(
96                    self.rect_size.x / sz_px,
97                    self.rect_size.y / sz_px 
98                );
99
100                let gradient_border = vec2(
101                    (self.pos.x - offset_uv.x) * scale_factor_border.x + dither,
102                    (self.pos.y - offset_uv.y) * scale_factor_border.y + dither
103                )
104
105                let scale_factor_fill = vec2(
106                    self.rect_size.x / sz_inner_px,
107                    self.rect_size.y / sz_inner_px 
108                );
109
110                let gradient_fill = vec2(
111                    (self.pos.x - offset_uv.x) * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
112                    (self.pos.y - offset_uv.y) * scale_factor_fill.y - border_sz_uv.y * 2. + dither
113                )
114
115                match self.check_type {
116                    CheckType::Check => {
117
118                        // Draw background
119                        sdf.box(
120                            offset_px.x + self.border_size,
121                            offset_px.y + self.border_size,
122                            sz_px - self.border_size * 2.,
123                            sz_px - self.border_size * 2.,
124                            self.border_radius * 0.5
125                        );
126
127                        sdf.stroke_keep(
128                            mix(
129                                mix(
130                                    mix(
131                                        mix(
132                                            mix(self.border_color_1, self.border_color_2, gradient_border.y),
133                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
134                                            self.focus
135                                        ),
136                                        mix(
137                                            mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
138                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
139                                            self.focus
140                                        ),
141                                        self.active
142                                    ),
143                                    mix(
144                                        mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
145                                        mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
146                                        self.down
147                                    ),
148                                    self.hover
149                                ),
150                                mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
151                                self.disabled
152                            ), self.border_size
153                        )
154
155                        sdf.fill(
156                            mix(
157                                mix(
158                                    mix(
159                                        mix(
160                                            self.color,
161                                            self.color_focus,
162                                            self.focus
163                                        ),
164                                        mix(
165                                            self.color_active,
166                                            self.color_focus,
167                                            self.focus
168                                        ),
169                                        self.active
170                                    ),
171                                    mix(
172                                        self.color_hover,
173                                        self.color_down,
174                                        self.down
175                                    ),
176                                    self.hover
177                                ),
178                                self.color_disabled,
179                                self.disabled
180                            )
181                        )
182
183                        // Draw mark
184                        let mark_padding = 0.275 * self.size
185                        sdf.move_to(mark_padding, center_px.y);
186                        sdf.line_to(center_px.x, center_px.y + sz_px * 0.5 - mark_padding);
187                        sdf.line_to(sz_px - mark_padding, offset_px.y + mark_padding);
188
189                        sdf.stroke(
190                            mix(
191                                mix(
192                                    mix(self.mark_color, self.mark_color_hover, self.hover),
193                                    mix(self.mark_color_active, self.mark_color_active_hover, self.hover),
194                                    self.active
195                                ),
196                                self.mark_color_disabled,
197                                self.disabled
198                            ), self.size * 0.09
199                        );
200
201                    }
202
203                    // CheckType::Toggle => { }
204
205                    CheckType::None => {
206                        sdf.fill(THEME_COLOR_D_HIDDEN);
207                    }
208                }
209                return sdf.result
210            }
211        }
212            
213        draw_text: {
214            instance focus: 0.0
215            instance hover: 0.0
216            instance down: 0.0
217            instance active: 0.0
218            instance disabled: 0.0
219
220            uniform color: (THEME_COLOR_LABEL_OUTER)
221            uniform color_hover: (THEME_COLOR_LABEL_OUTER_HOVER)
222            uniform color_down: (THEME_COLOR_LABEL_OUTER_DOWN)
223            uniform color_focus: (THEME_COLOR_LABEL_OUTER_FOCUS)
224            uniform color_active: (THEME_COLOR_LABEL_OUTER_ACTIVE)
225            uniform color_disabled: (THEME_COLOR_LABEL_OUTER_DISABLED)
226
227            fn get_color(self) -> vec4 {
228                return
229                    mix(
230                        mix(
231                            mix(
232                                mix(self.color, self.color_active, self.active),
233                                self.color_focus,
234                                self.focus
235                            ),
236                            mix(
237                                self.color_hover,
238                                self.color_down,
239                                self.down
240                            ),
241                            self.hover
242                        ),
243                        self.color_disabled,
244                        self.disabled
245                    )
246            }
247            text_style: <THEME_FONT_REGULAR> {
248                font_size: (THEME_FONT_SIZE_P)
249            }
250        }
251            
252        draw_icon: {
253            instance active: 0.0
254            instance disabled: 0.0
255
256            uniform color: (THEME_COLOR_ICON)
257            uniform color_active: (THEME_COLOR_ICON_ACTIVE)
258            uniform color_disabled: (THEME_COLOR_ICON_DISABLED)
259
260            fn get_color(self) -> vec4 {
261                return
262                    mix(
263                        mix(
264                            self.color,
265                            self.color_active,
266                            self.active
267                        ),
268                        self.color_disabled,
269                        self.disabled
270                    )
271
272            }
273        }
274            
275        icon_walk: {
276            width: 14.0, height: Fit
277        }
278            
279        animator: {
280            disabled = {
281                default: off,
282                off = {
283                    from: {all: Forward {duration: 0.}}
284                    apply: {
285                        draw_bg: {disabled: 0.0}
286                        draw_text: {disabled: 0.0}
287                        draw_icon: {disabled: 0.0}
288                    }
289                }
290                on = {
291                    from: {all: Forward {duration: 0.2}}
292                    apply: {
293                        draw_bg: {disabled: 1.0}
294                        draw_text: {disabled: 1.0}
295                        draw_icon: {disabled: 1.0}
296                    }
297                }
298            }
299            hover = {
300                default: off
301                off = {
302                    from: {all: Forward {duration: 0.15}}
303                    apply: {
304                        draw_bg: {down: [{time: 0.0, value: 0.0}], hover: 0.0}
305                        draw_text: {down: [{time: 0.0, value: 0.0}], hover: 0.0}
306                    }
307                }
308                on = {
309                    from: {all: Snap}
310                    apply: {
311                        draw_bg: {down: [{time: 0.0, value: 0.0}], hover: 1.0}
312                        draw_text: {down: [{time: 0.0, value: 0.0}], hover: 1.0}
313                    }
314                }
315                down = {
316                    from: {all: Forward {duration: 0.2}}
317                    apply: {
318                        draw_bg: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
319                        draw_text: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
320                    }
321                }
322            }
323            focus = {
324                default: off
325                off = {
326                    from: {all: Snap}
327                    apply: {
328                        draw_bg: {focus: 0.0}
329                        draw_text: {focus: 0.0}
330                    }
331                }
332                on = {
333                    from: {all: Snap}
334                    apply: {
335                        draw_bg: {focus: 1.0}
336                        draw_text: {focus: 1.0}
337                    }
338                }
339            }
340            active = {
341                default: off
342                off = {
343                    from: {all: Forward {duration: 0.1}}
344                    apply: {
345                        draw_bg: {active: 0.0},
346                        draw_text: {active: 0.0},
347                        draw_icon: {active: 0.0},
348                    }
349                }
350                on = {
351                    from: {all: Forward {duration: 0.0}}
352                    apply: {
353                        draw_bg: {active: 1.0}
354                        draw_text: {active: 1.0}
355                        draw_icon: {active: 1.0},
356                    }
357                }
358            }
359        }
360    }
361
362    pub CheckBoxFlat = <CheckBox> {
363        draw_bg: {
364            color: (THEME_COLOR_INSET)
365            color_hover: (THEME_COLOR_INSET_HOVER)
366            color_down: (THEME_COLOR_INSET_DOWN)
367            color_active: (THEME_COLOR_INSET_ACTIVE)
368            color_focus: (THEME_COLOR_INSET_FOCUS)
369            color_disabled: (THEME_COLOR_INSET_DISABLED)
370
371            border_color_1: (THEME_COLOR_BEVEL)
372            border_color_1_hover: (THEME_COLOR_BEVEL_HOVER)
373            border_color_1_down: (THEME_COLOR_BEVEL_DOWN)
374            border_color_1_active: (THEME_COLOR_BEVEL_ACTIVE)
375            border_color_1_focus: (THEME_COLOR_BEVEL_FOCUS)
376            border_color_1_down: (THEME_COLOR_BEVEL_DISABLED)
377
378            border_color_2: (THEME_COLOR_BEVEL)
379            border_color_2_hover: (THEME_COLOR_BEVEL_HOVER)
380            border_color_2_down: (THEME_COLOR_BEVEL_DOWN)
381            border_color_2_active: (THEME_COLOR_BEVEL_ACTIVE)
382            border_color_2_focus: (THEME_COLOR_BEVEL_FOCUS)
383            border_color_2_down: (THEME_COLOR_BEVEL_DISABLED)
384        }
385
386    }
387
388    pub CheckBoxFlatter = <CheckBoxFlat> {
389        draw_bg: {
390            border_color_1: (THEME_COLOR_U_HIDDEN)
391            border_color_1_hover: (THEME_COLOR_U_HIDDEN)
392            border_color_1_down: (THEME_COLOR_U_HIDDEN)
393            border_color_1_active: (THEME_COLOR_U_HIDDEN)
394            border_color_1_focus: (THEME_COLOR_U_HIDDEN)
395            border_color_1_disabled: (THEME_COLOR_U_HIDDEN)
396
397            border_color_2: (THEME_COLOR_U_HIDDEN)
398            border_color_2_hover: (THEME_COLOR_U_HIDDEN)
399            border_color_2_down: (THEME_COLOR_U_HIDDEN)
400            border_color_2_active: (THEME_COLOR_U_HIDDEN)
401            border_color_2_focus: (THEME_COLOR_U_HIDDEN)
402            border_color_2_disabled: (THEME_COLOR_U_HIDDEN)
403        }
404
405    }
406
407    pub CheckBoxGradientY = <CheckBox> {
408        width: Fit, height: Fit,
409        padding: <THEME_MSPACE_2> {}
410        align: { x: 0., y: 0. }
411        
412        label_walk: {
413            width: Fit, height: Fit,
414            margin: <THEME_MSPACE_H_1> { left: 13. }
415        }
416        
417        draw_bg: {
418            instance disabled: 0.0,
419            instance down: 0.0,
420
421            uniform size: 15.0;
422
423            uniform border_size: (THEME_BEVELING)
424            uniform border_radius: (THEME_CORNER_RADIUS)
425
426            uniform color_dither: 1.0
427
428            uniform color_1: (THEME_COLOR_INSET_1)
429            uniform color_1_hover: (THEME_COLOR_INSET_1_HOVER)
430            uniform color_1_down: (THEME_COLOR_INSET_1_DOWN)
431            uniform color_1_active: (THEME_COLOR_INSET_1_ACTIVE)
432            uniform color_1_focus: (THEME_COLOR_INSET_1_FOCUS)
433            uniform color_1_disabled: (THEME_COLOR_INSET_1_DISABLED)
434
435            uniform color_2: (THEME_COLOR_INSET_2)
436            uniform color_2_hover: (THEME_COLOR_INSET_2_HOVER)
437            uniform color_2_down: (THEME_COLOR_INSET_2_DOWN)
438            uniform color_2_active: (THEME_COLOR_INSET_2_ACTIVE)
439            uniform color_2_focus: (THEME_COLOR_INSET_2_FOCUS)
440            uniform color_2_disabled: (THEME_COLOR_INSET_2_DISABLED)
441
442            uniform border_color_1: (THEME_COLOR_BEVEL_INSET_2)
443            uniform border_color_1_hover: (THEME_COLOR_BEVEL_INSET_2_HOVER)
444            uniform border_color_1_down: (THEME_COLOR_BEVEL_INSET_2_DOWN)
445            uniform border_color_1_active: (THEME_COLOR_BEVEL_INSET_2_ACTIVE)
446            uniform border_color_1_focus: (THEME_COLOR_BEVEL_INSET_2_FOCUS)
447            uniform border_color_1_disabled: (THEME_COLOR_BEVEL_INSET_2_DISABLED)
448
449            uniform border_color_2: (THEME_COLOR_BEVEL_INSET_1)
450            uniform border_color_2_hover: (THEME_COLOR_BEVEL_INSET_1_HOVER)
451            uniform border_color_2_down: (THEME_COLOR_BEVEL_INSET_1_DOWN)
452            uniform border_color_2_active: (THEME_COLOR_BEVEL_INSET_1_ACTIVE)
453            uniform border_color_2_focus: (THEME_COLOR_BEVEL_INSET_1_FOCUS)
454            uniform border_color_2_disabled: (THEME_COLOR_BEVEL_INSET_1_DISABLED)
455
456            uniform mark_size: 0.65
457            uniform mark_color: (THEME_COLOR_U_HIDDEN)
458            uniform mark_color_hover: (THEME_COLOR_U_HIDDEN)
459            uniform mark_color_down: (THEME_COLOR_U_HIDDEN)
460            uniform mark_color_active: (THEME_COLOR_MARK_ACTIVE)
461            uniform mark_color_active_hover: (THEME_COLOR_MARK_ACTIVE_HOVER)
462            uniform mark_color_focus: (THEME_COLOR_MARK_FOCUS)
463            uniform mark_color_disabled: (THEME_COLOR_MARK_DISABLED)
464
465            fn pixel(self) -> vec4 {
466                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
467                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
468
469                let sz_px = self.size;
470                let sz_inner_px = sz_px - self.border_size * 2.;
471                let shift_px = vec2(0, 0)
472                let center_px = vec2(
473                    sz_px * 0.5,
474                    self.rect_size.y * 0.5
475                )
476                
477                let offset_px = vec2(
478                    shift_px.x,
479                    shift_px.y + center_px.y - sz_px * 0.5
480                )
481
482                let offset_uv = vec2(
483                    offset_px.x / self.rect_size.x,
484                    offset_px.y / self.rect_size.y
485                )
486
487                let border_sz_uv = vec2(
488                    self.border_size / self.rect_size.x,
489                    self.border_size / self.rect_size.y
490                )
491
492                let scale_factor_border = vec2(
493                    self.rect_size.x / sz_px,
494                    self.rect_size.y / sz_px 
495                );
496
497                let gradient_border = vec2(
498                    (self.pos.x - offset_uv.x) * scale_factor_border.x + dither,
499                    (self.pos.y - offset_uv.y) * scale_factor_border.y + dither
500                )
501
502                let scale_factor_fill = vec2(
503                    self.rect_size.x / sz_inner_px,
504                    self.rect_size.y / sz_inner_px 
505                );
506
507                let gradient_fill = vec2(
508                    (self.pos.x - offset_uv.x) * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
509                    (self.pos.y - offset_uv.y) * scale_factor_fill.y - border_sz_uv.y * 2. + dither
510                )
511
512                match self.check_type {
513                    CheckType::Check => {
514
515                        // Draw background
516                        sdf.box(
517                            offset_px.x + self.border_size,
518                            offset_px.y + self.border_size,
519                            sz_px - self.border_size * 2.,
520                            sz_px - self.border_size * 2.,
521                            self.border_radius * 0.5
522                        );
523
524                        sdf.stroke_keep(
525                            mix(
526                                mix(
527                                    mix(
528                                        mix(
529                                            mix(self.border_color_1, self.border_color_2, gradient_border.y),
530                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
531                                            self.focus
532                                        ),
533                                        mix(
534                                            mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
535                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
536                                            self.focus
537                                        ),
538                                        self.active
539                                    ),
540                                    mix(
541                                        mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
542                                        mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
543                                        self.down
544                                    ),
545                                    self.hover
546                                ),
547                                mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
548                                self.disabled
549                            ), self.border_size
550                        )
551
552                        sdf.fill(
553                            mix(
554                                mix(
555                                    mix(
556                                        mix(
557                                            mix(self.color_1, self.color_2, gradient_fill.y),
558                                            mix(self.color_1_focus, self.color_2_focus, gradient_fill.y),
559                                            self.focus
560                                        ),
561                                        mix(
562                                            mix(self.color_1_active, self.color_2_active, gradient_fill.y),
563                                            mix(self.color_1_focus, self.color_2_focus, gradient_fill.y),
564                                            self.focus
565                                        ),
566                                        self.active
567                                    ),
568                                    mix(
569                                        mix(self.color_1_hover, self.color_2_hover, gradient_fill.y),
570                                        mix(self.color_1_down, self.color_2_down, gradient_fill.y),
571                                        self.down
572                                    ),
573                                    self.hover
574                                ),
575                                mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.y),
576                                self.disabled
577                            )
578                        )
579
580                        // Draw mark
581                        let mark_padding = 0.275 * self.size
582                        sdf.move_to(mark_padding, center_px.y);
583                        sdf.line_to(center_px.x, center_px.y + sz_px * 0.5 - mark_padding);
584                        sdf.line_to(sz_px - mark_padding, offset_px.y + mark_padding);
585
586                        sdf.stroke(
587                            mix(
588                                mix(
589                                    mix(self.mark_color, self.mark_color_hover, self.hover),
590                                    mix(self.mark_color_active, self.mark_color_active_hover, self.hover),
591                                    self.active
592                                ),
593                                self.mark_color_disabled,
594                                self.disabled
595                            ), self.size * 0.09
596                        );
597
598                    }
599
600                    // CheckType::Toggle => { }
601
602                    CheckType::None => {
603                        sdf.fill(THEME_COLOR_D_HIDDEN);
604                    }
605                }
606                return sdf.result
607            }
608        }
609    }
610        
611    pub CheckBoxGradientX = <CheckBoxGradientY> {
612        draw_bg: {
613            fn pixel(self) -> vec4 {
614                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
615                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
616
617                let sz_px = self.size;
618                let sz_inner_px = sz_px - self.border_size * 2.;
619                let shift_px = vec2(0, 0)
620                let center_px = vec2(
621                    sz_px * 0.5,
622                    self.rect_size.y * 0.5
623                )
624                
625                let offset_px = vec2(
626                    shift_px.x,
627                    shift_px.y + center_px.y - sz_px * 0.5
628                )
629
630                let offset_uv = vec2(
631                    offset_px.x / self.rect_size.x,
632                    offset_px.y / self.rect_size.y
633                )
634
635                let border_sz_uv = vec2(
636                    self.border_size / self.rect_size.x,
637                    self.border_size / self.rect_size.y
638                )
639
640                let scale_factor_border = vec2(
641                    self.rect_size.x / sz_px,
642                    self.rect_size.y / sz_px 
643                );
644
645                let gradient_border = vec2(
646                    (self.pos.x - offset_uv.x) * scale_factor_border.x + dither,
647                    (self.pos.y - offset_uv.y) * scale_factor_border.y + dither
648                )
649
650                let scale_factor_fill = vec2(
651                    self.rect_size.x / sz_inner_px,
652                    self.rect_size.y / sz_inner_px 
653                );
654
655                let gradient_fill = vec2(
656                    (self.pos.x - offset_uv.x) * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
657                    (self.pos.y - offset_uv.y) * scale_factor_fill.y - border_sz_uv.y * 2. + dither
658                )
659
660                // Draw background
661                sdf.box(
662                    offset_px.x + self.border_size,
663                    offset_px.y + self.border_size,
664                    sz_px - self.border_size * 2.,
665                    sz_px - self.border_size * 2.,
666                    self.border_radius * 0.5
667                );
668
669                sdf.stroke_keep(
670                    mix(
671                        mix(
672                            mix(
673                                mix(
674                                    mix(self.border_color_1, self.border_color_2, gradient_border.y),
675                                    mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
676                                    self.focus
677                                ),
678                                mix(
679                                    mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
680                                    mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
681                                    self.focus
682                                ),
683                                self.active
684                            ),
685                            mix(
686                                mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
687                                mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
688                                self.down
689                            ),
690                            self.hover
691                        ),
692                        mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
693                        self.disabled
694                    ), self.border_size
695                )
696
697                sdf.fill(
698                    mix(
699                        mix(
700                            mix(
701                                mix(
702                                    mix(self.color_1, self.color_2, gradient_fill.x),
703                                    mix(self.color_1_focus, self.color_2_focus, gradient_fill.x),
704                                    self.focus
705                                ),
706                                mix(
707                                    mix(self.color_1_active, self.color_2_active, gradient_fill.x),
708                                    mix(self.color_1_focus, self.color_2_focus, gradient_fill.x),
709                                    self.focus
710                                ),
711                                self.active
712                            ),
713                            mix(
714                                mix(self.color_1_hover, self.color_2_hover, gradient_fill.x),
715                                mix(self.color_1_down, self.color_2_down, gradient_fill.x),
716                                self.down
717                            ),
718                            self.hover
719                        ),
720                        mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.x),
721                        self.disabled
722                    )
723                )
724
725                // Draw mark
726                let mark_padding = 0.275 * self.size
727                sdf.move_to(mark_padding, center_px.y);
728                sdf.line_to(center_px.x, center_px.y + sz_px * 0.5 - mark_padding);
729                sdf.line_to(sz_px - mark_padding, offset_px.y + mark_padding);
730
731                sdf.stroke(
732                    mix(
733                        mix(
734                            mix(self.mark_color, self.mark_color_hover, self.hover),
735                            mix(self.mark_color_active, self.mark_color_active_hover, self.hover),
736                            self.active
737                        ),
738                        self.mark_color_disabled,
739                        self.disabled
740                    ), self.size * 0.09
741                );
742
743                return sdf.result
744            }
745        } 
746    }
747
748    pub Toggle = <CheckBox> {
749        label_walk: {
750            margin: <THEME_MSPACE_H_1> { left: (15.0 + THEME_SPACE_2) }
751        }
752
753        draw_bg: {
754            uniform size: 15.;
755
756            mark_color: (THEME_COLOR_LABEL_OUTER)
757            mark_color_hover: (THEME_COLOR_LABEL_OUTER_ACTIVE)
758            mark_color_down: (THEME_COLOR_LABEL_OUTER_DOWN)
759
760            fn pixel(self) -> vec4 {
761                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
762                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
763
764                let sz_px = vec2(
765                    self.size * 1.6,
766                    self.size
767                );
768                let sz_inner_px = vec2(
769                    sz_px.x - self.border_size * 2.,
770                    sz_px.y - self.border_size * 2.
771                );
772                let shift_px = vec2(0., 0.);
773                let center_px = vec2(
774                    sz_px.x * 0.5,
775                    self.rect_size.y * 0.5
776                )
777                
778                let offset_px = vec2(
779                    shift_px.x,
780                    shift_px.y + center_px.y - sz_px.y * 0.5
781                )
782
783                let offset_uv = vec2(
784                    offset_px.x / self.rect_size.x,
785                    offset_px.y / self.rect_size.y
786                )
787
788                let border_sz_uv = vec2(
789                    self.border_size / self.rect_size.x,
790                    self.border_size / self.rect_size.y
791                )
792
793                let scale_factor_border = vec2(
794                    self.rect_size.x / sz_px.x,
795                    self.rect_size.y / sz_px.y
796                );
797
798                let gradient_border = vec2(
799                    (self.pos.x - offset_uv.x) * scale_factor_border.x + dither,
800                    (self.pos.y - offset_uv.y) * scale_factor_border.y + dither
801                )
802
803                let scale_factor_fill = vec2(
804                    self.rect_size.x / sz_inner_px.x,
805                    self.rect_size.y / sz_inner_px.y
806                );
807
808                let gradient_fill = vec2(
809                    (self.pos.x - offset_uv.x) * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
810                    (self.pos.y - offset_uv.y) * scale_factor_fill.y - border_sz_uv.y * 2. + dither
811                )
812
813                // Draw background                        
814                sdf.box(
815                    offset_px.x + self.border_size,
816                    offset_px.y + self.border_size,
817                    sz_px.x - self.border_size * 2.,
818                    sz_px.y - self.border_size * 2.,
819                    self.border_radius * self.size * 0.1
820                );
821
822                sdf.stroke_keep(
823                    mix(
824                        mix(
825                            mix(
826                                mix(
827                                    mix(self.border_color_1, self.border_color_2, gradient_border.y),
828                                    mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
829                                    self.focus
830                                ),
831                                mix(
832                                    mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
833                                    mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
834                                    self.focus
835                                ),
836                                self.active
837                            ),
838                            mix(
839                                mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
840                                mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
841                                self.down
842                            ),
843                            self.hover
844                        ),
845                        mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
846                        self.disabled
847                    ), self.border_size
848                )
849
850                sdf.fill(
851                    mix(
852                        mix(
853                            mix(
854                                mix(
855                                    self.color,
856                                    self.color_active,
857                                    self.active
858                                ),
859                                self.color_focus,
860                                self.focus
861                            ),
862                            mix(
863                                self.color_hover,
864                                self.color_down,
865                                self.down
866                            ),
867                            self.hover
868                        ),
869                        self.color_disabled,
870                        self.disabled
871                    )
872                )
873
874                    // mix(
875                    //     mix(
876                    //         mix(
877                    //             mix(
878                    //                 mix(self.color_1, self.color_2, gradient_fill.y),
879                    //                 mix(self.color_1_hover, self.color_2_hover, gradient_fill.y),
880                    //                 self.hover
881                    //             ),
882                    //             mix(
883                    //                 mix(self.color_1_active, self.color_2_active, gradient_fill.y),
884                    //                 mix(self.color_1_focus, self.color_2_focus, gradient_fill.y),
885                    //                 self.focus
886                    //             ),
887                    //             self.active
888                    //         ),
889                    //         mix(
890                    //             // mix(self.color_1_hover, self.color_2_hover, gradient_fill.y),
891                    //             #f00,
892                    //             mix(self.color_1_down, self.color_2_down, gradient_fill.y),
893                    //             self.down
894                    //         ),
895                    //         self.hover
896                    //     ),
897                    //     mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.y),
898                    //     self.disabled
899                    // )
900                // )
901                    
902                // Draw mark
903                let mark_padding = 1.5;
904                let mark_size = sz_px.y * 0.5 - self.border_size - mark_padding;
905                let mark_target_y = sz_px.y - sz_px.x + self.border_size + mark_padding;
906                let mark_pos_y = sz_px.y * 0.5 + self.border_size - mark_target_y * self.active;
907
908                sdf.circle(
909                    mark_pos_y,
910                    center_px.y,
911                    mark_size
912                );
913                sdf.circle(
914                    mark_pos_y,
915                    center_px.y,
916                    mark_size * 0.45
917                );
918                sdf.subtract();
919
920                sdf.circle(
921                    mark_pos_y,
922                    center_px.y,
923                    mark_size
924                );
925
926                sdf.blend(self.active)
927
928                sdf.fill(
929                    mix(
930                        mix(
931                            mix(self.mark_color, self.mark_color_hover, self.hover),
932                            mix(self.mark_color_active, self.mark_color_active_hover, self.hover),
933                            self.active
934                        ),
935                        self.mark_color_disabled,
936                        self.disabled
937                    )
938                )
939                return sdf.result
940            }
941        }
942
943        animator: {
944            disabled = {
945                default: off,
946                off = {
947                    from: {all: Forward {duration: 0.}}
948                    apply: {
949                        draw_bg: {disabled: 0.0}
950                        draw_text: {disabled: 0.0}
951                        draw_icon: {disabled: 0.0}
952                    }
953                }
954                on = {
955                    from: {all: Forward {duration: 0.2}}
956                    apply: {
957                        draw_bg: {disabled: 1.0}
958                        draw_text: {disabled: 1.0}
959                        draw_icon: {disabled: 1.0}
960                    }
961                }
962            }
963        
964            hover = {
965                default: off
966                off = {
967                    from: {all: Forward {duration: 0.15}}
968                    apply: {
969                        draw_bg: {down: [{time: 0.0, value: 0.0}], hover: 0.0}
970                        draw_text: {down: [{time: 0.0, value: 0.0}], hover: 0.0}
971                    }
972                }
973                on = {
974                    from: {all: Snap}
975                    apply: {
976                        draw_bg: {down: [{time: 0.0, value: 0.0}], hover: 1.0}
977                        draw_text: {down: [{time: 0.0, value: 0.0}], hover: 1.0}
978                    }
979                }
980                down = {
981                    from: {all: Forward {duration: 0.2}}
982                    apply: {
983                        draw_bg: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
984                        draw_text: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
985                    }
986                }
987            }
988
989            focus = {
990                default: off
991                off = {
992                    from: {all: Snap}
993                    apply: {
994                        draw_bg: {focus: 0.0}
995                        draw_text: {focus: 0.0}
996                    }
997                }
998                on = {
999                    from: {all: Snap}
1000                    apply: {
1001                        draw_bg: {focus: 1.0}
1002                        draw_text: {focus: 1.0}
1003                    }
1004                }
1005            }
1006            active = {
1007                default: off
1008                off = {
1009                    ease: OutQuad
1010                    from: {all: Forward {duration: 0.1}}
1011                    apply: {
1012                        draw_bg: {active: 0.0},
1013                        draw_text: {active: 0.0},
1014                        draw_icon: {active: 0.0},
1015                    }
1016                }
1017                on = {
1018                    ease: OutQuad
1019                    from: {all: Forward {duration: 0.1}}
1020                    apply: {
1021                        draw_bg: {active: 1.0}
1022                        draw_text: {active: 1.0}
1023                        draw_icon: {active: 1.0},
1024                    }
1025                }
1026            }
1027        }
1028    }
1029
1030    pub ToggleGradientY = <CheckBoxGradientY> {
1031        label_walk: {
1032            margin: <THEME_MSPACE_H_1> { left: (15.0 + THEME_SPACE_2) }
1033        }
1034
1035        draw_bg: {
1036            uniform size: 15.;
1037
1038            mark_color: (THEME_COLOR_LABEL_OUTER)
1039            mark_color_hover: (THEME_COLOR_LABEL_OUTER_ACTIVE)
1040            mark_color_down: (THEME_COLOR_LABEL_OUTER_DOWN)
1041
1042            fn pixel(self) -> vec4 {
1043                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
1044                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
1045
1046                let sz_px = vec2(
1047                    self.size * 1.6,
1048                    self.size
1049                );
1050                let sz_inner_px = vec2(
1051                    sz_px.x - self.border_size * 2.,
1052                    sz_px.y - self.border_size * 2.
1053                );
1054                let shift_px = vec2(0., 0.);
1055                let center_px = vec2(
1056                    sz_px.x * 0.5,
1057                    self.rect_size.y * 0.5
1058                )
1059                
1060                let offset_px = vec2(
1061                    shift_px.x,
1062                    shift_px.y + center_px.y - sz_px.y * 0.5
1063                )
1064
1065                let offset_uv = vec2(
1066                    offset_px.x / self.rect_size.x,
1067                    offset_px.y / self.rect_size.y
1068                )
1069
1070                let border_sz_uv = vec2(
1071                    self.border_size / self.rect_size.x,
1072                    self.border_size / self.rect_size.y
1073                )
1074
1075                let scale_factor_border = vec2(
1076                    self.rect_size.x / sz_px.x,
1077                    self.rect_size.y / sz_px.y
1078                );
1079
1080                let gradient_border = vec2(
1081                    (self.pos.x - offset_uv.x) * scale_factor_border.x + dither,
1082                    (self.pos.y - offset_uv.y) * scale_factor_border.y + dither
1083                )
1084
1085                let scale_factor_fill = vec2(
1086                    self.rect_size.x / sz_inner_px.x,
1087                    self.rect_size.y / sz_inner_px.y
1088                );
1089
1090                let gradient_fill = vec2(
1091                    (self.pos.x - offset_uv.x) * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
1092                    (self.pos.y - offset_uv.y) * scale_factor_fill.y - border_sz_uv.y * 2. + dither
1093                )
1094
1095                // Draw background                        
1096                sdf.box(
1097                    offset_px.x + self.border_size,
1098                    offset_px.y + self.border_size,
1099                    sz_px.x - self.border_size * 2.,
1100                    sz_px.y - self.border_size * 2.,
1101                    self.border_radius * self.size * 0.1
1102                );
1103
1104                sdf.stroke_keep(
1105                    mix(
1106                        mix(
1107                            mix(
1108                                mix(
1109                                    mix(self.border_color_1, self.border_color_2, gradient_border.y),
1110                                    mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
1111                                    self.focus
1112                                ),
1113                                mix(
1114                                    mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
1115                                    mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
1116                                    self.focus
1117                                ),
1118                                self.active
1119                            ),
1120                            mix(
1121                                mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
1122                                mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
1123                                self.down
1124                            ),
1125                            self.hover
1126                        ),
1127                        mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
1128                        self.disabled
1129                    ), self.border_size
1130                )
1131
1132                sdf.fill(
1133                    mix(
1134                        mix(
1135                            mix(
1136                                mix(
1137                                    mix(self.color_1, self.color_2, gradient_fill.y),
1138                                    mix(self.color_1_active, self.color_2_active, gradient_fill.y),
1139                                    self.active
1140                                ),
1141                                mix(self.color_1_focus, self.color_2_focus, gradient_fill.y),
1142                                self.focus
1143                            ),
1144                            mix(
1145                                mix(self.color_1_hover, self.color_2_hover, gradient_fill.y),
1146                                mix(self.color_1_down, self.color_2_down, gradient_fill.y),
1147                                self.down
1148                            ),
1149                            self.hover
1150                        ),
1151                        mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.y),
1152                        self.disabled
1153                    )
1154                )
1155                    
1156                // Draw mark
1157                let mark_padding = 1.5;
1158                let mark_size = sz_px.y * 0.5 - self.border_size - mark_padding;
1159                let mark_target_y = sz_px.y - sz_px.x + self.border_size + mark_padding;
1160                let mark_pos_y = sz_px.y * 0.5 + self.border_size - mark_target_y * self.active;
1161
1162                sdf.circle(
1163                    mark_pos_y,
1164                    center_px.y,
1165                    mark_size
1166                );
1167                sdf.circle(
1168                    mark_pos_y,
1169                    center_px.y,
1170                    mark_size * 0.45
1171                );
1172                sdf.subtract();
1173
1174                sdf.circle(
1175                    mark_pos_y,
1176                    center_px.y,
1177                    mark_size
1178                );
1179
1180                sdf.blend(self.active)
1181
1182                sdf.fill(
1183                    mix(
1184                        mix(
1185                            mix(self.mark_color, self.mark_color_hover, self.hover),
1186                            mix(self.mark_color_active, self.mark_color_active_hover, self.hover),
1187                            self.active
1188                        ),
1189                        self.mark_color_disabled,
1190                        self.disabled
1191                    )
1192                )
1193                return sdf.result
1194            }
1195        }
1196
1197        animator: {
1198            disabled = {
1199                default: off,
1200                off = {
1201                    from: {all: Forward {duration: 0.}}
1202                    apply: {
1203                        draw_bg: {disabled: 0.0}
1204                        draw_text: {disabled: 0.0}
1205                        draw_icon: {disabled: 0.0}
1206                    }
1207                }
1208                on = {
1209                    from: {all: Forward {duration: 0.2}}
1210                    apply: {
1211                        draw_bg: {disabled: 1.0}
1212                        draw_text: {disabled: 1.0}
1213                        draw_icon: {disabled: 1.0}
1214                    }
1215                }
1216            }
1217        
1218            hover = {
1219                default: off
1220                off = {
1221                    from: {all: Forward {duration: 0.15}}
1222                    apply: {
1223                        draw_bg: {down: [{time: 0.0, value: 0.0}], hover: 0.0}
1224                        draw_text: {down: [{time: 0.0, value: 0.0}], hover: 0.0}
1225                    }
1226                }
1227                on = {
1228                    from: {all: Snap}
1229                    apply: {
1230                        draw_bg: {down: [{time: 0.0, value: 0.0}], hover: 1.0}
1231                        draw_text: {down: [{time: 0.0, value: 0.0}], hover: 1.0}
1232                    }
1233                }
1234                down = {
1235                    from: {all: Forward {duration: 0.2}}
1236                    apply: {
1237                        draw_bg: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
1238                        draw_text: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
1239                    }
1240                }
1241            }
1242
1243            focus = {
1244                default: off
1245                off = {
1246                    from: {all: Snap}
1247                    apply: {
1248                        draw_bg: {focus: 0.0}
1249                        draw_text: {focus: 0.0}
1250                    }
1251                }
1252                on = {
1253                    from: {all: Snap}
1254                    apply: {
1255                        draw_bg: {focus: 1.0}
1256                        draw_text: {focus: 1.0}
1257                    }
1258                }
1259            }
1260            active = {
1261                default: off
1262                off = {
1263                    ease: OutQuad
1264                    from: {all: Forward {duration: 0.1}}
1265                    apply: {
1266                        draw_bg: {active: 0.0},
1267                        draw_text: {active: 0.0},
1268                        draw_icon: {active: 0.0},
1269                    }
1270                }
1271                on = {
1272                    ease: OutQuad
1273                    from: {all: Forward {duration: 0.1}}
1274                    apply: {
1275                        draw_bg: {active: 1.0}
1276                        draw_text: {active: 1.0}
1277                        draw_icon: {active: 1.0},
1278                    }
1279                }
1280            }
1281        }
1282    }
1283
1284    pub ToggleFlat = <Toggle> {
1285        draw_bg: {
1286            color: (THEME_COLOR_INSET)
1287            color_hover: (THEME_COLOR_INSET_HOVER)
1288            color_down: (THEME_COLOR_INSET_DOWN)
1289            color_active: (THEME_COLOR_INSET_ACTIVE)
1290            color_focus: (THEME_COLOR_INSET_FOCUS)
1291            color_down: (THEME_COLOR_INSET_DISABLED)
1292
1293            border_color_1: (THEME_COLOR_BEVEL)
1294            border_color_1_hover: (THEME_COLOR_BEVEL_HOVER)
1295            border_color_1_down: (THEME_COLOR_BEVEL_DOWN)
1296            border_color_1_active: (THEME_COLOR_BEVEL_ACTIVE)
1297            border_color_1_focus: (THEME_COLOR_BEVEL_FOCUS)
1298            border_color_1_disabled: (THEME_COLOR_BEVEL_DISABLED)
1299
1300            border_color_2: (THEME_COLOR_BEVEL)
1301            border_color_2_hover: (THEME_COLOR_BEVEL_HOVER)
1302            border_color_2_down: (THEME_COLOR_BEVEL_DOWN)
1303            border_color_2_active: (THEME_COLOR_BEVEL_ACTIVE)
1304            border_color_2_focus: (THEME_COLOR_BEVEL_FOCUS)
1305            border_color_2_disabled: (THEME_COLOR_BEVEL_DISABLED)
1306        }
1307    }
1308        
1309    pub ToggleFlatter = <ToggleFlat> {
1310        draw_bg: {
1311            border_color_1: (THEME_COLOR_U_HIDDEN)
1312            border_color_1_hover: (THEME_COLOR_U_HIDDEN)
1313            border_color_1_down: (THEME_COLOR_U_HIDDEN)
1314            border_color_1_active: (THEME_COLOR_U_HIDDEN)
1315            border_color_1_focus: (THEME_COLOR_U_HIDDEN)
1316            border_color_1_disabled: (THEME_COLOR_U_HIDDEN)
1317
1318            border_color_2: (THEME_COLOR_U_HIDDEN)
1319            border_color_2_hover: (THEME_COLOR_U_HIDDEN)
1320            border_color_2_down: (THEME_COLOR_U_HIDDEN)
1321            border_color_2_active: (THEME_COLOR_U_HIDDEN)
1322            border_color_2_focus: (THEME_COLOR_U_HIDDEN)
1323            border_color_2_disabled: (THEME_COLOR_U_HIDDEN)
1324        }
1325    }
1326
1327    pub ToggleGradientX = <ToggleGradientY> {
1328        draw_bg: {
1329            uniform size: 15.;
1330
1331            fn pixel(self) -> vec4 {
1332                let sdf = Sdf2d::viewport(self.pos * self.rect_size);
1333                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
1334
1335                let sz_px = vec2(
1336                    self.size * 1.6,
1337                    self.size
1338                );
1339                let sz_inner_px = vec2(
1340                    sz_px.x - self.border_size * 2.,
1341                    sz_px.y - self.border_size * 2.
1342                );
1343                let shift_px = vec2(0., 0.);
1344                let center_px = vec2(
1345                    sz_px.x * 0.5,
1346                    self.rect_size.y * 0.5
1347                )
1348                
1349                let offset_px = vec2(
1350                    shift_px.x,
1351                    shift_px.y + center_px.y - sz_px.y * 0.5
1352                )
1353
1354                let offset_uv = vec2(
1355                    offset_px.x / self.rect_size.x,
1356                    offset_px.y / self.rect_size.y
1357                )
1358
1359                let border_sz_uv = vec2(
1360                    self.border_size / self.rect_size.x,
1361                    self.border_size / self.rect_size.y
1362                )
1363
1364                let scale_factor_border = vec2(
1365                    self.rect_size.x / sz_px.x,
1366                    self.rect_size.y / sz_px.y
1367                );
1368
1369                let gradient_border = vec2(
1370                    (self.pos.x - offset_uv.x) * scale_factor_border.x + dither,
1371                    (self.pos.y - offset_uv.y) * scale_factor_border.y + dither
1372                )
1373
1374                let scale_factor_fill = vec2(
1375                    self.rect_size.x / sz_inner_px.x,
1376                    self.rect_size.y / sz_inner_px.y
1377                );
1378
1379                let gradient_fill = vec2(
1380                    (self.pos.x - offset_uv.x) * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
1381                    (self.pos.y - offset_uv.y) * scale_factor_fill.y - border_sz_uv.y * 2. + dither
1382                )
1383
1384                // Draw background                        
1385                sdf.box(
1386                    offset_px.x + self.border_size,
1387                    offset_px.y + self.border_size,
1388                    sz_px.x - self.border_size * 2.,
1389                    sz_px.y - self.border_size * 2.,
1390                    self.border_radius * self.size * 0.1
1391                );
1392
1393                sdf.fill_keep(
1394                    mix(
1395                        mix(
1396                            mix(
1397                                mix(
1398                                    mix(self.color_1, self.color_2, gradient_fill.x),
1399                                    mix(self.color_1_focus, self.color_2_focus, gradient_fill.x),
1400                                    self.focus
1401                                ),
1402                                mix(
1403                                    mix(self.color_1_active, self.color_2_active, gradient_fill.x),
1404                                    mix(self.color_1_focus, self.color_2_focus, gradient_fill.x),
1405                                    self.focus
1406                                ),
1407                                self.active
1408                            ),
1409                            mix(
1410                                mix(self.color_1_hover, self.color_2_hover, gradient_fill.x),
1411                                mix(self.color_1_down, self.color_2_down, gradient_fill.x),
1412                                self.down
1413                            ),
1414                            self.hover
1415                        ),
1416                        mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.x),
1417                        self.disabled
1418                    )
1419                )
1420 
1421                sdf.stroke(
1422                    mix(
1423                        mix(
1424                            mix(
1425                                mix(
1426                                    mix(self.border_color_1, self.border_color_2, gradient_border.y),
1427                                    mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
1428                                    self.focus
1429                                ),
1430                                mix(
1431                                    mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
1432                                    mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
1433                                    self.focus
1434                                ),
1435                                self.active
1436                            ),
1437                            mix(
1438                                mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
1439                                mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
1440                                self.down
1441                            ),
1442                            self.hover
1443                        ),
1444                        mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
1445                        self.disabled
1446                    ), self.border_size
1447                )
1448
1449
1450                // Draw mark
1451                let mark_padding = 1.5;
1452                let mark_size = sz_px.y * 0.5 - self.border_size - mark_padding;
1453                let mark_target_y = sz_px.y - sz_px.x + self.border_size + mark_padding;
1454                let mark_pos_y = sz_px.y * 0.5 + self.border_size - mark_target_y * self.active;
1455
1456                sdf.circle(
1457                    mark_pos_y,
1458                    center_px.y,
1459                    mark_size
1460                );
1461                sdf.circle(
1462                    mark_pos_y,
1463                    center_px.y,
1464                    mark_size * 0.45
1465                );
1466                sdf.subtract();
1467
1468                sdf.circle(
1469                    mark_pos_y,
1470                    center_px.y,
1471                    mark_size
1472                );
1473
1474                sdf.blend(self.active)
1475
1476                sdf.fill(
1477                    mix(
1478                        mix(
1479                            mix(self.mark_color, self.mark_color_hover, self.hover),
1480                            mix(self.mark_color_active, self.mark_color_active_hover, self.hover),
1481                            self.active
1482                        ),
1483                        self.mark_color_disabled,
1484                        self.disabled
1485                    )
1486                )
1487                return sdf.result
1488            }
1489        }
1490    }
1491
1492    pub CheckBoxCustom = <CheckBox> {
1493        draw_bg: { check_type: None }
1494        width: Fit, height: Fit,
1495
1496        padding: <THEME_MSPACE_2> {}
1497        align: { x: 0., y: 0.5 }
1498
1499        label_walk: {
1500            margin: <THEME_MSPACE_H_2> {}
1501        }
1502    }
1503}
1504
1505#[derive(Live, LiveHook, LiveRegister)]
1506#[repr(C)]
1507pub struct DrawCheckBox {
1508    #[deref] draw_super: DrawQuad,
1509    #[live] check_type: CheckType,
1510    #[live] hover: f32,
1511    #[live] focus: f32,
1512    #[live] active: f32
1513}
1514
1515#[derive(Live, LiveHook, LiveRegister)]
1516#[live_ignore]
1517#[repr(u32)]
1518pub enum CheckType {
1519    #[pick] Check = shader_enum(1),
1520    Radio = shader_enum(2),
1521    Toggle = shader_enum(3),
1522    None = shader_enum(4),
1523}
1524
1525#[derive(Live, Widget)]
1526pub struct CheckBox {
1527    
1528    #[walk] walk: Walk,
1529    #[layout] layout: Layout,
1530    #[animator] animator: Animator,
1531    
1532    #[live] icon_walk: Walk,
1533    #[live] label_walk: Walk,
1534    #[live] label_align: Align,
1535    
1536    #[redraw] #[live] draw_bg: DrawCheckBox,
1537    #[live] draw_text: DrawText,
1538    #[live] draw_icon: DrawIcon,
1539    
1540    #[live] text: ArcStringMut,
1541
1542    #[visible] #[live(true)]
1543    pub visible: bool,
1544    
1545    #[live(None)]
1546    pub active: Option<bool>,
1547    
1548    #[live] bind: String,
1549    #[action_data] #[rust] action_data: WidgetActionData,
1550}
1551
1552// map the 'active' bool to the animator state
1553impl LiveHook for CheckBox{
1554    fn after_new_from_doc(&mut self, cx: &mut Cx){
1555        if let Some(active) = self.active.take() {
1556            self.animator_toggle(cx, active, Animate::No, id!(active.on), id!(active.off));
1557        }
1558    }
1559}
1560
1561#[derive(Clone, Debug, DefaultNone)]
1562pub enum CheckBoxAction {
1563    Change(bool),
1564    None
1565}
1566
1567impl CheckBox {
1568    
1569    pub fn draw_walk(&mut self, cx: &mut Cx2d, walk: Walk) -> DrawStep {
1570        self.draw_bg.begin(cx, walk, self.layout);
1571        self.draw_icon.draw_walk(cx, self.icon_walk);
1572        self.draw_text.draw_walk(cx, self.label_walk, self.label_align, self.text.as_ref());
1573        self.draw_bg.end(cx);
1574        cx.add_nav_stop(self.draw_bg.area(), NavRole::TextInput, Margin::default());
1575        DrawStep::done() 
1576   }
1577}
1578
1579impl Widget for CheckBox {
1580
1581    fn set_disabled(&mut self, cx:&mut Cx, disabled:bool){
1582        self.animator_toggle(cx, disabled, Animate::Yes, id!(disabled.on), id!(disabled.off));
1583    }
1584                
1585    fn disabled(&self, cx:&Cx) -> bool {
1586        self.animator_in_state(cx, id!(disabled.on))
1587    }
1588    
1589    fn widget_to_data(&self, _cx: &mut Cx, actions: &Actions, nodes: &mut LiveNodeVec, path: &[LiveId]) -> bool {
1590        match actions.find_widget_action_cast(self.widget_uid()) {
1591            CheckBoxAction::Change(v) => {
1592                nodes.write_field_value(path, LiveValue::Bool(v));
1593                true
1594            }
1595            _ => false
1596        }
1597    }
1598    
1599    fn data_to_widget(&mut self, cx: &mut Cx, nodes: &[LiveNode], path: &[LiveId]) {
1600        if let Some(value) = nodes.read_field_value(path) {
1601            if let Some(value) = value.as_bool() {
1602                self.animator_toggle(cx, value, Animate::Yes, id!(active.on), id!(active.off));
1603            }
1604        }
1605    }
1606    
1607    fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
1608        let uid = self.widget_uid();
1609        self.animator_handle_event(cx, event);
1610                
1611        match event.hits(cx, self.draw_bg.area()) {
1612            Hit::KeyFocus(_) => {
1613                self.animator_play(cx, id!(focus.on));
1614            }
1615            Hit::KeyFocusLost(_) => {
1616                self.animator_play(cx, id!(focus.off));
1617                self.draw_bg.redraw(cx);
1618            }
1619            Hit::FingerHoverIn(_) => {
1620                cx.set_cursor(MouseCursor::Hand);
1621                self.animator_play(cx, id!(hover.on));
1622            }
1623            Hit::FingerHoverOut(_) => {
1624                self.animator_play(cx, id!(hover.off));
1625            },
1626            Hit::FingerDown(fe) if fe.is_primary_hit() => {
1627                self.set_key_focus(cx);
1628                if self.animator_in_state(cx, id!(active.on)) {
1629                    self.animator_play(cx, id!(active.off));
1630                    cx.widget_action_with_data(&self.action_data, uid, &scope.path, CheckBoxAction::Change(false));
1631                }
1632                else {
1633                    self.animator_play(cx, id!(active.on));
1634                    cx.widget_action_with_data(&self.action_data, uid, &scope.path, CheckBoxAction::Change(true));
1635                }
1636            },
1637            Hit::FingerUp(_fe) => {
1638                                    
1639            }
1640            Hit::FingerMove(_fe) => {
1641                                    
1642            }
1643            _ => ()
1644        }
1645    }
1646    
1647    fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep {
1648        if !self.visible {
1649            return DrawStep::done();
1650        }
1651        self.draw_walk(cx, walk)
1652    }
1653    
1654    fn text(&self) -> String {
1655        self.text.as_ref().to_string()
1656    }
1657    
1658    fn set_text(&mut self, cx:&mut Cx, v: &str) {
1659        self.text.as_mut_empty().push_str(v);
1660        self.redraw(cx);
1661    }
1662}
1663
1664impl CheckBoxRef {
1665
1666    pub fn changed(&self, actions: &Actions) -> Option<bool> {
1667        if let CheckBoxAction::Change(b) = actions.find_widget_action_cast(self.widget_uid()) {
1668            return Some(b)
1669        }
1670        None
1671    }
1672    
1673    pub fn set_text(&self, text: &str) {
1674        if let Some(mut inner) = self.borrow_mut() {
1675            let s = inner.text.as_mut_empty();
1676            s.push_str(text);
1677        }
1678    }
1679    
1680    pub fn active(&self, cx: &Cx) -> bool {
1681        if let Some(inner) = self.borrow() {
1682            inner.animator_in_state(cx, id!(active.on))
1683        }
1684        else {
1685            false
1686        }
1687    }
1688    
1689    pub fn set_active(&self, cx: &mut Cx, value: bool) {
1690        if let Some(mut inner) = self.borrow_mut() {
1691            inner.animator_toggle(cx, value, Animate::Yes, id!(active.on), id!(active.off));
1692        }
1693    }
1694}