dioxus_gestures/state/gestures/
hover.rs

1use std::{cell::RefCell, rc::Rc};
2
3use dioxus::{html::PointerData, prelude::Event};
4
5use crate::state::{
6    events::PointerEventReceiver,
7    gestures::pointer::{IncrementalOffsetPointer, InitialPointer, OffsetPointer, PointerId},
8};
9
10#[derive(Clone)]
11pub struct HoverGestureState {
12    hover: Hover,
13    pointers: Vec<HoverState>,
14}
15
16#[derive(Clone)]
17pub struct HoverState {
18    pointer: HoverPointerState,
19}
20
21#[derive(Clone)]
22pub struct HoverPointerState {
23    id: PointerId,
24    initial_state: Rc<PointerData>,
25    previous_state: Rc<PointerData>,
26}
27
28/// ```rust
29/// use dioxus::prelude::*;
30/// use dioxus_gestures::{
31///     state::gestures::hover::Hover,
32///     use_gestures::{use_gestures, Gestures},
33/// };
34///
35/// const UNHOVERED_TEXT: &str = "Hover over me!";
36/// const HOVERED_TEXT: &str = "Hovering ...";
37///
38/// #[component]
39/// pub fn HoverExample() -> Element {
40///     let mut text = use_signal(|| UNHOVERED_TEXT);
41///
42///     let gestures = use_gestures(
43///         Gestures::default().hover(
44///             Hover::default()
45///                 .on_start(move |_| text.set(HOVERED_TEXT))
46///                 .on_end(move |_| text.set(UNHOVERED_TEXT))
47///                 .on_cancel(move |_| text.set(UNHOVERED_TEXT)),
48///         ),
49///     );
50///
51///     rsx! {
52///         div {
53///         class: "target hover",
54///         style: format!("
55///             user-select: none;
56///             touch-action: none;
57///             position: relative;
58///         "),
59///         ..gestures.event_handlers(),
60///             "{text}"
61///         }
62///     }
63/// }
64/// ```
65
66#[derive(Default, Clone)]
67pub struct Hover {
68    pub on_start: Option<Rc<RefCell<dyn FnMut(())>>>,
69    pub on_end: Option<Rc<RefCell<dyn FnMut(())>>>,
70    pub on_cancel: Option<Rc<RefCell<dyn FnMut(())>>>,
71    pub on_pointer_appear: Option<Rc<RefCell<dyn FnMut(HoverPointerAppearData)>>>,
72    pub on_pointer_update: Option<Rc<RefCell<dyn FnMut(HoverPointerUpdateData)>>>,
73    pub on_pointer_disappear: Option<Rc<RefCell<dyn FnMut(HoverPointerDisappearData)>>>,
74    pub on_pointer_cancel: Option<Rc<RefCell<dyn FnMut(HoverPointerCancelData)>>>,
75}
76
77impl Hover {
78    pub fn on_start(mut self, handler: impl FnMut(()) + 'static) -> Self {
79        self.on_start = Some(Rc::new(RefCell::new(handler)));
80        self
81    }
82
83    pub fn on_end(mut self, handler: impl FnMut(()) + 'static) -> Self {
84        self.on_end = Some(Rc::new(RefCell::new(handler)));
85        self
86    }
87
88    pub fn on_cancel(mut self, handler: impl FnMut(()) + 'static) -> Self {
89        self.on_cancel = Some(Rc::new(RefCell::new(handler)));
90        self
91    }
92
93    pub fn on_pointer_appear(
94        mut self,
95        handler: impl FnMut(HoverPointerAppearData) + 'static,
96    ) -> Self {
97        self.on_pointer_appear = Some(Rc::new(RefCell::new(handler)));
98        self
99    }
100
101    pub fn on_pointer_update(
102        mut self,
103        handler: impl FnMut(HoverPointerUpdateData) + 'static,
104    ) -> Self {
105        self.on_pointer_update = Some(Rc::new(RefCell::new(handler)));
106        self
107    }
108
109    pub fn on_pointer_disappear(
110        mut self,
111        handler: impl FnMut(HoverPointerDisappearData) + 'static,
112    ) -> Self {
113        self.on_pointer_disappear = Some(Rc::new(RefCell::new(handler)));
114        self
115    }
116
117    pub fn on_pointer_cancel(
118        mut self,
119        handler: impl FnMut(HoverPointerCancelData) + 'static,
120    ) -> Self {
121        self.on_pointer_cancel = Some(Rc::new(RefCell::new(handler)));
122        self
123    }
124}
125
126pub struct HoverPointerAppearData {
127    pub pointer: InitialPointer,
128}
129
130pub struct HoverPointerUpdateData {
131    pub pointer: IncrementalOffsetPointer,
132}
133
134pub struct HoverPointerDisappearData {
135    pub pointer: OffsetPointer,
136}
137
138pub struct HoverPointerCancelData {
139    pub pointer: OffsetPointer,
140}
141
142impl HoverGestureState {
143    pub fn new(hover: Hover) -> Self {
144        Self {
145            hover,
146            pointers: Vec::new(),
147        }
148    }
149
150    fn add_hover_event(&mut self, pointer_data: Rc<PointerData>) {
151        let is_first = self.pointers.is_empty();
152        self.pointers.push(HoverState {
153            pointer: HoverPointerState {
154                id: PointerId::from(pointer_data.pointer_id()),
155                initial_state: Rc::clone(&pointer_data),
156                previous_state: Rc::clone(&pointer_data),
157            },
158        });
159
160        if is_first {
161            if let Some(handler) = &self.hover.on_start {
162                handler.borrow_mut()(());
163            }
164        }
165
166        if let Some(handler) = &self.hover.on_pointer_appear {
167            handler.borrow_mut()(HoverPointerAppearData {
168                pointer: InitialPointer { data: pointer_data },
169            });
170        }
171    }
172
173    fn update_known_hover_event(&mut self, index: usize, pointer_data: Rc<PointerData>) {
174        let initial_data = Rc::clone(&self.pointers[index].pointer.initial_state);
175        let preceding_data = Rc::clone(&self.pointers[index].pointer.previous_state);
176        self.pointers[index].pointer.previous_state = Rc::clone(&pointer_data);
177        if let Some(handler) = &self.hover.on_pointer_update {
178            handler.borrow_mut()(HoverPointerUpdateData {
179                pointer: IncrementalOffsetPointer {
180                    initial_data,
181                    preceding_data,
182                    current_data: pointer_data,
183                },
184            });
185        }
186    }
187
188    fn remove_known_hover_event(&mut self, index: usize, pointer_data: Rc<PointerData>) {
189        let hover = self.pointers.remove(index);
190        let initial_data = hover.pointer.initial_state;
191        if let Some(handler) = &self.hover.on_pointer_disappear {
192            handler.borrow_mut()(HoverPointerDisappearData {
193                pointer: OffsetPointer {
194                    initial_data,
195                    final_data: pointer_data,
196                },
197            });
198        }
199
200        if self.pointers.is_empty() {
201            if let Some(handler) = &self.hover.on_end {
202                handler.borrow_mut()(());
203            }
204        }
205    }
206
207    fn cancel_known_hover_event(&mut self, index: usize, pointer_data: Rc<PointerData>) {
208        let hover = self.pointers.remove(index);
209        let initial_data = hover.pointer.initial_state;
210        if let Some(handler) = &self.hover.on_pointer_cancel {
211            handler.borrow_mut()(HoverPointerCancelData {
212                pointer: OffsetPointer {
213                    initial_data,
214                    final_data: pointer_data,
215                },
216            });
217        }
218
219        if self.pointers.is_empty() {
220            if let Some(handler) = &self.hover.on_cancel {
221                handler.borrow_mut()(())
222            }
223        }
224    }
225
226    fn add_or_update(&mut self, event: &Event<PointerData>) {
227        let pointer_data = event.data();
228        let pointer_id = pointer_data.pointer_id();
229        let associated_hover_event = self
230            .pointers
231            .iter()
232            .position(|p| p.pointer.id.is_equal_i32(pointer_id));
233        match associated_hover_event {
234            Some(position) => {
235                self.update_known_hover_event(position, pointer_data);
236            }
237            None => {
238                self.add_hover_event(pointer_data);
239            }
240        };
241    }
242
243    fn remove(&mut self, event: &Event<PointerData>) {
244        let pointer_data = event.data();
245        let pointer_id = pointer_data.pointer_id();
246        let associated_hover_event = self
247            .pointers
248            .iter()
249            .position(|p| p.pointer.id.is_equal_i32(pointer_id));
250        match associated_hover_event {
251            Some(position) => {
252                self.remove_known_hover_event(position, pointer_data);
253            }
254            None => {}
255        };
256    }
257
258    fn cancel(&mut self, event: &Event<PointerData>) {
259        let pointer_data = event.data();
260        let pointer_id = pointer_data.pointer_id();
261        let associated_hover_event = self
262            .pointers
263            .iter()
264            .position(|p| p.pointer.id.is_equal_i32(pointer_id));
265        match associated_hover_event {
266            Some(position) => {
267                self.cancel_known_hover_event(position, pointer_data);
268            }
269            None => {}
270        };
271    }
272}
273
274impl PointerEventReceiver<&Event<PointerData>> for HoverGestureState {
275    fn pointer_over(&mut self, _: &Event<PointerData>) {}
276
277    fn pointer_enter(&mut self, event: &Event<PointerData>) {
278        self.add_or_update(event);
279    }
280
281    fn pointer_down(&mut self, event: &Event<PointerData>) {
282        self.add_or_update(event);
283    }
284
285    fn pointer_move(&mut self, event: &Event<PointerData>) {
286        self.add_or_update(event);
287    }
288
289    fn pointer_up(&mut self, event: &Event<PointerData>) {
290        self.add_or_update(event);
291    }
292
293    fn pointer_cancel(&mut self, event: &Event<PointerData>) {
294        self.cancel(event);
295    }
296
297    fn pointer_out(&mut self, _: &Event<PointerData>) {}
298
299    fn pointer_leave(&mut self, event: &Event<PointerData>) {
300        self.remove(event);
301    }
302}