mouse_region.rs

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