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}