interactive.rs

  1use crate::{
  2    point, Action, Bounds, DispatchContext, DispatchPhase, Element, FocusHandle, Keystroke,
  3    Modifiers, Pixels, Point, StatefulInteractivity, StatelessInteractivity, ViewContext,
  4};
  5use std::{
  6    any::{Any, TypeId},
  7    ops::Deref,
  8    sync::Arc,
  9};
 10
 11pub trait StatelesslyInteractive: Element {
 12    fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<Self::ViewState>;
 13
 14    fn on_mouse_down(
 15        mut self,
 16        button: MouseButton,
 17        handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext<Self::ViewState>)
 18            + Send
 19            + Sync
 20            + 'static,
 21    ) -> Self
 22    where
 23        Self: Sized,
 24    {
 25        self.stateless_interactivity()
 26            .mouse_down_listeners
 27            .push(Arc::new(move |view, event, bounds, phase, cx| {
 28                if phase == DispatchPhase::Bubble
 29                    && event.button == button
 30                    && bounds.contains_point(&event.position)
 31                {
 32                    handler(view, event, cx)
 33                }
 34            }));
 35        self
 36    }
 37
 38    fn on_mouse_up(
 39        mut self,
 40        button: MouseButton,
 41        handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext<Self::ViewState>)
 42            + Send
 43            + Sync
 44            + 'static,
 45    ) -> Self
 46    where
 47        Self: Sized,
 48    {
 49        self.stateless_interactivity()
 50            .mouse_up_listeners
 51            .push(Arc::new(move |view, event, bounds, phase, cx| {
 52                if phase == DispatchPhase::Bubble
 53                    && event.button == button
 54                    && bounds.contains_point(&event.position)
 55                {
 56                    handler(view, event, cx)
 57                }
 58            }));
 59        self
 60    }
 61
 62    fn on_mouse_down_out(
 63        mut self,
 64        button: MouseButton,
 65        handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext<Self::ViewState>)
 66            + Send
 67            + Sync
 68            + 'static,
 69    ) -> Self
 70    where
 71        Self: Sized,
 72    {
 73        self.stateless_interactivity()
 74            .mouse_down_listeners
 75            .push(Arc::new(move |view, event, bounds, phase, cx| {
 76                if phase == DispatchPhase::Capture
 77                    && event.button == button
 78                    && !bounds.contains_point(&event.position)
 79                {
 80                    handler(view, event, cx)
 81                }
 82            }));
 83        self
 84    }
 85
 86    fn on_mouse_up_out(
 87        mut self,
 88        button: MouseButton,
 89        handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext<Self::ViewState>)
 90            + Send
 91            + Sync
 92            + 'static,
 93    ) -> Self
 94    where
 95        Self: Sized,
 96    {
 97        self.stateless_interactivity()
 98            .mouse_up_listeners
 99            .push(Arc::new(move |view, event, bounds, phase, cx| {
100                if phase == DispatchPhase::Capture
101                    && event.button == button
102                    && !bounds.contains_point(&event.position)
103                {
104                    handler(view, event, cx);
105                }
106            }));
107        self
108    }
109
110    fn on_mouse_move(
111        mut self,
112        handler: impl Fn(&mut Self::ViewState, &MouseMoveEvent, &mut ViewContext<Self::ViewState>)
113            + Send
114            + Sync
115            + 'static,
116    ) -> Self
117    where
118        Self: Sized,
119    {
120        self.stateless_interactivity()
121            .mouse_move_listeners
122            .push(Arc::new(move |view, event, bounds, phase, cx| {
123                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
124                    handler(view, event, cx);
125                }
126            }));
127        self
128    }
129
130    fn on_scroll_wheel(
131        mut self,
132        handler: impl Fn(&mut Self::ViewState, &ScrollWheelEvent, &mut ViewContext<Self::ViewState>)
133            + Send
134            + Sync
135            + 'static,
136    ) -> Self
137    where
138        Self: Sized,
139    {
140        self.stateless_interactivity()
141            .scroll_wheel_listeners
142            .push(Arc::new(move |view, event, bounds, phase, cx| {
143                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
144                    handler(view, event, cx);
145                }
146            }));
147        self
148    }
149
150    fn on_key_down(
151        mut self,
152        listener: impl Fn(
153                &mut Self::ViewState,
154                &KeyDownEvent,
155                DispatchPhase,
156                &mut ViewContext<Self::ViewState>,
157            ) + Send
158            + Sync
159            + 'static,
160    ) -> Self
161    where
162        Self: Sized,
163    {
164        self.stateless_interactivity().key_listeners.push((
165            TypeId::of::<KeyDownEvent>(),
166            Arc::new(move |view, event, _, phase, cx| {
167                let event = event.downcast_ref().unwrap();
168                listener(view, event, phase, cx);
169                None
170            }),
171        ));
172        self
173    }
174
175    fn on_key_up(
176        mut self,
177        listener: impl Fn(&mut Self::ViewState, &KeyUpEvent, DispatchPhase, &mut ViewContext<Self::ViewState>)
178            + Send
179            + Sync
180            + 'static,
181    ) -> Self
182    where
183        Self: Sized,
184    {
185        self.stateless_interactivity().key_listeners.push((
186            TypeId::of::<KeyUpEvent>(),
187            Arc::new(move |view, event, _, phase, cx| {
188                let event = event.downcast_ref().unwrap();
189                listener(view, event, phase, cx);
190                None
191            }),
192        ));
193        self
194    }
195
196    fn on_action<A: 'static>(
197        mut self,
198        listener: impl Fn(&mut Self::ViewState, &A, DispatchPhase, &mut ViewContext<Self::ViewState>)
199            + Send
200            + Sync
201            + 'static,
202    ) -> Self
203    where
204        Self: Sized,
205    {
206        self.stateless_interactivity().key_listeners.push((
207            TypeId::of::<A>(),
208            Arc::new(move |view, event, _, phase, cx| {
209                let event = event.downcast_ref().unwrap();
210                listener(view, event, phase, cx);
211                None
212            }),
213        ));
214        self
215    }
216}
217
218pub trait StatefullyInteractive: StatelesslyInteractive {
219    fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState>;
220
221    fn on_click(
222        mut self,
223        handler: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
224            + Send
225            + Sync
226            + 'static,
227    ) -> Self
228    where
229        Self: Sized,
230    {
231        self.stateful_interactivity()
232            .mouse_click_listeners
233            .push(Arc::new(move |view, event, cx| handler(view, event, cx)));
234        self
235    }
236}
237
238#[derive(Clone, Debug, Eq, PartialEq)]
239pub struct KeyDownEvent {
240    pub keystroke: Keystroke,
241    pub is_held: bool,
242}
243
244#[derive(Clone, Debug)]
245pub struct KeyUpEvent {
246    pub keystroke: Keystroke,
247}
248
249#[derive(Clone, Debug, Default)]
250pub struct ModifiersChangedEvent {
251    pub modifiers: Modifiers,
252}
253
254impl Deref for ModifiersChangedEvent {
255    type Target = Modifiers;
256
257    fn deref(&self) -> &Self::Target {
258        &self.modifiers
259    }
260}
261
262/// The phase of a touch motion event.
263/// Based on the winit enum of the same name.
264#[derive(Clone, Copy, Debug)]
265pub enum TouchPhase {
266    Started,
267    Moved,
268    Ended,
269}
270
271#[derive(Clone, Debug, Default)]
272pub struct MouseDownEvent {
273    pub button: MouseButton,
274    pub position: Point<Pixels>,
275    pub modifiers: Modifiers,
276    pub click_count: usize,
277}
278
279#[derive(Clone, Debug, Default)]
280pub struct MouseUpEvent {
281    pub button: MouseButton,
282    pub position: Point<Pixels>,
283    pub modifiers: Modifiers,
284    pub click_count: usize,
285}
286
287#[derive(Clone, Debug, Default)]
288pub struct MouseClickEvent {
289    pub down: MouseDownEvent,
290    pub up: MouseUpEvent,
291}
292
293#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
294pub enum MouseButton {
295    Left,
296    Right,
297    Middle,
298    Navigate(NavigationDirection),
299}
300
301impl MouseButton {
302    pub fn all() -> Vec<Self> {
303        vec![
304            MouseButton::Left,
305            MouseButton::Right,
306            MouseButton::Middle,
307            MouseButton::Navigate(NavigationDirection::Back),
308            MouseButton::Navigate(NavigationDirection::Forward),
309        ]
310    }
311}
312
313impl Default for MouseButton {
314    fn default() -> Self {
315        Self::Left
316    }
317}
318
319#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
320pub enum NavigationDirection {
321    Back,
322    Forward,
323}
324
325impl Default for NavigationDirection {
326    fn default() -> Self {
327        Self::Back
328    }
329}
330
331#[derive(Clone, Debug, Default)]
332pub struct MouseMoveEvent {
333    pub position: Point<Pixels>,
334    pub pressed_button: Option<MouseButton>,
335    pub modifiers: Modifiers,
336}
337
338#[derive(Clone, Debug)]
339pub struct ScrollWheelEvent {
340    pub position: Point<Pixels>,
341    pub delta: ScrollDelta,
342    pub modifiers: Modifiers,
343    pub touch_phase: TouchPhase,
344}
345
346impl Deref for ScrollWheelEvent {
347    type Target = Modifiers;
348
349    fn deref(&self) -> &Self::Target {
350        &self.modifiers
351    }
352}
353
354#[derive(Clone, Copy, Debug)]
355pub enum ScrollDelta {
356    Pixels(Point<Pixels>),
357    Lines(Point<f32>),
358}
359
360impl Default for ScrollDelta {
361    fn default() -> Self {
362        Self::Lines(Default::default())
363    }
364}
365
366impl ScrollDelta {
367    pub fn precise(&self) -> bool {
368        match self {
369            ScrollDelta::Pixels(_) => true,
370            ScrollDelta::Lines(_) => false,
371        }
372    }
373
374    pub fn pixel_delta(&self, line_height: Pixels) -> Point<Pixels> {
375        match self {
376            ScrollDelta::Pixels(delta) => *delta,
377            ScrollDelta::Lines(delta) => point(line_height * delta.x, line_height * delta.y),
378        }
379    }
380}
381
382#[derive(Clone, Debug, Default)]
383pub struct MouseExitEvent {
384    pub position: Point<Pixels>,
385    pub pressed_button: Option<MouseButton>,
386    pub modifiers: Modifiers,
387}
388
389impl Deref for MouseExitEvent {
390    type Target = Modifiers;
391
392    fn deref(&self) -> &Self::Target {
393        &self.modifiers
394    }
395}
396
397#[derive(Clone, Debug)]
398pub enum InputEvent {
399    KeyDown(KeyDownEvent),
400    KeyUp(KeyUpEvent),
401    ModifiersChanged(ModifiersChangedEvent),
402    MouseDown(MouseDownEvent),
403    MouseUp(MouseUpEvent),
404    MouseMoved(MouseMoveEvent),
405    MouseExited(MouseExitEvent),
406    ScrollWheel(ScrollWheelEvent),
407}
408
409impl InputEvent {
410    pub fn position(&self) -> Option<Point<Pixels>> {
411        match self {
412            InputEvent::KeyDown { .. } => None,
413            InputEvent::KeyUp { .. } => None,
414            InputEvent::ModifiersChanged { .. } => None,
415            InputEvent::MouseDown(event) => Some(event.position),
416            InputEvent::MouseUp(event) => Some(event.position),
417            InputEvent::MouseMoved(event) => Some(event.position),
418            InputEvent::MouseExited(event) => Some(event.position),
419            InputEvent::ScrollWheel(event) => Some(event.position),
420        }
421    }
422
423    pub fn mouse_event<'a>(&'a self) -> Option<&'a dyn Any> {
424        match self {
425            InputEvent::KeyDown { .. } => None,
426            InputEvent::KeyUp { .. } => None,
427            InputEvent::ModifiersChanged { .. } => None,
428            InputEvent::MouseDown(event) => Some(event),
429            InputEvent::MouseUp(event) => Some(event),
430            InputEvent::MouseMoved(event) => Some(event),
431            InputEvent::MouseExited(event) => Some(event),
432            InputEvent::ScrollWheel(event) => Some(event),
433        }
434    }
435
436    pub fn keyboard_event<'a>(&'a self) -> Option<&'a dyn Any> {
437        match self {
438            InputEvent::KeyDown(event) => Some(event),
439            InputEvent::KeyUp(event) => Some(event),
440            InputEvent::ModifiersChanged(event) => Some(event),
441            InputEvent::MouseDown(_) => None,
442            InputEvent::MouseUp(_) => None,
443            InputEvent::MouseMoved(_) => None,
444            InputEvent::MouseExited(_) => None,
445            InputEvent::ScrollWheel(_) => None,
446        }
447    }
448}
449
450pub struct FocusEvent {
451    pub blurred: Option<FocusHandle>,
452    pub focused: Option<FocusHandle>,
453}
454
455pub type MouseDownListener<V> = Arc<
456    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
457        + Send
458        + Sync
459        + 'static,
460>;
461pub type MouseUpListener<V> = Arc<
462    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
463        + Send
464        + Sync
465        + 'static,
466>;
467pub type MouseClickListener<V> =
468    Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
469
470pub type MouseMoveListener<V> = Arc<
471    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
472        + Send
473        + Sync
474        + 'static,
475>;
476
477pub type ScrollWheelListener<V> = Arc<
478    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
479        + Send
480        + Sync
481        + 'static,
482>;
483
484pub type KeyListener<V> = Arc<
485    dyn Fn(
486            &mut V,
487            &dyn Any,
488            &[&DispatchContext],
489            DispatchPhase,
490            &mut ViewContext<V>,
491        ) -> Option<Box<dyn Action>>
492        + Send
493        + Sync
494        + 'static,
495>;