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 on_move(
200 mut self,
201 handler: impl Fn(MoveRegionEvent, &mut EventContext) + 'static,
202 ) -> Self {
203 self.set.insert((MouseRegionEvent::move_disc(), None),
204 Rc::new(move |region_event, cx| {
205 if let MouseRegionEvent::Move(e) = region_event {
206 handler(e, cx);
207 } else {
208 panic!(
209 "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Move, found {:?}",
210 region_event);
211 }
212 }));
213 self
214 }
215
216 pub fn on_down(
217 mut self,
218 button: MouseButton,
219 handler: impl Fn(DownRegionEvent, &mut EventContext) + 'static,
220 ) -> Self {
221 self.set.insert((MouseRegionEvent::down_disc(), Some(button)),
222 Rc::new(move |region_event, cx| {
223 if let MouseRegionEvent::Down(e) = region_event {
224 handler(e, cx);
225 } else {
226 panic!(
227 "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Down, found {:?}",
228 region_event);
229 }
230 }));
231 self
232 }
233
234 pub fn on_up(
235 mut self,
236 button: MouseButton,
237 handler: impl Fn(UpRegionEvent, &mut EventContext) + 'static,
238 ) -> Self {
239 self.set.insert((MouseRegionEvent::up_disc(), Some(button)),
240 Rc::new(move |region_event, cx| {
241 if let MouseRegionEvent::Up(e) = region_event {
242 handler(e, cx);
243 } else {
244 panic!(
245 "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Up, found {:?}",
246 region_event);
247 }
248 }));
249 self
250 }
251
252 pub fn on_click(
253 mut self,
254 button: MouseButton,
255 handler: impl Fn(ClickRegionEvent, &mut EventContext) + 'static,
256 ) -> Self {
257 self.set.insert((MouseRegionEvent::click_disc(), Some(button)),
258 Rc::new(move |region_event, cx| {
259 if let MouseRegionEvent::Click(e) = region_event {
260 handler(e, cx);
261 } else {
262 panic!(
263 "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Click, found {:?}",
264 region_event);
265 }
266 }));
267 self
268 }
269
270 pub fn on_down_out(
271 mut self,
272 button: MouseButton,
273 handler: impl Fn(DownOutRegionEvent, &mut EventContext) + 'static,
274 ) -> Self {
275 self.set.insert((MouseRegionEvent::down_out_disc(), Some(button)),
276 Rc::new(move |region_event, cx| {
277 if let MouseRegionEvent::DownOut(e) = region_event {
278 handler(e, cx);
279 } else {
280 panic!(
281 "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::DownOut, found {:?}",
282 region_event);
283 }
284 }));
285 self
286 }
287
288 pub fn on_up_out(
289 mut self,
290 button: MouseButton,
291 handler: impl Fn(UpOutRegionEvent, &mut EventContext) + 'static,
292 ) -> Self {
293 self.set.insert((MouseRegionEvent::up_out_disc(), Some(button)),
294 Rc::new(move |region_event, cx| {
295 if let MouseRegionEvent::UpOut(e) = region_event {
296 handler(e, cx);
297 } else {
298 panic!(
299 "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::UpOut, found {:?}",
300 region_event);
301 }
302 }));
303 self
304 }
305
306 pub fn on_drag(
307 mut self,
308 button: MouseButton,
309 handler: impl Fn(DragRegionEvent, &mut EventContext) + 'static,
310 ) -> Self {
311 self.set.insert((MouseRegionEvent::drag_disc(), Some(button)),
312 Rc::new(move |region_event, cx| {
313 if let MouseRegionEvent::Drag(e) = region_event {
314 handler(e, cx);
315 } else {
316 panic!(
317 "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Drag, found {:?}",
318 region_event);
319 }
320 }));
321 self
322 }
323
324 pub fn on_hover(
325 mut self,
326 handler: impl Fn(HoverRegionEvent, &mut EventContext) + 'static,
327 ) -> Self {
328 self.set.insert((MouseRegionEvent::hover_disc(), None),
329 Rc::new(move |region_event, cx| {
330 if let MouseRegionEvent::Hover(e) = region_event {
331 handler(e, cx);
332 } else {
333 panic!(
334 "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Hover, found {:?}",
335 region_event);
336 }
337 }));
338 self
339 }
340}