mouse_region.rs

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