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}