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 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 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 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 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 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 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 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 if let Some(index) = self.selected(cx, actions){
1442 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}