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