interactive.rs

  1use crate::{
  2    point, Action, AppContext, BorrowWindow, Bounds, DispatchContext, DispatchPhase, Element,
  3    ElementId, FocusHandle, KeyMatch, Keystroke, Modifiers, Pixels, Point, SharedString, Style,
  4    StyleRefinement, ViewContext,
  5};
  6use collections::HashMap;
  7use derive_more::{Deref, DerefMut};
  8use parking_lot::Mutex;
  9use refineable::Refineable;
 10use smallvec::SmallVec;
 11use std::{
 12    any::{Any, TypeId},
 13    ops::Deref,
 14    sync::Arc,
 15};
 16
 17pub trait StatelessInteractive: Element {
 18    fn stateless_interactivity(&mut self) -> &mut StatelessInteraction<Self::ViewState>;
 19
 20    fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 21    where
 22        Self: Sized,
 23    {
 24        self.stateless_interactivity().hover_style = f(StyleRefinement::default());
 25        self
 26    }
 27
 28    fn group_hover(
 29        mut self,
 30        group_name: impl Into<SharedString>,
 31        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 32    ) -> Self
 33    where
 34        Self: Sized,
 35    {
 36        self.stateless_interactivity().group_hover_style = Some(GroupStyle {
 37            group: group_name.into(),
 38            style: f(StyleRefinement::default()),
 39        });
 40        self
 41    }
 42
 43    fn on_mouse_down(
 44        mut self,
 45        button: MouseButton,
 46        handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext<Self::ViewState>)
 47            + Send
 48            + Sync
 49            + 'static,
 50    ) -> Self
 51    where
 52        Self: Sized,
 53    {
 54        self.stateless_interactivity()
 55            .mouse_down_listeners
 56            .push(Arc::new(move |view, event, bounds, phase, cx| {
 57                if phase == DispatchPhase::Bubble
 58                    && event.button == button
 59                    && bounds.contains_point(&event.position)
 60                {
 61                    handler(view, event, cx)
 62                }
 63            }));
 64        self
 65    }
 66
 67    fn on_mouse_up(
 68        mut self,
 69        button: MouseButton,
 70        handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext<Self::ViewState>)
 71            + Send
 72            + Sync
 73            + 'static,
 74    ) -> Self
 75    where
 76        Self: Sized,
 77    {
 78        self.stateless_interactivity()
 79            .mouse_up_listeners
 80            .push(Arc::new(move |view, event, bounds, phase, cx| {
 81                if phase == DispatchPhase::Bubble
 82                    && event.button == button
 83                    && bounds.contains_point(&event.position)
 84                {
 85                    handler(view, event, cx)
 86                }
 87            }));
 88        self
 89    }
 90
 91    fn on_mouse_down_out(
 92        mut self,
 93        button: MouseButton,
 94        handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext<Self::ViewState>)
 95            + Send
 96            + Sync
 97            + 'static,
 98    ) -> Self
 99    where
100        Self: Sized,
101    {
102        self.stateless_interactivity()
103            .mouse_down_listeners
104            .push(Arc::new(move |view, event, bounds, phase, cx| {
105                if phase == DispatchPhase::Capture
106                    && event.button == button
107                    && !bounds.contains_point(&event.position)
108                {
109                    handler(view, event, cx)
110                }
111            }));
112        self
113    }
114
115    fn on_mouse_up_out(
116        mut self,
117        button: MouseButton,
118        handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext<Self::ViewState>)
119            + Send
120            + Sync
121            + 'static,
122    ) -> Self
123    where
124        Self: Sized,
125    {
126        self.stateless_interactivity()
127            .mouse_up_listeners
128            .push(Arc::new(move |view, event, bounds, phase, cx| {
129                if phase == DispatchPhase::Capture
130                    && event.button == button
131                    && !bounds.contains_point(&event.position)
132                {
133                    handler(view, event, cx);
134                }
135            }));
136        self
137    }
138
139    fn on_mouse_move(
140        mut self,
141        handler: impl Fn(&mut Self::ViewState, &MouseMoveEvent, &mut ViewContext<Self::ViewState>)
142            + Send
143            + Sync
144            + 'static,
145    ) -> Self
146    where
147        Self: Sized,
148    {
149        self.stateless_interactivity()
150            .mouse_move_listeners
151            .push(Arc::new(move |view, event, bounds, phase, cx| {
152                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
153                    handler(view, event, cx);
154                }
155            }));
156        self
157    }
158
159    fn on_scroll_wheel(
160        mut self,
161        handler: impl Fn(&mut Self::ViewState, &ScrollWheelEvent, &mut ViewContext<Self::ViewState>)
162            + Send
163            + Sync
164            + 'static,
165    ) -> Self
166    where
167        Self: Sized,
168    {
169        self.stateless_interactivity()
170            .scroll_wheel_listeners
171            .push(Arc::new(move |view, event, bounds, phase, cx| {
172                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
173                    handler(view, event, cx);
174                }
175            }));
176        self
177    }
178
179    fn on_action<A: 'static>(
180        mut self,
181        listener: impl Fn(&mut Self::ViewState, &A, DispatchPhase, &mut ViewContext<Self::ViewState>)
182            + Send
183            + Sync
184            + 'static,
185    ) -> Self
186    where
187        Self: Sized,
188    {
189        self.stateless_interactivity().key_listeners.push((
190            TypeId::of::<A>(),
191            Arc::new(move |view, event, _, phase, cx| {
192                let event = event.downcast_ref().unwrap();
193                listener(view, event, phase, cx);
194                None
195            }),
196        ));
197        self
198    }
199
200    fn on_key_down(
201        mut self,
202        listener: impl Fn(
203                &mut Self::ViewState,
204                &KeyDownEvent,
205                DispatchPhase,
206                &mut ViewContext<Self::ViewState>,
207            ) + Send
208            + Sync
209            + 'static,
210    ) -> Self
211    where
212        Self: Sized,
213    {
214        self.stateless_interactivity().key_listeners.push((
215            TypeId::of::<KeyDownEvent>(),
216            Arc::new(move |view, event, _, phase, cx| {
217                let event = event.downcast_ref().unwrap();
218                listener(view, event, phase, cx);
219                None
220            }),
221        ));
222        self
223    }
224
225    fn on_key_up(
226        mut self,
227        listener: impl Fn(&mut Self::ViewState, &KeyUpEvent, DispatchPhase, &mut ViewContext<Self::ViewState>)
228            + Send
229            + Sync
230            + 'static,
231    ) -> Self
232    where
233        Self: Sized,
234    {
235        self.stateless_interactivity().key_listeners.push((
236            TypeId::of::<KeyUpEvent>(),
237            Arc::new(move |view, event, _, phase, cx| {
238                let event = event.downcast_ref().unwrap();
239                listener(view, event, phase, cx);
240                None
241            }),
242        ));
243        self
244    }
245}
246
247pub trait StatefulInteractive: StatelessInteractive {
248    fn stateful_interactivity(&mut self) -> &mut StatefulInteraction<Self::ViewState>;
249
250    fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
251    where
252        Self: Sized,
253    {
254        self.stateful_interactivity().active_style = f(StyleRefinement::default());
255        self
256    }
257
258    fn group_active(
259        mut self,
260        group_name: impl Into<SharedString>,
261        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
262    ) -> Self
263    where
264        Self: Sized,
265    {
266        self.stateful_interactivity().group_active_style = Some(GroupStyle {
267            group: group_name.into(),
268            style: f(StyleRefinement::default()),
269        });
270        self
271    }
272
273    fn on_click(
274        mut self,
275        handler: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
276            + Send
277            + Sync
278            + 'static,
279    ) -> Self
280    where
281        Self: Sized,
282    {
283        self.stateful_interactivity()
284            .mouse_click_listeners
285            .push(Arc::new(move |view, event, cx| handler(view, event, cx)));
286        self
287    }
288}
289
290pub trait ElementInteraction<V: 'static + Send + Sync>: 'static + Send + Sync {
291    fn as_stateless(&self) -> &StatelessInteraction<V>;
292    fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V>;
293    fn as_stateful(&self) -> Option<&StatefulInteraction<V>>;
294    fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>>;
295
296    fn initialize<R>(
297        &mut self,
298        cx: &mut ViewContext<V>,
299        f: impl FnOnce(&mut ViewContext<V>) -> R,
300    ) -> R {
301        if let Some(stateful) = self.as_stateful_mut() {
302            cx.with_element_id(stateful.id.clone(), |global_id, cx| {
303                stateful.key_listeners.push((
304                    TypeId::of::<KeyDownEvent>(),
305                    Arc::new(move |_, key_down, context, phase, cx| {
306                        if phase == DispatchPhase::Bubble {
307                            let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap();
308                            if let KeyMatch::Some(action) =
309                                cx.match_keystroke(&global_id, &key_down.keystroke, context)
310                            {
311                                return Some(action);
312                            }
313                        }
314
315                        None
316                    }),
317                ));
318                let result = stateful.stateless.initialize(cx, f);
319                stateful.key_listeners.pop();
320                result
321            })
322        } else {
323            cx.with_key_listeners(&self.as_stateless().key_listeners, f)
324        }
325    }
326
327    fn refine_style(
328        &self,
329        style: &mut Style,
330        bounds: Bounds<Pixels>,
331        element_state: &InteractiveElementState,
332        cx: &mut ViewContext<V>,
333    ) {
334        let mouse_position = cx.mouse_position();
335        let stateless = self.as_stateless();
336        if let Some(group_hover) = stateless.group_hover_style.as_ref() {
337            if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
338                if group_bounds.contains_point(&mouse_position) {
339                    style.refine(&group_hover.style);
340                }
341            }
342        }
343        if bounds.contains_point(&mouse_position) {
344            style.refine(&stateless.hover_style);
345        }
346
347        if let Some(stateful) = self.as_stateful() {
348            let active_state = element_state.active_state.lock();
349            if active_state.group {
350                if let Some(group_style) = stateful.group_active_style.as_ref() {
351                    style.refine(&group_style.style);
352                }
353            }
354            if active_state.element {
355                style.refine(&stateful.active_style);
356            }
357        }
358    }
359
360    fn paint(
361        &mut self,
362        bounds: Bounds<Pixels>,
363        element_state: &InteractiveElementState,
364        cx: &mut ViewContext<V>,
365    ) {
366        let stateless = self.as_stateless();
367        for listener in stateless.mouse_down_listeners.iter().cloned() {
368            cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
369                listener(state, event, &bounds, phase, cx);
370            })
371        }
372
373        for listener in stateless.mouse_up_listeners.iter().cloned() {
374            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
375                listener(state, event, &bounds, phase, cx);
376            })
377        }
378
379        for listener in stateless.mouse_move_listeners.iter().cloned() {
380            cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
381                listener(state, event, &bounds, phase, cx);
382            })
383        }
384
385        for listener in stateless.scroll_wheel_listeners.iter().cloned() {
386            cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
387                listener(state, event, &bounds, phase, cx);
388            })
389        }
390
391        let hover_group_bounds = stateless
392            .group_hover_style
393            .as_ref()
394            .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
395
396        if let Some(group_bounds) = hover_group_bounds {
397            paint_hover_listener(group_bounds, cx);
398        }
399
400        if stateless.hover_style.is_some() {
401            paint_hover_listener(bounds, cx);
402        }
403
404        if let Some(stateful) = self.as_stateful() {
405            let click_listeners = stateful.mouse_click_listeners.clone();
406
407            let pending_click = element_state.pending_click.clone();
408            let mouse_down = pending_click.lock().clone();
409            if let Some(mouse_down) = mouse_down {
410                cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
411                    if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
412                        let mouse_click = MouseClickEvent {
413                            down: mouse_down.clone(),
414                            up: event.clone(),
415                        };
416                        for listener in &click_listeners {
417                            listener(state, &mouse_click, cx);
418                        }
419                    }
420
421                    *pending_click.lock() = None;
422                });
423            } else {
424                cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
425                    if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
426                        *pending_click.lock() = Some(event.clone());
427                    }
428                });
429            }
430
431            let active_state = element_state.active_state.clone();
432            if active_state.lock().is_none() {
433                let active_group_bounds = stateful
434                    .group_active_style
435                    .as_ref()
436                    .and_then(|group_active| GroupBounds::get(&group_active.group, cx));
437                cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
438                    if phase == DispatchPhase::Bubble {
439                        let group = active_group_bounds
440                            .map_or(false, |bounds| bounds.contains_point(&down.position));
441                        let element = bounds.contains_point(&down.position);
442                        if group || element {
443                            *active_state.lock() = ActiveState { group, element };
444                            cx.notify();
445                        }
446                    }
447                });
448            } else {
449                cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
450                    if phase == DispatchPhase::Capture {
451                        *active_state.lock() = ActiveState::default();
452                        cx.notify();
453                    }
454                });
455            }
456        }
457    }
458}
459
460fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
461where
462    V: 'static + Send + Sync,
463{
464    let hovered = bounds.contains_point(&cx.mouse_position());
465    cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
466        if phase == DispatchPhase::Capture {
467            if bounds.contains_point(&event.position) != hovered {
468                cx.notify();
469            }
470        }
471    });
472}
473
474#[derive(Deref, DerefMut)]
475pub struct StatefulInteraction<V: 'static + Send + Sync> {
476    pub id: ElementId,
477    #[deref]
478    #[deref_mut]
479    stateless: StatelessInteraction<V>,
480    pub mouse_click_listeners: SmallVec<[MouseClickListener<V>; 2]>,
481    pub active_style: StyleRefinement,
482    pub group_active_style: Option<GroupStyle>,
483}
484
485impl<V> ElementInteraction<V> for StatefulInteraction<V>
486where
487    V: 'static + Send + Sync,
488{
489    fn as_stateful(&self) -> Option<&StatefulInteraction<V>> {
490        Some(self)
491    }
492
493    fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>> {
494        Some(self)
495    }
496
497    fn as_stateless(&self) -> &StatelessInteraction<V> {
498        &self.stateless
499    }
500
501    fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V> {
502        &mut self.stateless
503    }
504}
505
506impl<V> From<ElementId> for StatefulInteraction<V>
507where
508    V: 'static + Send + Sync,
509{
510    fn from(id: ElementId) -> Self {
511        Self {
512            id,
513            stateless: StatelessInteraction::default(),
514            mouse_click_listeners: SmallVec::new(),
515            active_style: StyleRefinement::default(),
516            group_active_style: None,
517        }
518    }
519}
520
521pub struct StatelessInteraction<V> {
522    pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
523    pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
524    pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
525    pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
526    pub key_listeners: SmallVec<[(TypeId, KeyListener<V>); 32]>,
527    pub hover_style: StyleRefinement,
528    pub group_hover_style: Option<GroupStyle>,
529}
530
531pub struct GroupStyle {
532    pub group: SharedString,
533    pub style: StyleRefinement,
534}
535
536#[derive(Default)]
537pub struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
538
539impl GroupBounds {
540    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
541        cx.default_global::<Self>()
542            .0
543            .get(name)
544            .and_then(|bounds_stack| bounds_stack.last())
545            .cloned()
546    }
547
548    pub fn push(name: SharedString, bounds: Bounds<Pixels>, cx: &mut AppContext) {
549        cx.default_global::<Self>()
550            .0
551            .entry(name)
552            .or_default()
553            .push(bounds);
554    }
555
556    pub fn pop(name: &SharedString, cx: &mut AppContext) {
557        cx.default_global::<GroupBounds>()
558            .0
559            .get_mut(name)
560            .unwrap()
561            .pop();
562    }
563}
564
565#[derive(Copy, Clone, Default, Eq, PartialEq)]
566struct ActiveState {
567    pub group: bool,
568    pub element: bool,
569}
570
571impl ActiveState {
572    pub fn is_none(&self) -> bool {
573        !self.group && !self.element
574    }
575}
576
577#[derive(Default)]
578pub struct InteractiveElementState {
579    active_state: Arc<Mutex<ActiveState>>,
580    pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
581}
582
583impl<V> Default for StatelessInteraction<V> {
584    fn default() -> Self {
585        Self {
586            mouse_down_listeners: SmallVec::new(),
587            mouse_up_listeners: SmallVec::new(),
588            mouse_move_listeners: SmallVec::new(),
589            scroll_wheel_listeners: SmallVec::new(),
590            key_listeners: SmallVec::new(),
591            hover_style: StyleRefinement::default(),
592            group_hover_style: None,
593        }
594    }
595}
596
597impl<V> ElementInteraction<V> for StatelessInteraction<V>
598where
599    V: 'static + Send + Sync,
600{
601    fn as_stateful(&self) -> Option<&StatefulInteraction<V>> {
602        None
603    }
604
605    fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>> {
606        None
607    }
608
609    fn as_stateless(&self) -> &StatelessInteraction<V> {
610        self
611    }
612
613    fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V> {
614        self
615    }
616}
617
618#[derive(Clone, Debug, Eq, PartialEq)]
619pub struct KeyDownEvent {
620    pub keystroke: Keystroke,
621    pub is_held: bool,
622}
623
624#[derive(Clone, Debug)]
625pub struct KeyUpEvent {
626    pub keystroke: Keystroke,
627}
628
629#[derive(Clone, Debug, Default)]
630pub struct ModifiersChangedEvent {
631    pub modifiers: Modifiers,
632}
633
634impl Deref for ModifiersChangedEvent {
635    type Target = Modifiers;
636
637    fn deref(&self) -> &Self::Target {
638        &self.modifiers
639    }
640}
641
642/// The phase of a touch motion event.
643/// Based on the winit enum of the same name.
644#[derive(Clone, Copy, Debug)]
645pub enum TouchPhase {
646    Started,
647    Moved,
648    Ended,
649}
650
651#[derive(Clone, Debug, Default)]
652pub struct MouseDownEvent {
653    pub button: MouseButton,
654    pub position: Point<Pixels>,
655    pub modifiers: Modifiers,
656    pub click_count: usize,
657}
658
659#[derive(Clone, Debug, Default)]
660pub struct MouseUpEvent {
661    pub button: MouseButton,
662    pub position: Point<Pixels>,
663    pub modifiers: Modifiers,
664    pub click_count: usize,
665}
666
667#[derive(Clone, Debug, Default)]
668pub struct MouseClickEvent {
669    pub down: MouseDownEvent,
670    pub up: MouseUpEvent,
671}
672
673#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
674pub enum MouseButton {
675    Left,
676    Right,
677    Middle,
678    Navigate(NavigationDirection),
679}
680
681impl MouseButton {
682    pub fn all() -> Vec<Self> {
683        vec![
684            MouseButton::Left,
685            MouseButton::Right,
686            MouseButton::Middle,
687            MouseButton::Navigate(NavigationDirection::Back),
688            MouseButton::Navigate(NavigationDirection::Forward),
689        ]
690    }
691}
692
693impl Default for MouseButton {
694    fn default() -> Self {
695        Self::Left
696    }
697}
698
699#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
700pub enum NavigationDirection {
701    Back,
702    Forward,
703}
704
705impl Default for NavigationDirection {
706    fn default() -> Self {
707        Self::Back
708    }
709}
710
711#[derive(Clone, Debug, Default)]
712pub struct MouseMoveEvent {
713    pub position: Point<Pixels>,
714    pub pressed_button: Option<MouseButton>,
715    pub modifiers: Modifiers,
716}
717
718#[derive(Clone, Debug)]
719pub struct ScrollWheelEvent {
720    pub position: Point<Pixels>,
721    pub delta: ScrollDelta,
722    pub modifiers: Modifiers,
723    pub touch_phase: TouchPhase,
724}
725
726impl Deref for ScrollWheelEvent {
727    type Target = Modifiers;
728
729    fn deref(&self) -> &Self::Target {
730        &self.modifiers
731    }
732}
733
734#[derive(Clone, Copy, Debug)]
735pub enum ScrollDelta {
736    Pixels(Point<Pixels>),
737    Lines(Point<f32>),
738}
739
740impl Default for ScrollDelta {
741    fn default() -> Self {
742        Self::Lines(Default::default())
743    }
744}
745
746impl ScrollDelta {
747    pub fn precise(&self) -> bool {
748        match self {
749            ScrollDelta::Pixels(_) => true,
750            ScrollDelta::Lines(_) => false,
751        }
752    }
753
754    pub fn pixel_delta(&self, line_height: Pixels) -> Point<Pixels> {
755        match self {
756            ScrollDelta::Pixels(delta) => *delta,
757            ScrollDelta::Lines(delta) => point(line_height * delta.x, line_height * delta.y),
758        }
759    }
760}
761
762#[derive(Clone, Debug, Default)]
763pub struct MouseExitEvent {
764    pub position: Point<Pixels>,
765    pub pressed_button: Option<MouseButton>,
766    pub modifiers: Modifiers,
767}
768
769impl Deref for MouseExitEvent {
770    type Target = Modifiers;
771
772    fn deref(&self) -> &Self::Target {
773        &self.modifiers
774    }
775}
776
777#[derive(Clone, Debug)]
778pub enum InputEvent {
779    KeyDown(KeyDownEvent),
780    KeyUp(KeyUpEvent),
781    ModifiersChanged(ModifiersChangedEvent),
782    MouseDown(MouseDownEvent),
783    MouseUp(MouseUpEvent),
784    MouseMoved(MouseMoveEvent),
785    MouseExited(MouseExitEvent),
786    ScrollWheel(ScrollWheelEvent),
787}
788
789impl InputEvent {
790    pub fn position(&self) -> Option<Point<Pixels>> {
791        match self {
792            InputEvent::KeyDown { .. } => None,
793            InputEvent::KeyUp { .. } => None,
794            InputEvent::ModifiersChanged { .. } => None,
795            InputEvent::MouseDown(event) => Some(event.position),
796            InputEvent::MouseUp(event) => Some(event.position),
797            InputEvent::MouseMoved(event) => Some(event.position),
798            InputEvent::MouseExited(event) => Some(event.position),
799            InputEvent::ScrollWheel(event) => Some(event.position),
800        }
801    }
802
803    pub fn mouse_event<'a>(&'a self) -> Option<&'a dyn Any> {
804        match self {
805            InputEvent::KeyDown { .. } => None,
806            InputEvent::KeyUp { .. } => None,
807            InputEvent::ModifiersChanged { .. } => None,
808            InputEvent::MouseDown(event) => Some(event),
809            InputEvent::MouseUp(event) => Some(event),
810            InputEvent::MouseMoved(event) => Some(event),
811            InputEvent::MouseExited(event) => Some(event),
812            InputEvent::ScrollWheel(event) => Some(event),
813        }
814    }
815
816    pub fn keyboard_event<'a>(&'a self) -> Option<&'a dyn Any> {
817        match self {
818            InputEvent::KeyDown(event) => Some(event),
819            InputEvent::KeyUp(event) => Some(event),
820            InputEvent::ModifiersChanged(event) => Some(event),
821            InputEvent::MouseDown(_) => None,
822            InputEvent::MouseUp(_) => None,
823            InputEvent::MouseMoved(_) => None,
824            InputEvent::MouseExited(_) => None,
825            InputEvent::ScrollWheel(_) => None,
826        }
827    }
828}
829
830pub struct FocusEvent {
831    pub blurred: Option<FocusHandle>,
832    pub focused: Option<FocusHandle>,
833}
834
835pub type MouseDownListener<V> = Arc<
836    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
837        + Send
838        + Sync
839        + 'static,
840>;
841pub type MouseUpListener<V> = Arc<
842    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
843        + Send
844        + Sync
845        + 'static,
846>;
847pub type MouseClickListener<V> =
848    Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
849
850pub type MouseMoveListener<V> = Arc<
851    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
852        + Send
853        + Sync
854        + 'static,
855>;
856
857pub type ScrollWheelListener<V> = Arc<
858    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
859        + Send
860        + Sync
861        + 'static,
862>;
863
864pub type KeyListener<V> = Arc<
865    dyn Fn(
866            &mut V,
867            &dyn Any,
868            &[&DispatchContext],
869            DispatchPhase,
870            &mut ViewContext<V>,
871        ) -> Option<Box<dyn Action>>
872        + Send
873        + Sync
874        + 'static,
875>;