drag.rs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint};
  2. use crate::input_data::{MouseButton, MouseButtonSet};
  3. use crate::prelude::PointInteraction;
  4. use dioxus_core::Event;
  5. use keyboard_types::Modifiers;
  6. use crate::HasMouseData;
  7. pub type DragEvent = Event<DragData>;
  8. /// The DragEvent interface is a DOM event that represents a drag and drop interaction. The user initiates a drag by
  9. /// placing a pointer device (such as a mouse) on the touch surface and then dragging the pointer to a new location
  10. /// (such as another DOM element). Applications are free to interpret a drag and drop interaction in an
  11. /// application-specific way.
  12. pub struct DragData {
  13. inner: Box<dyn HasDragData>,
  14. }
  15. impl<E: HasDragData> From<E> for DragData {
  16. fn from(e: E) -> Self {
  17. Self { inner: Box::new(e) }
  18. }
  19. }
  20. impl std::fmt::Debug for DragData {
  21. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  22. f.debug_struct("DragData")
  23. .field("coordinates", &self.coordinates())
  24. .field("modifiers", &self.modifiers())
  25. .field("held_buttons", &self.held_buttons())
  26. .field("trigger_button", &self.trigger_button())
  27. .finish()
  28. }
  29. }
  30. impl PartialEq for DragData {
  31. fn eq(&self, other: &Self) -> bool {
  32. self.coordinates() == other.coordinates()
  33. && self.modifiers() == other.modifiers()
  34. && self.held_buttons() == other.held_buttons()
  35. && self.trigger_button() == other.trigger_button()
  36. }
  37. }
  38. impl DragData {
  39. /// The event's coordinates relative to the application's viewport (as opposed to the coordinate within the page).
  40. ///
  41. /// For example, clicking in the top left corner of the viewport will always result in a mouse event with client coordinates (0., 0.), regardless of whether the page is scrolled horizontally.
  42. pub fn client_coordinates(&self) -> ClientPoint {
  43. self.inner.client_coordinates()
  44. }
  45. /// The event's coordinates relative to the padding edge of the target element
  46. ///
  47. /// For example, clicking in the top left corner of an element will result in element coordinates (0., 0.)
  48. pub fn element_coordinates(&self) -> ElementPoint {
  49. self.inner.element_coordinates()
  50. }
  51. /// The event's coordinates relative to the entire document. This includes any portion of the document not currently visible.
  52. ///
  53. /// For example, if the page is scrolled 200 pixels to the right and 300 pixels down, clicking in the top left corner of the viewport would result in page coordinates (200., 300.)
  54. pub fn page_coordinates(&self) -> PagePoint {
  55. self.inner.page_coordinates()
  56. }
  57. /// The event's coordinates relative to the entire screen. This takes into account the window's offset.
  58. pub fn screen_coordinates(&self) -> ScreenPoint {
  59. self.inner.screen_coordinates()
  60. }
  61. pub fn coordinates(&self) -> Coordinates {
  62. self.inner.coordinates()
  63. }
  64. /// The set of modifier keys which were pressed when the event occurred
  65. pub fn modifiers(&self) -> Modifiers {
  66. self.inner.modifiers()
  67. }
  68. /// The set of mouse buttons which were held when the event occurred.
  69. pub fn held_buttons(&self) -> MouseButtonSet {
  70. self.inner.held_buttons()
  71. }
  72. /// The mouse button that triggered the event
  73. ///
  74. // 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
  75. /// This is only guaranteed to indicate which button was pressed during events caused by pressing or releasing a button. As such, it is not reliable for events such as mouseenter, mouseleave, mouseover, mouseout, or mousemove. For example, a value of MouseButton::Primary may also indicate that no button was pressed.
  76. pub fn trigger_button(&self) -> Option<MouseButton> {
  77. self.inner.trigger_button()
  78. }
  79. /// Downcast this event data to a specific type
  80. pub fn downcast<T: 'static>(&self) -> Option<&T> {
  81. self.inner.as_any().downcast_ref::<T>()
  82. }
  83. }
  84. #[cfg(feature = "serialize")]
  85. #[derive(serde::Serialize, serde::Deserialize)]
  86. struct SerializedDragData {
  87. mouse: crate::point_interaction::SerializedPointInteraction,
  88. }
  89. #[cfg(feature = "serialize")]
  90. impl From<&DragData> for SerializedDragData {
  91. fn from(data: &DragData) -> Self {
  92. Self {
  93. mouse: crate::point_interaction::SerializedPointInteraction {
  94. client_coordinates: data.client_coordinates(),
  95. element_coordinates: data.element_coordinates(),
  96. page_coordinates: data.page_coordinates(),
  97. screen_coordinates: data.screen_coordinates(),
  98. modifiers: data.modifiers(),
  99. held_buttons: data.held_buttons(),
  100. trigger_button: data.trigger_button(),
  101. },
  102. }
  103. }
  104. }
  105. #[cfg(feature = "serialize")]
  106. impl HasDragData for SerializedDragData {}
  107. #[cfg(feature = "serialize")]
  108. impl HasMouseData for SerializedDragData {
  109. fn as_any(&self) -> &dyn std::any::Any {
  110. self
  111. }
  112. }
  113. #[cfg(feature = "serialize")]
  114. impl PointInteraction for SerializedDragData {
  115. fn client_coordinates(&self) -> ClientPoint {
  116. self.mouse.client_coordinates()
  117. }
  118. fn element_coordinates(&self) -> ElementPoint {
  119. self.mouse.element_coordinates()
  120. }
  121. fn page_coordinates(&self) -> PagePoint {
  122. self.mouse.page_coordinates()
  123. }
  124. fn screen_coordinates(&self) -> ScreenPoint {
  125. self.mouse.screen_coordinates()
  126. }
  127. fn coordinates(&self) -> Coordinates {
  128. self.mouse.coordinates()
  129. }
  130. fn modifiers(&self) -> Modifiers {
  131. self.mouse.modifiers()
  132. }
  133. fn held_buttons(&self) -> MouseButtonSet {
  134. self.mouse.held_buttons()
  135. }
  136. fn trigger_button(&self) -> Option<MouseButton> {
  137. self.mouse.trigger_button()
  138. }
  139. }
  140. #[cfg(feature = "serialize")]
  141. impl serde::Serialize for DragData {
  142. fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
  143. SerializedDragData::from(self).serialize(serializer)
  144. }
  145. }
  146. #[cfg(feature = "serialize")]
  147. impl<'de> serde::Deserialize<'de> for DragData {
  148. fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
  149. let data = SerializedDragData::deserialize(deserializer)?;
  150. Ok(Self {
  151. inner: Box::new(data),
  152. })
  153. }
  154. }
  155. /// A trait for any object that has the data for a drag event
  156. pub trait HasDragData: HasMouseData {}
  157. impl_event! {
  158. DragData;
  159. /// ondrag
  160. ondrag
  161. /// ondragend
  162. ondragend
  163. /// ondragenter
  164. ondragenter
  165. /// ondragexit
  166. ondragexit
  167. /// ondragleave
  168. ondragleave
  169. /// ondragover
  170. ondragover
  171. /// ondragstart
  172. ondragstart
  173. /// ondrop
  174. ondrop
  175. }