interactive.rs

  1use smallvec::SmallVec;
  2
  3use crate::{
  4    point, Action, Bounds, DispatchContext, DispatchPhase, Element, FocusHandle, Keystroke,
  5    Modifiers, Pixels, Point, ViewContext,
  6};
  7use std::{
  8    any::{Any, TypeId},
  9    ops::Deref,
 10    sync::Arc,
 11};
 12
 13pub trait Interactive: Element {
 14    fn interactive_state(&mut self) -> &mut InteractiveState<Self::ViewState>;
 15
 16    fn on_mouse_down(
 17        mut self,
 18        button: MouseButton,
 19        handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext<Self::ViewState>)
 20            + Send
 21            + Sync
 22            + 'static,
 23    ) -> Self
 24    where
 25        Self: Sized,
 26    {
 27        self.interactive_state().mouse_down.push(Arc::new(
 28            move |view, event, bounds, phase, cx| {
 29                if phase == DispatchPhase::Bubble
 30                    && event.button == button
 31                    && bounds.contains_point(&event.position)
 32                {
 33                    handler(view, event, cx)
 34                }
 35            },
 36        ));
 37        self
 38    }
 39
 40    fn on_mouse_up(
 41        mut self,
 42        button: MouseButton,
 43        handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext<Self::ViewState>)
 44            + Send
 45            + Sync
 46            + 'static,
 47    ) -> Self
 48    where
 49        Self: Sized,
 50    {
 51        self.interactive_state()
 52            .mouse_up
 53            .push(Arc::new(move |view, event, bounds, phase, cx| {
 54                if phase == DispatchPhase::Bubble
 55                    && event.button == button
 56                    && bounds.contains_point(&event.position)
 57                {
 58                    handler(view, event, cx)
 59                }
 60            }));
 61        self
 62    }
 63
 64    fn on_mouse_down_out(
 65        mut self,
 66        button: MouseButton,
 67        handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext<Self::ViewState>)
 68            + Send
 69            + Sync
 70            + 'static,
 71    ) -> Self
 72    where
 73        Self: Sized,
 74    {
 75        self.interactive_state().mouse_down.push(Arc::new(
 76            move |view, event, bounds, phase, cx| {
 77                if phase == DispatchPhase::Capture
 78                    && event.button == button
 79                    && !bounds.contains_point(&event.position)
 80                {
 81                    handler(view, event, cx)
 82                }
 83            },
 84        ));
 85        self
 86    }
 87
 88    fn on_mouse_up_out(
 89        mut self,
 90        button: MouseButton,
 91        handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext<Self::ViewState>)
 92            + Send
 93            + Sync
 94            + 'static,
 95    ) -> Self
 96    where
 97        Self: Sized,
 98    {
 99        self.interactive_state()
100            .mouse_up
101            .push(Arc::new(move |view, event, bounds, phase, cx| {
102                if phase == DispatchPhase::Capture
103                    && event.button == button
104                    && !bounds.contains_point(&event.position)
105                {
106                    handler(view, event, cx);
107                }
108            }));
109        self
110    }
111
112    fn on_mouse_move(
113        mut self,
114        handler: impl Fn(&mut Self::ViewState, &MouseMoveEvent, &mut ViewContext<Self::ViewState>)
115            + Send
116            + Sync
117            + 'static,
118    ) -> Self
119    where
120        Self: Sized,
121    {
122        self.interactive_state().mouse_move.push(Arc::new(
123            move |view, event, bounds, phase, cx| {
124                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
125                    handler(view, event, cx);
126                }
127            },
128        ));
129        self
130    }
131
132    fn on_scroll_wheel(
133        mut self,
134        handler: impl Fn(&mut Self::ViewState, &ScrollWheelEvent, &mut ViewContext<Self::ViewState>)
135            + Send
136            + Sync
137            + 'static,
138    ) -> Self
139    where
140        Self: Sized,
141    {
142        self.interactive_state().scroll_wheel.push(Arc::new(
143            move |view, event, bounds, phase, cx| {
144                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
145                    handler(view, event, cx);
146                }
147            },
148        ));
149        self
150    }
151
152    fn on_key_down(
153        mut self,
154        listener: impl Fn(
155                &mut Self::ViewState,
156                &KeyDownEvent,
157                DispatchPhase,
158                &mut ViewContext<Self::ViewState>,
159            ) + Send
160            + Sync
161            + 'static,
162    ) -> Self
163    where
164        Self: Sized,
165    {
166        self.interactive_state().key.push((
167            TypeId::of::<KeyDownEvent>(),
168            Arc::new(move |view, event, _, phase, cx| {
169                let event = event.downcast_ref().unwrap();
170                listener(view, event, phase, cx);
171                None
172            }),
173        ));
174        self
175    }
176
177    fn on_key_up(
178        mut self,
179        listener: impl Fn(&mut Self::ViewState, &KeyUpEvent, DispatchPhase, &mut ViewContext<Self::ViewState>)
180            + Send
181            + Sync
182            + 'static,
183    ) -> Self
184    where
185        Self: Sized,
186    {
187        self.interactive_state().key.push((
188            TypeId::of::<KeyUpEvent>(),
189            Arc::new(move |view, event, _, phase, cx| {
190                let event = event.downcast_ref().unwrap();
191                listener(view, event, phase, cx);
192                None
193            }),
194        ));
195        self
196    }
197
198    fn on_action<A: 'static>(
199        mut self,
200        listener: impl Fn(&mut Self::ViewState, &A, DispatchPhase, &mut ViewContext<Self::ViewState>)
201            + Send
202            + Sync
203            + 'static,
204    ) -> Self
205    where
206        Self: Sized,
207    {
208        self.interactive_state().key.push((
209            TypeId::of::<A>(),
210            Arc::new(move |view, event, _, phase, cx| {
211                let event = event.downcast_ref().unwrap();
212                listener(view, event, phase, cx);
213                None
214            }),
215        ));
216        self
217    }
218}
219
220pub trait Click: Interactive {
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.interactive_state()
232            .mouse_click
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>;
496
497pub struct InteractiveState<V: 'static> {
498    pub mouse_down: SmallVec<[MouseDownListener<V>; 2]>,
499    pub mouse_up: SmallVec<[MouseUpListener<V>; 2]>,
500    pub mouse_click: SmallVec<[MouseClickListener<V>; 2]>,
501    pub mouse_move: SmallVec<[MouseMoveListener<V>; 2]>,
502    pub scroll_wheel: SmallVec<[ScrollWheelListener<V>; 2]>,
503    pub key: SmallVec<[(TypeId, KeyListener<V>); 32]>,
504}
505
506impl<V> Default for InteractiveState<V> {
507    fn default() -> Self {
508        Self {
509            mouse_down: SmallVec::new(),
510            mouse_up: SmallVec::new(),
511            mouse_click: SmallVec::new(),
512            mouse_move: SmallVec::new(),
513            scroll_wheel: SmallVec::new(),
514            key: SmallVec::new(),
515        }
516    }
517}