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}