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