Skip to main content

ferroui_base/input/
input_element_gestures.rs

1//! The gesture-related part of [`InputElement`]: gesture events and the
2//! attached properties that configure gesture recognition.
3
4use super::input_element::routed_event_accessor;
5use super::{
6    ContextRequestedEventArgs, HoldingRoutedEventArgs, HoldingState, InputElement, PinchEndedEventArgs,
7    PinchEventArgs, PointerDeltaEventArgs, PullGestureEndedEventArgs, PullGestureEventArgs,
8    ScrollGestureEndedEventArgs, ScrollGestureEventArgs, ScrollGestureInertiaStartingEventArgs,
9    SwipeGestureEndedEventArgs, SwipeGestureEventArgs, TappedEventArgs,
10};
11use crate::interactivity::{
12    Interactive, RoutedEvent, RoutedEventArgs, RoutedEventHandlerToken, RoutingStrategies,
13};
14use crate::{ferro_property, ferro_routed_event, AttachedProperty, FerroProperty, StyledElement};
15
16crate::ferro_properties! { impl InputElement, fn register_gesture_properties {
17    ferro_property!(
18        /// Defines the `IsHoldingEnabled` attached property.
19        pub fn is_holding_enabled_property() -> AttachedProperty<bool> {
20            FerroProperty::register_attached::<InputElement, StyledElement, _>("IsHoldingEnabled", true)
21        }
22    );
23
24    ferro_property!(
25        /// Defines the `IsHoldWithMouseEnabled` attached property.
26        pub fn is_hold_with_mouse_enabled_property() -> AttachedProperty<bool> {
27            FerroProperty::register_attached::<InputElement, StyledElement, _>("IsHoldWithMouseEnabled", false)
28        }
29    );
30} }
31
32impl InputElement {
33    ferro_routed_event!(
34        /// Defines the `Pinch` event.
35        pub fn pinch_event() -> RoutedEvent<PinchEventArgs> {
36            RoutedEvent::register::<InputElement, _>("Pinch", RoutingStrategies::BUBBLE)
37        }
38    );
39
40    ferro_routed_event!(
41        /// Defines the `PinchEnded` event.
42        pub fn pinch_ended_event() -> RoutedEvent<PinchEndedEventArgs> {
43            RoutedEvent::register::<InputElement, _>("PinchEnded", RoutingStrategies::BUBBLE)
44        }
45    );
46
47    ferro_routed_event!(
48        /// Defines the `PullGesture` event.
49        pub fn pull_gesture_event() -> RoutedEvent<PullGestureEventArgs> {
50            RoutedEvent::register::<InputElement, _>("PullGesture", RoutingStrategies::BUBBLE)
51        }
52    );
53
54    ferro_routed_event!(
55        /// Defines the `PullGestureEnded` event.
56        pub fn pull_gesture_ended_event() -> RoutedEvent<PullGestureEndedEventArgs> {
57            RoutedEvent::register::<InputElement, _>("PullGestureEnded", RoutingStrategies::BUBBLE)
58        }
59    );
60
61    ferro_routed_event!(
62        /// Defines the `SwipeGesture` event.
63        pub fn swipe_gesture_event() -> RoutedEvent<SwipeGestureEventArgs> {
64            RoutedEvent::register::<InputElement, _>("SwipeGesture", RoutingStrategies::BUBBLE)
65        }
66    );
67
68    ferro_routed_event!(
69        /// Defines the `SwipeGestureEnded` event.
70        pub fn swipe_gesture_ended_event() -> RoutedEvent<SwipeGestureEndedEventArgs> {
71            RoutedEvent::register::<InputElement, _>("SwipeGestureEnded", RoutingStrategies::BUBBLE)
72        }
73    );
74
75    ferro_routed_event!(
76        /// Defines the `ScrollGesture` event.
77        pub fn scroll_gesture_event() -> RoutedEvent<ScrollGestureEventArgs> {
78            RoutedEvent::register::<InputElement, _>("ScrollGesture", RoutingStrategies::BUBBLE)
79        }
80    );
81
82    ferro_routed_event!(
83        /// Defines the `ScrollGestureInertiaStarting` event.
84        pub fn scroll_gesture_inertia_starting_event() -> RoutedEvent<ScrollGestureInertiaStartingEventArgs> {
85            RoutedEvent::register::<InputElement, _>("ScrollGestureInertiaStarting", RoutingStrategies::BUBBLE)
86        }
87    );
88
89    ferro_routed_event!(
90        /// Defines the `ScrollGestureEnded` event.
91        pub fn scroll_gesture_ended_event() -> RoutedEvent<ScrollGestureEndedEventArgs> {
92            RoutedEvent::register::<InputElement, _>("ScrollGestureEnded", RoutingStrategies::BUBBLE)
93        }
94    );
95
96    ferro_routed_event!(
97        /// Defines the `PointerTouchPadGestureMagnify` event.
98        pub fn pointer_touch_pad_gesture_magnify_event() -> RoutedEvent<PointerDeltaEventArgs> {
99            RoutedEvent::register::<InputElement, _>("PointerTouchPadGestureMagnify", RoutingStrategies::BUBBLE)
100        }
101    );
102
103    ferro_routed_event!(
104        /// Defines the `PointerTouchPadGestureRotate` event.
105        pub fn pointer_touch_pad_gesture_rotate_event() -> RoutedEvent<PointerDeltaEventArgs> {
106            RoutedEvent::register::<InputElement, _>("PointerTouchPadGestureRotate", RoutingStrategies::BUBBLE)
107        }
108    );
109
110    ferro_routed_event!(
111        /// Defines the `PointerTouchPadGestureSwipe` event.
112        pub fn pointer_touch_pad_gesture_swipe_event() -> RoutedEvent<PointerDeltaEventArgs> {
113            RoutedEvent::register::<InputElement, _>("PointerTouchPadGestureSwipe", RoutingStrategies::BUBBLE)
114        }
115    );
116
117    ferro_routed_event!(
118        /// Defines the `Tapped` event.
119        pub fn tapped_event() -> RoutedEvent<TappedEventArgs> {
120            RoutedEvent::register::<InputElement, _>("Tapped", RoutingStrategies::BUBBLE)
121        }
122    );
123
124    ferro_routed_event!(
125        /// Defines the `RightTapped` event.
126        pub fn right_tapped_event() -> RoutedEvent<TappedEventArgs> {
127            RoutedEvent::register::<InputElement, _>("RightTapped", RoutingStrategies::BUBBLE)
128        }
129    );
130
131    ferro_routed_event!(
132        /// Defines the `Holding` event.
133        pub fn holding_event() -> RoutedEvent<HoldingRoutedEventArgs> {
134            RoutedEvent::register::<InputElement, _>("Holding", RoutingStrategies::BUBBLE)
135        }
136    );
137
138    ferro_routed_event!(
139        /// Defines the `DoubleTapped` event.
140        pub fn double_tapped_event() -> RoutedEvent<TappedEventArgs> {
141            RoutedEvent::register::<InputElement, _>("DoubleTapped", RoutingStrategies::BUBBLE)
142        }
143    );
144
145    /// Registers the gesture events that have no class handler.
146    pub(super) fn register_gesture_events() {
147        Self::pinch_event();
148        Self::pinch_ended_event();
149        Self::pull_gesture_event();
150        Self::pull_gesture_ended_event();
151        Self::swipe_gesture_event();
152        Self::swipe_gesture_ended_event();
153        Self::scroll_gesture_event();
154        Self::scroll_gesture_inertia_starting_event();
155        Self::scroll_gesture_ended_event();
156        Self::pointer_touch_pad_gesture_magnify_event();
157        Self::pointer_touch_pad_gesture_rotate_event();
158        Self::pointer_touch_pad_gesture_swipe_event();
159    }
160
161    /// Gets whether the holding gesture is enabled on an element.
162    pub fn get_is_holding_enabled(element: &StyledElement) -> bool {
163        element.get_value(Self::is_holding_enabled_property())
164    }
165
166    /// Sets whether the holding gesture is enabled on an element.
167    pub fn set_is_holding_enabled(element: &StyledElement, value: bool) {
168        element.set_value(Self::is_holding_enabled_property(), value)
169    }
170
171    /// Gets whether the holding gesture can be performed with the mouse on
172    /// an element.
173    pub fn get_is_hold_with_mouse_enabled(element: &StyledElement) -> bool {
174        element.get_value(Self::is_hold_with_mouse_enabled_property())
175    }
176
177    /// Sets whether the holding gesture can be performed with the mouse on
178    /// an element.
179    pub fn set_is_hold_with_mouse_enabled(element: &StyledElement, value: bool) {
180        element.set_value(Self::is_hold_with_mouse_enabled_property(), value)
181    }
182
183    routed_event_accessor!(
184        /// Occurs when the user moves two contact points closer together.
185        pinch, pinch_event, PinchEventArgs
186    );
187
188    routed_event_accessor!(
189        /// Occurs when the user releases both contact points used in a
190        /// pinch gesture.
191        pinch_ended, pinch_ended_event, PinchEndedEventArgs
192    );
193
194    routed_event_accessor!(
195        /// Occurs when the user drags from the edge of a control.
196        pull_gesture, pull_gesture_event, PullGestureEventArgs
197    );
198
199    routed_event_accessor!(
200        /// Occurs when the user releases the pointer after a pull gesture.
201        pull_gesture_ended, pull_gesture_ended_event, PullGestureEndedEventArgs
202    );
203
204    routed_event_accessor!(
205        /// Occurs when the user continuously moves the pointer in the same
206        /// direction within the control's boundaries.
207        scroll_gesture, scroll_gesture_event, ScrollGestureEventArgs
208    );
209
210    routed_event_accessor!(
211        /// Occurs within the control's boundaries when a scroll gesture's
212        /// inertia begins.
213        scroll_gesture_inertia_starting, scroll_gesture_inertia_starting_event, ScrollGestureInertiaStartingEventArgs
214    );
215
216    routed_event_accessor!(
217        /// Occurs when a scroll gesture ends.
218        scroll_gesture_ended, scroll_gesture_ended_event, ScrollGestureEndedEventArgs
219    );
220
221    routed_event_accessor!(
222        /// Occurs when the user moves two contact points away from each
223        /// other on a touchpad.
224        pointer_touch_pad_gesture_magnify, pointer_touch_pad_gesture_magnify_event, PointerDeltaEventArgs
225    );
226
227    routed_event_accessor!(
228        /// Occurs when the user places two contact points and moves them in
229        /// a circular motion on a touchpad.
230        pointer_touch_pad_gesture_rotate, pointer_touch_pad_gesture_rotate_event, PointerDeltaEventArgs
231    );
232
233    routed_event_accessor!(
234        /// Occurs when the user rapidly drags the pointer in a single
235        /// direction across the control.
236        swipe_gesture, swipe_gesture_event, SwipeGestureEventArgs
237    );
238
239    routed_event_accessor!(
240        /// Occurs when a swipe gesture ends on the control.
241        swipe_gesture_ended, swipe_gesture_ended_event, SwipeGestureEndedEventArgs
242    );
243
244    routed_event_accessor!(
245        /// Occurs when the user rapidly drags the pointer in a single
246        /// direction on a touchpad.
247        pointer_touch_pad_gesture_swipe, pointer_touch_pad_gesture_swipe_event, PointerDeltaEventArgs
248    );
249
250    routed_event_accessor!(
251        /// Occurs when the user briefly contacts and releases a single
252        /// point on the control.
253        tapped, tapped_event, TappedEventArgs
254    );
255
256    routed_event_accessor!(
257        /// Occurs when the user briefly contacts and releases a single
258        /// point on the control using the secondary action.
259        right_tapped, right_tapped_event, TappedEventArgs
260    );
261
262    routed_event_accessor!(
263        /// Occurs when the user makes a single contact, then maintains
264        /// contact beyond a given time threshold without releasing or
265        /// making another contact.
266        holding, holding_event, HoldingRoutedEventArgs
267    );
268
269    routed_event_accessor!(
270        /// Occurs when the user briefly contacts and releases twice on a
271        /// single point, without significant movement between contacts.
272        double_tapped, double_tapped_event, TappedEventArgs
273    );
274
275    pub(super) fn on_preview_holding(sender: &Interactive, e: &HoldingRoutedEventArgs) {
276        let Some(input_element) = sender.downcast_ref::<InputElement>() else { return };
277
278        input_element.raise_event(e);
279
280        if !e.handled() && e.holding_state() == HoldingState::Started {
281            let context_event = ContextRequestedEventArgs::from_holding(e);
282            input_element.raise_event(&context_event);
283            e.set_handled(context_event.handled());
284
285            if context_event.handled() {
286                input_element.is_context_menu_on_holding.set(true);
287            }
288        } else if e.holding_state() == HoldingState::Canceled && input_element.is_context_menu_on_holding.get() {
289            let args = RoutedEventArgs::with_event_and_source(
290                InputElement::context_canceled_event(),
291                input_element.to_ref(),
292            );
293            input_element.raise_event(&args);
294            input_element.is_context_menu_on_holding.set(false);
295        } else if e.holding_state() == HoldingState::Completed {
296            input_element.is_context_menu_on_holding.set(false);
297        }
298    }
299}