|
@@ -1,91 +1,47 @@
|
|
use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint};
|
|
use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint};
|
|
-use crate::input_data::{
|
|
|
|
- decode_mouse_button_set, encode_mouse_button_set, MouseButton, MouseButtonSet,
|
|
|
|
-};
|
|
|
|
|
|
+use crate::input_data::{MouseButton, MouseButtonSet};
|
|
|
|
+use crate::prelude::*;
|
|
use dioxus_core::Event;
|
|
use dioxus_core::Event;
|
|
use keyboard_types::Modifiers;
|
|
use keyboard_types::Modifiers;
|
|
-use std::fmt::{Debug, Formatter};
|
|
|
|
|
|
|
|
pub type MouseEvent = Event<MouseData>;
|
|
pub type MouseEvent = Event<MouseData>;
|
|
|
|
|
|
/// A synthetic event that wraps a web-style [`MouseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent)
|
|
/// A synthetic event that wraps a web-style [`MouseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent)
|
|
-#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
-#[derive(Clone, Default, PartialEq, Eq)]
|
|
|
|
/// Data associated with a mouse event
|
|
/// Data associated with a mouse event
|
|
-///
|
|
|
|
-/// Do not use the deprecated fields; they may change or become private in the future.
|
|
|
|
pub struct MouseData {
|
|
pub struct MouseData {
|
|
- /// True if the alt key was down when the mouse event was fired.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use modifiers() instead")]
|
|
|
|
- pub alt_key: bool,
|
|
|
|
-
|
|
|
|
- /// The button number that was pressed (if applicable) when the mouse event was fired.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use trigger_button() instead")]
|
|
|
|
- pub button: i16,
|
|
|
|
-
|
|
|
|
- /// Indicates which buttons are pressed on the mouse (or other input device) when a mouse event is triggered.
|
|
|
|
- ///
|
|
|
|
- /// Each button that can be pressed is represented by a given number (see below). If more than one button is pressed, the button values are added together to produce a new number. For example, if the secondary (2) and auxiliary (4) buttons are pressed simultaneously, the value is 6 (i.e., 2 + 4).
|
|
|
|
- ///
|
|
|
|
- /// - 1: Primary button (usually the left button)
|
|
|
|
- /// - 2: Secondary button (usually the right button)
|
|
|
|
- /// - 4: Auxiliary button (usually the mouse wheel button or middle button)
|
|
|
|
- /// - 8: 4th button (typically the "Browser Back" button)
|
|
|
|
- /// - 16 : 5th button (typically the "Browser Forward" button)
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use held_buttons() instead")]
|
|
|
|
- pub buttons: u16,
|
|
|
|
-
|
|
|
|
- /// The horizontal coordinate within the application's viewport at which the event occurred (as opposed to the coordinate within the page).
|
|
|
|
- ///
|
|
|
|
- /// For example, clicking on the left edge of the viewport will always result in a mouse event with a clientX value of 0, regardless of whether the page is scrolled horizontally.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use client_coordinates() instead")]
|
|
|
|
- pub client_x: i32,
|
|
|
|
-
|
|
|
|
- /// The vertical coordinate within the application's viewport at which the event occurred (as opposed to the coordinate within the page).
|
|
|
|
- ///
|
|
|
|
- /// For example, clicking on the top edge of the viewport will always result in a mouse event with a clientY value of 0, regardless of whether the page is scrolled vertically.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use client_coordinates() instead")]
|
|
|
|
- pub client_y: i32,
|
|
|
|
-
|
|
|
|
- /// True if the control key was down when the mouse event was fired.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use modifiers() instead")]
|
|
|
|
- pub ctrl_key: bool,
|
|
|
|
-
|
|
|
|
- /// True if the meta key was down when the mouse event was fired.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use modifiers() instead")]
|
|
|
|
- pub meta_key: bool,
|
|
|
|
-
|
|
|
|
- /// The offset in the X coordinate of the mouse pointer between that event and the padding edge of the target node.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use element_coordinates() instead")]
|
|
|
|
- pub offset_x: i32,
|
|
|
|
-
|
|
|
|
- /// The offset in the Y coordinate of the mouse pointer between that event and the padding edge of the target node.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use element_coordinates() instead")]
|
|
|
|
- pub offset_y: i32,
|
|
|
|
-
|
|
|
|
- /// The X (horizontal) coordinate (in pixels) of the mouse, relative to the left edge of the entire document. This includes any portion of the document not currently visible.
|
|
|
|
- ///
|
|
|
|
- /// Being based on the edge of the document as it is, this property takes into account any horizontal scrolling of the page. For example, if the page is scrolled such that 200 pixels of the left side of the document are scrolled out of view, and the mouse is clicked 100 pixels inward from the left edge of the view, the value returned by pageX will be 300.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use page_coordinates() instead")]
|
|
|
|
- pub page_x: i32,
|
|
|
|
|
|
+ inner: Box<dyn HasMouseData>,
|
|
|
|
+}
|
|
|
|
|
|
- /// The Y (vertical) coordinate in pixels of the event relative to the whole document.
|
|
|
|
- ///
|
|
|
|
- /// See `page_x`.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use page_coordinates() instead")]
|
|
|
|
- pub page_y: i32,
|
|
|
|
|
|
+impl<E: HasMouseData + 'static> From<E> for MouseData {
|
|
|
|
+ fn from(e: E) -> Self {
|
|
|
|
+ Self { inner: Box::new(e) }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- /// The X coordinate of the mouse pointer in global (screen) coordinates.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use screen_coordinates() instead")]
|
|
|
|
- pub screen_x: i32,
|
|
|
|
|
|
+impl std::fmt::Debug for MouseData {
|
|
|
|
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
+ f.debug_struct("MouseData")
|
|
|
|
+ .field("coordinates", &self.coordinates())
|
|
|
|
+ .field("modifiers", &self.modifiers())
|
|
|
|
+ .field("held_buttons", &self.held_buttons())
|
|
|
|
+ .field("trigger_button", &self.trigger_button())
|
|
|
|
+ .finish()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- /// The Y coordinate of the mouse pointer in global (screen) coordinates.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use screen_coordinates() instead")]
|
|
|
|
- pub screen_y: i32,
|
|
|
|
|
|
+impl<E: HasMouseData> PartialEq<E> for MouseData {
|
|
|
|
+ fn eq(&self, other: &E) -> bool {
|
|
|
|
+ self.coordinates() == other.coordinates()
|
|
|
|
+ && self.modifiers() == other.modifiers()
|
|
|
|
+ && self.held_buttons() == other.held_buttons()
|
|
|
|
+ && self.trigger_button() == other.trigger_button()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- /// True if the shift key was down when the mouse event was fired.
|
|
|
|
- #[deprecated(since = "0.3.0", note = "use modifiers() instead")]
|
|
|
|
- pub shift_key: bool,
|
|
|
|
|
|
+/// A trait for any object that has the data for a mouse event
|
|
|
|
+pub trait HasMouseData: PointerInteraction {
|
|
|
|
+ /// return self as Any
|
|
|
|
+ fn as_any(&self) -> &dyn std::any::Any;
|
|
}
|
|
}
|
|
|
|
|
|
impl_event! {
|
|
impl_event! {
|
|
@@ -162,131 +118,172 @@ pub fn ondoubleclick<E: crate::EventReturn<T>, T>(
|
|
}
|
|
}
|
|
|
|
|
|
impl MouseData {
|
|
impl MouseData {
|
|
- /// Construct MouseData with the specified properties
|
|
|
|
|
|
+ /// Create a new instance of MouseData
|
|
|
|
+ pub fn new(inner: impl HasMouseData + 'static) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ inner: Box::new(inner),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Downcast this event to a concrete event type
|
|
|
|
+ pub fn downcast<T: 'static>(&self) -> Option<&T> {
|
|
|
|
+ self.inner.as_any().downcast_ref::<T>()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl InteractionLocation for MouseData {
|
|
|
|
+ fn client_coordinates(&self) -> ClientPoint {
|
|
|
|
+ self.inner.client_coordinates()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn page_coordinates(&self) -> PagePoint {
|
|
|
|
+ self.inner.page_coordinates()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn screen_coordinates(&self) -> ScreenPoint {
|
|
|
|
+ self.inner.screen_coordinates()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl InteractionElementOffset for MouseData {
|
|
|
|
+ fn element_coordinates(&self) -> ElementPoint {
|
|
|
|
+ self.inner.element_coordinates()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn coordinates(&self) -> Coordinates {
|
|
|
|
+ self.inner.coordinates()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl ModifiersInteraction for MouseData {
|
|
|
|
+ /// The set of modifier keys which were pressed when the event occurred
|
|
|
|
+ fn modifiers(&self) -> Modifiers {
|
|
|
|
+ self.inner.modifiers()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl PointerInteraction for MouseData {
|
|
|
|
+ /// The set of mouse buttons which were held when the event occurred.
|
|
|
|
+ fn held_buttons(&self) -> MouseButtonSet {
|
|
|
|
+ self.inner.held_buttons()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// The mouse button that triggered the event
|
|
///
|
|
///
|
|
- /// Note: the current implementation truncates coordinates. In the future, when we change the internal representation, it may also support a fractional part.
|
|
|
|
|
|
+ // 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
|
|
|
|
+ /// 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.
|
|
|
|
+ fn trigger_button(&self) -> Option<MouseButton> {
|
|
|
|
+ self.inner.trigger_button()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl PartialEq for MouseData {
|
|
|
|
+ fn eq(&self, other: &Self) -> bool {
|
|
|
|
+ self.coordinates() == other.coordinates()
|
|
|
|
+ && self.modifiers() == other.modifiers()
|
|
|
|
+ && self.held_buttons() == other.held_buttons()
|
|
|
|
+ && self.trigger_button() == other.trigger_button()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(feature = "serialize")]
|
|
|
|
+/// A serialized version of [`MouseData`]
|
|
|
|
+#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone, Default)]
|
|
|
|
+pub struct SerializedMouseData {
|
|
|
|
+ /// Common data for all pointer/mouse events
|
|
|
|
+ #[serde(flatten)]
|
|
|
|
+ point_data: crate::point_interaction::SerializedPointInteraction,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(feature = "serialize")]
|
|
|
|
+impl SerializedMouseData {
|
|
|
|
+ /// Create a new instance of SerializedMouseData
|
|
pub fn new(
|
|
pub fn new(
|
|
- coordinates: Coordinates,
|
|
|
|
trigger_button: Option<MouseButton>,
|
|
trigger_button: Option<MouseButton>,
|
|
held_buttons: MouseButtonSet,
|
|
held_buttons: MouseButtonSet,
|
|
|
|
+ coordinates: Coordinates,
|
|
modifiers: Modifiers,
|
|
modifiers: Modifiers,
|
|
) -> Self {
|
|
) -> Self {
|
|
- let alt_key = modifiers.contains(Modifiers::ALT);
|
|
|
|
- let ctrl_key = modifiers.contains(Modifiers::CONTROL);
|
|
|
|
- let meta_key = modifiers.contains(Modifiers::META);
|
|
|
|
- let shift_key = modifiers.contains(Modifiers::SHIFT);
|
|
|
|
-
|
|
|
|
- let [client_x, client_y]: [i32; 2] = coordinates.client().cast().into();
|
|
|
|
- let [offset_x, offset_y]: [i32; 2] = coordinates.element().cast().into();
|
|
|
|
- let [page_x, page_y]: [i32; 2] = coordinates.page().cast().into();
|
|
|
|
- let [screen_x, screen_y]: [i32; 2] = coordinates.screen().cast().into();
|
|
|
|
|
|
+ Self {
|
|
|
|
+ point_data: crate::point_interaction::SerializedPointInteraction::new(
|
|
|
|
+ trigger_button,
|
|
|
|
+ held_buttons,
|
|
|
|
+ coordinates,
|
|
|
|
+ modifiers,
|
|
|
|
+ ),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- #[allow(deprecated)]
|
|
|
|
|
|
+#[cfg(feature = "serialize")]
|
|
|
|
+impl From<&MouseData> for SerializedMouseData {
|
|
|
|
+ fn from(e: &MouseData) -> Self {
|
|
Self {
|
|
Self {
|
|
- alt_key,
|
|
|
|
- ctrl_key,
|
|
|
|
- meta_key,
|
|
|
|
- shift_key,
|
|
|
|
-
|
|
|
|
- button: trigger_button.map_or(0, |b| b.into_web_code()),
|
|
|
|
- buttons: encode_mouse_button_set(held_buttons),
|
|
|
|
-
|
|
|
|
- client_x,
|
|
|
|
- client_y,
|
|
|
|
- offset_x,
|
|
|
|
- offset_y,
|
|
|
|
- page_x,
|
|
|
|
- page_y,
|
|
|
|
- screen_x,
|
|
|
|
- screen_y,
|
|
|
|
|
|
+ point_data: crate::point_interaction::SerializedPointInteraction::from(e),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- /// The event's coordinates relative to the application's viewport (as opposed to the coordinate within the page).
|
|
|
|
- ///
|
|
|
|
- /// 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.
|
|
|
|
- pub fn client_coordinates(&self) -> ClientPoint {
|
|
|
|
- #[allow(deprecated)]
|
|
|
|
- ClientPoint::new(self.client_x.into(), self.client_y.into())
|
|
|
|
|
|
+#[cfg(feature = "serialize")]
|
|
|
|
+impl HasMouseData for SerializedMouseData {
|
|
|
|
+ fn as_any(&self) -> &dyn std::any::Any {
|
|
|
|
+ self
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- /// The event's coordinates relative to the padding edge of the target element
|
|
|
|
- ///
|
|
|
|
- /// For example, clicking in the top left corner of an element will result in element coordinates (0., 0.)
|
|
|
|
- pub fn element_coordinates(&self) -> ElementPoint {
|
|
|
|
- #[allow(deprecated)]
|
|
|
|
- ElementPoint::new(self.offset_x.into(), self.offset_y.into())
|
|
|
|
|
|
+#[cfg(feature = "serialize")]
|
|
|
|
+impl InteractionLocation for SerializedMouseData {
|
|
|
|
+ fn client_coordinates(&self) -> ClientPoint {
|
|
|
|
+ self.point_data.client_coordinates()
|
|
}
|
|
}
|
|
|
|
|
|
- /// The event's coordinates relative to the entire document. This includes any portion of the document not currently visible.
|
|
|
|
- ///
|
|
|
|
- /// 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.)
|
|
|
|
- pub fn page_coordinates(&self) -> PagePoint {
|
|
|
|
- #[allow(deprecated)]
|
|
|
|
- PagePoint::new(self.page_x.into(), self.page_y.into())
|
|
|
|
|
|
+ fn page_coordinates(&self) -> PagePoint {
|
|
|
|
+ self.point_data.page_coordinates()
|
|
}
|
|
}
|
|
|
|
|
|
- /// The event's coordinates relative to the entire screen. This takes into account the window's offset.
|
|
|
|
- pub fn screen_coordinates(&self) -> ScreenPoint {
|
|
|
|
- #[allow(deprecated)]
|
|
|
|
- ScreenPoint::new(self.screen_x.into(), self.screen_y.into())
|
|
|
|
|
|
+ fn screen_coordinates(&self) -> ScreenPoint {
|
|
|
|
+ self.point_data.screen_coordinates()
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- pub fn coordinates(&self) -> Coordinates {
|
|
|
|
- Coordinates::new(
|
|
|
|
- self.screen_coordinates(),
|
|
|
|
- self.client_coordinates(),
|
|
|
|
- self.element_coordinates(),
|
|
|
|
- self.page_coordinates(),
|
|
|
|
- )
|
|
|
|
|
|
+#[cfg(feature = "serialize")]
|
|
|
|
+impl InteractionElementOffset for SerializedMouseData {
|
|
|
|
+ fn element_coordinates(&self) -> ElementPoint {
|
|
|
|
+ self.point_data.element_coordinates()
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- /// The set of modifier keys which were pressed when the event occurred
|
|
|
|
- pub fn modifiers(&self) -> Modifiers {
|
|
|
|
- let mut modifiers = Modifiers::empty();
|
|
|
|
-
|
|
|
|
- #[allow(deprecated)]
|
|
|
|
- {
|
|
|
|
- if self.alt_key {
|
|
|
|
- modifiers.insert(Modifiers::ALT);
|
|
|
|
- }
|
|
|
|
- if self.ctrl_key {
|
|
|
|
- modifiers.insert(Modifiers::CONTROL);
|
|
|
|
- }
|
|
|
|
- if self.meta_key {
|
|
|
|
- modifiers.insert(Modifiers::META);
|
|
|
|
- }
|
|
|
|
- if self.shift_key {
|
|
|
|
- modifiers.insert(Modifiers::SHIFT);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+#[cfg(feature = "serialize")]
|
|
|
|
+impl ModifiersInteraction for SerializedMouseData {
|
|
|
|
+ fn modifiers(&self) -> Modifiers {
|
|
|
|
+ self.point_data.modifiers()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- modifiers
|
|
|
|
|
|
+#[cfg(feature = "serialize")]
|
|
|
|
+impl PointerInteraction for SerializedMouseData {
|
|
|
|
+ fn held_buttons(&self) -> MouseButtonSet {
|
|
|
|
+ self.point_data.held_buttons()
|
|
}
|
|
}
|
|
|
|
|
|
- /// The set of mouse buttons which were held when the event occurred.
|
|
|
|
- pub fn held_buttons(&self) -> MouseButtonSet {
|
|
|
|
- #[allow(deprecated)]
|
|
|
|
- decode_mouse_button_set(self.buttons)
|
|
|
|
|
|
+ fn trigger_button(&self) -> Option<MouseButton> {
|
|
|
|
+ self.point_data.trigger_button()
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- /// The mouse button that triggered the event
|
|
|
|
- ///
|
|
|
|
- // 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
|
|
|
|
- /// 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.
|
|
|
|
- pub fn trigger_button(&self) -> Option<MouseButton> {
|
|
|
|
- #[allow(deprecated)]
|
|
|
|
- Some(MouseButton::from_web_code(self.button))
|
|
|
|
|
|
+#[cfg(feature = "serialize")]
|
|
|
|
+impl serde::Serialize for MouseData {
|
|
|
|
+ fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
|
|
+ SerializedMouseData::from(self).serialize(serializer)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-impl Debug for MouseData {
|
|
|
|
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
- f.debug_struct("MouseData")
|
|
|
|
- .field("coordinates", &self.coordinates())
|
|
|
|
- .field("modifiers", &self.modifiers())
|
|
|
|
- .field("held_buttons", &self.held_buttons())
|
|
|
|
- .field("trigger_button", &self.trigger_button())
|
|
|
|
- .finish()
|
|
|
|
|
|
+#[cfg(feature = "serialize")]
|
|
|
|
+impl<'de> serde::Deserialize<'de> for MouseData {
|
|
|
|
+ fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
|
|
|
+ let data = SerializedMouseData::deserialize(deserializer)?;
|
|
|
|
+ Ok(Self {
|
|
|
|
+ inner: Box::new(data),
|
|
|
|
+ })
|
|
}
|
|
}
|
|
}
|
|
}
|