Skip to main content

ferroui_base/input/
pointer_point.rs

1use super::raw::RawPointerPoint;
2use super::{IPointer, MouseButton, RawInputModifiers};
3use crate::{Point, Rect};
4use std::rc::Rc;
5
6/// Provides basic properties for the input pointer associated with a single
7/// mouse, pen/stylus, or touch contact.
8#[derive(Clone)]
9pub struct PointerPoint {
10    /// The pointer associated with this point.
11    pub pointer: Rc<dyn IPointer>,
12    /// Extended information about the input pointer.
13    pub properties: PointerPointProperties,
14    /// The location of the pointer input in client coordinates.
15    pub position: Point,
16}
17
18impl PointerPoint {
19    /// Creates a pointer point.
20    pub fn new(pointer: Rc<dyn IPointer>, position: Point, properties: PointerPointProperties) -> Self {
21        Self { pointer, properties, position }
22    }
23}
24
25impl PartialEq for PointerPoint {
26    fn eq(&self, other: &Self) -> bool {
27        std::ptr::addr_eq(Rc::as_ptr(&self.pointer), Rc::as_ptr(&other.pointer))
28            && self.properties == other.properties
29            && self.position == other.position
30    }
31}
32
33/// Provides extended properties for a pointer point.
34#[derive(Clone, Copy, Debug, PartialEq)]
35pub struct PointerPointProperties {
36    /// The bounding rectangle of the contact area (typically from touch
37    /// input).
38    pub contact_rect: Rect,
39    /// Whether the pointer input was triggered by the primary action mode of
40    /// an input device.
41    pub is_left_button_pressed: bool,
42    /// Whether the pointer input was triggered by the tertiary action mode
43    /// of an input device.
44    pub is_middle_button_pressed: bool,
45    /// Whether the pointer input was triggered by the secondary action mode
46    /// (if supported) of an input device.
47    pub is_right_button_pressed: bool,
48    /// Whether the pointer input was triggered by the first extended mouse
49    /// button (XButton1).
50    pub is_x_button_1_pressed: bool,
51    /// Whether the pointer input was triggered by the second extended mouse
52    /// button (XButton2).
53    pub is_x_button_2_pressed: bool,
54    /// Whether the barrel button of the pen/stylus device is pressed.
55    pub is_barrel_button_pressed: bool,
56    /// Whether the input is from a pen eraser.
57    pub is_eraser: bool,
58    /// Whether the digitizer input is from an inverted pen.
59    pub is_inverted: bool,
60    /// The clockwise rotation in degrees of a pen device around its own
61    /// major axis (such as when the user spins the pen in their fingers).
62    /// A value between 0.0 and 359.0 in degrees of rotation; the default
63    /// value is 0.0.
64    pub twist: f32,
65    /// A value that indicates the force that the pointer device (typically
66    /// a pen/stylus) exerts on the surface of the digitizer. A value from 0
67    /// to 1.0; the default value is 0.5.
68    pub pressure: f32,
69    /// The plane angle between the Y-Z plane and the plane that contains
70    /// the Y axis and the axis of the input device (typically a
71    /// pen/stylus). The value is 0.0 when the finger or pen is
72    /// perpendicular to the digitizer surface, between 0.0 and 90.0 when
73    /// tilted to the right of perpendicular, and between 0.0 and -90.0 when
74    /// tilted to the left of perpendicular. The default value is 0.0.
75    pub x_tilt: f32,
76    /// The plane angle between the X-Z plane and the plane that contains
77    /// the X axis and the axis of the input device (typically a
78    /// pen/stylus). The value is 0.0 when the finger or pen is
79    /// perpendicular to the digitizer surface, between 0.0 and 90.0 when
80    /// tilted towards the user, and between 0.0 and -90.0 when tilted away
81    /// from the user. The default value is 0.0.
82    pub y_tilt: f32,
83    /// The kind of pointer state change.
84    pub pointer_update_kind: PointerUpdateKind,
85}
86
87impl Default for PointerPointProperties {
88    fn default() -> Self {
89        Self::NONE
90    }
91}
92
93impl PointerPointProperties {
94    /// The default properties: nothing pressed.
95    pub const NONE: PointerPointProperties = PointerPointProperties {
96        contact_rect: Rect::new(0.0, 0.0, 0.0, 0.0),
97        is_left_button_pressed: false,
98        is_middle_button_pressed: false,
99        is_right_button_pressed: false,
100        is_x_button_1_pressed: false,
101        is_x_button_2_pressed: false,
102        is_barrel_button_pressed: false,
103        is_eraser: false,
104        is_inverted: false,
105        twist: 0.0,
106        pressure: 0.5,
107        x_tilt: 0.0,
108        y_tilt: 0.0,
109        pointer_update_kind: PointerUpdateKind::LeftButtonPressed,
110    };
111
112    /// Creates properties from raw input modifiers and the kind of state
113    /// change.
114    pub fn new(modifiers: RawInputModifiers, kind: PointerUpdateKind) -> Self {
115        let mut result = Self {
116            pointer_update_kind: kind,
117            is_left_button_pressed: modifiers.contains(RawInputModifiers::LEFT_MOUSE_BUTTON),
118            is_middle_button_pressed: modifiers.contains(RawInputModifiers::MIDDLE_MOUSE_BUTTON),
119            is_right_button_pressed: modifiers.contains(RawInputModifiers::RIGHT_MOUSE_BUTTON),
120            is_x_button_1_pressed: modifiers.contains(RawInputModifiers::X_BUTTON_1_MOUSE_BUTTON),
121            is_x_button_2_pressed: modifiers.contains(RawInputModifiers::X_BUTTON_2_MOUSE_BUTTON),
122            is_inverted: modifiers.contains(RawInputModifiers::PEN_INVERTED),
123            is_eraser: modifiers.contains(RawInputModifiers::PEN_ERASER),
124            is_barrel_button_pressed: modifiers.contains(RawInputModifiers::PEN_BARREL_BUTTON),
125            ..Self::NONE
126        };
127
128        // The underlying input source might be reporting the previous state,
129        // so make sure that we reflect the current state.
130        match kind {
131            PointerUpdateKind::LeftButtonPressed => result.is_left_button_pressed = true,
132            PointerUpdateKind::LeftButtonReleased => result.is_left_button_pressed = false,
133            PointerUpdateKind::MiddleButtonPressed => result.is_middle_button_pressed = true,
134            PointerUpdateKind::MiddleButtonReleased => result.is_middle_button_pressed = false,
135            PointerUpdateKind::RightButtonPressed => result.is_right_button_pressed = true,
136            PointerUpdateKind::RightButtonReleased => result.is_right_button_pressed = false,
137            PointerUpdateKind::XButton1Pressed => result.is_x_button_1_pressed = true,
138            PointerUpdateKind::XButton1Released => result.is_x_button_1_pressed = false,
139            PointerUpdateKind::XButton2Pressed => result.is_x_button_2_pressed = true,
140            PointerUpdateKind::XButton2Released => result.is_x_button_2_pressed = false,
141            PointerUpdateKind::Other => {}
142        }
143
144        result
145    }
146
147    /// Creates properties with pen state.
148    pub fn with_pen_state(
149        modifiers: RawInputModifiers,
150        kind: PointerUpdateKind,
151        twist: f32,
152        pressure: f32,
153        x_tilt: f32,
154        y_tilt: f32,
155    ) -> Self {
156        Self::with_pen_state_and_contact_rect(modifiers, kind, twist, pressure, x_tilt, y_tilt, Rect::default())
157    }
158
159    /// Creates properties with pen state and a contact rectangle.
160    pub fn with_pen_state_and_contact_rect(
161        modifiers: RawInputModifiers,
162        kind: PointerUpdateKind,
163        twist: f32,
164        pressure: f32,
165        x_tilt: f32,
166        y_tilt: f32,
167        contact_rect: Rect,
168    ) -> Self {
169        Self { twist, pressure, x_tilt, y_tilt, contact_rect, ..Self::new(modifiers, kind) }
170    }
171
172    /// Creates properties from a raw pointer point.
173    pub fn from_raw_point(modifiers: RawInputModifiers, kind: PointerUpdateKind, raw_point: RawPointerPoint) -> Self {
174        Self::with_pen_state_and_contact_rect(
175            modifiers,
176            kind,
177            raw_point.twist,
178            raw_point.pressure,
179            raw_point.x_tilt,
180            raw_point.y_tilt,
181            raw_point.contact_rect(),
182        )
183    }
184
185    /// Creates the properties of an intermediate point: the button state of
186    /// `based_on` with the pen state of a raw pointer point.
187    pub fn based_on(based_on: PointerPointProperties, raw_point: RawPointerPoint) -> Self {
188        Self {
189            is_left_button_pressed: based_on.is_left_button_pressed,
190            is_middle_button_pressed: based_on.is_middle_button_pressed,
191            is_right_button_pressed: based_on.is_right_button_pressed,
192            is_x_button_1_pressed: based_on.is_x_button_1_pressed,
193            is_x_button_2_pressed: based_on.is_x_button_2_pressed,
194            is_inverted: based_on.is_inverted,
195            is_eraser: based_on.is_eraser,
196            is_barrel_button_pressed: based_on.is_barrel_button_pressed,
197            twist: raw_point.twist,
198            pressure: raw_point.pressure,
199            x_tilt: raw_point.x_tilt,
200            y_tilt: raw_point.y_tilt,
201            ..Self::NONE
202        }
203    }
204}
205
206/// The kind of state change of a pointer.
207#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
208pub enum PointerUpdateKind {
209    #[default]
210    LeftButtonPressed,
211    MiddleButtonPressed,
212    RightButtonPressed,
213    XButton1Pressed,
214    XButton2Pressed,
215    LeftButtonReleased,
216    MiddleButtonReleased,
217    RightButtonReleased,
218    XButton1Released,
219    XButton2Released,
220    Other,
221}
222
223impl PointerUpdateKind {
224    /// The mouse button whose state the update changed.
225    pub fn get_mouse_button(self) -> MouseButton {
226        match self {
227            PointerUpdateKind::LeftButtonPressed | PointerUpdateKind::LeftButtonReleased => MouseButton::Left,
228            PointerUpdateKind::MiddleButtonPressed | PointerUpdateKind::MiddleButtonReleased => MouseButton::Middle,
229            PointerUpdateKind::RightButtonPressed | PointerUpdateKind::RightButtonReleased => MouseButton::Right,
230            PointerUpdateKind::XButton1Pressed | PointerUpdateKind::XButton1Released => MouseButton::XButton1,
231            PointerUpdateKind::XButton2Pressed | PointerUpdateKind::XButton2Released => MouseButton::XButton2,
232            PointerUpdateKind::Other => MouseButton::None,
233        }
234    }
235}