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}