dioxus_html/
point_interaction.rs

1use keyboard_types::Modifiers;
2
3use crate::{
4    geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint},
5    input_data::{MouseButton, MouseButtonSet},
6};
7
8/// A interaction that contains data about the location of the event.
9pub trait InteractionLocation {
10    /// Gets the coordinates of the event relative to the browser viewport.
11    fn client_coordinates(&self) -> ClientPoint;
12
13    /// Gets the coordinates of the event relative to the screen.
14    fn screen_coordinates(&self) -> ScreenPoint;
15
16    /// Gets the coordinates of the event relative to the page.
17    fn page_coordinates(&self) -> PagePoint;
18}
19
20/// A interaction that contains data about the location of the event.
21pub trait InteractionElementOffset: InteractionLocation {
22    /// Gets the coordinates of the event.
23    fn coordinates(&self) -> Coordinates {
24        Coordinates::new(
25            self.screen_coordinates(),
26            self.client_coordinates(),
27            self.element_coordinates(),
28            self.page_coordinates(),
29        )
30    }
31
32    /// Gets the coordinates of the event relative to the target element.
33    fn element_coordinates(&self) -> ElementPoint;
34}
35
36/// A interaction that contains data about the pointer button(s) that triggered the event.
37pub trait PointerInteraction: InteractionElementOffset + ModifiersInteraction {
38    /// Gets the button that triggered the event.
39    fn trigger_button(&self) -> Option<MouseButton>;
40
41    /// Gets the buttons that are currently held down.
42    fn held_buttons(&self) -> MouseButtonSet;
43}
44
45/// A interaction that contains data about the current state of the keyboard modifiers.
46pub trait ModifiersInteraction {
47    /// Gets the modifiers of the pointer event.
48    fn modifiers(&self) -> Modifiers;
49}
50
51#[cfg(feature = "serialize")]
52#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone, Default)]
53pub struct SerializedPointInteraction {
54    pub alt_key: bool,
55
56    /// The button number that was pressed (if applicable) when the mouse event was fired.
57    pub button: i16,
58
59    /// Indicates which buttons are pressed on the mouse (or other input device) when a mouse event is triggered.
60    ///
61    /// 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).
62    ///
63    /// - 1: Primary button (usually the left button)
64    /// - 2: Secondary button (usually the right button)
65    /// - 4: Auxiliary button (usually the mouse wheel button or middle button)
66    /// - 8: 4th button (typically the "Browser Back" button)
67    /// - 16 : 5th button (typically the "Browser Forward" button)
68    pub buttons: u16,
69
70    /// The horizontal coordinate within the application's viewport at which the event occurred (as opposed to the coordinate within the page).
71    ///
72    /// 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.
73    pub client_x: i32,
74
75    /// The vertical coordinate within the application's viewport at which the event occurred (as opposed to the coordinate within the page).
76    ///
77    /// 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.
78    pub client_y: i32,
79
80    /// True if the control key was down when the mouse event was fired.
81    pub ctrl_key: bool,
82
83    /// True if the meta key was down when the mouse event was fired.
84    pub meta_key: bool,
85
86    /// The offset in the X coordinate of the mouse pointer between that event and the padding edge of the target node.
87    pub offset_x: i32,
88
89    /// The offset in the Y coordinate of the mouse pointer between that event and the padding edge of the target node.
90    pub offset_y: i32,
91
92    /// 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.
93    ///
94    /// 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.
95    pub page_x: i32,
96
97    /// The Y (vertical) coordinate in pixels of the event relative to the whole document.
98    ///
99    /// See `page_x`.
100    pub page_y: i32,
101
102    /// The X coordinate of the mouse pointer in global (screen) coordinates.
103    pub screen_x: i32,
104
105    /// The Y coordinate of the mouse pointer in global (screen) coordinates.
106    pub screen_y: i32,
107
108    /// True if the shift key was down when the mouse event was fired.
109    pub shift_key: bool,
110}
111
112#[cfg(feature = "serialize")]
113impl SerializedPointInteraction {
114    pub fn new(
115        trigger_button: Option<MouseButton>,
116        held_buttons: MouseButtonSet,
117        coordinates: Coordinates,
118        modifiers: Modifiers,
119    ) -> Self {
120        let alt_key = modifiers.contains(Modifiers::ALT);
121        let ctrl_key = modifiers.contains(Modifiers::CONTROL);
122        let meta_key = modifiers.contains(Modifiers::META);
123        let shift_key = modifiers.contains(Modifiers::SHIFT);
124
125        let [client_x, client_y]: [i32; 2] = coordinates.client().cast().into();
126        let [offset_x, offset_y]: [i32; 2] = coordinates.element().cast().into();
127        let [page_x, page_y]: [i32; 2] = coordinates.page().cast().into();
128        let [screen_x, screen_y]: [i32; 2] = coordinates.screen().cast().into();
129        Self {
130            button: trigger_button
131                .map_or(MouseButton::default(), |b| b)
132                .into_web_code(),
133            buttons: crate::input_data::encode_mouse_button_set(held_buttons),
134            meta_key,
135            ctrl_key,
136            shift_key,
137            alt_key,
138            client_x,
139            client_y,
140            screen_x,
141            screen_y,
142            offset_x,
143            offset_y,
144            page_x,
145            page_y,
146        }
147    }
148}
149
150#[cfg(feature = "serialize")]
151impl<E: PointerInteraction> From<&E> for SerializedPointInteraction {
152    fn from(data: &E) -> Self {
153        let trigger_button = data.trigger_button();
154        let held_buttons = data.held_buttons();
155        let coordinates = data.coordinates();
156        let modifiers = data.modifiers();
157        Self::new(trigger_button, held_buttons, coordinates, modifiers)
158    }
159}
160
161#[cfg(feature = "serialize")]
162impl PointerInteraction for SerializedPointInteraction {
163    fn held_buttons(&self) -> MouseButtonSet {
164        crate::input_data::decode_mouse_button_set(self.buttons)
165    }
166
167    fn trigger_button(&self) -> Option<MouseButton> {
168        Some(MouseButton::from_web_code(self.button))
169    }
170}
171
172#[cfg(feature = "serialize")]
173impl ModifiersInteraction for SerializedPointInteraction {
174    fn modifiers(&self) -> Modifiers {
175        let mut modifiers = Modifiers::empty();
176
177        if self.alt_key {
178            modifiers.insert(Modifiers::ALT);
179        }
180        if self.ctrl_key {
181            modifiers.insert(Modifiers::CONTROL);
182        }
183        if self.meta_key {
184            modifiers.insert(Modifiers::META);
185        }
186        if self.shift_key {
187            modifiers.insert(Modifiers::SHIFT);
188        }
189
190        modifiers
191    }
192}
193
194#[cfg(feature = "serialize")]
195impl InteractionLocation for SerializedPointInteraction {
196    fn client_coordinates(&self) -> ClientPoint {
197        ClientPoint::new(self.client_x.into(), self.client_y.into())
198    }
199
200    fn screen_coordinates(&self) -> ScreenPoint {
201        ScreenPoint::new(self.screen_x.into(), self.screen_y.into())
202    }
203
204    fn page_coordinates(&self) -> PagePoint {
205        PagePoint::new(self.page_x.into(), self.page_y.into())
206    }
207}
208
209#[cfg(feature = "serialize")]
210impl InteractionElementOffset for SerializedPointInteraction {
211    fn element_coordinates(&self) -> ElementPoint {
212        ElementPoint::new(self.offset_x.into(), self.offset_y.into())
213    }
214}