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 on_move(
200        mut self,
201        handler: impl Fn(MoveRegionEvent, &mut EventContext) + 'static,
202    ) -> Self {
203        self.set.insert((MouseRegionEvent::move_disc(), None),
204            Rc::new(move |region_event, cx| {
205                if let MouseRegionEvent::Move(e) = region_event {
206                    handler(e, cx);
207                } else {
208                    panic!(
209                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Move, found {:?}", 
210                        region_event);
211                }
212            }));
213        self
214    }
215
216    pub fn on_down(
217        mut self,
218        button: MouseButton,
219        handler: impl Fn(DownRegionEvent, &mut EventContext) + 'static,
220    ) -> Self {
221        self.set.insert((MouseRegionEvent::down_disc(), Some(button)),
222            Rc::new(move |region_event, cx| {
223                if let MouseRegionEvent::Down(e) = region_event {
224                    handler(e, cx);
225                } else {
226                    panic!(
227                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Down, found {:?}", 
228                        region_event);
229                }
230            }));
231        self
232    }
233
234    pub fn on_up(
235        mut self,
236        button: MouseButton,
237        handler: impl Fn(UpRegionEvent, &mut EventContext) + 'static,
238    ) -> Self {
239        self.set.insert((MouseRegionEvent::up_disc(), Some(button)),
240            Rc::new(move |region_event, cx| {
241                if let MouseRegionEvent::Up(e) = region_event {
242                    handler(e, cx);
243                } else {
244                    panic!(
245                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Up, found {:?}", 
246                        region_event);
247                }
248            }));
249        self
250    }
251
252    pub fn on_click(
253        mut self,
254        button: MouseButton,
255        handler: impl Fn(ClickRegionEvent, &mut EventContext) + 'static,
256    ) -> Self {
257        self.set.insert((MouseRegionEvent::click_disc(), Some(button)),
258            Rc::new(move |region_event, cx| {
259                if let MouseRegionEvent::Click(e) = region_event {
260                    handler(e, cx);
261                } else {
262                    panic!(
263                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Click, found {:?}", 
264                        region_event);
265                }
266            }));
267        self
268    }
269
270    pub fn on_down_out(
271        mut self,
272        button: MouseButton,
273        handler: impl Fn(DownOutRegionEvent, &mut EventContext) + 'static,
274    ) -> Self {
275        self.set.insert((MouseRegionEvent::down_out_disc(), Some(button)),
276            Rc::new(move |region_event, cx| {
277                if let MouseRegionEvent::DownOut(e) = region_event {
278                    handler(e, cx);
279                } else {
280                    panic!(
281                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::DownOut, found {:?}", 
282                        region_event);
283                }
284            }));
285        self
286    }
287
288    pub fn on_up_out(
289        mut self,
290        button: MouseButton,
291        handler: impl Fn(UpOutRegionEvent, &mut EventContext) + 'static,
292    ) -> Self {
293        self.set.insert((MouseRegionEvent::up_out_disc(), Some(button)),
294            Rc::new(move |region_event, cx| {
295                if let MouseRegionEvent::UpOut(e) = region_event {
296                    handler(e, cx);
297                } else {
298                    panic!(
299                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::UpOut, found {:?}", 
300                        region_event);
301                }
302            }));
303        self
304    }
305
306    pub fn on_drag(
307        mut self,
308        button: MouseButton,
309        handler: impl Fn(DragRegionEvent, &mut EventContext) + 'static,
310    ) -> Self {
311        self.set.insert((MouseRegionEvent::drag_disc(), Some(button)),
312            Rc::new(move |region_event, cx| {
313                if let MouseRegionEvent::Drag(e) = region_event {
314                    handler(e, cx);
315                } else {
316                    panic!(
317                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Drag, found {:?}", 
318                        region_event);
319                }
320            }));
321        self
322    }
323
324    pub fn on_hover(
325        mut self,
326        handler: impl Fn(HoverRegionEvent, &mut EventContext) + 'static,
327    ) -> Self {
328        self.set.insert((MouseRegionEvent::hover_disc(), None),
329            Rc::new(move |region_event, cx| {
330                if let MouseRegionEvent::Hover(e) = region_event {
331                    handler(e, cx);
332                } else {
333                    panic!(
334                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Hover, found {:?}", 
335                        region_event);
336                }
337            }));
338        self
339    }
340}