makepad_widgets/
radio_button.rs

1use crate::{
2        makepad_derive_widget::*,
3        makepad_draw::*,
4        widget::*,
5        View,
6        Image,
7    };
8
9live_design!{
10    link widgets;
11    use link::theme::*;
12    use link::shaders::*;
13    use crate::view_ui::CachedRoundedView;
14    
15    DrawRadioButton = {{DrawRadioButton}} {}
16    pub RadioButtonBase = {{RadioButton}} {}
17    pub RadioButtonGroupBase = {{RadioButtonGroup }} {}
18    
19    pub RadioButton = <RadioButtonBase> {
20        width: Fit, height: Fit,
21        align: { x: 0., y: 0. }
22        padding: <THEME_MSPACE_V_2> { left: (THEME_SPACE_2)}
23        
24        icon_walk: { margin: { left: 20. } }
25        
26        label_walk: {
27            width: Fit, height: Fit,
28            margin: <THEME_MSPACE_H_1> { left: 13. }
29        }
30        label_align: { y: 0.0 }
31        
32        draw_bg: {
33            instance disabled: 0.,
34            instance down: 0.,
35
36            uniform size: 15.0,
37
38            uniform border_size: (THEME_BEVELING)
39            uniform border_radius: (THEME_CORNER_RADIUS)
40
41            uniform color_dither: 1.0
42
43            uniform color: (THEME_COLOR_INSET)
44            uniform color_hover: (THEME_COLOR_INSET_HOVER)
45            uniform color_down: (THEME_COLOR_INSET_DOWN)
46            uniform color_active: (THEME_COLOR_INSET_ACTIVE)
47            uniform color_focus: (THEME_COLOR_INSET_FOCUS)
48            uniform color_disabled: (THEME_COLOR_INSET_DISABLED)
49
50            uniform border_color_1: (THEME_COLOR_BEVEL_INSET_2)
51            uniform border_color_1_hover: (THEME_COLOR_BEVEL_INSET_2_HOVER)
52            uniform border_color_1_down: (THEME_COLOR_BEVEL_INSET_2_DOWN)
53            uniform border_color_1_active: (THEME_COLOR_BEVEL_INSET_2_ACTIVE)
54            uniform border_color_1_focus: (THEME_COLOR_BEVEL_INSET_2_FOCUS)
55            uniform border_color_1_disabled: (THEME_COLOR_BEVEL_INSET_2_DISABLED)
56
57            uniform border_color_2: (THEME_COLOR_BEVEL_INSET_1)
58            uniform border_color_2_hover: (THEME_COLOR_BEVEL_INSET_1_HOVER)
59            uniform border_color_2_down: (THEME_COLOR_BEVEL_INSET_1_DOWN)
60            uniform border_color_2_active: (THEME_COLOR_BEVEL_INSET_1_ACTIVE)
61            uniform border_color_2_focus: (THEME_COLOR_BEVEL_INSET_1_FOCUS)
62            uniform border_color_2_disabled: (THEME_COLOR_BEVEL_INSET_1_DISABLED)
63
64            uniform mark_color: (THEME_COLOR_MARK_OFF)
65            uniform mark_color_active: (THEME_COLOR_MARK_ACTIVE)
66            uniform mark_color_disabled: (THEME_COLOR_MARK_DISABLED)
67            uniform mark_offset: -0.5
68            
69            fn pixel(self) -> vec4 {
70                let sdf = Sdf2d::viewport(self.pos * self.rect_size)
71                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
72
73                let sz_px = self.size;
74                let sz_inner_px = sz_px - self.border_size * 4.;
75
76                let radius_px = sz_px * 0.5
77
78                let border_sz_uv = vec2(
79                    self.border_size / self.rect_size.x,
80                    self.border_size / self.rect_size.y
81                )
82
83                let center_px = vec2(
84                    radius_px,
85                    self.rect_size.y * 0.5
86                )
87
88                let offset_px = vec2(
89                    0.,
90                    center_px.y - radius_px
91                )
92
93                let offset_uv = vec2(
94                    offset_px.x / self.rect_size.x,
95                    offset_px.y / self.rect_size.y
96                )
97
98                let scale_factor_border = vec2(
99                    self.rect_size.x / sz_px,
100                    self.rect_size.y / sz_px
101                );
102
103                let scale_factor_fill = vec2(
104                    self.rect_size.x / sz_inner_px,
105                    self.rect_size.y / sz_inner_px 
106                );
107
108                let gradient_border = vec2(
109                    (self.pos.x - offset_uv.x) * scale_factor_border.x + dither,
110                    (self.pos.y - offset_uv.y) * scale_factor_border.y + dither
111                )
112
113                let gradient_fill = vec2(
114                    (self.pos.x - offset_uv.x - border_sz_uv.x * 2.) * scale_factor_fill.x + dither,
115                    (self.pos.y - offset_uv.y - border_sz_uv.y * 2.) * scale_factor_fill.y + dither
116                )
117
118                match self.radio_type {
119                    RadioType::Round => {
120
121                        // Draw background
122                        sdf.circle(
123                            center_px.x,
124                            center_px.y,
125                            radius_px - self.border_size
126                        );
127
128                        sdf.fill_keep(
129                            mix(
130                                mix(
131                                    mix(
132                                        mix(
133                                            self.color,
134                                            self.color_focus,
135                                            self.focus
136                                        ),
137                                        mix(
138                                            self.color_active,
139                                            self.color_focus,
140                                            self.focus
141                                        ),
142                                        self.active
143                                    ),
144                                    mix(
145                                        self.color_hover,
146                                        self.color_down,
147                                        self.down
148                                    ),
149                                    self.hover
150                                ),
151                                self.color_disabled,
152                                self.disabled
153                            )
154                        )
155
156                        sdf.stroke(
157                            mix(
158                                mix(
159                                    mix(
160                                        mix(
161                                            mix(self.border_color_1, self.border_color_2, gradient_border.y),
162                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
163                                            self.focus
164                                        ),
165                                        mix(
166                                            mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
167                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
168                                            self.focus
169                                        ),
170                                        self.active
171                                    ),
172                                    mix(
173                                        mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
174                                        mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
175                                        self.down
176                                    ),
177                                    self.hover
178                                ),
179                                mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
180                                self.disabled
181                            ), self.border_size
182                        )
183
184                        // Draw mark
185                        sdf.circle(
186                            center_px.x,
187                            center_px.y + self.mark_offset,
188                            radius_px * 0.5 - self.border_size * 0.75
189                        );
190
191                        sdf.fill(
192                            mix(
193                                mix(
194                                    self.mark_color,
195                                    self.mark_color_active,
196                                    self.active
197                                ),
198                                self.mark_color_disabled,
199                                self.disabled
200                            )
201                        );
202                    }
203                    RadioType::Tab => {
204                        let border_sz_uv = vec2(
205                            self.border_size / self.rect_size.x,
206                            self.border_size / self.rect_size.y
207                        )
208
209                        let scale_factor_border = vec2(
210                            self.rect_size.x / self.rect_size.x,
211                            self.rect_size.y / self.rect_size.y
212                        );
213
214                        let gradient_border = vec2(
215                            self.pos.x * scale_factor_border.x + dither,
216                            self.pos.y * scale_factor_border.y + dither
217                        )
218
219                        let sz_inner_px = vec2(
220                            self.rect_size.x - self.border_size * 2.,
221                            self.rect_size.y - self.border_size * 2.
222                        );
223
224                        let scale_factor_fill = vec2(
225                            self.rect_size.x / sz_inner_px.x,
226                            self.rect_size.y / sz_inner_px.y
227                        );
228
229                        let gradient_fill = vec2(
230                            self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
231                            self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
232                        )
233
234                        sdf.box(
235                            self.border_size,
236                            self.border_size,
237                            self.rect_size.x - self.border_size * 2.,
238                            self.rect_size.y - self.border_size * 2.,
239                            self.border_radius
240                        )
241
242                        sdf.fill_keep(
243                            mix(
244                                mix(
245                                    self.color,
246                                    self.color_active,
247                                    self.active
248                                ),
249                                self.color_disabled,
250                                self.disabled
251                            )
252                        )
253
254                        sdf.stroke(
255                            mix(
256                                mix(
257                                    mix(
258                                        mix(
259                                            mix(self.border_color_1, self.border_color_2, gradient_border.y),
260                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
261                                            self.focus
262                                        ),
263                                        mix(
264                                            mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
265                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
266                                            self.focus
267                                        ),
268                                        self.active
269                                    ),
270                                    mix(
271                                        mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
272                                        mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
273                                        self.down
274                                    ),
275                                    self.hover
276                                ),
277                                mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
278                                self.disabled
279                            ), self.border_size
280                        )
281                            
282                    }
283                }
284                return sdf.result
285            }
286        }
287            
288        draw_text: {
289            instance active: 0.0
290            instance focus: 0.0
291            instance down: 0.,
292            instance hover: 0.0
293            instance disabled: 0.,
294                
295            uniform color: (THEME_COLOR_LABEL_OUTER)
296            uniform color_hover: (THEME_COLOR_LABEL_OUTER_HOVER)
297            uniform color_down: (THEME_COLOR_LABEL_OUTER_DOWN)
298            uniform color_active: (THEME_COLOR_LABEL_OUTER_ACTIVE)
299            uniform color_focus: (THEME_COLOR_LABEL_OUTER_FOCUS)
300            uniform color_disabled: (THEME_COLOR_LABEL_OUTER_DISABLED)
301                
302            text_style: <THEME_FONT_REGULAR> {
303                font_size: (THEME_FONT_SIZE_P)
304            }
305            fn get_color(self) -> vec4 {
306                return
307                    mix(
308                        mix(
309                            mix(
310                                mix(self.color, self.color_active, self.active),
311                                self.color_focus,
312                                self.focus
313                            ),
314                            mix(
315                                self.color_hover,
316                                self.color_down,
317                                self.down
318                            ),
319                            self.hover
320                        ),
321                        self.color_disabled,
322                        self.disabled
323                    )
324            }
325        }
326            
327        draw_icon: {
328            instance focus: 0.0
329            instance disabled: 0.,
330            instance active: 0.0
331
332            uniform color_dither: 1.0
333            uniform color_1: (THEME_COLOR_LABEL_OUTER)
334            uniform color_1_active: (THEME_COLOR_LABEL_OUTER_ACTIVE)
335            uniform color_1_disabled: (THEME_COLOR_LABEL_OUTER_DISABLED)
336
337            uniform color_2: (THEME_COLOR_LABEL_OUTER)
338            uniform color_2_active: (THEME_COLOR_LABEL_OUTER_ACTIVE)
339            uniform color_2_disabled: (THEME_COLOR_LABEL_OUTER_DISABLED)
340
341            fn get_color(self) -> vec4 {
342                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
343                return
344                    mix(
345                        mix(
346                            mix(self.color_1, self.color_2, self.pos.y + dither),
347                            mix(self.color_1_active, self.color_2_active, self.pos.y + dither),
348                            self.active
349                        ),
350                        mix(self.color_1_disabled, self.color_2_disabled, self.pos.y + dither),
351                        self.disabled
352                    )
353            }
354        }
355            
356        animator: {
357            disabled = {
358                default: off,
359                off = {
360                    from: {all: Forward {duration: 0.}}
361                    apply: {
362                        draw_bg: {disabled: 0.0}
363                        draw_text: {disabled: 0.0}
364                        draw_icon: {disabled: 0.0}
365                    }
366                }
367                on = {
368                    from: {all: Forward {duration: 0.2}}
369                    apply: {
370                        draw_bg: {disabled: 1.0}
371                        draw_text: {disabled: 1.0}
372                        draw_icon: {disabled: 1.0}
373                    }
374                }
375            }
376            hover = {
377                default: off
378                off = {
379                    from: {all: Forward {duration: 0.15}}
380                    apply: {
381                        draw_bg: {down: [{time: 0.0, value: 0.0}], hover: 0.0}
382                        draw_text: {down: [{time: 0.0, value: 0.0}], hover: 0.0}
383                    }
384                }
385                on = {
386                    from: {all: Snap}
387                    apply: {
388                        draw_bg: {down: [{time: 0.0, value: 0.0}], hover: 1.0}
389                        draw_text: {down: [{time: 0.0, value: 0.0}], hover: 1.0}
390                    }
391                }
392                down = {
393                    from: {all: Forward {duration: 0.2}}
394                    apply: {
395                        draw_bg: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
396                        draw_text: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
397                    }
398                }
399            }
400            active = {
401                default: off
402                off = {
403                    from: {all: Forward {duration: 0.2}}
404                    apply: {
405                        draw_bg: {active: 0.0}
406                        draw_icon: {active: 0.0}
407                        draw_text: {active: 0.0}
408                    }
409                }
410                on = {
411                    from: {all: Forward {duration: 0.0}}
412                    apply: {
413                        draw_bg: {active: 1.0}
414                        draw_icon: {active: 1.0}
415                        draw_text: {active: 1.0}
416                    }
417                }
418            }
419            focus = {
420                default: off
421                off = {
422                    from: {all: Forward {duration: 0.2}}
423                    apply: {
424                        draw_bg: {focus: 0.0}
425                        draw_text: {focus: 0.0}
426                    }
427                }
428                on = {
429                    from: {all: Forward {duration: 0.0}}
430                    apply: {
431                        draw_bg: {focus: 1.0}
432                        draw_text: {focus: 1.0}
433                    }
434                }
435            }
436        }
437    }
438        
439
440    pub RadioButtonGradientY = <RadioButton> {
441        draw_bg: {
442            instance disabled: 0.,
443            instance down: 0.,
444
445            uniform size: 15.0,
446
447            uniform border_size: (THEME_BEVELING)
448            uniform border_radius: (THEME_CORNER_RADIUS)
449
450            uniform color_dither: 1.0
451
452            uniform color_1: (THEME_COLOR_INSET_1)
453            uniform color_1_hover: (THEME_COLOR_INSET_1_HOVER)
454            uniform color_1_down: (THEME_COLOR_INSET_1_DOWN)
455            uniform color_1_active: (THEME_COLOR_INSET_1_ACTIVE)
456            uniform color_1_focus: (THEME_COLOR_INSET_1_FOCUS)
457            uniform color_1_disabled: (THEME_COLOR_INSET_1_DISABLED)
458
459            uniform color_2: (THEME_COLOR_INSET_2)
460            uniform color_2_hover: (THEME_COLOR_INSET_2_HOVER)
461            uniform color_2_down: (THEME_COLOR_INSET_2_DOWN)
462            uniform color_2_active: (THEME_COLOR_INSET_2_ACTIVE)
463            uniform color_2_focus: (THEME_COLOR_INSET_2_FOCUS)
464            uniform color_2_disabled: (THEME_COLOR_INSET_2_DISABLED)
465
466            uniform border_color_1: (THEME_COLOR_BEVEL_INSET_2)
467            uniform border_color_1_hover: (THEME_COLOR_BEVEL_INSET_2_HOVER)
468            uniform border_color_1_down: (THEME_COLOR_BEVEL_INSET_2_DOWN)
469            uniform border_color_1_active: (THEME_COLOR_BEVEL_INSET_2_ACTIVE)
470            uniform border_color_1_focus: (THEME_COLOR_BEVEL_INSET_2_FOCUS)
471            uniform border_color_1_disabled: (THEME_COLOR_BEVEL_INSET_2_DISABLED)
472
473            uniform border_color_2: (THEME_COLOR_BEVEL_INSET_1)
474            uniform border_color_2_hover: (THEME_COLOR_BEVEL_INSET_1_HOVER)
475            uniform border_color_2_down: (THEME_COLOR_BEVEL_INSET_1_DOWN)
476            uniform border_color_2_active: (THEME_COLOR_BEVEL_INSET_1_ACTIVE)
477            uniform border_color_2_focus: (THEME_COLOR_BEVEL_INSET_1_FOCUS)
478            uniform border_color_2_disabled: (THEME_COLOR_BEVEL_INSET_1_DISABLED)
479
480            uniform mark_color: (THEME_COLOR_MARK_OFF)
481            uniform mark_color_active: (THEME_COLOR_MARK_ACTIVE)
482            uniform mark_color_disabled: (THEME_COLOR_MARK_DISABLED)
483            uniform mark_offset: -0.5
484
485            fn pixel(self) -> vec4 {
486                let sdf = Sdf2d::viewport(self.pos * self.rect_size)
487                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
488
489                let sz_px = self.size;
490                let sz_inner_px = sz_px - self.border_size * 4.;
491
492                let radius_px = sz_px * 0.5
493
494                let border_sz_uv = vec2(
495                    self.border_size / self.rect_size.x,
496                    self.border_size / self.rect_size.y
497                )
498
499                let center_px = vec2(
500                    radius_px,
501                    self.rect_size.y * 0.5
502                )
503
504                let offset_px = vec2(
505                    0.,
506                    center_px.y - radius_px
507                )
508
509                let offset_uv = vec2(
510                    offset_px.x / self.rect_size.x,
511                    offset_px.y / self.rect_size.y
512                )
513
514                let scale_factor_border = vec2(
515                    self.rect_size.x / sz_px,
516                    self.rect_size.y / sz_px
517                );
518
519                let scale_factor_fill = vec2(
520                    self.rect_size.x / sz_inner_px,
521                    self.rect_size.y / sz_inner_px 
522                );
523
524                let gradient_border = vec2(
525                    (self.pos.x - offset_uv.x) * scale_factor_border.x + dither,
526                    (self.pos.y - offset_uv.y) * scale_factor_border.y + dither
527                )
528
529                let gradient_fill = vec2(
530                    (self.pos.x - offset_uv.x - border_sz_uv.x * 2.) * scale_factor_fill.x + dither,
531                    (self.pos.y - offset_uv.y - border_sz_uv.y * 2.) * scale_factor_fill.y + dither
532                )
533
534                match self.radio_type {
535                    RadioType::Round => {
536
537                        // Draw background
538                        sdf.circle(
539                            center_px.x,
540                            center_px.y,
541                            radius_px - self.border_size
542                        );
543
544                        sdf.fill_keep(
545                            mix(
546                                mix(
547                                    mix(
548                                        mix(
549                                            mix(self.color_1, self.color_2, gradient_fill.y),
550                                            mix(self.color_1_focus, self.color_2_focus, gradient_fill.y),
551                                            self.focus
552                                        ),
553                                        mix(
554                                            mix(self.color_1_active, self.color_2_active, gradient_fill.y),
555                                            mix(self.color_1_focus, self.color_2_focus, gradient_fill.y),
556                                            self.focus
557                                        ),
558                                        self.active
559                                    ),
560                                    mix(
561                                        mix(self.color_1_hover, self.color_2_hover, gradient_fill.y),
562                                        mix(self.color_1_down, self.color_2_down, gradient_fill.y),
563                                        self.down
564                                    ),
565                                    self.hover
566                                ),
567                                mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.y),
568                                self.disabled
569                            )
570                        )
571
572                        sdf.stroke(
573                            mix(
574                                mix(
575                                    mix(
576                                        mix(
577                                            mix(self.border_color_1, self.border_color_2, gradient_border.y),
578                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
579                                            self.focus
580                                        ),
581                                        mix(
582                                            mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
583                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
584                                            self.focus
585                                        ),
586                                        self.active
587                                    ),
588                                    mix(
589                                        mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
590                                        mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
591                                        self.down
592                                    ),
593                                    self.hover
594                                ),
595                                mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
596                                self.disabled
597                            ), self.border_size
598                        )
599
600                        // Draw mark
601                        sdf.circle(
602                            center_px.x,
603                            center_px.y + self.mark_offset,
604                            radius_px * 0.5 - self.border_size * 0.75
605                        );
606
607                        sdf.fill(
608                            mix(
609                                mix(
610                                    self.mark_color,
611                                    self.mark_color_active,
612                                    self.active
613                                ),
614                                self.mark_color_disabled,
615                                self.disabled
616                            )
617                        );
618                    }
619                    RadioType::Tab => {
620                        let border_sz_uv = vec2(
621                            self.border_size / self.rect_size.x,
622                            self.border_size / self.rect_size.y
623                        )
624
625                        let scale_factor_border = vec2(
626                            self.rect_size.x / self.rect_size.x,
627                            self.rect_size.y / self.rect_size.y
628                        );
629
630                        let gradient_border = vec2(
631                            self.pos.x * scale_factor_border.x + dither,
632                            self.pos.y * scale_factor_border.y + dither
633                        )
634
635                        let sz_inner_px = vec2(
636                            self.rect_size.x - self.border_size * 2.,
637                            self.rect_size.y - self.border_size * 2.
638                        );
639
640                        let scale_factor_fill = vec2(
641                            self.rect_size.x / sz_inner_px.x,
642                            self.rect_size.y / sz_inner_px.y
643                        );
644
645                        let gradient_fill = vec2(
646                            self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
647                            self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
648                        )
649
650                        sdf.box(
651                            self.border_size,
652                            self.border_size,
653                            self.rect_size.x - self.border_size * 2.,
654                            self.rect_size.y - self.border_size * 2.,
655                            self.border_radius
656                        )
657
658                        sdf.fill_keep(
659                            mix(
660                                mix(
661                                    mix(self.color_1, self.color_2, gradient_fill.y),
662                                    mix(self.color_1_active, self.color_2_active, gradient_fill.y),
663                                    self.active
664                                ),
665                                mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.y),
666                                self.disabled
667                            )
668                        )
669
670                        sdf.stroke(
671                            mix(
672                                mix(
673                                    mix(
674                                        mix(
675                                            mix(self.border_color_1, self.border_color_2, gradient_border.y),
676                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
677                                            self.focus
678                                        ),
679                                        mix(
680                                            mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
681                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
682                                            self.focus
683                                        ),
684                                        self.active
685                                    ),
686                                    mix(
687                                        mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
688                                        mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
689                                        self.down
690                                    ),
691                                    self.hover
692                                ),
693                                mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
694                                self.disabled
695                            ), self.border_size
696                        )
697                            
698                    }
699                }
700                return sdf.result
701            }
702        }
703    }
704
705    pub RadioButtonGradientX = <RadioButtonGradientY> {
706        draw_bg: {
707            fn pixel(self) -> vec4 {
708                let sdf = Sdf2d::viewport(self.pos * self.rect_size)
709                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
710
711                let sz_px = self.size;
712                let sz_inner_px = sz_px - self.border_size * 4.;
713
714                let radius_px = sz_px * 0.5
715
716                let border_sz_uv = vec2(
717                    self.border_size / self.rect_size.x,
718                    self.border_size / self.rect_size.y
719                )
720
721                let center_px = vec2(
722                    radius_px,
723                    self.rect_size.y * 0.5
724                )
725
726                let offset_px = vec2(
727                    0.,
728                    center_px.y - radius_px
729                )
730
731                let offset_uv = vec2(
732                    offset_px.x / self.rect_size.x,
733                    offset_px.y / self.rect_size.y
734                )
735
736                let scale_factor_border = vec2(
737                    self.rect_size.x / sz_px,
738                    self.rect_size.y / sz_px
739                );
740
741                let scale_factor_fill = vec2(
742                    self.rect_size.x / sz_inner_px,
743                    self.rect_size.y / sz_inner_px 
744                );
745
746                let gradient_border = vec2(
747                    (self.pos.x - offset_uv.x) * scale_factor_border.x + dither,
748                    (self.pos.y - offset_uv.y) * scale_factor_border.y + dither
749                )
750
751                let gradient_fill = vec2(
752                    (self.pos.x - offset_uv.x - border_sz_uv.x * 2.) * scale_factor_fill.x + dither,
753                    (self.pos.y - offset_uv.y - border_sz_uv.y * 2.) * scale_factor_fill.y + dither
754                )
755
756                match self.radio_type {
757                    RadioType::Round => {
758
759                        // Draw background
760                        sdf.circle(
761                            center_px.x,
762                            center_px.y,
763                            radius_px - self.border_size
764                        );
765
766                        sdf.fill_keep(
767                            mix(
768                                mix(
769                                    mix(
770                                        mix(
771                                            mix(self.color_1, self.color_2, gradient_fill.x),
772                                            mix(self.color_1_focus, self.color_2_focus, gradient_fill.x),
773                                            self.focus
774                                        ),
775                                        mix(
776                                            mix(self.color_1_active, self.color_2_active, gradient_fill.x),
777                                            mix(self.color_1_focus, self.color_2_focus, gradient_fill.x),
778                                            self.focus
779                                        ),
780                                        self.active
781                                    ),
782                                    mix(
783                                        mix(self.color_1_hover, self.color_2_hover, gradient_fill.x),
784                                        mix(self.color_1_down, self.color_2_down, gradient_fill.x),
785                                        self.down
786                                    ),
787                                    self.hover
788                                ),
789                                mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.x),
790                                self.disabled
791                            )
792                        )
793
794                        sdf.stroke(
795                            mix(
796                                mix(
797                                    mix(
798                                        mix(
799                                            mix(self.border_color_1, self.border_color_2, gradient_border.y),
800                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
801                                            self.focus
802                                        ),
803                                        mix(
804                                            mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
805                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
806                                            self.focus
807                                        ),
808                                        self.active
809                                    ),
810                                    mix(
811                                        mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
812                                        mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
813                                        self.down
814                                    ),
815                                    self.hover
816                                ),
817                                mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
818                                self.disabled
819                            ), self.border_size
820                        )
821
822                        // Draw mark
823                        sdf.circle(
824                            center_px.x,
825                            center_px.y + self.mark_offset,
826                            radius_px * 0.5 - self.border_size * 0.75
827                        );
828
829                        sdf.fill(
830                            mix(
831                                mix(
832                                    self.mark_color,
833                                    self.mark_color_active,
834                                    self.active
835                                ),
836                                self.mark_color_disabled,
837                                self.disabled
838                            )
839                        );
840                    }
841                    RadioType::Tab => {
842                        let border_sz_uv = vec2(
843                            self.border_size / self.rect_size.x,
844                            self.border_size / self.rect_size.y
845                        )
846
847                        let scale_factor_border = vec2(
848                            self.rect_size.x / self.rect_size.x,
849                            self.rect_size.y / self.rect_size.y
850                        );
851
852                        let gradient_border = vec2(
853                            self.pos.x * scale_factor_border.x + dither,
854                            self.pos.y * scale_factor_border.y + dither
855                        )
856
857                        let sz_inner_px = vec2(
858                            self.rect_size.x - self.border_size * 2.,
859                            self.rect_size.y - self.border_size * 2.
860                        );
861
862                        let scale_factor_fill = vec2(
863                            self.rect_size.x / sz_inner_px.x,
864                            self.rect_size.y / sz_inner_px.y
865                        );
866
867                        let gradient_fill = vec2(
868                            self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
869                            self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
870                        )
871
872                        sdf.box(
873                            self.border_size,
874                            self.border_size,
875                            self.rect_size.x - self.border_size * 2.,
876                            self.rect_size.y - self.border_size * 2.,
877                            self.border_radius
878                        )
879
880                        sdf.fill_keep(
881                            mix(
882                                mix(
883                                    mix(self.color_1, self.color_2, gradient_fill.y),
884                                    mix(self.color_1_active, self.color_2_active, gradient_fill.y),
885                                    self.active
886                                ),
887                                mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.y),
888                                self.disabled
889                            )
890                        )
891
892                        sdf.stroke(
893                            mix(
894                                mix(
895                                    mix(
896                                        mix(
897                                            mix(self.border_color_1, self.border_color_2, gradient_border.y),
898                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
899                                            self.focus
900                                        ),
901                                        mix(
902                                            mix(self.border_color_1_active, self.border_color_2_active, gradient_border.y),
903                                            mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
904                                            self.focus
905                                        ),
906                                        self.active
907                                    ),
908                                    mix(
909                                        mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
910                                        mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
911                                        self.down
912                                    ),
913                                    self.hover
914                                ),
915                                mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
916                                self.disabled
917                            ), self.border_size
918                        )
919                            
920                    }
921                }
922                return sdf.result
923            }
924        }
925    }
926
927    pub RadioButtonFlat = <RadioButton> {
928        draw_bg: {
929            color: (THEME_COLOR_INSET)
930            color_hover: (THEME_COLOR_INSET_HOVER)
931            color_down: (THEME_COLOR_INSET_DOWN)
932            color_active: (THEME_COLOR_INSET_ACTIVE)
933            color_focus: (THEME_COLOR_INSET_FOCUS)
934            color_disabled: (THEME_COLOR_INSET_DISABLED)
935
936            border_color_1: (THEME_COLOR_BEVEL)
937            border_color_1_hover: (THEME_COLOR_BEVEL_HOVER)
938            border_color_1_down: (THEME_COLOR_BEVEL_DOWN)
939            border_color_1_active: (THEME_COLOR_BEVEL_ACTIVE)
940            border_color_1_focus: (THEME_COLOR_BEVEL_FOCUS)
941            border_color_1_disabled: (THEME_COLOR_BEVEL_DISABLED)
942
943            border_color_2: (THEME_COLOR_BEVEL)
944            border_color_2_hover: (THEME_COLOR_BEVEL_HOVER)
945            border_color_2_down: (THEME_COLOR_BEVEL_DOWN)
946            border_color_2_active: (THEME_COLOR_BEVEL_ACTIVE)
947            border_color_2_focus: (THEME_COLOR_BEVEL_FOCUS)
948            border_color_2_disabled: (THEME_COLOR_BEVEL_DISABLED)
949
950            mark_offset: 0.
951            mark_color_active: (THEME_COLOR_MARK_ACTIVE)
952        }
953
954    }
955
956    pub RadioButtonFlatter = <RadioButtonFlat> {
957        draw_bg: {
958            border_size: 0.
959        }
960
961    }
962         
963    pub RadioButtonCustom = <RadioButton> {
964        draw_bg: {
965            fn pixel(self) -> vec4 {
966                let sdf = Sdf2d::viewport(self.pos * self.rect_size)
967                return sdf.result
968            }
969        }
970
971        draw_icon: {
972            color_1: (THEME_COLOR_MARK_EMPTY)
973            color_1_active: (THEME_COLOR_MARK_ACTIVE)
974            color_1_disabled: (THEME_COLOR_MARK_DISABLED)
975
976            color_2: (THEME_COLOR_MARK_EMPTY)
977            color_2_active: (THEME_COLOR_MARK_ACTIVE)
978            color_2_disabled: (THEME_COLOR_MARK_DISABLED)
979        }
980        margin: { left: -17.5 }
981
982        label_walk: { margin: { left: (THEME_SPACE_2) } }
983    }
984        
985    pub RadioButtonTextual = <RadioButton> {
986        draw_text: {
987            color: (THEME_COLOR_LABEL_OUTER_OFF)
988            color_hover: (THEME_COLOR_LABEL_OUTER_HOVER)
989            color_down: (THEME_COLOR_LABEL_OUTER_DOWN)
990            color_active: (THEME_COLOR_LABEL_OUTER_ACTIVE)
991            color_disabled: (THEME_COLOR_LABEL_OUTER_DISABLED)
992        }
993
994        label_walk: { margin: 0. }
995
996        draw_bg: {
997            fn pixel(self) -> vec4 {
998                let sdf = Sdf2d::viewport(self.pos * self.rect_size)
999                return sdf.result
1000            }
1001        }
1002    }
1003        
1004    pub RadioButtonTab = <RadioButton> {
1005        height: Fit,
1006        label_walk: {
1007            margin: {
1008                left: (THEME_SPACE_3 * 2.)
1009                right: (THEME_SPACE_1)
1010            }
1011        }
1012
1013        draw_bg: {
1014            radio_type: Tab
1015
1016            color: (THEME_COLOR_OUTSET)
1017            color_active: (THEME_COLOR_OUTSET_ACTIVE)
1018            color_disabled: (THEME_COLOR_OUTSET_DISABLED)
1019
1020            border_color_1: (THEME_COLOR_BEVEL_OUTSET_1)
1021            border_color_1_hover: (THEME_COLOR_BEVEL_OUTSET_1_HOVER)
1022            border_color_1_down: (THEME_COLOR_BEVEL_OUTSET_1_DOWN)
1023            border_color_1_active: (THEME_COLOR_BEVEL_OUTSET_1_ACTIVE)
1024            border_color_1_focus: (THEME_COLOR_BEVEL_OUTSET_1_FOCUS)
1025            border_color_1_disabled: (THEME_COLOR_BEVEL_OUTSET_1_DISABLED)
1026
1027            border_color_2: (THEME_COLOR_BEVEL_OUTSET_2)
1028            border_color_2_hover: (THEME_COLOR_BEVEL_OUTSET_2_HOVER)
1029            border_color_2_down: (THEME_COLOR_BEVEL_OUTSET_2_DOWN)
1030            border_color_2_active: (THEME_COLOR_BEVEL_OUTSET_2_ACTIVE)
1031            border_color_2_focus: (THEME_COLOR_BEVEL_OUTSET_2_FOCUS)
1032            border_color_2_disabled: (THEME_COLOR_BEVEL_OUTSET_2_DISABLED)
1033        }
1034
1035        padding: <THEME_MSPACE_2> { left: (THEME_SPACE_2 * -1.25)}
1036            
1037        draw_text: {
1038            color: (THEME_COLOR_LABEL_INNER)
1039            color_hover: (THEME_COLOR_LABEL_INNER_HOVER)
1040            color_down: (THEME_COLOR_LABEL_INNER_DOWN)
1041            color_active: (THEME_COLOR_LABEL_INNER_ACTIVE)
1042            color_disabled: (THEME_COLOR_LABEL_INNER_DISABLED)
1043        }
1044    }
1045    
1046
1047    pub RadioButtonTabFlat = <RadioButtonTab> {
1048        draw_bg: {
1049            color: (THEME_COLOR_OUTSET)
1050            color_active: (THEME_COLOR_OUTSET_ACTIVE)
1051            color_disabled: (THEME_COLOR_OUTSET_DISABLED)
1052
1053            border_color_1: (THEME_COLOR_BEVEL)
1054            border_color_1_hover: (THEME_COLOR_BEVEL_HOVER)
1055            border_color_1_down: (THEME_COLOR_BEVEL_DOWN)
1056            border_color_1_active: (THEME_COLOR_BEVEL_ACTIVE)
1057            border_color_1_focus: (THEME_COLOR_BEVEL_FOCUS)
1058            border_color_1_disabled: (THEME_COLOR_BEVEL_DISABLED)
1059
1060            border_color_2: (THEME_COLOR_BEVEL)
1061            border_color_2_hover: (THEME_COLOR_BEVEL_HOVER)
1062            border_color_2_down: (THEME_COLOR_BEVEL_DOWN)
1063            border_color_2_active: (THEME_COLOR_BEVEL_ACTIVE)
1064            border_color_2_focus: (THEME_COLOR_BEVEL_FOCUS)
1065            border_color_2_disabled: (THEME_COLOR_BEVEL_DISABLED)
1066        }
1067    }
1068
1069    pub RadioButtonTabFlatter = <RadioButtonTabFlat> { draw_bg: { border_size: 0.  }
1070    }
1071
1072    pub RadioButtonTabGradientX = <RadioButtonTab> {
1073        draw_bg: {
1074            uniform border_size: (THEME_BEVELING)
1075            uniform border_radius: (THEME_CORNER_RADIUS)
1076
1077            uniform color_dither: 1.0
1078
1079            uniform color_1: (THEME_COLOR_OUTSET_1)
1080            uniform color_1_active: (THEME_COLOR_OUTSET_1_ACTIVE)
1081            uniform color_1_disabled: (THEME_COLOR_OUTSET_1_DISABLED)
1082
1083            uniform color_2: (THEME_COLOR_OUTSET_2)
1084            uniform color_2_active: (THEME_COLOR_OUTSET_2_ACTIVE)
1085            uniform color_2_disabled: (THEME_COLOR_OUTSET_2_DISABLED)
1086
1087            uniform border_color_1: (THEME_COLOR_BEVEL_OUTSET_1)
1088            uniform border_color_1_hover: (THEME_COLOR_BEVEL_OUTSET_1_HOVER)
1089            uniform border_color_1_down: (THEME_COLOR_BEVEL_OUTSET_1_DOWN)
1090            uniform border_color_1_active: (THEME_COLOR_BEVEL_OUTSET_1_ACTIVE)
1091            uniform border_color_1_disabled: (THEME_COLOR_BEVEL_OUTSET_1_DISABLED)
1092            uniform border_color_1_active_focus: (THEME_COLOR_BEVEL_OUTSET_1_FOCUS)
1093
1094            uniform border_color_2: (THEME_COLOR_BEVEL_OUTSET_2)
1095            uniform border_color_2_hover: (THEME_COLOR_BEVEL_OUTSET_2_HOVER)
1096            uniform border_color_2_down: (THEME_COLOR_BEVEL_OUTSET_2_DOWN)
1097            uniform border_color_2_active: (THEME_COLOR_BEVEL_OUTSET_2_ACTIVE)
1098            uniform border_color_2_active_focus: (THEME_COLOR_BEVEL_OUTSET_2_ACTIVE)
1099            uniform border_color_2_disabled: (THEME_COLOR_BEVEL_OUTSET_2_DISABLED)
1100
1101            fn pixel(self) -> vec4 {
1102                let sdf = Sdf2d::viewport(self.pos * self.rect_size)
1103                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
1104
1105                sdf.box(
1106                    self.border_size,
1107                    self.border_size,
1108                    self.rect_size.x - self.border_size * 2.,
1109                    self.rect_size.y - self.border_size * 2.,
1110                    self.border_radius
1111                )
1112
1113                sdf.fill_keep(
1114                    mix(
1115                        mix(
1116                            mix(self.color_1, self.color_2, self.pos.x + dither),
1117                            mix(self.color_1_active, self.color_2_active, self.pos.x + dither),
1118                            self.active
1119                        ),
1120                        mix(self.color_1_disabled, self.color_2_disabled, self.pos.x + dither),
1121                        self.disabled
1122                    )
1123                )
1124
1125                sdf.stroke(
1126                    mix(
1127                        mix(
1128                            mix(
1129                                mix(
1130                                    mix(self.border_color_1, self.border_color_2, self.pos.y + dither),
1131                                    mix(self.border_color_1_focus, self.border_color_2_focus, self.pos.y + dither),
1132                                    self.focus
1133                                ),
1134                                mix(
1135                                    mix(self.border_color_1_active, self.border_color_2_active, self.pos.y + dither),
1136                                    mix(self.border_color_1_focus, self.border_color_2_focus, self.pos.y + dither),
1137                                    self.focus
1138                                ),
1139                                self.active
1140                            ),
1141                            mix(
1142                                mix(self.border_color_1_hover, self.border_color_2_hover, self.pos.y + dither),
1143                                mix(self.border_color_1_down, self.border_color_2_down, self.pos.y + dither),
1144                                self.down
1145                            ),
1146                            self.hover
1147                        ),
1148                        mix(self.border_color_1_disabled, self.border_color_2_disabled, self.pos.y + dither),
1149                        self.disabled
1150                    ), self.border_size
1151                )
1152                return sdf.result
1153            }
1154        }
1155    }
1156
1157    pub RadioButtonTabGradientY = <RadioButtonTabGradientX> {
1158        draw_bg: {
1159            fn pixel(self) -> vec4 {
1160                let sdf = Sdf2d::viewport(self.pos * self.rect_size)
1161                let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
1162
1163                sdf.box(
1164                    self.border_size,
1165                    self.border_size,
1166                    self.rect_size.x - self.border_size * 2.,
1167                    self.rect_size.y - self.border_size * 2.,
1168                    self.border_radius
1169                )
1170
1171                sdf.fill_keep(
1172                    mix(
1173                        mix(
1174                            mix(self.color_1, self.color_2, self.pos.y + dither),
1175                            mix(self.color_1_active, self.color_2_active, self.pos.y + dither),
1176                            self.active
1177                        ),
1178                        mix(self.color_1_disabled, self.color_2_disabled, self.pos.y + dither),
1179                        self.disabled
1180                    )
1181                )
1182
1183                sdf.stroke(
1184                    mix(
1185                        mix(
1186                            mix(
1187                                mix(
1188                                    mix(self.border_color_1, self.border_color_2, self.pos.y + dither),
1189                                    mix(self.border_color_1_focus, self.border_color_2_focus, self.pos.y + dither),
1190                                    self.focus
1191                                ),
1192                                mix(
1193                                    mix(self.border_color_1_active, self.border_color_2_active, self.pos.y + dither),
1194                                    mix(self.border_color_1_focus, self.border_color_2_focus, self.pos.y + dither),
1195                                    self.focus
1196                                ),
1197                                self.active
1198                            ),
1199                            mix(
1200                                mix(self.border_color_1_hover, self.border_color_2_hover, self.pos.y + dither),
1201                                mix(self.border_color_1_down, self.border_color_2_down, self.pos.y + dither),
1202                                self.down
1203                            ),
1204                            self.hover
1205                        ),
1206                        mix(self.border_color_1_disabled, self.border_color_2_disabled, self.pos.y + dither),
1207                        self.disabled
1208                    ), self.border_size
1209                )
1210                return sdf.result
1211            }
1212        }
1213    }
1214    
1215    pub ButtonGroup = <CachedRoundedView> {
1216        flow: Right
1217        height: Fit, width: Fit,
1218        spacing: (THEME_SPACE_2)
1219        align: { x: 0.0, y: 0.5 }
1220    }
1221
1222    pub RadioButtonGroupTab = <RadioButtonTab> {
1223        height: Fit,
1224        draw_bg: { radio_type: Tab }
1225        padding: <THEME_MSPACE_2> { left: (THEME_SPACE_2 * -1.25), right: (THEME_SPACE_2 * 2.)}
1226            
1227    }
1228}
1229
1230#[derive(Live, LiveHook, LiveRegister)]
1231#[repr(C)]
1232pub struct DrawRadioButton {
1233    #[deref] draw_super: DrawQuad,
1234    #[live] radio_type: RadioType,
1235    #[live] hover: f32,
1236    #[live] focus: f32,
1237    #[live] active: f32
1238}
1239
1240
1241#[derive(Live, LiveHook)]
1242#[live_ignore]
1243#[repr(u32)]
1244pub enum RadioType {
1245    #[pick] Round = shader_enum(1),
1246    Tab = shader_enum(2),
1247}
1248
1249#[derive(Live, LiveHook)]
1250#[live_ignore]
1251pub enum MediaType {
1252    Image,
1253    #[pick] Icon,
1254    None,
1255}
1256
1257#[derive(Live, LiveHook, Widget)]
1258pub struct RadioButtonGroup {
1259    #[deref] frame: View
1260}
1261
1262#[derive(Live, LiveHook, Widget)]
1263pub struct RadioButton {
1264    #[redraw] #[live] draw_bg: DrawRadioButton,
1265    #[live] draw_icon: DrawIcon,
1266    #[live] draw_text: DrawText,
1267
1268    #[live] value: LiveValue,
1269
1270    #[live] media: MediaType,
1271    
1272    #[live] icon_walk: Walk,
1273    #[walk] walk: Walk,
1274
1275    #[live] image: Image,
1276
1277    #[layout] layout: Layout,
1278    #[animator] animator: Animator,
1279    
1280    #[live] label_walk: Walk,
1281    #[live] label_align: Align,
1282    #[live] text: ArcStringMut,
1283    
1284    #[live] bind: String,
1285}
1286
1287#[derive(Clone, Debug, DefaultNone)]
1288pub enum RadioButtonAction {
1289    Clicked,
1290    None
1291}
1292
1293
1294impl RadioButtonGroup {
1295    pub fn draw_walk(&mut self, _cx: &mut Cx2d, _walk: Walk) {}
1296}
1297
1298impl RadioButton {
1299    pub fn draw_walk(&mut self, cx: &mut Cx2d, walk: Walk) {
1300        self.draw_bg.begin(cx, walk, self.layout);
1301        match self.media {
1302            MediaType::Image => {
1303                let image_walk = self.image.walk(cx);
1304                let _ = self.image.draw_walk(cx, image_walk);
1305            }
1306            MediaType::Icon => {
1307                self.draw_icon.draw_walk(cx, self.icon_walk);
1308            }
1309            MediaType::None => {}
1310        }
1311        self.draw_text.draw_walk(cx, self.label_walk, self.label_align, self.text.as_ref());
1312        self.draw_bg.end(cx);
1313        cx.add_nav_stop(self.draw_bg.area(), NavRole::TextInput, Margin::default());
1314    }
1315        
1316}
1317
1318impl Widget for RadioButtonGroup {
1319    
1320    fn handle_event(&mut self, cx: &mut Cx, event: &Event, _scope: &mut Scope) {
1321        //let uid = self.widget_uid();
1322        self.animator_handle_event(cx, event);
1323              
1324    }
1325    
1326    fn draw_walk(&mut self, cx: &mut Cx2d, _scope:&mut Scope, walk: Walk) -> DrawStep {
1327        self.draw_walk(cx, walk);
1328        DrawStep::done()
1329    }
1330    
1331}
1332
1333impl Widget for RadioButton {
1334    
1335    fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
1336        let uid = self.widget_uid();
1337        self.animator_handle_event(cx, event);
1338                
1339        match event.hits(cx, self.draw_bg.area()) {
1340            Hit::KeyFocus(_) => {
1341                self.animator_play(cx, id!(focus.on));
1342            }
1343            Hit::KeyFocusLost(_) => {
1344                self.animator_play(cx, id!(focus.off));
1345                self.draw_bg.redraw(cx);
1346            }
1347            Hit::FingerHoverIn(_) => {
1348                cx.set_cursor(MouseCursor::Hand);
1349                self.animator_play(cx, id!(hover.on));
1350            }
1351            Hit::FingerHoverOut(_) => {
1352                cx.set_cursor(MouseCursor::Arrow);
1353                self.animator_play(cx, id!(hover.off));
1354            },
1355            Hit::FingerDown(fe) if fe.is_primary_hit() => {
1356                if self.animator_in_state(cx, id!(active.off)) {
1357                    self.animator_play(cx, id!(hover.down));
1358                }
1359                self.set_key_focus(cx);
1360            },
1361            Hit::FingerUp(_fe) => {
1362                self.animator_play(cx, id!(hover.on));
1363                if self.animator_in_state(cx, id!(active.off)) {
1364                    self.animator_play(cx, id!(active.on));
1365                    cx.widget_action(uid, &scope.path, RadioButtonAction::Clicked);
1366                } else {
1367                    self.animator_play(cx, id!(active.off));
1368                }
1369            }
1370            Hit::FingerMove(_fe) => {
1371                                
1372            }
1373            _ => ()
1374        }
1375
1376    }
1377    
1378    fn set_disabled(&mut self, cx:&mut Cx, disabled:bool){
1379        self.animator_toggle(cx, disabled, Animate::Yes, id!(disabled.on), id!(disabled.off));
1380    }
1381                
1382    fn disabled(&self, cx:&Cx) -> bool {
1383        self.animator_in_state(cx, id!(disabled.on))
1384    }
1385
1386    fn draw_walk(&mut self, cx: &mut Cx2d, _scope:&mut Scope, walk: Walk) -> DrawStep {
1387        self.draw_walk(cx, walk);
1388        DrawStep::done()
1389    }
1390    
1391    fn text(&self) -> String {
1392        self.text.as_ref().to_string()
1393    }
1394            
1395    fn set_text(&mut self, cx:&mut Cx, v: &str) {
1396        self.text.as_mut_empty().push_str(v);
1397        self.redraw(cx);
1398    }
1399}
1400
1401impl RadioButtonRef{
1402    fn unselect(&self, cx:&mut Cx){
1403        if let Some(mut inner) = self.borrow_mut(){
1404            inner.animator_play(cx, id!(active.off));
1405        }
1406    }
1407
1408    pub fn select(&self, cx: &mut Cx, scope: &mut Scope){
1409        if let Some(mut inner) = self.borrow_mut(){
1410            if inner.animator_in_state(cx, id!(active.off)) {
1411                inner.animator_play(cx, id!(active.on));
1412                cx.widget_action(inner.widget_uid(), &scope.path, RadioButtonAction::Clicked);
1413            }
1414        }
1415    }
1416}
1417
1418impl RadioButtonSet{
1419    
1420    pub fn selected(&self, cx: &mut Cx, actions: &Actions)->Option<usize>{
1421        for action in actions{
1422            if let Some(action) = action.as_widget_action(){
1423                match action.cast(){
1424                    RadioButtonAction::Clicked => if let Some(index) = self.0.iter().position(|v| action.widget_uid == v.widget_uid()){
1425                        for (i, item) in self.0.iter().enumerate(){
1426                            if i != index{
1427                                RadioButtonRef(item.clone()).unselect(cx);
1428                            }
1429                        }
1430                        return Some(index);
1431                    }
1432                    _ => ()
1433                }
1434            }
1435        }
1436        None
1437    }
1438    
1439    pub fn selected_to_visible(&self, cx: &mut Cx, ui:&WidgetRef, actions: &Actions, paths:&[&[LiveId]] ) {
1440        // find a widget action that is in our radiogroup
1441        if let Some(index) = self.selected(cx, actions){
1442            // ok now we set visible
1443            for (i,path) in paths.iter().enumerate(){
1444                let widget = ui.widget(path);
1445                widget.apply_over(cx, live!{visible:(i == index)});
1446                widget.redraw(cx);
1447            }
1448        }
1449    }
1450}