interactive.rs

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