devela/ui/event/
pointer.rs

1// devela::ui::event::pointer
2//
3//! Defines [`EventMouse`], [`EventPointer`], [`EventPointerType`],
4//! [`EventButton`], [`EventButtonState`], [`EventWheel`].
5//
6// TOC
7// - definitions
8// - impls
9// - tests
10
11use crate::{EventTimestamp, NonZeroU8};
12
13/* definitions */
14
15/// Represents a basic mouse event.
16#[derive(Clone, Copy, Debug, PartialEq)]
17pub struct EventMouse {
18    /// The x-coordinate of the mouse cursor.
19    pub x: i32,
20    /// The y-coordinate of the mouse cursor.
21    pub y: i32,
22    /// The mouse button involved in the event.
23    pub button: Option<EventButton>,
24    /// The state of the mouse button (pressed, released, moved).
25    pub state: EventButtonState,
26    /// A bitmask of currently pressed buttons (`1`: left, `2`: right, `4`: middle).
27    pub buttons: u8,
28    /// The time stamp of when the event occurred.
29    pub time_stamp: Option<EventTimestamp>,
30}
31
32/// Represents a pointer event (mouse, touch, or pen).
33#[derive(Clone, Copy, Debug, PartialEq)]
34pub struct EventPointer {
35    /// The type of pointer (mouse, touch, pen).
36    pub kind: EventPointerType,
37    /// Unique ID for touch and pen inputs (e.g., multi-touch gestures).
38    pub id: u32,
39    /// The x-coordinate of the pointer.
40    pub x: i32,
41    /// The y-coordinate of the pointer.
42    pub y: i32,
43    /// The delta movement since the last event.
44    pub dx: i32,
45    ///
46    pub dy: i32,
47    /// The pressure applied (0.0 to 1.0), applicable for pen/touch.
48    pub pressure: f32,
49    /// The tilt angle of a stylus (if applicable).
50    pub tilt_x: i8,
51    /// The tilt of the stylus along the Y-axis (-90° to 90°).
52    pub tilt_y: i8,
53    /// The rotation of the stylus around its own axis (0° to 359°).
54    pub twist: u16,
55    /// The button involved.
56    pub button: Option<EventButton>,
57    /// The state of the pointer (pressed, released, moved).
58    pub state: EventButtonState,
59    // /// The phase of the pointer (useful for touch events).
60    // pub phase: EventPointerPhase,
61    /// The time stamp of the event.
62    pub time_stamp: Option<EventTimestamp>,
63}
64/// Enum representing the type of pointer.
65#[derive(Clone, Copy, Debug, PartialEq, Eq)]
66pub enum EventPointerType {
67    /// A mouse pointer.
68    Mouse,
69    /// A touch pointer.
70    Touch,
71    /// A pen pointer.
72    Pen,
73}
74// /// Represents the phase of a pointer (useful for touch events).
75// #[derive(Clone, Copy, Debug, PartialEq, Eq)]
76// pub enum EventPointerPhase {
77//     /// The pointer has started touching the surface.
78//     Start,
79//     /// The pointer is moving.
80//     Move,
81//     /// The pointer was lifted from the surface.
82//     End,
83//     /// The input was cancelled (e.g., interrupted by system gestures).
84//     Cancel,
85// }
86
87/// Represents mouse, touch, or pen buttons.
88#[derive(Clone, Copy, Debug, PartialEq, Eq)]
89pub enum EventButton {
90    /// Left mouse button.
91    Left,
92    /// Right mouse button.
93    Right,
94    /// Middle mouse button (usually the scroll wheel button).
95    Middle,
96    /// Additional buttons (e.g., side buttons on advanced mice).
97    Other(NonZeroU8),
98}
99
100/// Represents the state of a button.
101#[derive(Clone, Copy, Debug, PartialEq, Eq)]
102pub enum EventButtonState {
103    /// The button was pressed.
104    Pressed,
105    /// The button was released.
106    Released,
107    /// The pointer moved without a button press/release.
108    Moved,
109}
110
111/// Represents a mouse wheel event.
112#[derive(Clone, Copy, Debug, PartialEq, Eq)]
113pub struct EventWheel {
114    /// The amount scrolled horizontally.
115    pub delta_x: i32,
116    /// The amount scrolled vertically.
117    pub delta_y: i32,
118    /// The x-coordinate of the mouse cursor during the event.
119    pub x: i32,
120    /// The y-coordinate of the mouse cursor during the event.
121    pub y: i32,
122    /// The timestamp of when the event occurred.
123    pub timestamp: Option<EventTimestamp>,
124}
125
126/* impls */
127
128#[rustfmt::skip]
129#[cfg(all(feature = "js", not(windows)))]
130mod impl_js {
131    use super::*;
132    use crate::{is, js_number, WebEventKind, WebEventMouse, JsInstant};
133
134    /* mouse */
135
136    impl EventMouse {
137        /// Converts `WebEventMouse` to `EventMouse`.
138        pub const fn from_js(js: WebEventMouse) -> EventMouse {
139            EventMouse {
140                x: js.x as i32,
141                y: js.y as i32,
142                button: EventButton::from_js(js.button),
143                state: EventButtonState::from_js(js.etype),
144                buttons: js.buttons,
145                time_stamp: EventTimestamp::try_from_js(js.time_stamp),
146            }
147        }
148    }
149
150    impl EventMouse {
151        /// Converts `EventMouse` to `WebEventMouse`.
152        pub const fn to_js(self) -> WebEventMouse {
153            WebEventMouse {
154                x: self.x as js_number,
155                y: self.y as js_number,
156                button: is![let Some(b) = self.button; b.to_js(); 255], // IMPROVE to_js
157                buttons: self.buttons, // Already a bitmask, directly compatible
158                etype: self.state.to_js_as_mouse(),
159                time_stamp: is![let Some(t) = self.time_stamp; t.to_js(); JsInstant { ms: 0.0 }],
160            }
161        }
162    }
163
164    impl From<WebEventMouse> for EventMouse {
165        fn from(from: WebEventMouse) -> Self { Self::from_js(from) }
166    }
167    impl From<EventMouse> for WebEventMouse {
168        fn from(from: EventMouse) -> Self { from.to_js() }
169    }
170
171    /* button */
172
173    impl EventButton {
174        /// Converts a JavaScript button index in [`WebEventMouse`] into `EventButton`.
175        pub const fn from_js(js_button: u8) -> Option<Self> {
176            match js_button {
177                0 => Some(EventButton::Left),
178                1 => Some(EventButton::Middle),
179                2 => Some(EventButton::Right),
180                255 => None, // (== -1_i8) represents "no button"
181                n => Some(EventButton::Other(NonZeroU8::new(n).unwrap())),
182            }
183        }
184        /// Converts an EventButton to a JavaScript button index in [`WebEventMouse`].
185        pub const fn to_js(self) -> u8 {
186            match self {
187                EventButton::Left => 0,
188                EventButton::Right => 1,
189                EventButton::Middle => 2,
190                EventButton::Other(n) => n.get(),
191            }
192        }
193    }
194
195    // IMPROVE: MAYBE impl try_ methods
196    impl EventButtonState {
197        /// Converts a `WebEventKind` into `EventButtonState`.
198        pub const fn from_js(js_event: WebEventKind) -> Self {
199            use {WebEventKind as J, EventButtonState as E};
200            match js_event {
201                J::Click | J::MouseDown | J::PointerDown => E::Pressed,
202                J::MouseUp | J::PointerUp => E::Released,
203                _ => E::Moved,
204            }
205        }
206        /// Converts a `EventButtonState` into a `WebEventKind`.
207        pub const fn to_js_as_mouse(self) -> WebEventKind {
208            use {WebEventKind as J, EventButtonState as E};
209            match self {
210                E::Pressed => J::MouseDown,
211                E::Released => J::MouseUp,
212                E::Moved => J::MouseMove,
213            }
214        }
215        /// Converts a `EventButtonState` into a `WebEventKind`.
216        pub const fn to_js_as_pointer(self) -> WebEventKind {
217            use {WebEventKind as J, EventButtonState as E};
218            match self {
219                E::Pressed => J::PointerDown,
220                E::Released => J::PointerUp,
221                E::Moved => J::PointerMove,
222            }
223        }
224    }
225}
226
227#[cfg(test)]
228mod tests {
229    use super::*;
230
231    #[test] #[rustfmt::skip]
232    fn sizes_of() {
233        assert_eq![16, size_of::<EventMouse>()];        // 128
234        assert_eq![02, size_of::<EventButton>()];       // 16
235        assert_eq![01, size_of::<EventButtonState>()];  // 8
236        assert_eq![36, size_of::<EventPointer>()];      // 288
237        assert_eq![01, size_of::<EventPointerType>()];  // 8
238        // assert_eq![01, size_of::<EventPointerPhase>()]; // 8
239        assert_eq![20, size_of::<EventWheel>()];        // 160
240    }
241}