1use super::raw::RawPointerPoint;
2use super::{
3 CaptureSource, IKeyModifiersEventArgs, IPointer, InputElement, KeyModifiers, Pointer, PointerPoint,
4 PointerPointProperties,
5};
6use crate::interactivity::{RoutedEvent, RoutedEventArgs};
7use crate::rendering::IPresentationSource;
8use crate::{ferro_routed_event_args, FerroObject, Nullable, Point, Ref, Visual};
9use std::any::Any;
10use std::cell::LazyCell;
11use std::rc::Rc;
12
13pub type IntermediatePoints =
16 Rc<LazyCell<Option<Vec<RawPointerPoint>>, Box<dyn FnOnce() -> Option<Vec<RawPointerPoint>>>>>;
17
18#[derive(Clone)]
20pub struct PointerEventArgs {
21 base: RoutedEventArgs,
22 event_presentation_source: Option<Rc<dyn IPresentationSource>>,
24 presentation_source_position: Point,
25 properties: PointerPointProperties,
26 previous_points: Option<IntermediatePoints>,
27 pointer: Rc<dyn IPointer>,
28 timestamp: u64,
29 platform_input_event_cookie: Option<Rc<dyn Any>>,
30 key_modifiers: KeyModifiers,
31}
32
33ferro_routed_event_args!(PointerEventArgs: RoutedEventArgs);
34
35impl PointerEventArgs {
36 #[allow(clippy::too_many_arguments)]
42 pub fn new<T: ?Sized>(
43 routed_event: Option<&RoutedEvent<T>>,
44 source: impl Into<Nullable<FerroObject>>,
45 pointer: Rc<dyn IPointer>,
46 root_visual: Option<&Visual>,
47 root_visual_position: Point,
48 timestamp: u64,
49 properties: PointerPointProperties,
50 modifiers: KeyModifiers,
51 ) -> Self {
52 let base = RoutedEventArgs::new();
53 base.set_routed_event(routed_event);
54 base.set_source(source);
55
56 Self {
57 base,
58 event_presentation_source: root_visual.and_then(Visual::presentation_source),
59 presentation_source_position: root_visual_position,
60 properties,
61 previous_points: None,
62 pointer,
63 timestamp,
64 platform_input_event_cookie: None,
65 key_modifiers: modifiers,
66 }
67 }
68
69 pub fn with_previous_points(mut self, previous_points: Option<IntermediatePoints>) -> Self {
71 self.previous_points = previous_points;
72 self
73 }
74
75 pub fn with_platform_input_event_cookie(mut self, cookie: Option<Rc<dyn Any>>) -> Self {
77 self.platform_input_event_cookie = cookie;
78 self
79 }
80
81 #[inline]
83 pub fn pointer(&self) -> &Rc<dyn IPointer> {
84 &self.pointer
85 }
86
87 #[inline]
90 pub fn timestamp(&self) -> u64 {
91 self.timestamp
92 }
93
94 #[inline]
97 pub fn platform_input_event_cookie(&self) -> Option<&Rc<dyn Any>> {
98 self.platform_input_event_cookie.as_ref()
99 }
100
101 pub(crate) fn is_gesture_recognition_skipped(&self) -> bool {
103 self.pointer.as_any().downcast_ref::<Pointer>().is_some_and(Pointer::is_gesture_recognition_skipped)
104 }
105
106 #[inline]
108 pub fn key_modifiers(&self) -> KeyModifiers {
109 self.key_modifiers
110 }
111
112 fn get_position_of(&self, pt: Point, relative_to: Option<&Visual>) -> Point {
113 let Some(relative_to) = relative_to else { return pt };
114
115 let Some(event_source) = &self.event_presentation_source else { return Point::default() };
116 let Some(target_source) = relative_to.presentation_source() else { return Point::default() };
117 let Some(target_root) = target_source.root_visual() else { return Point::default() };
118
119 let mut pt = pt;
120
121 if !std::ptr::addr_eq(Rc::as_ptr(&target_source), Rc::as_ptr(event_source)) {
122 match event_source.point_to_screen(pt).and_then(|screen_pt| target_source.point_to_client(screen_pt)) {
123 Some(target_client_pt) => pt = target_client_pt,
124 None => return Point::default(),
125 }
126 }
127
128 target_root.translate_point(pt, relative_to).unwrap_or_default()
129 }
130
131 pub fn get_position(&self, relative_to: Option<&Visual>) -> Point {
135 self.get_position_of(self.presentation_source_position, relative_to)
136 }
137
138 pub fn get_current_point(&self, relative_to: Option<&Visual>) -> PointerPoint {
141 PointerPoint::new(self.pointer.clone(), self.get_position(relative_to), self.properties)
142 }
143
144 pub fn get_intermediate_points(&self, relative_to: Option<&Visual>) -> Vec<PointerPoint> {
147 let previous_points = match &self.previous_points {
148 Some(lazy) => match &***lazy {
149 Some(points) if !points.is_empty() => points.as_slice(),
150 _ => &[],
151 },
152 None => &[],
153 };
154
155 let mut points = Vec::with_capacity(previous_points.len() + 1);
156
157 for pt in previous_points {
158 let point_properties = PointerPointProperties::based_on(self.properties, *pt);
159 points.push(PointerPoint::new(
160 self.pointer.clone(),
161 self.get_position_of(pt.position, relative_to),
162 point_properties,
163 ));
164 }
165
166 points.push(self.get_current_point(relative_to));
167 points
168 }
169
170 pub fn prevent_gesture_recognition(&self) {
173 if let Some(pointer) = self.pointer.as_any().downcast_ref::<Pointer>() {
174 pointer.set_is_gesture_recognition_skipped(true);
175 }
176 }
177
178 #[inline]
180 pub fn properties(&self) -> PointerPointProperties {
181 self.properties
182 }
183}
184
185impl IKeyModifiersEventArgs for PointerEventArgs {
186 fn key_modifiers(&self) -> KeyModifiers {
187 self.key_modifiers
188 }
189}
190
191#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
193pub enum MouseButton {
194 #[default]
195 None,
196 Left,
197 Right,
198 Middle,
199 XButton1,
200 XButton2,
201}
202
203#[derive(Clone)]
205pub struct PointerPressedEventArgs {
206 base: PointerEventArgs,
207 click_count: i32,
208}
209
210ferro_routed_event_args!(PointerPressedEventArgs: PointerEventArgs);
211
212impl PointerPressedEventArgs {
213 #[allow(clippy::too_many_arguments)]
215 pub fn new(
216 source: impl Into<Nullable<FerroObject>>,
217 pointer: Rc<dyn IPointer>,
218 root_visual: &Visual,
219 root_visual_position: Point,
220 timestamp: u64,
221 properties: PointerPointProperties,
222 modifiers: KeyModifiers,
223 click_count: i32,
224 ) -> Self {
225 Self {
226 base: PointerEventArgs::new(
227 Some(InputElement::pointer_pressed_event()),
228 source,
229 pointer,
230 Some(root_visual),
231 root_visual_position,
232 timestamp,
233 properties,
234 modifiers,
235 ),
236 click_count,
237 }
238 }
239
240 pub fn with_platform_input_event_cookie(mut self, cookie: Option<Rc<dyn Any>>) -> Self {
242 self.base = self.base.with_platform_input_event_cookie(cookie);
243 self
244 }
245
246 #[inline]
249 pub fn click_count(&self) -> i32 {
250 self.click_count
251 }
252}
253
254#[derive(Clone)]
256pub struct PointerReleasedEventArgs {
257 base: PointerEventArgs,
258 initial_press_mouse_button: MouseButton,
259}
260
261ferro_routed_event_args!(PointerReleasedEventArgs: PointerEventArgs);
262
263impl PointerReleasedEventArgs {
264 #[allow(clippy::too_many_arguments)]
266 pub fn new(
267 source: impl Into<Nullable<FerroObject>>,
268 pointer: Rc<dyn IPointer>,
269 root_visual: &Visual,
270 root_visual_position: Point,
271 timestamp: u64,
272 properties: PointerPointProperties,
273 modifiers: KeyModifiers,
274 initial_press_mouse_button: MouseButton,
275 ) -> Self {
276 Self {
277 base: PointerEventArgs::new(
278 Some(InputElement::pointer_released_event()),
279 source,
280 pointer,
281 Some(root_visual),
282 root_visual_position,
283 timestamp,
284 properties,
285 modifiers,
286 ),
287 initial_press_mouse_button,
288 }
289 }
290
291 #[inline]
294 pub fn initial_press_mouse_button(&self) -> MouseButton {
295 self.initial_press_mouse_button
296 }
297}
298
299#[derive(Clone)]
301pub struct PointerCaptureLostEventArgs {
302 base: RoutedEventArgs,
303 pointer: Rc<dyn IPointer>,
304}
305
306ferro_routed_event_args!(PointerCaptureLostEventArgs: RoutedEventArgs);
307
308impl PointerCaptureLostEventArgs {
309 pub fn new(source: impl Into<Nullable<FerroObject>>, pointer: Rc<dyn IPointer>) -> Self {
311 Self {
312 base: RoutedEventArgs::with_event_and_source(InputElement::pointer_capture_lost_event(), source),
313 pointer,
314 }
315 }
316
317 #[inline]
319 pub fn pointer(&self) -> &Rc<dyn IPointer> {
320 &self.pointer
321 }
322}
323
324#[derive(Clone)]
327pub struct PointerCaptureChangingEventArgs {
328 base: RoutedEventArgs,
329 pointer: Rc<dyn IPointer>,
330 capture_source: CaptureSource,
331 new_value: Option<Ref<InputElement>>,
332}
333
334ferro_routed_event_args!(PointerCaptureChangingEventArgs: RoutedEventArgs);
335
336impl PointerCaptureChangingEventArgs {
337 pub(crate) fn new(
338 source: impl Into<Nullable<FerroObject>>,
339 pointer: Rc<dyn IPointer>,
340 new_value: Option<Ref<InputElement>>,
341 capture_source: CaptureSource,
342 ) -> Self {
343 Self {
344 base: RoutedEventArgs::with_event_and_source(InputElement::pointer_capture_changing_event(), source),
345 pointer,
346 capture_source,
347 new_value,
348 }
349 }
350
351 #[inline]
353 pub fn pointer(&self) -> &Rc<dyn IPointer> {
354 &self.pointer
355 }
356
357 #[inline]
359 pub fn capture_source(&self) -> CaptureSource {
360 self.capture_source
361 }
362
363 #[inline]
365 pub fn new_value(&self) -> Option<&Ref<InputElement>> {
366 self.new_value.as_ref()
367 }
368}