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, _: &MouseMoveEvent, phase, cx| {
468 if phase == DispatchPhase::Bubble {
469 let any_drag = drag_listener(view_state, cx);
470 cx.start_drag(any_drag);
471 }
472 });
473 }
474
475 cx.on_mouse_event(move |view_state, event: &MouseUpEvent, phase, cx| {
476 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position)
477 {
478 let mouse_click = ClickEvent {
479 down: mouse_down.clone(),
480 up: event.clone(),
481 };
482 for listener in &click_listeners {
483 listener(view_state, &mouse_click, cx);
484 }
485 }
486
487 cx.end_drag();
488 *pending_mouse_down.lock() = None;
489 });
490 } else {
491 cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
492 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position)
493 {
494 *pending_mouse_down.lock() = Some(event.clone());
495 }
496 });
497 }
498 }
499
500 let active_state = element_state.active_state.clone();
501 if active_state.lock().is_none() {
502 let active_group_bounds = stateful
503 .group_active_style
504 .as_ref()
505 .and_then(|group_active| GroupBounds::get(&group_active.group, cx));
506 cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
507 if phase == DispatchPhase::Bubble {
508 let group = active_group_bounds
509 .map_or(false, |bounds| bounds.contains_point(&down.position));
510 let element = bounds.contains_point(&down.position);
511 if group || element {
512 *active_state.lock() = ActiveState { group, element };
513 cx.notify();
514 }
515 }
516 });
517 } else {
518 cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
519 if phase == DispatchPhase::Capture {
520 *active_state.lock() = ActiveState::default();
521 cx.notify();
522 }
523 });
524 }
525
526 if overflow.x == Overflow::Scroll || overflow.y == Overflow::Scroll {
527 let scroll_offset = element_state
528 .scroll_offset
529 .get_or_insert_with(Arc::default)
530 .clone();
531 let line_height = cx.line_height();
532 let scroll_max = (content_size - bounds.size).max(&Size::default());
533
534 cx.on_mouse_event(move |_, event: &ScrollWheelEvent, phase, cx| {
535 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
536 let mut scroll_offset = scroll_offset.lock();
537 let old_scroll_offset = *scroll_offset;
538 let delta = event.delta.pixel_delta(line_height);
539
540 if overflow.x == Overflow::Scroll {
541 scroll_offset.x =
542 (scroll_offset.x - delta.x).clamp(px(0.), scroll_max.width);
543 }
544
545 if overflow.y == Overflow::Scroll {
546 scroll_offset.y =
547 (scroll_offset.y - delta.y).clamp(px(0.), scroll_max.height);
548 }
549
550 if *scroll_offset != old_scroll_offset {
551 cx.notify();
552 cx.stop_propagation();
553 }
554 }
555 });
556 }
557 }
558 }
559}
560
561fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
562where
563 V: 'static + Send + Sync,
564{
565 let hovered = bounds.contains_point(&cx.mouse_position());
566 cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
567 if phase == DispatchPhase::Capture {
568 if bounds.contains_point(&event.position) != hovered {
569 cx.notify();
570 }
571 }
572 });
573}
574
575#[derive(Deref, DerefMut)]
576pub struct StatefulInteraction<V: 'static + Send + Sync> {
577 pub id: ElementId,
578 #[deref]
579 #[deref_mut]
580 stateless: StatelessInteraction<V>,
581 pub click_listeners: SmallVec<[ClickListener<V>; 2]>,
582 pub(crate) drag_listener: Option<DragListener<V>>,
583 pub active_style: StyleRefinement,
584 pub group_active_style: Option<GroupStyle>,
585}
586
587impl<V> ElementInteraction<V> for StatefulInteraction<V>
588where
589 V: 'static + Send + Sync,
590{
591 fn as_stateful(&self) -> Option<&StatefulInteraction<V>> {
592 Some(self)
593 }
594
595 fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>> {
596 Some(self)
597 }
598
599 fn as_stateless(&self) -> &StatelessInteraction<V> {
600 &self.stateless
601 }
602
603 fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V> {
604 &mut self.stateless
605 }
606}
607
608impl<V> From<ElementId> for StatefulInteraction<V>
609where
610 V: 'static + Send + Sync,
611{
612 fn from(id: ElementId) -> Self {
613 Self {
614 id,
615 stateless: StatelessInteraction::default(),
616 click_listeners: SmallVec::new(),
617 drag_listener: None,
618 active_style: StyleRefinement::default(),
619 group_active_style: None,
620 }
621 }
622}
623
624pub struct StatelessInteraction<V> {
625 pub dispatch_context: DispatchContext,
626 pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
627 pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
628 pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
629 pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
630 pub key_listeners: SmallVec<[(TypeId, KeyListener<V>); 32]>,
631 pub hover_style: StyleRefinement,
632 pub group_hover_style: Option<GroupStyle>,
633}
634
635impl<V> StatelessInteraction<V>
636where
637 V: 'static + Send + Sync,
638{
639 pub fn into_stateful(self, id: impl Into<ElementId>) -> StatefulInteraction<V> {
640 StatefulInteraction {
641 id: id.into(),
642 stateless: self,
643 click_listeners: SmallVec::new(),
644 drag_listener: None,
645 active_style: StyleRefinement::default(),
646 group_active_style: None,
647 }
648 }
649}
650
651pub struct GroupStyle {
652 pub group: SharedString,
653 pub style: StyleRefinement,
654}
655
656#[derive(Default)]
657pub struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
658
659impl GroupBounds {
660 pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
661 cx.default_global_mut::<Self>()
662 .0
663 .get(name)
664 .and_then(|bounds_stack| bounds_stack.last())
665 .cloned()
666 }
667
668 pub fn push(name: SharedString, bounds: Bounds<Pixels>, cx: &mut AppContext) {
669 cx.default_global_mut::<Self>()
670 .0
671 .entry(name)
672 .or_default()
673 .push(bounds);
674 }
675
676 pub fn pop(name: &SharedString, cx: &mut AppContext) {
677 cx.default_global_mut::<Self>()
678 .0
679 .get_mut(name)
680 .unwrap()
681 .pop();
682 }
683}
684
685#[derive(Copy, Clone, Default, Eq, PartialEq)]
686struct ActiveState {
687 pub group: bool,
688 pub element: bool,
689}
690
691impl ActiveState {
692 pub fn is_none(&self) -> bool {
693 !self.group && !self.element
694 }
695}
696
697#[derive(Default)]
698pub struct InteractiveElementState {
699 active_state: Arc<Mutex<ActiveState>>,
700 pending_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
701 scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
702}
703
704impl InteractiveElementState {
705 pub fn scroll_offset(&self) -> Option<Point<Pixels>> {
706 self.scroll_offset
707 .as_ref()
708 .map(|offset| offset.lock().clone())
709 }
710}
711
712impl<V> Default for StatelessInteraction<V> {
713 fn default() -> Self {
714 Self {
715 dispatch_context: DispatchContext::default(),
716 mouse_down_listeners: SmallVec::new(),
717 mouse_up_listeners: SmallVec::new(),
718 mouse_move_listeners: SmallVec::new(),
719 scroll_wheel_listeners: SmallVec::new(),
720 key_listeners: SmallVec::new(),
721 hover_style: StyleRefinement::default(),
722 group_hover_style: None,
723 }
724 }
725}
726
727impl<V> ElementInteraction<V> for StatelessInteraction<V>
728where
729 V: 'static + Send + Sync,
730{
731 fn as_stateful(&self) -> Option<&StatefulInteraction<V>> {
732 None
733 }
734
735 fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>> {
736 None
737 }
738
739 fn as_stateless(&self) -> &StatelessInteraction<V> {
740 self
741 }
742
743 fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V> {
744 self
745 }
746}
747
748#[derive(Clone, Debug, Eq, PartialEq)]
749pub struct KeyDownEvent {
750 pub keystroke: Keystroke,
751 pub is_held: bool,
752}
753
754#[derive(Clone, Debug)]
755pub struct KeyUpEvent {
756 pub keystroke: Keystroke,
757}
758
759#[derive(Clone, Debug, Default)]
760pub struct ModifiersChangedEvent {
761 pub modifiers: Modifiers,
762}
763
764impl Deref for ModifiersChangedEvent {
765 type Target = Modifiers;
766
767 fn deref(&self) -> &Self::Target {
768 &self.modifiers
769 }
770}
771
772/// The phase of a touch motion event.
773/// Based on the winit enum of the same name.
774#[derive(Clone, Copy, Debug)]
775pub enum TouchPhase {
776 Started,
777 Moved,
778 Ended,
779}
780
781#[derive(Clone, Debug, Default)]
782pub struct MouseDownEvent {
783 pub button: MouseButton,
784 pub position: Point<Pixels>,
785 pub modifiers: Modifiers,
786 pub click_count: usize,
787}
788
789#[derive(Clone, Debug, Default)]
790pub struct MouseUpEvent {
791 pub button: MouseButton,
792 pub position: Point<Pixels>,
793 pub modifiers: Modifiers,
794 pub click_count: usize,
795}
796
797#[derive(Clone, Debug, Default)]
798pub struct ClickEvent {
799 pub down: MouseDownEvent,
800 pub up: MouseUpEvent,
801}
802
803pub struct Drag<S, R, V, E>
804where
805 S: 'static + Send + Sync,
806 R: Fn(&mut V, &mut ViewContext<V>) -> E,
807 V: 'static + Send + Sync,
808 E: Element<ViewState = V>,
809{
810 pub state: S,
811 pub render_drag_handle: R,
812 view_type: PhantomData<V>,
813}
814
815impl<S, R, V, E> Drag<S, R, V, E>
816where
817 S: 'static + Send + Sync,
818 R: Fn(&mut V, &mut ViewContext<V>) -> E + Send + Sync,
819 V: 'static + Send + Sync,
820 E: Element<ViewState = V>,
821{
822 pub fn new(state: S, render_drag_handle: R) -> Self {
823 Drag {
824 state,
825 render_drag_handle,
826 view_type: PhantomData,
827 }
828 }
829}
830
831#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
832pub enum MouseButton {
833 Left,
834 Right,
835 Middle,
836 Navigate(NavigationDirection),
837}
838
839impl MouseButton {
840 pub fn all() -> Vec<Self> {
841 vec![
842 MouseButton::Left,
843 MouseButton::Right,
844 MouseButton::Middle,
845 MouseButton::Navigate(NavigationDirection::Back),
846 MouseButton::Navigate(NavigationDirection::Forward),
847 ]
848 }
849}
850
851impl Default for MouseButton {
852 fn default() -> Self {
853 Self::Left
854 }
855}
856
857#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
858pub enum NavigationDirection {
859 Back,
860 Forward,
861}
862
863impl Default for NavigationDirection {
864 fn default() -> Self {
865 Self::Back
866 }
867}
868
869#[derive(Clone, Debug, Default)]
870pub struct MouseMoveEvent {
871 pub position: Point<Pixels>,
872 pub pressed_button: Option<MouseButton>,
873 pub modifiers: Modifiers,
874}
875
876#[derive(Clone, Debug)]
877pub struct ScrollWheelEvent {
878 pub position: Point<Pixels>,
879 pub delta: ScrollDelta,
880 pub modifiers: Modifiers,
881 pub touch_phase: TouchPhase,
882}
883
884impl Deref for ScrollWheelEvent {
885 type Target = Modifiers;
886
887 fn deref(&self) -> &Self::Target {
888 &self.modifiers
889 }
890}
891
892#[derive(Clone, Copy, Debug)]
893pub enum ScrollDelta {
894 Pixels(Point<Pixels>),
895 Lines(Point<f32>),
896}
897
898impl Default for ScrollDelta {
899 fn default() -> Self {
900 Self::Lines(Default::default())
901 }
902}
903
904impl ScrollDelta {
905 pub fn precise(&self) -> bool {
906 match self {
907 ScrollDelta::Pixels(_) => true,
908 ScrollDelta::Lines(_) => false,
909 }
910 }
911
912 pub fn pixel_delta(&self, line_height: Pixels) -> Point<Pixels> {
913 match self {
914 ScrollDelta::Pixels(delta) => *delta,
915 ScrollDelta::Lines(delta) => point(line_height * delta.x, line_height * delta.y),
916 }
917 }
918}
919
920#[derive(Clone, Debug, Default)]
921pub struct MouseExitEvent {
922 pub position: Point<Pixels>,
923 pub pressed_button: Option<MouseButton>,
924 pub modifiers: Modifiers,
925}
926
927impl Deref for MouseExitEvent {
928 type Target = Modifiers;
929
930 fn deref(&self) -> &Self::Target {
931 &self.modifiers
932 }
933}
934
935#[derive(Clone, Debug)]
936pub enum InputEvent {
937 KeyDown(KeyDownEvent),
938 KeyUp(KeyUpEvent),
939 ModifiersChanged(ModifiersChangedEvent),
940 MouseDown(MouseDownEvent),
941 MouseUp(MouseUpEvent),
942 MouseMoved(MouseMoveEvent),
943 MouseExited(MouseExitEvent),
944 ScrollWheel(ScrollWheelEvent),
945}
946
947impl InputEvent {
948 pub fn position(&self) -> Option<Point<Pixels>> {
949 match self {
950 InputEvent::KeyDown { .. } => None,
951 InputEvent::KeyUp { .. } => None,
952 InputEvent::ModifiersChanged { .. } => None,
953 InputEvent::MouseDown(event) => Some(event.position),
954 InputEvent::MouseUp(event) => Some(event.position),
955 InputEvent::MouseMoved(event) => Some(event.position),
956 InputEvent::MouseExited(event) => Some(event.position),
957 InputEvent::ScrollWheel(event) => Some(event.position),
958 }
959 }
960
961 pub fn mouse_event<'a>(&'a self) -> Option<&'a dyn Any> {
962 match self {
963 InputEvent::KeyDown { .. } => None,
964 InputEvent::KeyUp { .. } => None,
965 InputEvent::ModifiersChanged { .. } => None,
966 InputEvent::MouseDown(event) => Some(event),
967 InputEvent::MouseUp(event) => Some(event),
968 InputEvent::MouseMoved(event) => Some(event),
969 InputEvent::MouseExited(event) => Some(event),
970 InputEvent::ScrollWheel(event) => Some(event),
971 }
972 }
973
974 pub fn keyboard_event<'a>(&'a self) -> Option<&'a dyn Any> {
975 match self {
976 InputEvent::KeyDown(event) => Some(event),
977 InputEvent::KeyUp(event) => Some(event),
978 InputEvent::ModifiersChanged(event) => Some(event),
979 InputEvent::MouseDown(_) => None,
980 InputEvent::MouseUp(_) => None,
981 InputEvent::MouseMoved(_) => None,
982 InputEvent::MouseExited(_) => None,
983 InputEvent::ScrollWheel(_) => None,
984 }
985 }
986}
987
988pub struct FocusEvent {
989 pub blurred: Option<FocusHandle>,
990 pub focused: Option<FocusHandle>,
991}
992
993pub type MouseDownListener<V> = Arc<
994 dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
995 + Send
996 + Sync
997 + 'static,
998>;
999pub type MouseUpListener<V> = Arc<
1000 dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
1001 + Send
1002 + Sync
1003 + 'static,
1004>;
1005
1006pub type MouseMoveListener<V> = Arc<
1007 dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
1008 + Send
1009 + Sync
1010 + 'static,
1011>;
1012
1013pub type ScrollWheelListener<V> = Arc<
1014 dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
1015 + Send
1016 + Sync
1017 + 'static,
1018>;
1019
1020pub type ClickListener<V> =
1021 Arc<dyn Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
1022
1023pub(crate) type DragListener<V> =
1024 Arc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyDrag + Send + Sync + 'static>;
1025
1026pub type KeyListener<V> = Arc<
1027 dyn Fn(
1028 &mut V,
1029 &dyn Any,
1030 &[&DispatchContext],
1031 DispatchPhase,
1032 &mut ViewContext<V>,
1033 ) -> Option<Box<dyn Action>>
1034 + Send
1035 + Sync
1036 + 'static,
1037>;