mouse_region.rs

  1use std::{any::TypeId, mem::Discriminant, rc::Rc};
  2
  3use collections::HashMap;
  4
  5use pathfinder_geometry::rect::RectF;
  6
  7use crate::{EventContext, MouseButton};
  8
  9use super::mouse_region_event::{
 10    ClickRegionEvent, DownOutRegionEvent, DownRegionEvent, DragRegionEvent, HoverRegionEvent,
 11    MouseRegionEvent, MoveRegionEvent, UpOutRegionEvent, UpRegionEvent,
 12};
 13
 14#[derive(Clone, Default)]
 15pub struct MouseRegion {
 16    pub view_id: usize,
 17    pub discriminant: Option<(TypeId, usize)>,
 18    pub bounds: RectF,
 19    pub handlers: HandlerSet,
 20    pub hoverable: bool,
 21}
 22
 23impl MouseRegion {
 24    pub fn new(view_id: usize, discriminant: Option<(TypeId, usize)>, bounds: RectF) -> Self {
 25        Self::from_handlers(view_id, discriminant, bounds, Default::default())
 26    }
 27
 28    pub fn from_handlers(
 29        view_id: usize,
 30        discriminant: Option<(TypeId, usize)>,
 31        bounds: RectF,
 32        handlers: HandlerSet,
 33    ) -> Self {
 34        Self {
 35            view_id,
 36            discriminant,
 37            bounds,
 38            handlers,
 39            hoverable: true,
 40        }
 41    }
 42
 43    pub fn handle_all(
 44        view_id: usize,
 45        discriminant: Option<(TypeId, usize)>,
 46        bounds: RectF,
 47    ) -> Self {
 48        Self {
 49            view_id,
 50            discriminant,
 51            bounds,
 52            handlers: HandlerSet::capture_all(),
 53            hoverable: true,
 54        }
 55    }
 56
 57    pub fn on_down(
 58        mut self,
 59        button: MouseButton,
 60        handler: impl Fn(DownRegionEvent, &mut EventContext) + 'static,
 61    ) -> Self {
 62        self.handlers = self.handlers.on_down(button, handler);
 63        self
 64    }
 65
 66    pub fn on_up(
 67        mut self,
 68        button: MouseButton,
 69        handler: impl Fn(UpRegionEvent, &mut EventContext) + 'static,
 70    ) -> Self {
 71        self.handlers = self.handlers.on_up(button, handler);
 72        self
 73    }
 74
 75    pub fn on_click(
 76        mut self,
 77        button: MouseButton,
 78        handler: impl Fn(ClickRegionEvent, &mut EventContext) + 'static,
 79    ) -> Self {
 80        self.handlers = self.handlers.on_click(button, handler);
 81        self
 82    }
 83
 84    pub fn on_down_out(
 85        mut self,
 86        button: MouseButton,
 87        handler: impl Fn(DownOutRegionEvent, &mut EventContext) + 'static,
 88    ) -> Self {
 89        self.handlers = self.handlers.on_down_out(button, handler);
 90        self
 91    }
 92
 93    pub fn on_up_out(
 94        mut self,
 95        button: MouseButton,
 96        handler: impl Fn(UpOutRegionEvent, &mut EventContext) + 'static,
 97    ) -> Self {
 98        self.handlers = self.handlers.on_up_out(button, handler);
 99        self
100    }
101
102    pub fn on_drag(
103        mut self,
104        button: MouseButton,
105        handler: impl Fn(DragRegionEvent, &mut EventContext) + 'static,
106    ) -> Self {
107        self.handlers = self.handlers.on_drag(button, handler);
108        self
109    }
110
111    pub fn on_hover(
112        mut self,
113        handler: impl Fn(HoverRegionEvent, &mut EventContext) + 'static,
114    ) -> Self {
115        self.handlers = self.handlers.on_hover(handler);
116        self
117    }
118
119    pub fn on_move(
120        mut self,
121        handler: impl Fn(MoveRegionEvent, &mut EventContext) + 'static,
122    ) -> Self {
123        self.handlers = self.handlers.on_move(handler);
124        self
125    }
126
127    pub fn with_hoverable(mut self, is_hoverable: bool) -> Self {
128        self.hoverable = is_hoverable;
129        self
130    }
131}
132
133#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
134pub struct MouseRegionId {
135    pub view_id: usize,
136    pub discriminant: (TypeId, usize),
137}
138
139#[derive(Clone, Default)]
140pub struct HandlerSet {
141    #[allow(clippy::type_complexity)]
142    pub set: HashMap<
143        (Discriminant<MouseRegionEvent>, Option<MouseButton>),
144        Rc<dyn Fn(MouseRegionEvent, &mut EventContext)>,
145    >,
146}
147
148impl HandlerSet {
149    pub fn capture_all() -> Self {
150        #[allow(clippy::type_complexity)]
151        let mut set: HashMap<
152            (Discriminant<MouseRegionEvent>, Option<MouseButton>),
153            Rc<dyn Fn(MouseRegionEvent, &mut EventContext)>,
154        > = Default::default();
155
156        set.insert((MouseRegionEvent::move_disc(), None), Rc::new(|_, _| {}));
157        set.insert((MouseRegionEvent::hover_disc(), None), Rc::new(|_, _| {}));
158        for button in MouseButton::all() {
159            set.insert(
160                (MouseRegionEvent::drag_disc(), Some(button)),
161                Rc::new(|_, _| {}),
162            );
163            set.insert(
164                (MouseRegionEvent::down_disc(), Some(button)),
165                Rc::new(|_, _| {}),
166            );
167            set.insert(
168                (MouseRegionEvent::up_disc(), Some(button)),
169                Rc::new(|_, _| {}),
170            );
171            set.insert(
172                (MouseRegionEvent::click_disc(), Some(button)),
173                Rc::new(|_, _| {}),
174            );
175            set.insert(
176                (MouseRegionEvent::down_out_disc(), Some(button)),
177                Rc::new(|_, _| {}),
178            );
179            set.insert(
180                (MouseRegionEvent::up_out_disc(), Some(button)),
181                Rc::new(|_, _| {}),
182            );
183        }
184        set.insert(
185            (MouseRegionEvent::scroll_wheel_disc(), None),
186            Rc::new(|_, _| {}),
187        );
188
189        HandlerSet { set }
190    }
191
192    pub fn get(
193        &self,
194        key: &(Discriminant<MouseRegionEvent>, Option<MouseButton>),
195    ) -> Option<Rc<dyn Fn(MouseRegionEvent, &mut EventContext)>> {
196        self.set.get(key).cloned()
197    }
198
199    pub fn contains_handler(
200        &self,
201        event: Discriminant<MouseRegionEvent>,
202        button: Option<MouseButton>,
203    ) -> bool {
204        self.set.contains_key(&(event, button))
205    }
206
207    pub fn on_move(
208        mut self,
209        handler: impl Fn(MoveRegionEvent, &mut EventContext) + 'static,
210    ) -> Self {
211        self.set.insert((MouseRegionEvent::move_disc(), None),
212            Rc::new(move |region_event, cx| {
213                if let MouseRegionEvent::Move(e) = region_event {
214                    handler(e, cx);
215                } else {
216                    panic!(
217                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Move, found {:?}", 
218                        region_event);
219                }
220            }));
221        self
222    }
223
224    pub fn on_down(
225        mut self,
226        button: MouseButton,
227        handler: impl Fn(DownRegionEvent, &mut EventContext) + 'static,
228    ) -> Self {
229        self.set.insert((MouseRegionEvent::down_disc(), Some(button)),
230            Rc::new(move |region_event, cx| {
231                if let MouseRegionEvent::Down(e) = region_event {
232                    handler(e, cx);
233                } else {
234                    panic!(
235                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Down, found {:?}", 
236                        region_event);
237                }
238            }));
239        self
240    }
241
242    pub fn on_up(
243        mut self,
244        button: MouseButton,
245        handler: impl Fn(UpRegionEvent, &mut EventContext) + 'static,
246    ) -> Self {
247        self.set.insert((MouseRegionEvent::up_disc(), Some(button)),
248            Rc::new(move |region_event, cx| {
249                if let MouseRegionEvent::Up(e) = region_event {
250                    handler(e, cx);
251                } else {
252                    panic!(
253                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Up, found {:?}", 
254                        region_event);
255                }
256            }));
257        self
258    }
259
260    pub fn on_click(
261        mut self,
262        button: MouseButton,
263        handler: impl Fn(ClickRegionEvent, &mut EventContext) + 'static,
264    ) -> Self {
265        self.set.insert((MouseRegionEvent::click_disc(), Some(button)),
266            Rc::new(move |region_event, cx| {
267                if let MouseRegionEvent::Click(e) = region_event {
268                    handler(e, cx);
269                } else {
270                    panic!(
271                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Click, found {:?}", 
272                        region_event);
273                }
274            }));
275        self
276    }
277
278    pub fn on_down_out(
279        mut self,
280        button: MouseButton,
281        handler: impl Fn(DownOutRegionEvent, &mut EventContext) + 'static,
282    ) -> Self {
283        self.set.insert((MouseRegionEvent::down_out_disc(), Some(button)),
284            Rc::new(move |region_event, cx| {
285                if let MouseRegionEvent::DownOut(e) = region_event {
286                    handler(e, cx);
287                } else {
288                    panic!(
289                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::DownOut, found {:?}", 
290                        region_event);
291                }
292            }));
293        self
294    }
295
296    pub fn on_up_out(
297        mut self,
298        button: MouseButton,
299        handler: impl Fn(UpOutRegionEvent, &mut EventContext) + 'static,
300    ) -> Self {
301        self.set.insert((MouseRegionEvent::up_out_disc(), Some(button)),
302            Rc::new(move |region_event, cx| {
303                if let MouseRegionEvent::UpOut(e) = region_event {
304                    handler(e, cx);
305                } else {
306                    panic!(
307                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::UpOut, found {:?}", 
308                        region_event);
309                }
310            }));
311        self
312    }
313
314    pub fn on_drag(
315        mut self,
316        button: MouseButton,
317        handler: impl Fn(DragRegionEvent, &mut EventContext) + 'static,
318    ) -> Self {
319        self.set.insert((MouseRegionEvent::drag_disc(), Some(button)),
320            Rc::new(move |region_event, cx| {
321                if let MouseRegionEvent::Drag(e) = region_event {
322                    handler(e, cx);
323                } else {
324                    panic!(
325                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Drag, found {:?}", 
326                        region_event);
327                }
328            }));
329        self
330    }
331
332    pub fn on_hover(
333        mut self,
334        handler: impl Fn(HoverRegionEvent, &mut EventContext) + 'static,
335    ) -> Self {
336        self.set.insert((MouseRegionEvent::hover_disc(), None),
337            Rc::new(move |region_event, cx| {
338                if let MouseRegionEvent::Hover(e) = region_event {
339                    handler(e, cx);
340                } else {
341                    panic!(
342                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Hover, found {:?}", 
343                        region_event);
344                }
345            }));
346        self
347    }
348}