1use crate::{makepad_derive_widget::*, makepad_draw::*, widget::*,};
2
3live_design! {
4 link widgets;
5 use link::theme::*;
6 use link::shaders::*;
7
8 pub ButtonBase = {{Button}} {}
9 pub Button = <ButtonBase> {
10 text: ""
11 width: Fit, height: Fit,
12 spacing: (THEME_SPACE_2),
13 align: {x: 0.5, y: 0.5},
14 padding: <THEME_MSPACE_1> { left: (THEME_SPACE_2), right: (THEME_SPACE_2) }
15 margin: <THEME_MSPACE_V_1> {}
16 label_walk: { width: Fit, height: Fit },
17
18 draw_text: {
19 instance hover: 0.0,
20 instance down: 0.0,
21 instance focus: 0.0,
22 instance disabled: 0.0
23
24 color: (THEME_COLOR_LABEL_INNER)
25 uniform color_hover: (THEME_COLOR_LABEL_INNER_HOVER)
26 uniform color_down: (THEME_COLOR_LABEL_INNER_DOWN)
27 uniform color_focus: (THEME_COLOR_LABEL_INNER_FOCUS)
28 uniform color_disabled: (THEME_COLOR_LABEL_INNER_DISABLED)
29
30 text_style: <THEME_FONT_REGULAR> {
31 font_size: (THEME_FONT_SIZE_P)
32 }
33 fn get_color(self) -> vec4 {
34 return mix(
35 mix(
36 mix(
37 mix(self.color, self.color_focus, self.focus),
38 self.color_hover,
39 self.hover
40 ),
41 self.color_down,
42 self.down
43 ),
44 self.color_disabled,
45 self.disabled
46 )
47 }
48 }
49
50 icon_walk: {
51 width: (THEME_DATA_ICON_WIDTH), height: Fit,
52 }
53
54 draw_icon: {
55 instance hover: 0.0
56 instance down: 0.0
57 instance focus: 0.0
58 instance disabled: 0.0
59
60 uniform color: (THEME_COLOR_LABEL_INNER)
61 uniform color_hover: (THEME_COLOR_LABEL_INNER_HOVER)
62 uniform color_down: (THEME_COLOR_LABEL_INNER_DOWN)
63 uniform color_focus: (THEME_COLOR_LABEL_INNER_FOCUS)
64 uniform color_disabled: (THEME_COLOR_LABEL_INNER_DISABLED)
65
66 fn get_color(self) -> vec4 {
67 return mix(
68 mix(
69 mix(
70 mix(self.color, self.color_focus, self.focus),
71 self.color_hover,
72 self.hover
73 ),
74 self.color_down,
75 self.down
76 ),
77 self.color_disabled,
78 self.disabled
79 )
80 }
81 }
82
83 draw_bg: {
84 instance hover: 0.0
85 instance down: 0.0
86 instance enabled: 1.0
87 instance disabled: 0.0
88 instance focus: 0.0
89
90 uniform color_dither: 1.0
91
92 uniform border_size: (THEME_BEVELING)
93 uniform border_radius: (THEME_CORNER_RADIUS)
94
95 uniform color: (THEME_COLOR_OUTSET)
96 uniform color_hover: (THEME_COLOR_OUTSET_HOVER)
97 uniform color_down: (THEME_COLOR_OUTSET_DOWN)
98 uniform color_focus: (THEME_COLOR_OUTSET_FOCUS)
99 uniform color_disabled: (THEME_COLOR_OUTSET_DISABLED)
100
101 uniform border_color_1: (THEME_COLOR_BEVEL_OUTSET_1)
102 uniform border_color_1_hover: (THEME_COLOR_BEVEL_OUTSET_1_HOVER)
103 uniform border_color_1_down: (THEME_COLOR_BEVEL_OUTSET_1_DOWN)
104 uniform border_color_1_focus: (THEME_COLOR_BEVEL_OUTSET_1_FOCUS)
105 uniform border_color_1_disabled: (THEME_COLOR_BEVEL_OUTSET_1_DISABLED)
106
107 uniform border_color_2: (THEME_COLOR_BEVEL_OUTSET_2)
108 uniform border_color_2_hover: (THEME_COLOR_BEVEL_OUTSET_2_HOVER)
109 uniform border_color_2_down: (THEME_COLOR_BEVEL_OUTSET_2_DOWN)
110 uniform border_color_2_focus: (THEME_COLOR_BEVEL_OUTSET_2_FOCUS)
111 uniform border_color_2_disabled: (THEME_COLOR_BEVEL_OUTSET_2_DISABLED)
112
113 fn pixel(self) -> vec4 {
114 let sdf = Sdf2d::viewport(self.pos * self.rect_size)
115 let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
116
117 let border_sz_uv = vec2(
118 self.border_size / self.rect_size.x,
119 self.border_size / self.rect_size.y
120 )
121
122 let gradient_border = vec2(
123 self.pos.x + dither,
124 self.pos.y + dither
125 )
126
127 let sz_inner_px = vec2(
128 self.rect_size.x - self.border_size * 2.,
129 self.rect_size.y - self.border_size * 2.
130 );
131
132 let scale_factor_fill = vec2(
133 self.rect_size.x / sz_inner_px.x,
134 self.rect_size.y / sz_inner_px.y
135 );
136
137 let gradient_fill = vec2(
138 self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
139 self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
140 )
141
142 sdf.box(
143 self.border_size,
144 self.border_size,
145 self.rect_size.x - self.border_size * 2.,
146 self.rect_size.y - self.border_size * 2.,
147 self.border_radius
148 )
149
150 sdf.fill_keep(
151 mix(
152 mix(
153 mix(
154 mix(self.color, self.color_focus, self.focus),
155 self.color_hover,
156 self.hover
157 ),
158 self.color_down,
159 self.down
160 ),
161 self.color_disabled,
162 self.disabled
163 )
164 )
165
166 sdf.stroke(
167 mix(
168 mix(
169 mix(
170 mix(
171 mix(self.border_color_1, self.border_color_2, gradient_border.y),
172 mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
173 self.focus
174 ),
175 mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
176 self.hover
177 ),
178 mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
179 self.down
180 ),
181 mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
182 self.disabled
183 ), self.border_size
184 )
185 return sdf.result;
186 }
187 }
188
189 animator: {
190 disabled = {
191 default: off,
192 off = {
193 from: {all: Forward {duration: 0.}}
194 apply: {
195 draw_bg: {disabled: 0.0}
196 draw_text: {disabled: 0.0}
197 draw_icon: {disabled: 0.0}
198 }
199 }
200 on = {
201 from: {all: Forward {duration: 0.2}}
202 apply: {
203 draw_bg: {disabled: 1.0}
204 draw_text: {disabled: 1.0}
205 draw_icon: {disabled: 1.0}
206 }
207 }
208 }
209 time = {
210 default: off,
211 off = {
212 from: {all: Forward {duration: 0.}}
213 apply: {
214 }
216 }
217 on = {
218 from: {all: Loop {duration: 1.0, end:1000000000.0}}
219 apply: {
220 draw_bg: {anim_time: [{time: 0.0, value: 0.0},{time:1.0, value:1.0}]}
221 }
222 }
223 }
224 hover = {
225 default: off,
226 off = {
227 from: {all: Forward {duration: 0.1}}
228 apply: {
229 draw_bg: {down: 0.0, hover: 0.0}
230 draw_icon: {down: 0.0, hover: 0.0}
231 draw_text: {down: 0.0, hover: 0.0}
232 }
233 }
234
235 on = {
236 from: {
237 all: Forward {duration: 0.1}
238 down: Forward {duration: 0.01}
239 }
240 apply: {
241 draw_bg: {down: 0.0, hover: [{time: 0.0, value: 1.0}],}
242 draw_icon: {down: 0.0, hover: [{time: 0.0, value: 1.0}],}
243 draw_text: {down: 0.0, hover: [{time: 0.0, value: 1.0}],}
244 }
245 }
246
247 down = {
248 from: {all: Forward {duration: 0.2}}
249 apply: {
250 draw_bg: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
251 draw_icon: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
252 draw_text: {down: [{time: 0.0, value: 1.0}], hover: 1.0,}
253 }
254 }
255 }
256 focus = {
257 default: off
258 off = {
259 from: {all: Forward {duration: 0.2}}
260 apply: {
261 draw_bg: {focus: 0.0}
262 draw_icon: {focus: 0.0}
263 draw_text: {focus: 0.0}
264 }
265 }
266 on = {
267 cursor: Arrow,
268 from: {all: Forward {duration: 0.0}}
269 apply: {
270 draw_bg: {focus: 1.0}
271 draw_icon: {focus: 1.0}
272 draw_text: {focus: 1.0}
273 }
274 }
275 }
276 }
277 }
278
279 pub ButtonGradientX = <Button> {
280 draw_bg: {
281 instance hover: 0.0
282 instance down: 0.0
283 instance enabled: 1.0
284 instance disabled: 1.0
285
286 border_size: (THEME_BEVELING)
287 border_radius: (THEME_CORNER_RADIUS)
288
289 color_dither: 1.0
290
291 uniform color_1: (THEME_COLOR_OUTSET_1)
292 uniform color_1_hover: (THEME_COLOR_OUTSET_1_HOVER)
293 uniform color_1_down: (THEME_COLOR_OUTSET_1_DOWN)
294 uniform color_1_focus: (THEME_COLOR_OUTSET_1_FOCUS)
295 uniform color_1_disabled: (THEME_COLOR_OUTSET_1_DISABLED)
296
297 uniform color_2: (THEME_COLOR_OUTSET_2)
298 uniform color_2_hover: (THEME_COLOR_OUTSET_2_HOVER)
299 uniform color_2_down: (THEME_COLOR_OUTSET_2_DOWN)
300 uniform color_2_focus: (THEME_COLOR_OUTSET_2_FOCUS)
301 uniform color_2_disabled: (THEME_COLOR_OUTSET_2_DISABLED)
302
303 border_color_1: (THEME_COLOR_BEVEL_OUTSET_1)
304 border_color_1_hover: (THEME_COLOR_BEVEL_OUTSET_1_HOVER)
305 border_color_1_down: (THEME_COLOR_BEVEL_OUTSET_1_DOWN)
306 border_color_1_focus: (THEME_COLOR_BEVEL_OUTSET_1_FOCUS)
307 border_color_1_disabled: (THEME_COLOR_BEVEL_OUTSET_1_DISABLED)
308
309 border_color_2: (THEME_COLOR_BEVEL_OUTSET_2)
310 border_color_2_hover: (THEME_COLOR_BEVEL_OUTSET_2_HOVER)
311 border_color_2_down: (THEME_COLOR_BEVEL_OUTSET_2_DOWN)
312 border_color_2_focus: (THEME_COLOR_BEVEL_OUTSET_2_FOCUS)
313 border_color_2_disabled: (THEME_COLOR_BEVEL_OUTSET_2_DISABLED)
314
315 fn pixel(self) -> vec4 {
316 let sdf = Sdf2d::viewport(self.pos * self.rect_size)
317 let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
318
319 let border_sz_uv = vec2(
320 self.border_size / self.rect_size.x,
321 self.border_size / self.rect_size.y
322 )
323
324 let gradient_border = vec2(
325 self.pos.x + dither,
326 self.pos.y + dither
327 )
328
329 let sz_inner_px = vec2(
330 self.rect_size.x - self.border_size * 2.,
331 self.rect_size.y - self.border_size * 2.
332 );
333
334 let scale_factor_fill = vec2(
335 self.rect_size.x / sz_inner_px.x,
336 self.rect_size.y / sz_inner_px.y
337 );
338
339 let gradient_fill = vec2(
340 self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
341 self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
342 )
343
344 sdf.box(
345 self.border_size,
346 self.border_size,
347 self.rect_size.x - self.border_size * 2.,
348 self.rect_size.y - self.border_size * 2.,
349 self.border_radius
350 )
351
352 sdf.fill_keep(
353 mix(
354 mix(
355 mix(
356 mix(
357 mix(self.color_1, self.color_2, gradient_fill.x),
358 mix(self.color_1_focus, self.color_2_focus, gradient_fill.x),
359 self.focus
360 ),
361 mix(self.color_1_hover, self.color_2_hover, gradient_fill.x),
362 self.hover
363 ),
364 mix(self.color_1_down, self.color_2_down, gradient_fill.x),
365 self.down
366 ),
367 mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.x),
368 self.disabled
369 )
370 )
371
372 sdf.stroke(
373 mix(
374 mix(
375 mix(
376 mix(
377 mix(self.border_color_1, self.border_color_2, gradient_border.y),
378 mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
379 self.focus
380 ),
381 mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
382 self.hover
383 ),
384 mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
385 self.down
386 ),
387 mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
388 self.disabled
389 ), self.border_size
390 )
391 return sdf.result
392 }
393 }
394 }
395
396 pub ButtonGradientY = <ButtonGradientX> {
397 draw_bg: {
398 fn pixel(self) -> vec4 {
399 let sdf = Sdf2d::viewport(self.pos * self.rect_size)
400 let dither = Math::random_2d(self.pos.xy) * 0.04 * self.color_dither;
401
402 let border_sz_uv = vec2(
403 self.border_size / self.rect_size.x,
404 self.border_size / self.rect_size.y
405 )
406
407 let gradient_border = vec2(
408 self.pos.x + dither,
409 self.pos.y + dither
410 )
411
412 let sz_inner_px = vec2(
413 self.rect_size.x - self.border_size * 2.,
414 self.rect_size.y - self.border_size * 2.
415 );
416
417 let scale_factor_fill = vec2(
418 self.rect_size.x / sz_inner_px.x,
419 self.rect_size.y / sz_inner_px.y
420 );
421
422 let gradient_fill = vec2(
423 self.pos.x * scale_factor_fill.x - border_sz_uv.x * 2. + dither,
424 self.pos.y * scale_factor_fill.y - border_sz_uv.y * 2. + dither
425 )
426
427 sdf.box(
428 self.border_size,
429 self.border_size,
430 self.rect_size.x - self.border_size * 2.,
431 self.rect_size.y - self.border_size * 2.,
432 self.border_radius
433 )
434
435 sdf.fill_keep(
436 mix(
437 mix(
438 mix(
439 mix(
440 mix(self.color_1, self.color_2, gradient_fill.y),
441 mix(self.color_1_focus, self.color_2_focus, gradient_fill.y),
442 self.focus
443 ),
444 mix(self.color_1_hover, self.color_2_hover, gradient_fill.y),
445 self.hover
446 ),
447 mix(self.color_1_down, self.color_2_down, gradient_fill.y),
448 self.down
449 ),
450 mix(self.color_1_disabled, self.color_2_disabled, gradient_fill.y),
451 self.disabled
452 )
453 )
454
455 sdf.stroke(
456 mix(
457 mix(
458 mix(
459 mix(
460 mix((THEME_COLOR_BEVEL_OUTSET_1), self.border_color_2, gradient_border.y),
461 mix(self.border_color_1_focus, self.border_color_2_focus, gradient_border.y),
462 self.focus
463 ),
464 mix(self.border_color_1_hover, self.border_color_2_hover, gradient_border.y),
465 self.hover
466 ),
467 mix(self.border_color_1_down, self.border_color_2_down, gradient_border.y),
468 self.down
469 ),
470 mix(self.border_color_1_disabled, self.border_color_2_disabled, gradient_border.y),
471 self.disabled
472 ), self.border_size
473 )
474
475 return sdf.result
476 }
477 }
478 }
479
480 pub ButtonFlat = <Button> {
481 draw_bg: {
482 color: (THEME_COLOR_OUTSET)
483 color_hover: (THEME_COLOR_OUTSET_HOVER)
484 color_down: (THEME_COLOR_OUTSET_DOWN)
485 color_disabled: (THEME_COLOR_OUTSET_DISABLED)
486
487 border_color_1: (THEME_COLOR_BEVEL)
488 border_color_1_hover: (THEME_COLOR_BEVEL_HOVER)
489 border_color_1_down: (THEME_COLOR_BEVEL_DOWN)
490 border_color_1_focus: (THEME_COLOR_BEVEL_FOCUS)
491 border_color_1_disabled: (THEME_COLOR_BEVEL_DISABLED)
492
493 border_color_2: (THEME_COLOR_BEVEL)
494 border_color_2_hover: (THEME_COLOR_BEVEL_HOVER)
495 border_color_2_down: (THEME_COLOR_BEVEL_DOWN)
496 border_color_2_focus: (THEME_COLOR_BEVEL_FOCUS)
497 border_color_2_disabled: (THEME_COLOR_BEVEL_DISABLED)
498
499 }
500
501 }
502
503 pub ButtonFlatter = <ButtonFlat> {
504 draw_bg: {
505
506 color: (THEME_COLOR_U_HIDDEN)
507 color_hover: (THEME_COLOR_U_HIDDEN)
508 color_down: (THEME_COLOR_U_HIDDEN)
509 color_disabled: (THEME_COLOR_OUTSET_DISABLED)
510
511 border_color_1: (THEME_COLOR_U_HIDDEN)
512 border_color_1_hover: (THEME_COLOR_U_HIDDEN)
513 border_color_1_down: (THEME_COLOR_U_HIDDEN)
514 border_color_1_focus: (THEME_COLOR_U_HIDDEN)
515 border_color_1_disabled: (THEME_COLOR_U_HIDDEN)
516
517 border_color_2: (THEME_COLOR_U_HIDDEN)
518 border_color_2_hover: (THEME_COLOR_U_HIDDEN)
519 border_color_2_down: (THEME_COLOR_U_HIDDEN)
520 border_color_2_focus: (THEME_COLOR_U_HIDDEN)
521 border_color_2_disabled: (THEME_COLOR_U_HIDDEN)
522 }
523 }
524
525 pub ButtonIcon = <Button> {
526 spacing: 0.
527 text: ""
528 }
529
530 pub ButtonGradientXIcon = <ButtonGradientX> {
531 spacing: 0.
532 text: ""
533 }
534
535 pub ButtonGradientYIcon = <ButtonGradientY> {
536 spacing: 0.
537 text: ""
538 }
539
540 pub ButtonFlatIcon = <ButtonFlat> {
541 spacing: 0.
542 text: ""
543 }
544
545 pub ButtonFlatterIcon = <ButtonFlatter> {
546 draw_bg: { color_focus: (THEME_COLOR_U_HIDDEN)}
547 spacing: 0.
548 text: ""
549 }
550
551}
552
553#[derive(Clone, Debug, DefaultNone)]
564pub enum ButtonAction {
565 None,
566 Pressed(KeyModifiers),
568 LongPressed,
570 Clicked(KeyModifiers),
572 Released(KeyModifiers),
575}
576
577#[derive(Live, LiveHook, Widget)]
579pub struct Button {
580 #[animator]
581 animator: Animator,
582
583 #[redraw]
584 #[live]
585 draw_bg: DrawQuad,
586 #[live]
587 draw_text: DrawText,
588 #[live]
589 draw_icon: DrawIcon,
590 #[live]
591 icon_walk: Walk,
592 #[live]
593 label_walk: Walk,
594 #[walk]
595 walk: Walk,
596
597 #[layout]
598 layout: Layout,
599
600 #[live(true)]
601 grab_key_focus: bool,
602
603 #[live(true)]
604 enabled: bool,
605
606 #[live(true)]
607 #[visible] visible: bool,
608
609 #[live]
626 pub enable_long_press: bool,
627
628 #[live]
632 reset_hover_on_click: bool,
633
634 #[live]
635 pub text: ArcStringMut,
636
637 #[action_data] #[rust] action_data: WidgetActionData,
638}
639
640impl Widget for Button {
641 fn set_disabled(&mut self, cx:&mut Cx, disabled:bool){
642 self.animator_toggle(cx, disabled, Animate::Yes, id!(disabled.on), id!(disabled.off));
643 }
644
645 fn disabled(&self, cx:&Cx) -> bool {
646 self.animator_in_state(cx, id!(disabled.on))
647 }
648
649 fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
650 let uid = self.widget_uid();
651 if self.animator_handle_event(cx, event).must_redraw() {
652 self.draw_bg.redraw(cx);
653 }
654
655 match event.hit_designer(cx, self.draw_bg.area()){
656 HitDesigner::DesignerPick(_e)=>{
657 cx.widget_action_with_data(&self.action_data, uid, &scope.path, WidgetDesignAction::PickedBody)
658 }
659 _=>()
660 }
661
662
663 match event.hits(cx, self.draw_bg.area()) {
667 Hit::KeyFocus(_) => {
668 self.animator_play(cx, id!(focus.on));
669 }
670 Hit::KeyFocusLost(_) => {
671 self.animator_play(cx, id!(focus.off));
672 self.draw_bg.redraw(cx);
673 }
674 Hit::FingerDown(fe) if self.enabled && fe.is_primary_hit() => {
675 if self.grab_key_focus {
676 cx.set_key_focus(self.draw_bg.area());
677 }
678 cx.widget_action_with_data(&self.action_data, uid, &scope.path, ButtonAction::Pressed(fe.modifiers));
679 self.animator_play(cx, id!(hover.down));
680 self.set_key_focus(cx);
681 }
682 Hit::FingerHoverIn(_) => {
683 if self.enabled {
684 cx.set_cursor(MouseCursor::Hand);
685 self.animator_play(cx, id!(hover.on));
686 } else {
687 cx.set_cursor(MouseCursor::NotAllowed);
688 }
689 }
690 Hit::FingerHoverOut(_) => {
691 self.animator_play(cx, id!(hover.off));
692 }
693 Hit::FingerLongPress(_lp) if self.enabled && self.enable_long_press => {
694 cx.widget_action_with_data(&self.action_data, uid, &scope.path, ButtonAction::LongPressed);
695 }
696 Hit::FingerUp(fe) if self.enabled && fe.is_primary_hit() => {
697 let was_clicked = fe.is_over && if self.enable_long_press { fe.was_tap() } else { true };
698 if was_clicked {
699 cx.widget_action_with_data(&self.action_data, uid, &scope.path, ButtonAction::Clicked(fe.modifiers));
700 if self.reset_hover_on_click {
701 self.animator_cut(cx, id!(hover.off));
702 } else if fe.has_hovers() {
703 self.animator_play(cx, id!(hover.on));
704 } else {
705 self.animator_play(cx, id!(hover.off));
706 }
707 } else {
708 cx.widget_action_with_data(&self.action_data, uid, &scope.path, ButtonAction::Released(fe.modifiers));
709 self.animator_play(cx, id!(hover.off));
710 }
711 }
712 _ => (),
713 }
714 }
715
716 fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep {
717 if !self.visible {
718 return DrawStep::done();
719 }
720
721 self.draw_bg.begin(cx, walk, self.layout);
722 self.draw_icon.draw_walk(cx, self.icon_walk);
723 self.draw_text
724 .draw_walk(cx, self.label_walk, Align::default(), self.text.as_ref());
725 self.draw_bg.end(cx);
726 cx.add_nav_stop(self.draw_bg.area(), NavRole::TextInput, Margin::default());
727 DrawStep::done()
728 }
729
730 fn text(&self) -> String {
731 self.text.as_ref().to_string()
732 }
733
734 fn set_text(&mut self, cx:&mut Cx, v: &str) {
735 self.text.as_mut_empty().push_str(v);
736 self.redraw(cx);
737 }
738}
739
740impl Button {
741
742 pub fn draw_button(&mut self, cx: &mut Cx2d, label:&str) {
743 self.draw_bg.begin(cx, self.walk, self.layout);
744 self.draw_icon.draw_walk(cx, self.icon_walk);
745 self.draw_text
746 .draw_walk(cx, self.label_walk, Align::default(), label);
747 self.draw_bg.end(cx);
748 }
749
750 pub fn clicked(&self, actions: &Actions) -> bool {
754 self.clicked_modifiers(actions).is_some()
755 }
756
757 pub fn pressed(&self, actions: &Actions) -> bool {
761 self.pressed_modifiers(actions).is_some()
762 }
763
764 pub fn long_pressed(&self, actions: &Actions) -> bool {
769 matches!(
770 actions.find_widget_action(self.widget_uid()).cast_ref(),
771 ButtonAction::LongPressed,
772 )
773 }
774
775 pub fn released(&self, actions: &Actions) -> bool {
779 self.released_modifiers(actions).is_some()
780 }
781
782 pub fn clicked_modifiers(&self, actions: &Actions) -> Option<KeyModifiers> {
786 if let ButtonAction::Clicked(m) = actions.find_widget_action(self.widget_uid()).cast_ref() {
787 Some(*m)
788 } else {
789 None
790 }
791 }
792
793 pub fn pressed_modifiers(&self, actions: &Actions) -> Option<KeyModifiers> {
797 if let ButtonAction::Pressed(m) = actions.find_widget_action(self.widget_uid()).cast_ref() {
798 Some(*m)
799 } else {
800 None
801 }
802 }
803
804 pub fn released_modifiers(&self, actions: &Actions) -> Option<KeyModifiers> {
809 if let ButtonAction::Released(m) = actions.find_widget_action(self.widget_uid()).cast_ref() {
810 Some(*m)
811 } else {
812 None
813 }
814 }
815}
816
817impl ButtonRef {
818 pub fn clicked(&self, actions: &Actions) -> bool {
820 self.borrow().is_some_and(|inner| inner.clicked(actions))
821 }
822
823 pub fn pressed(&self, actions: &Actions) -> bool {
825 self.borrow().is_some_and(|inner| inner.pressed(actions))
826 }
827
828 pub fn long_pressed(&self, actions: &Actions) -> bool {
830 self.borrow().is_some_and(|inner| inner.long_pressed(actions))
831 }
832
833 pub fn released(&self, actions: &Actions) -> bool {
835 self.borrow().is_some_and(|inner| inner.released(actions))
836 }
837
838 pub fn clicked_modifiers(&self, actions: &Actions) -> Option<KeyModifiers> {
840 self.borrow().and_then(|inner| inner.clicked_modifiers(actions))
841 }
842
843 pub fn pressed_modifiers(&self, actions: &Actions) -> Option<KeyModifiers> {
845 self.borrow().and_then(|inner| inner.pressed_modifiers(actions))
846 }
847
848 pub fn released_modifiers(&self, actions: &Actions) -> Option<KeyModifiers> {
850 self.borrow().and_then(|inner| inner.released_modifiers(actions))
851 }
852
853 pub fn set_visible(&self, cx: &mut Cx, visible: bool) {
854 if let Some(mut inner) = self.borrow_mut() {
855 inner.visible = visible;
856 inner.redraw(cx);
857 }
858 }
859
860 pub fn set_enabled(&self, cx: &mut Cx, enabled: bool) {
861 if let Some(mut inner) = self.borrow_mut() {
862 inner.enabled = enabled;
863 inner.redraw(cx);
864 }
865 }
866
867 pub fn reset_hover(&self, cx: &mut Cx) {
872 if let Some(mut inner) = self.borrow_mut() {
873 inner.animator_cut(cx, id!(hover.off));
874 }
875 }
876}
877
878impl ButtonSet {
879 pub fn clicked(&self, actions: &Actions) -> bool {
880 self.iter().any(|v| v.clicked(actions))
881 }
882 pub fn pressed(&self, actions: &Actions) -> bool {
883 self.iter().any(|v| v.pressed(actions))
884 }
885 pub fn released(&self, actions: &Actions) -> bool {
886 self.iter().any(|v| v.released(actions))
887 }
888
889 pub fn reset_hover(&self, cx: &mut Cx) {
890 for item in self.iter() {
891 item.reset_hover(cx)
892 }
893 }
894
895 pub fn which_clicked_modifiers(&self, actions: &Actions) -> Option<(usize,KeyModifiers)> {
896 for (index,btn) in self.iter().enumerate(){
897 if let Some(km) = btn.clicked_modifiers(actions){
898 return Some((index, km))
899 }
900 }
901 None
902 }
903
904 pub fn set_visible(&self, cx:&mut Cx, visible: bool) {
905 for item in self.iter() {
906 item.set_visible(cx, visible)
907 }
908 }
909 pub fn set_enabled(&self, cx:&mut Cx, enabled: bool) {
910 for item in self.iter() {
911 item.set_enabled(cx, enabled)
912 }
913 }
914}