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