dioxus_html/events/
touch.rs

1use dioxus_core::Event;
2use keyboard_types::Modifiers;
3
4use crate::geometry::*;
5use crate::{InteractionLocation, ModifiersInteraction};
6
7pub type TouchEvent = Event<TouchData>;
8pub struct TouchData {
9    inner: Box<dyn HasTouchData>,
10}
11
12impl<E: HasTouchData> From<E> for TouchData {
13    fn from(e: E) -> Self {
14        Self { inner: Box::new(e) }
15    }
16}
17
18impl std::fmt::Debug for TouchData {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        f.debug_struct("TouchData")
21            .field("modifiers", &self.modifiers())
22            .field("touches", &self.touches())
23            .field("touches_changed", &self.touches_changed())
24            .field("target_touches", &self.target_touches())
25            .finish()
26    }
27}
28
29impl PartialEq for TouchData {
30    fn eq(&self, other: &Self) -> bool {
31        self.modifiers() == other.modifiers()
32    }
33}
34
35impl TouchData {
36    /// Create a new TouchData
37    pub fn new(inner: impl HasTouchData + 'static) -> Self {
38        Self {
39            inner: Box::new(inner),
40        }
41    }
42
43    /// Get the pointers that are currently down
44    pub fn touches(&self) -> Vec<TouchPoint> {
45        self.inner.touches()
46    }
47
48    /// Get the touches that have changed since the last event
49    pub fn touches_changed(&self) -> Vec<TouchPoint> {
50        self.inner.touches_changed()
51    }
52
53    /// Get the touches that started and stayed on the element that triggered this event
54    pub fn target_touches(&self) -> Vec<TouchPoint> {
55        self.inner.target_touches()
56    }
57
58    /// Downcast this event to a concrete event type
59    #[inline(always)]
60    pub fn downcast<T: 'static>(&self) -> Option<&T> {
61        self.inner.as_any().downcast_ref::<T>()
62    }
63}
64
65impl ModifiersInteraction for TouchData {
66    fn modifiers(&self) -> Modifiers {
67        self.inner.modifiers()
68    }
69}
70
71#[cfg(feature = "serialize")]
72/// A serialized version of TouchData
73#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
74pub struct SerializedTouchData {
75    alt_key: bool,
76    ctrl_key: bool,
77    meta_key: bool,
78    shift_key: bool,
79    touches: Vec<SerializedTouchPoint>,
80    changed_touches: Vec<SerializedTouchPoint>,
81    target_touches: Vec<SerializedTouchPoint>,
82}
83
84#[cfg(feature = "serialize")]
85impl From<&TouchData> for SerializedTouchData {
86    fn from(data: &TouchData) -> Self {
87        let modifiers = data.modifiers();
88        Self {
89            alt_key: modifiers.contains(Modifiers::ALT),
90            ctrl_key: modifiers.contains(Modifiers::CONTROL),
91            meta_key: modifiers.contains(Modifiers::META),
92            shift_key: modifiers.contains(Modifiers::SHIFT),
93            touches: data.touches().iter().map(|t| t.into()).collect(),
94            changed_touches: data.touches_changed().iter().map(|t| t.into()).collect(),
95            target_touches: data.target_touches().iter().map(|t| t.into()).collect(),
96        }
97    }
98}
99
100#[cfg(feature = "serialize")]
101impl ModifiersInteraction for SerializedTouchData {
102    fn modifiers(&self) -> Modifiers {
103        let mut modifiers = Modifiers::default();
104        if self.alt_key {
105            modifiers.insert(Modifiers::ALT);
106        }
107        if self.ctrl_key {
108            modifiers.insert(Modifiers::CONTROL);
109        }
110        if self.meta_key {
111            modifiers.insert(Modifiers::META);
112        }
113        if self.shift_key {
114            modifiers.insert(Modifiers::SHIFT);
115        }
116        modifiers
117    }
118}
119
120#[cfg(feature = "serialize")]
121impl HasTouchData for SerializedTouchData {
122    fn touches(&self) -> Vec<TouchPoint> {
123        self.touches.clone().into_iter().map(Into::into).collect()
124    }
125
126    fn touches_changed(&self) -> Vec<TouchPoint> {
127        self.changed_touches
128            .clone()
129            .into_iter()
130            .map(Into::into)
131            .collect()
132    }
133
134    fn target_touches(&self) -> Vec<TouchPoint> {
135        self.target_touches
136            .clone()
137            .into_iter()
138            .map(Into::into)
139            .collect()
140    }
141
142    fn as_any(&self) -> &dyn std::any::Any {
143        self
144    }
145}
146
147#[cfg(feature = "serialize")]
148impl serde::Serialize for TouchData {
149    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
150        SerializedTouchData::from(self).serialize(serializer)
151    }
152}
153
154#[cfg(feature = "serialize")]
155impl<'de> serde::Deserialize<'de> for TouchData {
156    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
157        let data = SerializedTouchData::deserialize(deserializer)?;
158        Ok(Self {
159            inner: Box::new(data),
160        })
161    }
162}
163
164pub trait HasTouchData: ModifiersInteraction + std::any::Any {
165    /// Get the touches that are currently down
166    fn touches(&self) -> Vec<TouchPoint>;
167
168    /// Get the touches that have changed since the last event
169    fn touches_changed(&self) -> Vec<TouchPoint>;
170
171    /// Get the touches that started and stayed on the element that triggered this event
172    fn target_touches(&self) -> Vec<TouchPoint>;
173
174    /// return self as Any
175    fn as_any(&self) -> &dyn std::any::Any;
176}
177
178pub struct TouchPoint {
179    inner: Box<dyn HasTouchPointData>,
180}
181
182impl<E: HasTouchPointData> From<E> for TouchPoint {
183    fn from(e: E) -> Self {
184        Self { inner: Box::new(e) }
185    }
186}
187
188impl TouchPoint {
189    /// Create a new TouchPoint
190    pub fn new(inner: impl HasTouchPointData + 'static) -> Self {
191        Self {
192            inner: Box::new(inner),
193        }
194    }
195
196    /// A unique identifier for this touch point that will be the same for the duration of the touch
197    fn identifier(&self) -> i32 {
198        self.inner.identifier()
199    }
200
201    /// the pressure of the touch
202    fn force(&self) -> f64 {
203        self.inner.force()
204    }
205
206    /// the radius of the touch
207    fn radius(&self) -> ScreenPoint {
208        self.inner.radius()
209    }
210
211    /// the rotation of the touch in degrees between 0 and 90
212    fn rotation(&self) -> f64 {
213        self.inner.rotation()
214    }
215
216    /// Downcast this event to a concrete event type
217    #[inline(always)]
218    pub fn downcast<T: 'static>(&self) -> Option<&T> {
219        self.inner.as_any().downcast_ref::<T>()
220    }
221}
222
223impl std::fmt::Debug for TouchPoint {
224    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225        f.debug_struct("TouchPoint")
226            .field("client_coordinates", &self.client_coordinates())
227            .field("page_coordinates", &self.page_coordinates())
228            .field("screen_coordinates", &self.screen_coordinates())
229            .field("identifier", &self.identifier())
230            .field("force", &self.force())
231            .field("radius", &self.radius())
232            .field("rotation", &self.rotation())
233            .finish()
234    }
235}
236
237impl InteractionLocation for TouchPoint {
238    fn client_coordinates(&self) -> ClientPoint {
239        self.inner.client_coordinates()
240    }
241
242    fn page_coordinates(&self) -> PagePoint {
243        self.inner.page_coordinates()
244    }
245
246    fn screen_coordinates(&self) -> ScreenPoint {
247        self.inner.screen_coordinates()
248    }
249}
250
251/// A trait for touch point data
252pub trait HasTouchPointData: InteractionLocation + std::any::Any {
253    /// A unique identifier for this touch point that will be the same for the duration of the touch
254    fn identifier(&self) -> i32;
255
256    /// the pressure of the touch
257    fn force(&self) -> f64;
258
259    /// the radius of the touch
260    fn radius(&self) -> ScreenPoint;
261
262    /// the rotation of the touch in degrees between 0 and 90
263    fn rotation(&self) -> f64;
264
265    /// return self as Any
266    fn as_any(&self) -> &dyn std::any::Any;
267}
268
269#[cfg(feature = "serialize")]
270/// A serialized version of TouchPoint
271#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
272struct SerializedTouchPoint {
273    identifier: i32,
274    client_x: f64,
275    client_y: f64,
276    page_x: f64,
277    page_y: f64,
278    screen_x: f64,
279    screen_y: f64,
280    force: f64,
281    radius_x: f64,
282    radius_y: f64,
283    rotation_angle: f64,
284}
285
286#[cfg(feature = "serialize")]
287impl From<&TouchPoint> for SerializedTouchPoint {
288    fn from(point: &TouchPoint) -> Self {
289        let client_coordinates = point.client_coordinates();
290
291        let page_coordinates = point.page_coordinates();
292        let screen_coordinates = point.screen_coordinates();
293        Self {
294            identifier: point.identifier(),
295            client_x: client_coordinates.x,
296            client_y: client_coordinates.y,
297            page_x: page_coordinates.x,
298            page_y: page_coordinates.y,
299            screen_x: screen_coordinates.x,
300            screen_y: screen_coordinates.y,
301            force: point.force(),
302            radius_x: point.radius().x,
303            radius_y: point.radius().y,
304            rotation_angle: point.rotation(),
305        }
306    }
307}
308
309#[cfg(feature = "serialize")]
310impl HasTouchPointData for SerializedTouchPoint {
311    /// A unique identifier for this touch point that will be the same for the duration of the touch
312    fn identifier(&self) -> i32 {
313        self.identifier
314    }
315
316    /// the pressure of the touch
317    fn force(&self) -> f64 {
318        self.force
319    }
320
321    /// the radius of the touch
322    fn radius(&self) -> ScreenPoint {
323        ScreenPoint::new(self.radius_x, self.radius_y)
324    }
325
326    /// the rotation of the touch in degrees between 0 and 90
327    fn rotation(&self) -> f64 {
328        self.rotation_angle
329    }
330
331    /// return self as Any
332    fn as_any(&self) -> &dyn std::any::Any {
333        self
334    }
335}
336
337#[cfg(feature = "serialize")]
338impl InteractionLocation for SerializedTouchPoint {
339    /// Gets the coordinates of the event relative to the browser viewport.
340    fn client_coordinates(&self) -> ClientPoint {
341        ClientPoint::new(self.client_x, self.client_y)
342    }
343
344    /// Gets the coordinates of the event relative to the screen.
345    fn screen_coordinates(&self) -> ScreenPoint {
346        ScreenPoint::new(self.screen_x, self.screen_y)
347    }
348
349    /// Gets the coordinates of the event relative to the page.
350    fn page_coordinates(&self) -> PagePoint {
351        PagePoint::new(self.page_x, self.page_y)
352    }
353}
354
355impl_event! {
356    TouchData;
357    /// touchstart
358    ontouchstart
359
360    /// touchmove
361    ontouchmove
362
363    /// touchend
364    ontouchend
365
366    /// touchcancel
367    ontouchcancel
368}