interactive.rs

  1use crate::{
  2    Bounds, DispatchPhase, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
  3    ScrollWheelEvent, ViewContext,
  4};
  5use smallvec::SmallVec;
  6use std::sync::Arc;
  7
  8pub trait Interactive<S: 'static + Send + Sync> {
  9    fn listeners(&mut self) -> &mut MouseEventListeners<S>;
 10
 11    fn on_mouse_down(
 12        mut self,
 13        button: MouseButton,
 14        handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext<S>) + Send + Sync + 'static,
 15    ) -> Self
 16    where
 17        Self: Sized,
 18    {
 19        self.listeners()
 20            .mouse_down
 21            .push(Arc::new(move |view, event, bounds, phase, cx| {
 22                if phase == DispatchPhase::Bubble
 23                    && event.button == button
 24                    && bounds.contains_point(event.position)
 25                {
 26                    handler(view, event, cx)
 27                }
 28            }));
 29        self
 30    }
 31
 32    fn on_mouse_up(
 33        mut self,
 34        button: MouseButton,
 35        handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext<S>) + Send + Sync + 'static,
 36    ) -> Self
 37    where
 38        Self: Sized,
 39    {
 40        self.listeners()
 41            .mouse_up
 42            .push(Arc::new(move |view, event, bounds, phase, cx| {
 43                if phase == DispatchPhase::Bubble
 44                    && event.button == button
 45                    && bounds.contains_point(event.position)
 46                {
 47                    handler(view, event, cx)
 48                }
 49            }));
 50        self
 51    }
 52
 53    fn on_mouse_down_out(
 54        mut self,
 55        button: MouseButton,
 56        handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext<S>) + Send + Sync + 'static,
 57    ) -> Self
 58    where
 59        Self: Sized,
 60    {
 61        self.listeners()
 62            .mouse_down
 63            .push(Arc::new(move |view, event, bounds, phase, cx| {
 64                if phase == DispatchPhase::Capture
 65                    && event.button == button
 66                    && !bounds.contains_point(event.position)
 67                {
 68                    handler(view, event, cx)
 69                }
 70            }));
 71        self
 72    }
 73
 74    fn on_mouse_up_out(
 75        mut self,
 76        button: MouseButton,
 77        handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext<S>) + Send + Sync + 'static,
 78    ) -> Self
 79    where
 80        Self: Sized,
 81    {
 82        self.listeners()
 83            .mouse_up
 84            .push(Arc::new(move |view, event, bounds, phase, cx| {
 85                if phase == DispatchPhase::Capture
 86                    && event.button == button
 87                    && !bounds.contains_point(event.position)
 88                {
 89                    handler(view, event, cx);
 90                }
 91            }));
 92        self
 93    }
 94
 95    fn on_mouse_move(
 96        mut self,
 97        handler: impl Fn(&mut S, &MouseMoveEvent, &mut ViewContext<S>) + Send + Sync + 'static,
 98    ) -> Self
 99    where
100        Self: Sized,
101    {
102        self.listeners()
103            .mouse_move
104            .push(Arc::new(move |view, event, bounds, phase, cx| {
105                if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
106                    handler(view, event, cx);
107                }
108            }));
109        self
110    }
111
112    fn on_scroll_wheel(
113        mut self,
114        handler: impl Fn(&mut S, &ScrollWheelEvent, &mut ViewContext<S>) + Send + Sync + 'static,
115    ) -> Self
116    where
117        Self: Sized,
118    {
119        self.listeners()
120            .scroll_wheel
121            .push(Arc::new(move |view, event, bounds, phase, cx| {
122                if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
123                    handler(view, event, cx);
124                }
125            }));
126        self
127    }
128}
129
130type MouseDownHandler<V> = Arc<
131    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
132        + Send
133        + Sync
134        + 'static,
135>;
136type MouseUpHandler<V> = Arc<
137    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
138        + Send
139        + Sync
140        + 'static,
141>;
142
143type MouseMoveHandler<V> = Arc<
144    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
145        + Send
146        + Sync
147        + 'static,
148>;
149type ScrollWheelHandler<V> = Arc<
150    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
151        + Send
152        + Sync
153        + 'static,
154>;
155
156pub struct MouseEventListeners<V: 'static> {
157    mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
158    mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
159    mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
160    scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
161}
162
163impl<S: Send + Sync + 'static> MouseEventListeners<S> {
164    pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<S>) {
165        for handler in self.mouse_down.iter().cloned() {
166            cx.on_mouse_event(move |view, event: &MouseDownEvent, phase, cx| {
167                handler(view, event, &bounds, phase, cx);
168            })
169        }
170        for handler in self.mouse_up.iter().cloned() {
171            cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
172                handler(view, event, &bounds, phase, cx);
173            })
174        }
175        for handler in self.mouse_move.iter().cloned() {
176            cx.on_mouse_event(move |view, event: &MouseMoveEvent, phase, cx| {
177                handler(view, event, &bounds, phase, cx);
178            })
179        }
180
181        for handler in self.scroll_wheel.iter().cloned() {
182            cx.on_mouse_event(move |view, event: &ScrollWheelEvent, phase, cx| {
183                handler(view, event, &bounds, phase, cx);
184            })
185        }
186    }
187}
188
189impl<V> Default for MouseEventListeners<V> {
190    fn default() -> Self {
191        Self {
192            mouse_down: Default::default(),
193            mouse_up: Default::default(),
194            mouse_move: Default::default(),
195            scroll_wheel: Default::default(),
196        }
197    }
198}