dioxus_html/events/
drag.rs

1use crate::input_data::{MouseButton, MouseButtonSet};
2use crate::*;
3use crate::{
4    data_transfer::DataTransfer,
5    geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint},
6};
7
8use dioxus_core::Event;
9use keyboard_types::Modifiers;
10
11use crate::HasMouseData;
12
13pub type DragEvent = Event<DragData>;
14
15/// The DragEvent interface is a DOM event that represents a drag and drop interaction. The user initiates a drag by
16/// placing a pointer device (such as a mouse) on the touch surface and then dragging the pointer to a new location
17/// (such as another DOM element). Applications are free to interpret a drag and drop interaction in an
18/// application-specific way.
19pub struct DragData {
20    inner: Box<dyn HasDragData>,
21}
22
23impl<E: HasDragData + 'static> From<E> for DragData {
24    fn from(e: E) -> Self {
25        Self { inner: Box::new(e) }
26    }
27}
28
29impl std::fmt::Debug for DragData {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        f.debug_struct("DragData")
32            .field("coordinates", &self.coordinates())
33            .field("modifiers", &self.modifiers())
34            .field("held_buttons", &self.held_buttons())
35            .field("trigger_button", &self.trigger_button())
36            .finish()
37    }
38}
39
40impl PartialEq for DragData {
41    fn eq(&self, other: &Self) -> bool {
42        self.coordinates() == other.coordinates()
43            && self.modifiers() == other.modifiers()
44            && self.held_buttons() == other.held_buttons()
45            && self.trigger_button() == other.trigger_button()
46    }
47}
48
49impl DragData {
50    /// Create a new DragData
51    pub fn new(inner: impl HasDragData + 'static) -> Self {
52        Self {
53            inner: Box::new(inner),
54        }
55    }
56
57    /// The DataTransfer object is used to hold the data that is being dragged during a drag and drop operation.
58    pub fn data_transfer(&self) -> DataTransfer {
59        self.inner.data_transfer()
60    }
61
62    /// Downcast this event data to a specific type
63    #[inline(always)]
64    pub fn downcast<T: 'static>(&self) -> Option<&T> {
65        HasDragData::as_any(&*self.inner).downcast_ref::<T>()
66    }
67}
68
69impl crate::HasFileData for DragData {
70    fn files(&self) -> Vec<FileData> {
71        self.inner.files()
72    }
73}
74
75impl InteractionLocation for DragData {
76    fn client_coordinates(&self) -> ClientPoint {
77        self.inner.client_coordinates()
78    }
79
80    fn page_coordinates(&self) -> PagePoint {
81        self.inner.page_coordinates()
82    }
83
84    fn screen_coordinates(&self) -> ScreenPoint {
85        self.inner.screen_coordinates()
86    }
87}
88
89impl InteractionElementOffset for DragData {
90    fn element_coordinates(&self) -> ElementPoint {
91        self.inner.element_coordinates()
92    }
93
94    fn coordinates(&self) -> Coordinates {
95        self.inner.coordinates()
96    }
97}
98
99impl ModifiersInteraction for DragData {
100    fn modifiers(&self) -> Modifiers {
101        self.inner.modifiers()
102    }
103}
104
105impl PointerInteraction for DragData {
106    fn held_buttons(&self) -> MouseButtonSet {
107        self.inner.held_buttons()
108    }
109
110    // todo the following is kind of bad; should we just return None when the trigger_button is unreliable (and frankly irrelevant)? i guess we would need the event_type here
111    fn trigger_button(&self) -> Option<MouseButton> {
112        self.inner.trigger_button()
113    }
114}
115
116#[cfg(feature = "serialize")]
117pub use ser::*;
118
119#[cfg(feature = "serialize")]
120mod ser {
121    use super::*;
122
123    /// A serialized version of DragData
124    #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
125    pub struct SerializedDragData {
126        pub mouse: crate::point_interaction::SerializedPointInteraction,
127
128        pub data_transfer: crate::data_transfer::SerializedDataTransfer,
129    }
130
131    impl SerializedDragData {
132        fn new(drag: &DragData) -> Self {
133            Self {
134                mouse: crate::point_interaction::SerializedPointInteraction::from(drag),
135                data_transfer: crate::data_transfer::SerializedDataTransfer::from(drag),
136            }
137        }
138    }
139
140    impl HasDataTransferData for SerializedDragData {
141        fn data_transfer(&self) -> crate::data_transfer::DataTransfer {
142            crate::data_transfer::DataTransfer::new(self.data_transfer.clone())
143        }
144    }
145
146    impl HasDragData for SerializedDragData {
147        fn as_any(&self) -> &dyn std::any::Any {
148            self
149        }
150    }
151
152    impl crate::file_data::HasFileData for SerializedDragData {
153        fn files(&self) -> Vec<FileData> {
154            self.data_transfer
155                .files
156                .iter()
157                .map(|f| FileData::new(f.clone()))
158                .collect()
159        }
160    }
161
162    impl HasMouseData for SerializedDragData {
163        fn as_any(&self) -> &dyn std::any::Any {
164            self
165        }
166    }
167
168    impl InteractionLocation for SerializedDragData {
169        fn client_coordinates(&self) -> ClientPoint {
170            self.mouse.client_coordinates()
171        }
172
173        fn page_coordinates(&self) -> PagePoint {
174            self.mouse.page_coordinates()
175        }
176
177        fn screen_coordinates(&self) -> ScreenPoint {
178            self.mouse.screen_coordinates()
179        }
180    }
181
182    impl InteractionElementOffset for SerializedDragData {
183        fn element_coordinates(&self) -> ElementPoint {
184            self.mouse.element_coordinates()
185        }
186
187        fn coordinates(&self) -> Coordinates {
188            self.mouse.coordinates()
189        }
190    }
191
192    impl ModifiersInteraction for SerializedDragData {
193        fn modifiers(&self) -> Modifiers {
194            self.mouse.modifiers()
195        }
196    }
197
198    impl PointerInteraction for SerializedDragData {
199        fn held_buttons(&self) -> MouseButtonSet {
200            self.mouse.held_buttons()
201        }
202
203        fn trigger_button(&self) -> Option<MouseButton> {
204            self.mouse.trigger_button()
205        }
206    }
207
208    impl serde::Serialize for DragData {
209        fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
210            SerializedDragData::new(self).serialize(serializer)
211        }
212    }
213
214    impl<'de> serde::Deserialize<'de> for DragData {
215        fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
216            let data = SerializedDragData::deserialize(deserializer)?;
217            Ok(Self {
218                inner: Box::new(data),
219            })
220        }
221    }
222}
223
224/// A trait for any object that has the data for a drag event
225pub trait HasDragData: HasMouseData + crate::HasFileData + crate::HasDataTransferData {
226    /// return self as Any
227    fn as_any(&self) -> &dyn std::any::Any;
228}
229
230impl_event! {
231    DragData;
232
233    /// ondrag
234    ondrag
235
236    /// ondragend
237    ondragend
238
239    /// ondragenter
240    ondragenter
241
242    /// ondragexit
243    ondragexit
244
245    /// ondragleave
246    ondragleave
247
248    /// ondragover
249    ondragover
250
251    /// ondragstart
252    ondragstart
253
254    /// ondrop
255    ondrop
256}