Skip to main content

ferroui_base/input/gesture_recognizers/
gesture_recognizer_collection.rs

1use super::GestureRecognizer;
2use crate::input::{
3    IPointer, InputElement, Pointer, PointerEventArgs, PointerPressedEventArgs, PointerReleasedEventArgs,
4};
5use crate::{FerroObject, Ref, StyledElement, WeakRef};
6use std::cell::RefCell;
7use std::rc::Rc;
8
9/// The gesture recognizers attached to an input element.
10///
11/// The value is a shared handle: clones refer to the same collection, and
12/// handles compare by identity.
13#[derive(Clone)]
14pub struct GestureRecognizerCollection(Rc<GestureRecognizerCollectionData>);
15
16struct GestureRecognizerCollectionData {
17    input_element: WeakRef<InputElement>,
18    recognizers: RefCell<Vec<Ref<GestureRecognizer>>>,
19}
20
21impl PartialEq for GestureRecognizerCollection {
22    fn eq(&self, other: &Self) -> bool {
23        Rc::ptr_eq(&self.0, &other.0)
24    }
25}
26
27impl std::fmt::Debug for GestureRecognizerCollection {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        write!(f, "GestureRecognizerCollection({})", self.count())
30    }
31}
32
33impl GestureRecognizerCollection {
34    /// Creates the collection of an input element.
35    pub fn new(input_element: &Ref<InputElement>) -> Self {
36        Self(Rc::new(GestureRecognizerCollectionData {
37            input_element: input_element.downgrade(),
38            recognizers: RefCell::new(Vec::new()),
39        }))
40    }
41
42    fn snapshot(&self) -> Vec<Ref<GestureRecognizer>> {
43        self.0.recognizers.borrow().clone()
44    }
45
46    /// Attaches a recognizer to the element.
47    pub fn add(&self, recognizer: impl crate::IntoRef<GestureRecognizer>) {
48        let recognizer = recognizer.into_ref();
49        self.0.recognizers.borrow_mut().push(recognizer.clone());
50
51        let Some(input_element) = self.0.input_element.upgrade() else { return };
52        recognizer.set_target(Some(&input_element));
53
54        // Make the recognizer a logical child of the element so that
55        // bindings and inherited values work, and keep its templated parent
56        // in sync with the element's.
57        recognizer.set_parent(input_element.clone().upcast::<StyledElement>());
58        recognizer.set_templated_parent(input_element.templated_parent());
59
60        let weak = recognizer.downgrade();
61        input_element.property_changed(move |e| {
62            if e.property() == StyledElement::templated_parent_property().as_property() {
63                if let Some(recognizer) = weak.upgrade() {
64                    recognizer.set_templated_parent(e.get_new_value::<Option<Ref<FerroObject>>>());
65                }
66            }
67        });
68    }
69
70    /// Detaches a recognizer from the element. Returns whether it was
71    /// attached.
72    pub fn remove(&self, recognizer: &GestureRecognizer) -> bool {
73        let removed = {
74            let mut recognizers = self.0.recognizers.borrow_mut();
75            recognizers
76                .iter()
77                .position(|r| std::ptr::eq::<GestureRecognizer>(&**r, recognizer))
78                .map(|index| recognizers.remove(index))
79        };
80
81        match removed {
82            Some(removed) => {
83                removed.set_target(None);
84                removed.set_parent(None);
85                true
86            }
87            None => false,
88        }
89    }
90
91    /// The attached recognizers.
92    pub fn to_vec(&self) -> Vec<Ref<GestureRecognizer>> {
93        self.snapshot()
94    }
95
96    /// The number of attached recognizers.
97    pub fn count(&self) -> usize {
98        self.0.recognizers.borrow().len()
99    }
100
101    fn captured_recognizer(pointer: &Rc<dyn IPointer>) -> Option<Ref<GestureRecognizer>> {
102        pointer.as_any().downcast_ref::<Pointer>().and_then(Pointer::captured_gesture_recognizer)
103    }
104
105    pub(crate) fn handle_pointer_pressed(&self, e: &PointerPressedEventArgs) -> bool {
106        if self.0.recognizers.borrow().is_empty() {
107            return false;
108        }
109
110        for r in self.snapshot() {
111            r.pointer_pressed_internal(e);
112        }
113
114        e.handled()
115    }
116
117    pub(crate) fn handle_capture_lost(&self, pointer: &Rc<dyn IPointer>) {
118        if self.0.recognizers.borrow().is_empty() || pointer.as_any().downcast_ref::<Pointer>().is_none() {
119            return;
120        }
121
122        for r in self.snapshot() {
123            if Self::captured_recognizer(pointer).as_ref() == Some(&r) {
124                continue;
125            }
126
127            r.pointer_capture_lost_internal(pointer);
128        }
129    }
130
131    pub(crate) fn handle_pointer_released(&self, e: &PointerReleasedEventArgs) -> bool {
132        if self.0.recognizers.borrow().is_empty() {
133            return false;
134        }
135
136        for r in self.snapshot() {
137            if Self::captured_recognizer(e.pointer()).is_some() {
138                break;
139            }
140
141            r.pointer_released_internal(e);
142        }
143
144        e.handled()
145    }
146
147    pub(crate) fn handle_pointer_moved(&self, e: &PointerEventArgs) -> bool {
148        if self.0.recognizers.borrow().is_empty() {
149            return false;
150        }
151
152        for r in self.snapshot() {
153            if Self::captured_recognizer(e.pointer()).is_some() {
154                break;
155            }
156
157            r.pointer_moved_internal(e);
158        }
159
160        e.handled()
161    }
162}