input/
mouse.rs

1//! Back-end agnostic mouse buttons.
2
3use crate::{Event, Input, Motion};
4
5/// Represent a mouse button.
6#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Ord, PartialOrd, Hash, Debug)]
7pub enum MouseButton {
8    /// Unknown mouse button.
9    Unknown,
10    /// Left mouse button.
11    Left,
12    /// Right mouse button.
13    Right,
14    /// Middle mouse button.
15    Middle,
16    /// Extra mouse button number 1.
17    X1,
18    /// Extra mouse button number 2.
19    X2,
20    /// Mouse button number 6.
21    Button6,
22    /// Mouse button number 7.
23    Button7,
24    /// Mouse button number 8.
25    Button8,
26}
27
28impl From<u32> for MouseButton {
29    fn from(n: u32) -> MouseButton {
30        match n {
31            0 => MouseButton::Unknown,
32            1 => MouseButton::Left,
33            2 => MouseButton::Right,
34            3 => MouseButton::Middle,
35            4 => MouseButton::X1,
36            5 => MouseButton::X2,
37            6 => MouseButton::Button6,
38            7 => MouseButton::Button7,
39            8 => MouseButton::Button8,
40            _ => MouseButton::Unknown,
41        }
42    }
43}
44
45impl From<MouseButton> for u32 {
46    fn from(button: MouseButton) -> u32 {
47        match button {
48            MouseButton::Unknown => 0,
49            MouseButton::Left => 1,
50            MouseButton::Right => 2,
51            MouseButton::Middle => 3,
52            MouseButton::X1 => 4,
53            MouseButton::X2 => 5,
54            MouseButton::Button6 => 6,
55            MouseButton::Button7 => 7,
56            MouseButton::Button8 => 8,
57        }
58    }
59}
60
61#[cfg(test)]
62mod mouse_button_tests {
63    use super::*;
64
65    #[test]
66    fn test_mouse_button_primitives() {
67        for i in 0u32..9 {
68            let button: MouseButton = i.into();
69            let j: u32 = button.into();
70            assert_eq!(i, j);
71        }
72    }
73}
74
75/// The position of the mouse cursor.
76pub trait MouseCursorEvent: Sized {
77    /// Creates a mouse cursor event.
78    ///
79    /// Preserves time stamp from original input event, if any.
80    fn from_pos(pos: [f64; 2], old_event: &Self) -> Option<Self>;
81    /// Calls closure if this is a mouse cursor event.
82    fn mouse_cursor<U, F>(&self, f: F) -> Option<U>
83    where
84        F: FnMut([f64; 2]) -> U;
85    /// Returns mouse cursor arguments.
86    fn mouse_cursor_args(&self) -> Option<[f64; 2]> {
87        self.mouse_cursor(|pos| pos)
88    }
89}
90
91impl MouseCursorEvent for Event {
92    fn from_pos(pos: [f64; 2], old_event: &Self) -> Option<Self> {
93        let timestamp = if let Event::Input(_, x) = old_event {
94            *x
95        } else {
96            None
97        };
98        Some(Event::Input(
99            Input::Move(Motion::MouseCursor(pos)),
100            timestamp,
101        ))
102    }
103
104    fn mouse_cursor<U, F>(&self, mut f: F) -> Option<U>
105    where
106        F: FnMut([f64; 2]) -> U,
107    {
108        match *self {
109            Event::Input(Input::Move(Motion::MouseCursor(pos)), _) => Some(f(pos)),
110            _ => None,
111        }
112    }
113}
114
115/// The relative movement of mouse cursor.
116///
117/// These events might be emitted even the cursor is captured by the window.
118pub trait MouseRelativeEvent: Sized {
119    /// Creates a mouse relative event.
120    ///
121    /// Preserves time stamp from original input event, if any.
122    fn from_pos(x: [f64; 2], old_event: &Self) -> Option<Self>;
123    /// Calls closure if this is a mouse relative event.
124    fn mouse_relative<U, F>(&self, f: F) -> Option<U>
125    where
126        F: FnMut([f64; 2]) -> U;
127    /// Returns mouse relative arguments.
128    fn mouse_relative_args(&self) -> Option<[f64; 2]> {
129        self.mouse_relative(|pos| pos)
130    }
131}
132
133impl MouseRelativeEvent for Event {
134    fn from_pos(pos: [f64; 2], old_event: &Self) -> Option<Self> {
135        let timestamp = if let Event::Input(_, x) = old_event {
136            *x
137        } else {
138            None
139        };
140        Some(Event::Input(
141            Input::Move(Motion::MouseRelative(pos)),
142            timestamp,
143        ))
144    }
145
146    fn mouse_relative<U, F>(&self, mut f: F) -> Option<U>
147    where
148        F: FnMut([f64; 2]) -> U,
149    {
150        match *self {
151            Event::Input(Input::Move(Motion::MouseRelative(pos)), _) => Some(f(pos)),
152            _ => None,
153        }
154    }
155}
156
157/// The scroll of the mouse wheel.
158pub trait MouseScrollEvent: Sized {
159    /// Creates a mouse scroll event.
160    ///
161    /// Preserves time stamp from original input event, if any.
162    fn from_pos(pos: [f64; 2], old_event: &Self) -> Option<Self>;
163    /// Calls a closure if this is a mouse scroll event.
164    fn mouse_scroll<U, F>(&self, f: F) -> Option<U>
165    where
166        F: FnMut([f64; 2]) -> U;
167    /// Returns mouse scroll arguments.
168    fn mouse_scroll_args(&self) -> Option<[f64; 2]> {
169        self.mouse_scroll(|pos| pos)
170    }
171}
172
173impl MouseScrollEvent for Event {
174    fn from_pos(pos: [f64; 2], old_event: &Self) -> Option<Self> {
175        let timestamp = if let Event::Input(_, x) = old_event {
176            *x
177        } else {
178            None
179        };
180        Some(Event::Input(
181            Input::Move(Motion::MouseScroll(pos)),
182            timestamp,
183        ))
184    }
185
186    fn mouse_scroll<U, F>(&self, mut f: F) -> Option<U>
187    where
188        F: FnMut([f64; 2]) -> U,
189    {
190        match *self {
191            Event::Input(Input::Move(Motion::MouseScroll(pos)), _) => Some(f(pos)),
192            _ => None,
193        }
194    }
195}
196
197#[cfg(test)]
198mod mouse_event_tests {
199    use super::*;
200
201    #[test]
202    fn test_input_mouse_cursor() {
203        use super::super::Motion;
204
205        let e: Event = Motion::MouseCursor([0.0, 0.0]).into();
206        let a: Option<Event> = MouseCursorEvent::from_pos([1.0, 0.0], &e);
207        let b: Option<Event> = a
208            .clone()
209            .unwrap()
210            .mouse_cursor(|pos| MouseCursorEvent::from_pos(pos, a.as_ref().unwrap()))
211            .unwrap();
212        assert_eq!(a, b);
213    }
214
215    #[test]
216    fn test_input_mouse_relative() {
217        use super::super::Motion;
218
219        let e: Event = Motion::MouseRelative([0.0, 0.0]).into();
220        let a: Option<Event> = MouseRelativeEvent::from_pos([1.0, 0.0], &e);
221        let b: Option<Event> = a
222            .clone()
223            .unwrap()
224            .mouse_relative(|pos| MouseRelativeEvent::from_pos(pos, a.as_ref().unwrap()))
225            .unwrap();
226        assert_eq!(a, b);
227    }
228
229    #[test]
230    fn test_input_mouse_scroll() {
231        use super::super::Motion;
232
233        let e: Event = Motion::MouseScroll([0.0, 0.0]).into();
234        let a: Option<Event> = MouseScrollEvent::from_pos([1.0, 0.0], &e);
235        let b: Option<Event> = a
236            .clone()
237            .unwrap()
238            .mouse_scroll(|pos| MouseScrollEvent::from_pos(pos, a.as_ref().unwrap()))
239            .unwrap();
240        assert_eq!(a, b);
241    }
242}