Skip to main content

rosin_core/
pointer.rs

1//! Pointer input types used by the event system.
2
3use keyboard_types::Modifiers;
4use kurbo::{Point, Vec2};
5
6/// Identifies a specific button on a pointer device.
7#[repr(u8)]
8#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
9pub enum PointerButton {
10    #[default]
11    None = 0,
12
13    /// The primary pointer button, usually the left mouse button.
14    Primary = 1,
15
16    /// The secondary pointer button, usually the right mouse button.
17    Secondary = 2,
18
19    /// The auxiliary pointer button, usually the wheel or middle mouse button.
20    Auxiliary = 3,
21
22    /// The fourth pointer button, usually the back button.
23    X1 = 4,
24
25    /// The fifth pointer button, usually the forward button.
26    X2 = 5,
27}
28
29impl From<isize> for PointerButton {
30    fn from(value: isize) -> Self {
31        match value {
32            0 => PointerButton::None,
33            1 => PointerButton::Primary,
34            2 => PointerButton::Secondary,
35            3 => PointerButton::Auxiliary,
36            4 => PointerButton::X1,
37            5 => PointerButton::X2,
38            _ => PointerButton::None,
39        }
40    }
41}
42
43impl PointerButton {
44    /// Returns `true` if this is [`PointerButton::Primary`].
45    #[inline]
46    pub fn is_primary(self) -> bool {
47        self == PointerButton::Primary
48    }
49
50    /// Returns `true` if this is [`PointerButton::Secondary`].
51    #[inline]
52    pub fn is_secondary(self) -> bool {
53        self == PointerButton::Secondary
54    }
55
56    /// Returns `true` if this is [`PointerButton::Auxiliary`].
57    #[inline]
58    pub fn is_auxiliary(self) -> bool {
59        self == PointerButton::Auxiliary
60    }
61
62    /// Returns `true` if this is [`PointerButton::X1`].
63    #[inline]
64    pub fn is_x1(self) -> bool {
65        self == PointerButton::X1
66    }
67
68    /// Returns `true` if this is [`PointerButton::X2`].
69    #[inline]
70    pub fn is_x2(self) -> bool {
71        self == PointerButton::X2
72    }
73}
74
75/// A set of pressed pointer buttons.
76#[derive(PartialEq, Eq, Clone, Copy, Default)]
77pub struct PointerButtons(u8);
78
79impl PointerButtons {
80    /// Creates an empty set of buttons.
81    #[inline]
82    pub fn empty() -> PointerButtons {
83        PointerButtons(0)
84    }
85
86    #[inline]
87    fn mask(button: PointerButton) -> u8 {
88        match button {
89            PointerButton::None => 0,
90            _ => 1u8 << ((button as u8) - 1),
91        }
92    }
93
94    /// Adds a button to the set.
95    #[inline]
96    pub fn insert(&mut self, button: PointerButton) {
97        self.0 |= Self::mask(button);
98    }
99
100    /// Adds multiple buttons to the set.
101    #[inline]
102    pub fn insert_all(&mut self, buttons: PointerButtons) {
103        self.0 |= buttons.0;
104    }
105
106    /// Removes a button from the set.
107    #[inline]
108    pub fn remove(&mut self, button: PointerButton) {
109        self.0 &= !Self::mask(button);
110    }
111
112    /// Removes multiple buttons from the set.
113    #[inline]
114    pub fn remove_all(&mut self, buttons: PointerButtons) {
115        self.0 &= !buttons.0;
116    }
117
118    /// Returns the set with a button added.
119    #[inline]
120    pub fn with(mut self, button: PointerButton) -> PointerButtons {
121        self.0 |= Self::mask(button);
122        self
123    }
124
125    /// Returns the set with a button removed.
126    #[inline]
127    pub fn without(mut self, button: PointerButton) -> PointerButtons {
128        self.0 &= !Self::mask(button);
129        self
130    }
131
132    /// Clears the set.
133    #[inline]
134    pub fn clear(&mut self) {
135        self.0 = 0;
136    }
137
138    /// Returns `true` if `button` is in the set.
139    #[inline]
140    pub fn contains(self, button: PointerButton) -> bool {
141        (self.0 & Self::mask(button)) != 0
142    }
143
144    /// Returns `true` if the set is empty.
145    #[inline]
146    pub fn is_empty(self) -> bool {
147        self.0 == 0
148    }
149
150    /// Returns `true` if all `buttons` are in the set.
151    #[inline]
152    pub fn is_superset(self, buttons: PointerButtons) -> bool {
153        self.0 & buttons.0 == buttons.0
154    }
155
156    /// Returns `true` if [`PointerButton::Primary`] is in the set.
157    #[inline]
158    pub fn has_primary(self) -> bool {
159        self.contains(PointerButton::Primary)
160    }
161
162    /// Returns `true` if [`PointerButton::Secondary`] is in the set.
163    #[inline]
164    pub fn has_secondary(self) -> bool {
165        self.contains(PointerButton::Secondary)
166    }
167
168    /// Returns `true` if [`PointerButton::Auxiliary`] is in the set.
169    #[inline]
170    pub fn has_auxiliary(self) -> bool {
171        self.contains(PointerButton::Auxiliary)
172    }
173
174    /// Returns `true` if [`PointerButton::X1`] is in the set.
175    #[inline]
176    pub fn has_x1(self) -> bool {
177        self.contains(PointerButton::X1)
178    }
179
180    /// Returns `true` if [`PointerButton::X2`] is in the set.
181    #[inline]
182    pub fn has_x2(self) -> bool {
183        self.contains(PointerButton::X2)
184    }
185}
186
187impl From<u8> for PointerButtons {
188    fn from(value: u8) -> Self {
189        PointerButtons(value & 0b1_1111)
190    }
191}
192
193impl std::fmt::Debug for PointerButtons {
194    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
195        write!(f, "PointerButtons({:05b})", self.0)
196    }
197}
198
199/// The device type associated with a pointer event.
200#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
201pub enum PointerType {
202    #[default]
203    Mouse,
204    Pen,
205}
206
207/// Information about a pointer event.
208#[derive(Debug, Clone, Copy, Default)]
209pub struct PointerEvent {
210    /// The position of the pointer event in the viewport.
211    pub viewport_pos: Point,
212
213    /// The scroll amount.
214    pub wheel_delta: Vec2,
215
216    /// The button responsible for a pointer event.
217    /// This will always be [`PointerButton::None`] for an [`On::PointerMove`](crate::events::On::PointerMove) event.
218    pub button: PointerButton,
219
220    /// Pointer buttons being held down during a move or after a click event.
221    /// It will contain the button that caused an [`On::PointerDown`](crate::events::On::PointerDown) event,
222    /// but it will not contain the button that caused an [`On::PointerUp`](crate::events::On::PointerUp) event.
223    pub buttons: PointerButtons,
224
225    /// Keyboard modifier keys pressed at the time of the event.
226    pub mods: Modifiers,
227
228    /// The number of clicks associated with this event.
229    /// This will always be 0 for [`On::PointerUp`](crate::events::On::PointerUp) and [`On::PointerMove`](crate::events::On::PointerMove) events.
230    pub count: u8,
231
232    /// This is set to `true` if the pointer event caused the window to gain focus.
233    pub did_focus_window: bool,
234
235    /// The normalized pressure of the pointer input in the range 0 to 1, where 0 and 1 represent
236    /// the minimum and maximum pressure the hardware is capable of detecting, respectively.
237    pub pressure: f32,
238
239    /// The normalized tangential pressure of the pointer input
240    /// in the range -1 to 1, where 0 is the neutral position of the control.
241    pub tangential_pressure: f32,
242
243    /// The tilt of the pen in the X and Y axis, from -1 to 1.
244    pub tilt: Vec2,
245
246    /// The clockwise rotation of the pen stylus around
247    /// its major axis in degrees, with a value in the range 0 to 359.
248    pub twist: f32,
249
250    /// Indicates the device type that caused the event.
251    pub pointer_type: PointerType,
252}
253
254impl PointerEvent {
255    #[inline]
256    pub(crate) fn synthetic_move(viewport_pos: Point) -> Self {
257        Self {
258            viewport_pos,
259            button: PointerButton::None,
260            buttons: PointerButtons::empty(),
261            count: 0,
262            ..Self::default()
263        }
264    }
265
266    #[inline]
267    pub(crate) fn synthetic_primary_down(viewport_pos: Point, click_count: u8) -> Self {
268        let buttons = PointerButtons::empty().with(PointerButton::Primary);
269        Self {
270            viewport_pos,
271            button: PointerButton::Primary,
272            buttons,
273            count: click_count.max(1),
274            pressure: 1.0,
275            ..Self::default()
276        }
277    }
278
279    #[inline]
280    pub(crate) fn synthetic_primary_up(viewport_pos: Point) -> Self {
281        Self {
282            viewport_pos,
283            button: PointerButton::Primary,
284            buttons: PointerButtons::empty(),
285            count: 0,
286            pressure: 0.0,
287            ..Self::default()
288        }
289    }
290}