mouse.rs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint};
  2. use crate::input_data::{MouseButton, MouseButtonSet};
  3. use crate::prelude::*;
  4. use dioxus_core::Event;
  5. use keyboard_types::Modifiers;
  6. pub type MouseEvent = Event<MouseData>;
  7. /// A synthetic event that wraps a web-style [`MouseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent)
  8. /// Data associated with a mouse event
  9. pub struct MouseData {
  10. inner: Box<dyn HasMouseData>,
  11. }
  12. impl<E: HasMouseData + 'static> From<E> for MouseData {
  13. fn from(e: E) -> Self {
  14. Self { inner: Box::new(e) }
  15. }
  16. }
  17. impl std::fmt::Debug for MouseData {
  18. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  19. f.debug_struct("MouseData")
  20. .field("coordinates", &self.coordinates())
  21. .field("modifiers", &self.modifiers())
  22. .field("held_buttons", &self.held_buttons())
  23. .field("trigger_button", &self.trigger_button())
  24. .finish()
  25. }
  26. }
  27. impl<E: HasMouseData> PartialEq<E> for MouseData {
  28. fn eq(&self, other: &E) -> bool {
  29. self.coordinates() == other.coordinates()
  30. && self.modifiers() == other.modifiers()
  31. && self.held_buttons() == other.held_buttons()
  32. && self.trigger_button() == other.trigger_button()
  33. }
  34. }
  35. /// A trait for any object that has the data for a mouse event
  36. pub trait HasMouseData: PointerInteraction {
  37. /// return self as Any
  38. fn as_any(&self) -> &dyn std::any::Any;
  39. }
  40. impl_event! {
  41. MouseData;
  42. /// Execute a callback when a button is clicked.
  43. ///
  44. /// ## Description
  45. ///
  46. /// An element receives a click event when a pointing device button (such as a mouse's primary mouse button)
  47. /// is both pressed and released while the pointer is located inside the element.
  48. ///
  49. /// - Bubbles: Yes
  50. /// - Cancelable: Yes
  51. /// - Interface(InteData): [`MouseEvent`]
  52. ///
  53. /// If the button is pressed on one element and the pointer is moved outside the element before the button
  54. /// is released, the event is fired on the most specific ancestor element that contained both elements.
  55. /// `click` fires after both the `mousedown` and `mouseup` events have fired, in that order.
  56. ///
  57. /// ## Example
  58. /// ```rust, ignore
  59. /// rsx!( button { "click me", onclick: move |_| tracing::info!("Clicked!`") } )
  60. /// ```
  61. ///
  62. /// ## Reference
  63. /// - <https://www.w3schools.com/tags/ev_onclick.asp>
  64. /// - <https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event>
  65. onclick
  66. /// oncontextmenu
  67. oncontextmenu
  68. #[deprecated(since = "0.5.0", note = "use ondoubleclick instead")]
  69. ondblclick
  70. /// onmousedown
  71. onmousedown
  72. /// onmouseenter
  73. onmouseenter
  74. /// onmouseleave
  75. onmouseleave
  76. /// onmousemove
  77. onmousemove
  78. /// onmouseout
  79. onmouseout
  80. /// onmouseover
  81. ///
  82. /// Triggered when the users's mouse hovers over an element.
  83. onmouseover
  84. /// onmouseup
  85. onmouseup
  86. }
  87. /// ondoubleclick
  88. #[inline]
  89. pub fn ondoubleclick<'a, E: crate::EventReturn<T>, T>(
  90. _cx: &'a ::dioxus_core::ScopeState,
  91. mut _f: impl FnMut(::dioxus_core::Event<MouseData>) -> E + 'a,
  92. ) -> ::dioxus_core::MountedAttribute<'a> {
  93. ::dioxus_core::Attribute::new(
  94. "ondblclick",
  95. _cx.listener(move |e: ::dioxus_core::Event<MouseData>| {
  96. _f(e).spawn(_cx);
  97. }),
  98. None,
  99. false,
  100. )
  101. .into()
  102. }
  103. impl MouseData {
  104. /// Create a new instance of MouseData
  105. pub fn new(inner: impl HasMouseData + 'static) -> Self {
  106. Self {
  107. inner: Box::new(inner),
  108. }
  109. }
  110. /// Downcast this event to a concrete event type
  111. pub fn downcast<T: 'static>(&self) -> Option<&T> {
  112. self.inner.as_any().downcast_ref::<T>()
  113. }
  114. }
  115. impl InteractionLocation for MouseData {
  116. fn client_coordinates(&self) -> ClientPoint {
  117. self.inner.client_coordinates()
  118. }
  119. fn page_coordinates(&self) -> PagePoint {
  120. self.inner.page_coordinates()
  121. }
  122. fn screen_coordinates(&self) -> ScreenPoint {
  123. self.inner.screen_coordinates()
  124. }
  125. }
  126. impl InteractionElementOffset for MouseData {
  127. fn element_coordinates(&self) -> ElementPoint {
  128. self.inner.element_coordinates()
  129. }
  130. fn coordinates(&self) -> Coordinates {
  131. self.inner.coordinates()
  132. }
  133. }
  134. impl ModifiersInteraction for MouseData {
  135. /// The set of modifier keys which were pressed when the event occurred
  136. fn modifiers(&self) -> Modifiers {
  137. self.inner.modifiers()
  138. }
  139. }
  140. impl PointerInteraction for MouseData {
  141. /// The set of mouse buttons which were held when the event occurred.
  142. fn held_buttons(&self) -> MouseButtonSet {
  143. self.inner.held_buttons()
  144. }
  145. /// The mouse button that triggered the event
  146. ///
  147. // 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
  148. /// 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.
  149. fn trigger_button(&self) -> Option<MouseButton> {
  150. self.inner.trigger_button()
  151. }
  152. }
  153. impl PartialEq for MouseData {
  154. fn eq(&self, other: &Self) -> bool {
  155. self.coordinates() == other.coordinates()
  156. && self.modifiers() == other.modifiers()
  157. && self.held_buttons() == other.held_buttons()
  158. && self.trigger_button() == other.trigger_button()
  159. }
  160. }
  161. #[cfg(feature = "serialize")]
  162. /// A serialized version of [`MouseData`]
  163. #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone, Default)]
  164. pub struct SerializedMouseData {
  165. /// Common data for all pointer/mouse events
  166. #[serde(flatten)]
  167. point_data: crate::point_interaction::SerializedPointInteraction,
  168. }
  169. #[cfg(feature = "serialize")]
  170. impl SerializedMouseData {
  171. /// Create a new instance of SerializedMouseData
  172. pub fn new(
  173. trigger_button: Option<MouseButton>,
  174. held_buttons: MouseButtonSet,
  175. coordinates: Coordinates,
  176. modifiers: Modifiers,
  177. ) -> Self {
  178. Self {
  179. point_data: crate::point_interaction::SerializedPointInteraction::new(
  180. trigger_button,
  181. held_buttons,
  182. coordinates,
  183. modifiers,
  184. ),
  185. }
  186. }
  187. }
  188. #[cfg(feature = "serialize")]
  189. impl From<&MouseData> for SerializedMouseData {
  190. fn from(e: &MouseData) -> Self {
  191. Self {
  192. point_data: crate::point_interaction::SerializedPointInteraction::from(e),
  193. }
  194. }
  195. }
  196. #[cfg(feature = "serialize")]
  197. impl HasMouseData for SerializedMouseData {
  198. fn as_any(&self) -> &dyn std::any::Any {
  199. self
  200. }
  201. }
  202. #[cfg(feature = "serialize")]
  203. impl InteractionLocation for SerializedMouseData {
  204. fn client_coordinates(&self) -> ClientPoint {
  205. self.point_data.client_coordinates()
  206. }
  207. fn page_coordinates(&self) -> PagePoint {
  208. self.point_data.page_coordinates()
  209. }
  210. fn screen_coordinates(&self) -> ScreenPoint {
  211. self.point_data.screen_coordinates()
  212. }
  213. }
  214. #[cfg(feature = "serialize")]
  215. impl InteractionElementOffset for SerializedMouseData {
  216. fn element_coordinates(&self) -> ElementPoint {
  217. self.point_data.element_coordinates()
  218. }
  219. }
  220. #[cfg(feature = "serialize")]
  221. impl ModifiersInteraction for SerializedMouseData {
  222. fn modifiers(&self) -> Modifiers {
  223. self.point_data.modifiers()
  224. }
  225. }
  226. #[cfg(feature = "serialize")]
  227. impl PointerInteraction for SerializedMouseData {
  228. fn held_buttons(&self) -> MouseButtonSet {
  229. self.point_data.held_buttons()
  230. }
  231. fn trigger_button(&self) -> Option<MouseButton> {
  232. self.point_data.trigger_button()
  233. }
  234. }
  235. #[cfg(feature = "serialize")]
  236. impl serde::Serialize for MouseData {
  237. fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
  238. SerializedMouseData::from(self).serialize(serializer)
  239. }
  240. }
  241. #[cfg(feature = "serialize")]
  242. impl<'de> serde::Deserialize<'de> for MouseData {
  243. fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
  244. let data = SerializedMouseData::deserialize(deserializer)?;
  245. Ok(Self {
  246. inner: Box::new(data),
  247. })
  248. }
  249. }