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