1use super::raw::{IRawInputEventArgs, RawDragEvent, RawPointerEventArgs, RawPointerEventType};
2use super::{
3 IInputDevice, IInputRoot, IPointer, InputElement, KeyModifiers, PointerEventArgs, PointerPointProperties,
4 PointerType,
5};
6use crate::reactive::IObserver;
7use crate::{PixelPoint, Point, Rect, Ref};
8use std::cell::{Cell, RefCell};
9use std::rc::Rc;
10
11pub struct PointerOverPreProcessor {
18 last_active_pointer_device: RefCell<Option<Rc<dyn IInputDevice>>>,
19 current_pointer: RefCell<Option<(Rc<dyn IPointer>, PixelPoint)>>,
20 last_known_position: Cell<Option<PixelPoint>>,
21 input_root: Rc<dyn IInputRoot>,
22}
23
24impl PointerOverPreProcessor {
25 pub fn new(input_root: Rc<dyn IInputRoot>) -> Self {
27 Self {
28 last_active_pointer_device: RefCell::new(None),
29 current_pointer: RefCell::new(None),
30 last_known_position: Cell::new(None),
31 input_root,
32 }
33 }
34
35 pub fn last_position(&self) -> Option<PixelPoint> {
37 self.last_known_position.get()
38 }
39
40 fn take_current_pointer(&self) -> Option<(Rc<dyn IPointer>, PixelPoint)> {
41 self.current_pointer.borrow_mut().take()
42 }
43
44 fn current_pointer(&self) -> Option<(Rc<dyn IPointer>, PixelPoint)> {
45 self.current_pointer.borrow().clone()
46 }
47
48 fn set_current_pointer(&self, value: Option<(Rc<dyn IPointer>, PixelPoint)>) {
49 let old = self.current_pointer.replace(value);
50 drop(old);
51 }
52
53 fn set_last_active_pointer_device(&self, value: Option<Rc<dyn IInputDevice>>) {
54 let old = self.last_active_pointer_device.replace(value);
55 drop(old);
56 }
57
58 fn is_this_root(&self, root: &Rc<dyn IInputRoot>) -> bool {
59 std::ptr::addr_eq(Rc::as_ptr(root), Rc::as_ptr(&self.input_root))
60 }
61
62 fn process(&self, value: &dyn IRawInputEventArgs) {
63 if let Some(drag_args) = value.downcast_ref::<RawDragEvent>() {
64 self.last_known_position
74 .set(Some(self.input_root.root_element().point_to_screen(drag_args.location())));
75 return;
76 }
77
78 let Some(args) = value.downcast_ref::<RawPointerEventArgs>() else { return };
79
80 if !self.is_this_root(args.root()) {
81 return;
82 }
83
84 let device = value.device();
85 let Some(pointer_device) = device.as_pointer_device() else { return };
86
87 let is_last_active = self
88 .last_active_pointer_device
89 .borrow()
90 .as_ref()
91 .is_some_and(|last| std::ptr::addr_eq(Rc::as_ptr(last), Rc::as_ptr(device)));
92
93 if !is_last_active {
94 self.clear_pointer_over();
95
96 self.set_last_active_pointer_device(Some(device.clone()));
100 }
101
102 let type_ = args.type_();
103 let root = args.root();
104
105 if matches!(
106 type_,
107 RawPointerEventType::LeaveWindow
108 | RawPointerEventType::NonClientLeftButtonDown
109 | RawPointerEventType::TouchCancel
110 | RawPointerEventType::TouchEnd
111 ) {
112 if let Some((last_pointer, last_position)) = self.take_current_pointer() {
113 self.clear_pointer_over_for(
114 &last_pointer,
115 root,
116 0,
117 Some(Self::point_to_client(root, last_position)),
118 PointerPointProperties::new(args.input_modifiers(), type_.to_update_kind()),
119 args.input_modifiers().to_key_modifiers(),
120 );
121 }
122 } else if matches!(type_, RawPointerEventType::TouchBegin | RawPointerEventType::TouchUpdate) {
123 self.last_known_position.set(Some(root.root_element().point_to_screen(args.position())));
124 } else if let Some(pointer) = pointer_device.try_get_pointer(args) {
125 if pointer.type_() != PointerType::Touch && type_ != RawPointerEventType::CancelCapture {
126 let element =
127 Self::get_effective_pointer_over_element(args.input_hit_test_result().1, pointer.captured());
128
129 self.set_pointer_over(
130 &pointer,
131 root,
132 element,
133 args.timestamp(),
134 args.position(),
135 PointerPointProperties::new(args.input_modifiers(), type_.to_update_kind()),
136 args.input_modifiers().to_key_modifiers(),
137 );
138 }
139 }
140 }
141
142 pub fn scene_invalidated(&self, dirty_rect: Rect) {
145 let Some((pointer, position)) = self.current_pointer() else { return };
146
147 let root_element = self.input_root.root_element();
148 let client_point = Self::point_to_client(&self.input_root, position);
149
150 if dirty_rect.contains(client_point) {
151 let element = Self::get_effective_pointer_over_element(
152 root_element.input_hit_test(client_point),
153 pointer.captured(),
154 );
155
156 self.set_pointer_over(
157 &pointer,
158 &self.input_root,
159 element,
160 0,
161 client_point,
162 PointerPointProperties::NONE,
163 KeyModifiers::NONE,
164 );
165 } else if !root_element.bounds().contains(client_point) {
166 self.clear_pointer_over_for(
167 &pointer,
168 &self.input_root,
169 0,
170 Some(client_point),
171 PointerPointProperties::NONE,
172 KeyModifiers::NONE,
173 );
174 }
175 }
176
177 fn get_effective_pointer_over_element(
178 hit_test_element: Option<Ref<InputElement>>,
179 captured: Option<Ref<InputElement>>,
180 ) -> Option<Ref<InputElement>> {
181 if captured.is_some() && hit_test_element != captured {
182 None
183 } else {
184 hit_test_element
185 }
186 }
187
188 fn clear_pointer_over(&self) {
189 if let Some((pointer, position)) = self.current_pointer() {
190 let client_point = Self::point_to_client(&self.input_root, position);
191 self.clear_pointer_over_for(
192 &pointer,
193 &self.input_root,
194 0,
195 Some(client_point),
196 PointerPointProperties::NONE,
197 KeyModifiers::NONE,
198 );
199 }
200
201 self.set_current_pointer(None);
202 self.set_last_active_pointer_device(None);
203 }
204
205 fn clear_pointer_over_for(
206 &self,
207 pointer: &Rc<dyn IPointer>,
208 root: &Rc<dyn IInputRoot>,
209 timestamp: u64,
210 position: Option<Point>,
211 properties: PointerPointProperties,
212 input_modifiers: KeyModifiers,
213 ) {
214 let Some(element) = root.pointer_over_element() else { return };
215
216 let root_element = root.root_element();
217
218 let e = PointerEventArgs::new(
221 Some(InputElement::pointer_exited_event()),
222 &element,
223 pointer.clone(),
224 position.map(|_| &***root_element as &crate::Visual),
225 position.unwrap_or_default(),
226 timestamp,
227 properties,
228 input_modifiers,
229 );
230
231 if !element.is_attached_to_visual_tree() {
232 if root_element.is_pointer_over() {
235 Self::clear_children_pointer_over(&e, &root_element, true);
236 }
237 }
238
239 let mut current = Some(element);
240
241 while let Some(element) = current {
242 e.set_source(&element);
243 e.set_handled(false);
244 element.raise_event(&e);
245 current = Self::get_visual_parent(&element);
246 }
247
248 root.set_pointer_over_element(None);
249 root.set_cursor_element(pointer.captured());
250
251 self.set_last_active_pointer_device(None);
252 self.set_current_pointer(None);
253 }
254
255 fn clear_children_pointer_over(e: &PointerEventArgs, element: &Ref<InputElement>, clear_root: bool) {
256 if let Some(children) = element.visual_children_snapshot() {
257 for el in children.iter() {
258 if let Some(child) = el.cast::<InputElement>() {
259 if child.is_pointer_over() {
260 Self::clear_children_pointer_over(e, &child, true);
261 break;
262 }
263 }
264 }
265 }
266
267 if clear_root {
268 e.set_source(element);
269 e.set_handled(false);
270 element.raise_event(e);
271 }
272 }
273
274 #[allow(clippy::too_many_arguments)]
275 fn set_pointer_over(
276 &self,
277 pointer: &Rc<dyn IPointer>,
278 root: &Rc<dyn IInputRoot>,
279 element: Option<Ref<InputElement>>,
280 timestamp: u64,
281 position: Point,
282 properties: PointerPointProperties,
283 input_modifiers: KeyModifiers,
284 ) {
285 let pointer_over_element = root.pointer_over_element();
286 let screen_position = root.root_element().point_to_screen(position);
287 self.last_known_position.set(Some(screen_position));
288
289 if element != pointer_over_element {
290 match &element {
291 Some(element) => self.set_pointer_over_to_element(
292 pointer,
293 root,
294 element,
295 timestamp,
296 position,
297 properties,
298 input_modifiers,
299 ),
300 None => self.clear_pointer_over_for(
301 pointer,
302 root,
303 timestamp,
304 Some(position),
305 properties,
306 input_modifiers,
307 ),
308 }
309 }
310
311 self.set_current_pointer(Some((pointer.clone(), screen_position)));
312 }
313
314 #[allow(clippy::too_many_arguments)]
315 fn set_pointer_over_to_element(
316 &self,
317 pointer: &Rc<dyn IPointer>,
318 root: &Rc<dyn IInputRoot>,
319 element: &Ref<InputElement>,
320 timestamp: u64,
321 position: Point,
322 properties: PointerPointProperties,
323 input_modifiers: KeyModifiers,
324 ) {
325 let mut branch: Option<Ref<InputElement>> = None;
326 let mut el = Some(element.clone());
327
328 while let Some(current) = el {
329 if current.is_pointer_over() {
330 branch = Some(current);
331 break;
332 }
333 el = Self::get_visual_parent(¤t);
334 }
335
336 el = root.pointer_over_element();
337
338 let root_element = root.root_element();
339 let e = PointerEventArgs::new(
340 Some(InputElement::pointer_exited_event()),
341 el.clone().map(Ref::upcast::<crate::FerroObject>),
342 pointer.clone(),
343 Some(&root_element),
344 position,
345 timestamp,
346 properties,
347 input_modifiers,
348 );
349
350 if let (Some(old), Some(branch)) = (&el, &branch) {
351 if !old.is_attached_to_visual_tree() {
352 Self::clear_children_pointer_over(&e, branch, false);
353 }
354 }
355
356 while let Some(current) = el {
357 if Some(¤t) == branch.as_ref() {
358 break;
359 }
360 e.set_source(¤t);
361 e.set_handled(false);
362 current.raise_event(&e);
363 el = Self::get_visual_parent(¤t);
364 }
365
366 root.set_pointer_over_element(Some(element.clone()));
367 el = Some(element.clone());
368 root.set_cursor_element(pointer.captured().or_else(|| Some(element.clone())));
369
370 e.set_routed_event(Some(InputElement::pointer_entered_event()));
371
372 while let Some(current) = el {
373 if Some(¤t) == branch.as_ref() {
374 break;
375 }
376 e.set_source(¤t);
377 e.set_handled(false);
378 current.raise_event(&e);
379 el = Self::get_visual_parent(¤t);
380 }
381 }
382
383 fn get_visual_parent(e: &InputElement) -> Option<Ref<InputElement>> {
384 e.visual_parent().and_then(|parent| parent.downcast::<InputElement>().ok())
385 }
386
387 fn point_to_client(root: &Rc<dyn IInputRoot>, p: PixelPoint) -> Point {
388 root.root_element().point_to_client(p)
389 }
390}
391
392impl IObserver<Rc<dyn IRawInputEventArgs>> for PointerOverPreProcessor {
393 fn on_next(&self, value: Rc<dyn IRawInputEventArgs>) {
394 self.process(&*value);
395 }
396
397 fn on_completed(&self) {
398 self.clear_pointer_over();
399 }
400}