vizia_core/modifiers/
actions.rs

1use crate::prelude::*;
2use std::any::TypeId;
3
4#[derive(Lens)]
5pub(crate) struct ModalModel {
6    pub tooltip_visible: (bool, bool),
7    pub menu_visible: bool,
8}
9
10/// An event used to modify the modal properties of a view, such as an attached tooltip.
11pub enum ModalEvent {
12    /// Show the attached tooltip.
13    ShowTooltip,
14    /// Hide the attached tooltip.
15    HideTooltip,
16    /// Show the attached menu.
17    ShowMenu,
18    /// Hide the attached menu.
19    HideMenu,
20}
21
22impl Model for ModalModel {
23    fn event(&mut self, _cx: &mut EventContext, event: &mut Event) {
24        event.map(|modal_event, _| match modal_event {
25            ModalEvent::ShowTooltip => {
26                self.tooltip_visible = (true, true);
27            }
28
29            ModalEvent::HideTooltip => {
30                self.tooltip_visible = (false, true);
31            }
32
33            ModalEvent::ShowMenu => {
34                self.menu_visible = true;
35            }
36
37            ModalEvent::HideMenu => {
38                self.menu_visible = false;
39            }
40        });
41
42        event.map(|window_event, _| match window_event {
43            WindowEvent::MouseOver => {
44                if !self.tooltip_visible.0 {
45                    self.tooltip_visible = (true, true);
46                }
47            }
48            WindowEvent::MouseOut => self.tooltip_visible = (false, true),
49            WindowEvent::FocusIn => {
50                if !self.tooltip_visible.0 {
51                    self.tooltip_visible = (true, false);
52                }
53            }
54            WindowEvent::FocusOut => self.tooltip_visible = (false, false),
55            WindowEvent::FocusVisibility(vis) if !(*vis) => self.tooltip_visible = (false, false),
56            WindowEvent::KeyDown(code, _) if *code == Code::Escape => {
57                self.tooltip_visible = (false, false)
58            }
59            WindowEvent::PressDown { mouse: _ } => self.tooltip_visible = (false, true),
60            _ => {}
61        });
62    }
63}
64
65pub(crate) struct ActionsModel {
66    pub(crate) on_press: Option<Box<dyn Fn(&mut EventContext) + Send + Sync>>,
67    pub(crate) on_press_down: Option<Box<dyn Fn(&mut EventContext) + Send + Sync>>,
68    pub(crate) on_double_click: Option<Box<dyn Fn(&mut EventContext, MouseButton) + Send + Sync>>,
69    pub(crate) on_hover: Option<Box<dyn Fn(&mut EventContext) + Send + Sync>>,
70    pub(crate) on_hover_out: Option<Box<dyn Fn(&mut EventContext) + Send + Sync>>,
71    pub(crate) on_over: Option<Box<dyn Fn(&mut EventContext) + Send + Sync>>,
72    pub(crate) on_over_out: Option<Box<dyn Fn(&mut EventContext) + Send + Sync>>,
73    pub(crate) on_mouse_move: Option<Box<dyn Fn(&mut EventContext, f32, f32) + Send + Sync>>,
74    pub(crate) on_mouse_down: Option<Box<dyn Fn(&mut EventContext, MouseButton) + Send + Sync>>,
75    pub(crate) on_mouse_up: Option<Box<dyn Fn(&mut EventContext, MouseButton) + Send + Sync>>,
76    pub(crate) on_focus_in: Option<Box<dyn Fn(&mut EventContext) + Send + Sync>>,
77    pub(crate) on_focus_out: Option<Box<dyn Fn(&mut EventContext) + Send + Sync>>,
78    pub(crate) on_geo_changed: Option<Box<dyn Fn(&mut EventContext, GeoChanged) + Send + Sync>>,
79    pub(crate) on_drag_start: Option<Box<dyn Fn(&mut EventContext) + Send + Sync>>,
80    pub(crate) on_drop: Option<Box<dyn Fn(&mut EventContext, DropData) + Send + Sync>>,
81}
82
83impl ActionsModel {
84    pub(crate) fn new() -> Self {
85        Self {
86            on_press: None,
87            on_press_down: None,
88            on_double_click: None,
89            on_hover: None,
90            on_hover_out: None,
91            on_over: None,
92            on_over_out: None,
93            on_mouse_move: None,
94            on_mouse_down: None,
95            on_mouse_up: None,
96            on_focus_in: None,
97            on_focus_out: None,
98            on_geo_changed: None,
99            on_drag_start: None,
100            on_drop: None,
101        }
102    }
103}
104
105impl Model for ActionsModel {
106    fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
107        event.take(|actions_event, _| match actions_event {
108            ActionsEvent::OnPress(on_press) => {
109                self.on_press = Some(on_press);
110            }
111
112            ActionsEvent::OnPressDown(on_press_down) => {
113                self.on_press_down = Some(on_press_down);
114            }
115
116            ActionsEvent::OnDoubleClick(on_double_click) => {
117                self.on_double_click = Some(on_double_click);
118            }
119
120            ActionsEvent::OnHover(on_hover) => {
121                self.on_hover = Some(on_hover);
122            }
123
124            ActionsEvent::OnHoverOut(on_hover_out) => {
125                self.on_hover_out = Some(on_hover_out);
126            }
127
128            ActionsEvent::OnOver(on_over) => {
129                self.on_over = Some(on_over);
130            }
131
132            ActionsEvent::OnOverOut(on_over_out) => {
133                self.on_over_out = Some(on_over_out);
134            }
135
136            ActionsEvent::OnMouseMove(on_move) => {
137                self.on_mouse_move = Some(on_move);
138            }
139
140            ActionsEvent::OnMouseDown(on_mouse_down) => {
141                self.on_mouse_down = Some(on_mouse_down);
142            }
143
144            ActionsEvent::OnMouseUp(on_mouse_up) => {
145                self.on_mouse_up = Some(on_mouse_up);
146            }
147
148            ActionsEvent::OnFocusIn(on_focus_in) => {
149                self.on_focus_in = Some(on_focus_in);
150            }
151
152            ActionsEvent::OnFocusOut(on_focus_out) => {
153                self.on_focus_out = Some(on_focus_out);
154            }
155
156            ActionsEvent::OnGeoChanged(on_geo_changed) => {
157                self.on_geo_changed = Some(on_geo_changed);
158                cx.cache.set_bounds(cx.current, BoundingBox::default());
159                cx.needs_relayout();
160            }
161
162            ActionsEvent::OnDragStart(on_drag_start) => {
163                self.on_drag_start = Some(on_drag_start);
164            }
165
166            ActionsEvent::OnDrop(on_drop) => {
167                self.on_drop = Some(on_drop);
168            }
169        });
170
171        event.map(|window_event, meta| match window_event {
172            WindowEvent::Press { mouse } => {
173                let over = if *mouse { cx.hovered() } else { cx.focused() };
174                if cx.current() != over && !over.is_descendant_of(cx.tree, cx.current()) {
175                    return;
176                }
177
178                if !cx.is_disabled() && cx.current == meta.target {
179                    if let Some(action) = &self.on_press {
180                        (action)(cx);
181                    }
182                }
183            }
184
185            WindowEvent::PressDown { mouse } => {
186                let over = if *mouse { cx.hovered() } else { cx.focused() };
187                if cx.current() != over && !over.is_descendant_of(cx.tree, cx.current()) {
188                    return;
189                }
190                if !cx.is_disabled() && cx.current == meta.target {
191                    if let Some(action) = &self.on_press_down {
192                        (action)(cx);
193                    }
194                }
195            }
196
197            WindowEvent::MouseDoubleClick(button) => {
198                if meta.target == cx.current && !cx.is_disabled() {
199                    if let Some(action) = &self.on_double_click {
200                        (action)(cx, *button);
201                    }
202                }
203            }
204
205            WindowEvent::MouseEnter => {
206                if meta.target == cx.current() {
207                    if let Some(action) = &self.on_hover {
208                        (action)(cx);
209                    }
210                }
211            }
212
213            WindowEvent::MouseLeave => {
214                if meta.target == cx.current() {
215                    if let Some(action) = &self.on_hover_out {
216                        (action)(cx);
217                    }
218                }
219            }
220
221            WindowEvent::MouseOver => {
222                if let Some(action) = &self.on_over {
223                    (action)(cx);
224                }
225            }
226
227            WindowEvent::MouseOut => {
228                // if meta.target == cx.current() {
229                if let Some(action) = &self.on_over_out {
230                    (action)(cx);
231                }
232
233                if cx.mouse.left.state == MouseButtonState::Pressed
234                    && cx.mouse.left.pressed == cx.current()
235                    && cx.is_draggable()
236                {
237                    if let Some(action) = &self.on_drag_start {
238                        (action)(cx);
239                    }
240                }
241                // }
242            }
243
244            WindowEvent::MouseMove(x, y) => {
245                if let Some(action) = &self.on_mouse_move {
246                    (action)(cx, *x, *y);
247                }
248                if cx.mouse.left.state == MouseButtonState::Released {
249                    if let Some(drop_data) = cx.drop_data.take() {
250                        if let Some(action) = &self.on_drop {
251                            (action)(cx, drop_data);
252                        }
253                    }
254                }
255            }
256
257            WindowEvent::MouseDown(mouse_button) => {
258                if let Some(action) = &self.on_mouse_down {
259                    (action)(cx, *mouse_button);
260                }
261            }
262
263            WindowEvent::MouseUp(mouse_button) => {
264                if let Some(action) = &self.on_mouse_up {
265                    (action)(cx, *mouse_button);
266                }
267                if let Some(drop_data) = cx.drop_data.take() {
268                    if let Some(action) = &self.on_drop {
269                        (action)(cx, drop_data);
270                    }
271                }
272            }
273
274            WindowEvent::FocusIn => {
275                if let Some(action) = &self.on_focus_in {
276                    (action)(cx);
277                }
278            }
279
280            WindowEvent::FocusOut => {
281                if let Some(action) = &self.on_focus_out {
282                    (action)(cx);
283                }
284            }
285
286            WindowEvent::GeometryChanged(geo) => {
287                if meta.target == cx.current() {
288                    if let Some(action) = &self.on_geo_changed {
289                        (action)(cx, *geo);
290                    }
291                }
292            }
293
294            _ => {}
295        });
296    }
297}
298
299pub(crate) enum ActionsEvent {
300    OnPress(Box<dyn Fn(&mut EventContext) + Send + Sync>),
301    OnPressDown(Box<dyn Fn(&mut EventContext) + Send + Sync>),
302    OnDoubleClick(Box<dyn Fn(&mut EventContext, MouseButton) + Send + Sync>),
303    OnHover(Box<dyn Fn(&mut EventContext) + Send + Sync>),
304    OnHoverOut(Box<dyn Fn(&mut EventContext) + Send + Sync>),
305    OnOver(Box<dyn Fn(&mut EventContext) + Send + Sync>),
306    OnOverOut(Box<dyn Fn(&mut EventContext) + Send + Sync>),
307    OnMouseMove(Box<dyn Fn(&mut EventContext, f32, f32) + Send + Sync>),
308    OnMouseDown(Box<dyn Fn(&mut EventContext, MouseButton) + Send + Sync>),
309    OnMouseUp(Box<dyn Fn(&mut EventContext, MouseButton) + Send + Sync>),
310    OnFocusIn(Box<dyn Fn(&mut EventContext) + Send + Sync>),
311    OnFocusOut(Box<dyn Fn(&mut EventContext) + Send + Sync>),
312    OnGeoChanged(Box<dyn Fn(&mut EventContext, GeoChanged) + Send + Sync>),
313    OnDragStart(Box<dyn Fn(&mut EventContext) + Send + Sync>),
314    OnDrop(Box<dyn Fn(&mut EventContext, DropData) + Send + Sync>),
315}
316
317/// Modifiers which add an action callback to a view.
318pub trait ActionModifiers<V> {
319    /// Adds a callback which is performed when the the view receives the [`Press`](crate::prelude::WindowEvent::Press) event.
320    /// By default a view receives the [`Press`](crate::prelude::WindowEvent::Press) event when the left mouse button is pressed and then released on the view,
321    /// or when the space or enter keys are pressed and then released while the view is focused.
322    ///
323    /// # Example
324    /// ```rust
325    /// # use vizia_core::prelude::*;
326    /// # let mut cx = &mut Context::default();
327    /// Element::new(cx).on_press(|_| debug!("View was pressed!"));
328    /// ```
329    fn on_press<F>(self, action: F) -> Self
330    where
331        F: 'static + Fn(&mut EventContext) + Send + Sync;
332
333    /// Adds a callback which is performed when the the view receives the [`PressDown`](crate::prelude::WindowEvent::PressDown) event.
334    // By default a view receives the [`PressDown`](crate::prelude::WindowEvent::PressDown) event when the left mouse button is pressed on the view,
335    /// or when the space or enter keys are pressed while the view is focused.
336    ///
337    /// # Example
338    /// ```rust
339    /// # use vizia_core::prelude::*;
340    /// # let mut cx = &mut Context::default();
341    /// Element::new(cx).on_press_down(|_| debug!("View was pressed down!"));
342    /// ```
343    fn on_press_down<F>(self, action: F) -> Self
344    where
345        F: 'static + Fn(&mut EventContext) + Send + Sync;
346
347    /// Adds a callback which is performed when the the view receives the [`MouseDoubleClick`](crate::prelude::WindowEvent::MouseDoubleClick) event.
348    ///
349    /// # Example
350    /// ```rust
351    /// # use vizia_core::prelude::*;
352    /// # let mut cx = &mut Context::default();
353    /// Element::new(cx).on_double_click(|_, _button| debug!("View was double clicked on!"));
354    /// ```
355    fn on_double_click<F>(self, action: F) -> Self
356    where
357        F: 'static + Fn(&mut EventContext, MouseButton) + Send + Sync;
358
359    /// Adds a callback which is performed when the mouse pointer moves over a view.
360    /// This callback is not triggered when the mouse pointer moves over an overlapping child of the view.
361    ///
362    /// # Example
363    /// ```rust
364    /// # use vizia_core::prelude::*;
365    /// # let mut cx = &mut Context::default();
366    /// Element::new(cx).on_hover(|_| debug!("Mouse cursor entered the view!"));
367    /// ```
368    fn on_hover<F>(self, action: F) -> Self
369    where
370        F: 'static + Fn(&mut EventContext) + Send + Sync;
371
372    /// Adds a callback which is performed when the mouse pointer moves away from a view.
373    /// This callback is not triggered when the mouse pointer moves away from an overlapping child of the view.
374    ///
375    /// # Example
376    /// ```rust
377    /// # use vizia_core::prelude::*;
378    /// # let mut cx = &mut Context::default();
379    /// Element::new(cx).on_hover_out(|_| debug!("Mouse cursor left the view!"));
380    /// ```
381    fn on_hover_out<F>(self, action: F) -> Self
382    where
383        F: 'static + Fn(&mut EventContext) + Send + Sync;
384
385    /// Adds a callback which is performed when the mouse pointer moves over the bounds of a view,
386    /// including any overlapping children.
387    ///
388    /// # Example
389    /// ```rust
390    /// # use vizia_core::prelude::*;
391    /// # let mut cx = &mut Context::default();
392    /// Element::new(cx).on_over(|_| debug!("Mouse cursor entered the view bounds!"));
393    /// ```
394    fn on_over<F>(self, action: F) -> Self
395    where
396        F: 'static + Fn(&mut EventContext) + Send + Sync;
397
398    /// Adds a callback which is performed when the mouse pointer moves away from the bounds of a view,
399    /// including any overlapping children.
400    ///
401    /// # Example
402    /// ```rust
403    /// # use vizia_core::prelude::*;
404    /// # let mut cx = &mut Context::default();
405    /// Element::new(cx).on_over_out(|_| debug!("Mouse cursor left the view bounds!"));
406    /// ```
407    fn on_over_out<F>(self, action: F) -> Self
408    where
409        F: 'static + Fn(&mut EventContext) + Send + Sync;
410
411    /// Adds a callback which is performed when the mouse pointer moves within the bounds of a view.
412    ///
413    /// # Example
414    /// ```rust
415    /// # use vizia_core::prelude::*;
416    /// # let mut cx = &mut Context::default();
417    /// Element::new(cx).on_mouse_move(|_, x, y| debug!("Cursor moving: {} {}", x, y));
418    /// ```
419    fn on_mouse_move<F>(self, action: F) -> Self
420    where
421        F: 'static + Fn(&mut EventContext, f32, f32) + Send + Sync;
422
423    /// Adds a callback which is performed when a mouse button is pressed on the view.
424    /// Unlike the `on_press` callback, this callback is triggered for all mouse buttons and not for any keyboard keys.
425    ///
426    /// # Example
427    /// ```rust
428    /// # use vizia_core::prelude::*;
429    /// # let mut cx = &mut Context::default();
430    /// Element::new(cx).on_mouse_down(|_, button| debug!("Mouse button, {:?}, was pressed!", button));
431    /// ```
432    fn on_mouse_down<F>(self, action: F) -> Self
433    where
434        F: 'static + Fn(&mut EventContext, MouseButton) + Send + Sync;
435
436    /// Adds a callback which is performed when a mouse button is released on the view.
437    /// Unlike the `on_release` callback, this callback is triggered for all mouse buttons and not for any keyboard keys.
438    ///
439    /// # Example
440    /// ```rust
441    /// # use vizia_core::prelude::*;
442    /// # let mut cx = &mut Context::default();
443    /// Element::new(cx).on_mouse_up(|_, button| debug!("Mouse button, {:?}, was released!", button));
444    /// ```
445    fn on_mouse_up<F>(self, action: F) -> Self
446    where
447        F: 'static + Fn(&mut EventContext, MouseButton) + Send + Sync;
448
449    /// Adds a callback which is performed when the view gains keyboard focus.
450    ///
451    /// # Example
452    /// ```rust
453    /// # use vizia_core::prelude::*;
454    /// # let mut cx = &mut Context::default();
455    /// Element::new(cx).on_focus_in(|_| debug!("View gained keyboard focus!"));
456    /// ```
457    fn on_focus_in<F>(self, action: F) -> Self
458    where
459        F: 'static + Fn(&mut EventContext) + Send + Sync;
460
461    /// Adds a callback which is performed when the view loses keyboard focus.
462    ///
463    /// # Example
464    /// ```rust
465    /// # use vizia_core::prelude::*;
466    /// # let mut cx = &mut Context::default();
467    /// Element::new(cx).on_focus_out(|_| debug!("View lost keyboard focus!"));
468    /// ```
469    fn on_focus_out<F>(self, action: F) -> Self
470    where
471        F: 'static + Fn(&mut EventContext) + Send + Sync;
472
473    /// Adds a callback which is performed when the the view changes size or position after layout.
474    ///
475    /// # Example
476    /// ```rust
477    /// # use vizia_core::prelude::*;
478    /// # let mut cx = &mut Context::default();
479    /// Element::new(cx).on_geo_changed(|_, _| debug!("View geometry changed!"));
480    /// ```
481    fn on_geo_changed<F>(self, action: F) -> Self
482    where
483        F: 'static + Fn(&mut EventContext, GeoChanged) + Send + Sync;
484
485    /// Adds a popup tooltip to the view.
486    fn tooltip<C: Fn(&mut Context) -> Handle<'_, Tooltip> + 'static>(self, content: C) -> Self;
487
488    /// Adds a popup menu to the view.
489    fn menu<C: FnOnce(&mut Context) -> Handle<'_, T>, T: View>(self, content: C) -> Self;
490
491    /// Adds a callback which is performed when the view is dragged during a drag and drop operation.
492    fn on_drag<F>(self, action: F) -> Self
493    where
494        F: 'static + Fn(&mut EventContext) + Send + Sync;
495
496    /// Adds a callback which is performed when data is dropped on the view during a drag and drop operation.
497    fn on_drop<F>(self, action: F) -> Self
498    where
499        F: 'static + Fn(&mut EventContext, DropData) + Send + Sync;
500}
501
502// If the entity doesn't have an `ActionsModel` then add one to the entity
503fn build_action_model(cx: &mut Context, entity: Entity) {
504    if cx.models.get(&entity).and_then(|models| models.get(&TypeId::of::<ActionsModel>())).is_none()
505    {
506        cx.with_current(entity, |cx| {
507            ActionsModel::new().build(cx);
508        });
509    }
510}
511
512fn build_modal_model(cx: &mut Context, entity: Entity) {
513    if cx.models.get(&entity).and_then(|models| models.get(&TypeId::of::<ModalModel>())).is_none() {
514        cx.with_current(entity, |cx| {
515            ModalModel { tooltip_visible: (false, true), menu_visible: false }.build(cx);
516        });
517    }
518}
519
520impl<V: View> ActionModifiers<V> for Handle<'_, V> {
521    fn tooltip<C: Fn(&mut Context) -> Handle<'_, Tooltip> + 'static>(self, content: C) -> Self {
522        let entity = self.entity();
523
524        build_modal_model(self.cx, entity);
525
526        self.cx.with_current(entity, move |cx| {
527            Binding::new(cx, ModalModel::tooltip_visible, move |cx, tooltip_visible| {
528                let tooltip_visible = tooltip_visible.get(cx);
529                if tooltip_visible.0 {
530                    (content)(cx).on_build(|cx| {
531                        if tooltip_visible.1 {
532                            cx.play_animation(
533                                "tooltip_fade",
534                                Duration::from_millis(100),
535                                Duration::from_millis(500),
536                            )
537                        }
538                    });
539                }
540            });
541        });
542
543        self
544    }
545
546    fn menu<C: FnOnce(&mut Context) -> Handle<'_, T>, T: View>(self, content: C) -> Self {
547        let entity = self.entity();
548
549        build_modal_model(self.cx, entity);
550
551        self.cx.with_current(entity, |cx| {
552            (content)(cx).bind(ModalModel::menu_visible, |mut handle, vis| {
553                let is_visible = vis.get(&handle);
554                handle = handle.toggle_class("vis", is_visible);
555
556                if is_visible {
557                    handle.context().emit(WindowEvent::GeometryChanged(GeoChanged::empty()));
558                }
559            });
560        });
561
562        self
563    }
564
565    fn on_press<F>(mut self, action: F) -> Self
566    where
567        F: 'static + Fn(&mut EventContext) + Send + Sync,
568    {
569        self = self.hoverable(true);
570
571        if let Some(view) = self
572            .cx
573            .views
574            .get_mut(&self.entity)
575            .and_then(|view_handler| view_handler.downcast_mut::<Button>())
576        {
577            view.action = Some(Box::new(action));
578            return self;
579        }
580
581        build_action_model(self.cx, self.entity);
582
583        self.cx.emit_custom(
584            Event::new(ActionsEvent::OnPress(Box::new(action)))
585                .target(self.entity)
586                .origin(self.entity),
587        );
588
589        self
590    }
591
592    fn on_press_down<F>(self, action: F) -> Self
593    where
594        F: 'static + Fn(&mut EventContext) + Send + Sync,
595    {
596        build_action_model(self.cx, self.entity);
597
598        self.cx.emit_custom(
599            Event::new(ActionsEvent::OnPressDown(Box::new(action)))
600                .target(self.entity)
601                .origin(self.entity),
602        );
603
604        self
605    }
606
607    fn on_double_click<F>(self, action: F) -> Self
608    where
609        F: 'static + Fn(&mut EventContext, MouseButton) + Send + Sync,
610    {
611        build_action_model(self.cx, self.entity);
612
613        self.cx.emit_custom(
614            Event::new(ActionsEvent::OnDoubleClick(Box::new(action)))
615                .target(self.entity)
616                .origin(self.entity),
617        );
618
619        self
620    }
621
622    fn on_hover<F>(self, action: F) -> Self
623    where
624        F: 'static + Fn(&mut EventContext) + Send + Sync,
625    {
626        build_action_model(self.cx, self.entity);
627
628        self.cx.emit_custom(
629            Event::new(ActionsEvent::OnHover(Box::new(action)))
630                .target(self.entity)
631                .origin(self.entity),
632        );
633
634        self
635    }
636
637    fn on_hover_out<F>(self, action: F) -> Self
638    where
639        F: 'static + Fn(&mut EventContext) + Send + Sync,
640    {
641        build_action_model(self.cx, self.entity);
642
643        self.cx.emit_custom(
644            Event::new(ActionsEvent::OnHoverOut(Box::new(action)))
645                .target(self.entity)
646                .origin(self.entity),
647        );
648
649        self
650    }
651
652    fn on_over<F>(self, action: F) -> Self
653    where
654        F: 'static + Fn(&mut EventContext) + Send + Sync,
655    {
656        build_action_model(self.cx, self.entity);
657
658        self.cx.emit_custom(
659            Event::new(ActionsEvent::OnOver(Box::new(action)))
660                .target(self.entity)
661                .origin(self.entity),
662        );
663
664        self
665    }
666
667    fn on_over_out<F>(self, action: F) -> Self
668    where
669        F: 'static + Fn(&mut EventContext) + Send + Sync,
670    {
671        build_action_model(self.cx, self.entity);
672
673        self.cx.emit_custom(
674            Event::new(ActionsEvent::OnOverOut(Box::new(action)))
675                .target(self.entity)
676                .origin(self.entity),
677        );
678
679        self
680    }
681
682    fn on_mouse_move<F>(self, action: F) -> Self
683    where
684        F: 'static + Fn(&mut EventContext, f32, f32) + Send + Sync,
685    {
686        build_action_model(self.cx, self.entity);
687
688        self.cx.emit_custom(
689            Event::new(ActionsEvent::OnMouseMove(Box::new(action)))
690                .target(self.entity)
691                .origin(self.entity),
692        );
693
694        self
695    }
696
697    fn on_mouse_down<F>(self, action: F) -> Self
698    where
699        F: 'static + Fn(&mut EventContext, MouseButton) + Send + Sync,
700    {
701        build_action_model(self.cx, self.entity);
702
703        self.cx.emit_custom(
704            Event::new(ActionsEvent::OnMouseDown(Box::new(action)))
705                .target(self.entity)
706                .origin(self.entity),
707        );
708
709        self
710    }
711
712    fn on_mouse_up<F>(self, action: F) -> Self
713    where
714        F: 'static + Fn(&mut EventContext, MouseButton) + Send + Sync,
715    {
716        build_action_model(self.cx, self.entity);
717
718        self.cx.emit_custom(
719            Event::new(ActionsEvent::OnMouseUp(Box::new(action)))
720                .target(self.entity)
721                .origin(self.entity),
722        );
723
724        self
725    }
726
727    fn on_focus_in<F>(self, action: F) -> Self
728    where
729        F: 'static + Fn(&mut EventContext) + Send + Sync,
730    {
731        build_action_model(self.cx, self.entity);
732
733        self.cx.emit_custom(
734            Event::new(ActionsEvent::OnFocusIn(Box::new(action)))
735                .target(self.entity)
736                .origin(self.entity),
737        );
738
739        self
740    }
741
742    fn on_focus_out<F>(self, action: F) -> Self
743    where
744        F: 'static + Fn(&mut EventContext) + Send + Sync,
745    {
746        build_action_model(self.cx, self.entity);
747
748        self.cx.emit_custom(
749            Event::new(ActionsEvent::OnFocusOut(Box::new(action)))
750                .target(self.entity)
751                .origin(self.entity),
752        );
753
754        self
755    }
756
757    fn on_geo_changed<F>(self, action: F) -> Self
758    where
759        F: 'static + Fn(&mut EventContext, GeoChanged) + Send + Sync,
760    {
761        build_action_model(self.cx, self.entity);
762
763        self.cx.emit_custom(
764            Event::new(ActionsEvent::OnGeoChanged(Box::new(action)))
765                .target(self.entity)
766                .origin(self.entity),
767        );
768
769        self
770    }
771
772    fn on_drag<F>(self, action: F) -> Self
773    where
774        F: 'static + Fn(&mut EventContext) + Send + Sync,
775    {
776        build_action_model(self.cx, self.entity);
777
778        if let Some(abilities) = self.cx.style.abilities.get_mut(self.entity) {
779            abilities.set(Abilities::DRAGGABLE, true);
780        }
781
782        self.cx.emit_custom(
783            Event::new(ActionsEvent::OnDragStart(Box::new(action)))
784                .target(self.entity)
785                .origin(self.entity),
786        );
787
788        self
789    }
790
791    fn on_drop<F>(self, action: F) -> Self
792    where
793        F: 'static + Fn(&mut EventContext, DropData) + Send + Sync,
794    {
795        build_action_model(self.cx, self.entity);
796
797        self.cx.emit_custom(
798            Event::new(ActionsEvent::OnDrop(Box::new(action)))
799                .target(self.entity)
800                .origin(self.entity),
801        );
802
803        self
804    }
805}