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