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    pub set: HashMap<
111        (Discriminant<MouseRegionEvent>, Option<MouseButton>),
112        Rc<dyn Fn(MouseRegionEvent, &mut EventContext)>,
113    >,
114}
115
116impl HandlerSet {
117    pub fn handle_all() -> Self {
118        let mut set: HashMap<
119            (Discriminant<MouseRegionEvent>, Option<MouseButton>),
120            Rc<dyn Fn(MouseRegionEvent, &mut EventContext)>,
121        > = Default::default();
122
123        set.insert((MouseRegionEvent::move_disc(), None), Rc::new(|_, _| {}));
124        set.insert((MouseRegionEvent::hover_disc(), None), Rc::new(|_, _| {}));
125        for button in MouseButton::all() {
126            set.insert(
127                (MouseRegionEvent::drag_disc(), Some(button)),
128                Rc::new(|_, _| {}),
129            );
130            set.insert(
131                (MouseRegionEvent::down_disc(), Some(button)),
132                Rc::new(|_, _| {}),
133            );
134            set.insert(
135                (MouseRegionEvent::up_disc(), Some(button)),
136                Rc::new(|_, _| {}),
137            );
138            set.insert(
139                (MouseRegionEvent::click_disc(), Some(button)),
140                Rc::new(|_, _| {}),
141            );
142            set.insert(
143                (MouseRegionEvent::down_out_disc(), Some(button)),
144                Rc::new(|_, _| {}),
145            );
146        }
147        set.insert(
148            (MouseRegionEvent::scroll_wheel_disc(), None),
149            Rc::new(|_, _| {}),
150        );
151
152        HandlerSet { set }
153    }
154
155    pub fn get(
156        &self,
157        key: &(Discriminant<MouseRegionEvent>, Option<MouseButton>),
158    ) -> Option<Rc<dyn Fn(MouseRegionEvent, &mut EventContext)>> {
159        self.set.get(key).cloned()
160    }
161
162    pub fn on_down(
163        mut self,
164        button: MouseButton,
165        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
166    ) -> Self {
167        self.set.insert((MouseRegionEvent::down_disc(), Some(button)),
168            Rc::new(move |region_event, cx| {
169                if let MouseRegionEvent::Down(mouse_button_event) = region_event {
170                    handler(mouse_button_event, cx);
171                } else {
172                    panic!(
173                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Down, found {:?}", 
174                        region_event);
175                }
176            }));
177        self
178    }
179
180    pub fn on_up(
181        mut self,
182        button: MouseButton,
183        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
184    ) -> Self {
185        self.set.insert((MouseRegionEvent::up_disc(), Some(button)),
186            Rc::new(move |region_event, cx| {
187                if let MouseRegionEvent::Up(mouse_button_event) = region_event {
188                    handler(mouse_button_event, cx);
189                } else {
190                    panic!(
191                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Up, found {:?}", 
192                        region_event);
193                }
194            }));
195        self
196    }
197
198    pub fn on_click(
199        mut self,
200        button: MouseButton,
201        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
202    ) -> Self {
203        self.set.insert((MouseRegionEvent::click_disc(), Some(button)),
204            Rc::new(move |region_event, cx| {
205                if let MouseRegionEvent::Click(mouse_button_event) = region_event {
206                    handler(mouse_button_event, cx);
207                } else {
208                    panic!(
209                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Click, found {:?}", 
210                        region_event);
211                }
212            }));
213        self
214    }
215
216    pub fn on_down_out(
217        mut self,
218        button: MouseButton,
219        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
220    ) -> Self {
221        self.set.insert((MouseRegionEvent::down_out_disc(), Some(button)),
222            Rc::new(move |region_event, cx| {
223                if let MouseRegionEvent::DownOut(mouse_button_event) = region_event {
224                    handler(mouse_button_event, cx);
225                } else {
226                    panic!(
227                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::DownOut, found {:?}", 
228                        region_event);
229                }
230            }));
231        self
232    }
233
234    pub fn on_drag(
235        mut self,
236        button: MouseButton,
237        handler: impl Fn(Vector2F, MouseMovedEvent, &mut EventContext) + 'static,
238    ) -> Self {
239        self.set.insert((MouseRegionEvent::drag_disc(), Some(button)),
240            Rc::new(move |region_event, cx| {
241                if let MouseRegionEvent::Drag(prev_drag_position, mouse_moved_event) = region_event {
242                    handler(prev_drag_position, mouse_moved_event, cx);
243                } else {
244                    panic!(
245                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Drag, found {:?}", 
246                        region_event);
247                }
248            }));
249        self
250    }
251
252    pub fn on_hover(
253        mut self,
254        handler: impl Fn(bool, MouseMovedEvent, &mut EventContext) + 'static,
255    ) -> Self {
256        self.set.insert((MouseRegionEvent::hover_disc(), None),
257            Rc::new(move |region_event, cx| {
258                if let MouseRegionEvent::Hover(hover, mouse_moved_event) = region_event {
259                    handler(hover, mouse_moved_event, cx);
260                } else {
261                    panic!(
262                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Hover, found {:?}", 
263                        region_event);
264                }
265            }));
266        self
267    }
268}
269
270#[derive(Debug)]
271pub enum MouseRegionEvent {
272    Move(MouseMovedEvent),
273    Drag(Vector2F, MouseMovedEvent),
274    Hover(bool, MouseMovedEvent),
275    Down(MouseButtonEvent),
276    Up(MouseButtonEvent),
277    Click(MouseButtonEvent),
278    DownOut(MouseButtonEvent),
279    ScrollWheel(ScrollWheelEvent),
280}
281
282impl MouseRegionEvent {
283    pub fn move_disc() -> Discriminant<MouseRegionEvent> {
284        std::mem::discriminant(&MouseRegionEvent::Move(Default::default()))
285    }
286    pub fn drag_disc() -> Discriminant<MouseRegionEvent> {
287        std::mem::discriminant(&MouseRegionEvent::Drag(
288            Default::default(),
289            Default::default(),
290        ))
291    }
292    pub fn hover_disc() -> Discriminant<MouseRegionEvent> {
293        std::mem::discriminant(&MouseRegionEvent::Hover(
294            Default::default(),
295            Default::default(),
296        ))
297    }
298    pub fn down_disc() -> Discriminant<MouseRegionEvent> {
299        std::mem::discriminant(&MouseRegionEvent::Down(Default::default()))
300    }
301    pub fn up_disc() -> Discriminant<MouseRegionEvent> {
302        std::mem::discriminant(&MouseRegionEvent::Up(Default::default()))
303    }
304    pub fn click_disc() -> Discriminant<MouseRegionEvent> {
305        std::mem::discriminant(&MouseRegionEvent::Click(Default::default()))
306    }
307    pub fn down_out_disc() -> Discriminant<MouseRegionEvent> {
308        std::mem::discriminant(&MouseRegionEvent::DownOut(Default::default()))
309    }
310    pub fn scroll_wheel_disc() -> Discriminant<MouseRegionEvent> {
311        std::mem::discriminant(&MouseRegionEvent::ScrollWheel(Default::default()))
312    }
313
314    pub fn handler_key(&self) -> (Discriminant<MouseRegionEvent>, Option<MouseButton>) {
315        match self {
316            MouseRegionEvent::Move(_) => (Self::move_disc(), None),
317            MouseRegionEvent::Drag(_, MouseMovedEvent { pressed_button, .. }) => {
318                (Self::drag_disc(), *pressed_button)
319            }
320            MouseRegionEvent::Hover(_, _) => (Self::hover_disc(), None),
321            MouseRegionEvent::Down(MouseButtonEvent { button, .. }) => {
322                (Self::down_disc(), Some(*button))
323            }
324            MouseRegionEvent::Up(MouseButtonEvent { button, .. }) => {
325                (Self::up_disc(), Some(*button))
326            }
327            MouseRegionEvent::Click(MouseButtonEvent { button, .. }) => {
328                (Self::click_disc(), Some(*button))
329            }
330            MouseRegionEvent::DownOut(MouseButtonEvent { button, .. }) => {
331                (Self::down_out_disc(), Some(*button))
332            }
333            MouseRegionEvent::ScrollWheel(_) => (Self::scroll_wheel_disc(), None),
334        }
335    }
336}