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>;