conrod_core/input/
state.rs

1//! Everything related to storing the state of user input.
2//!
3//! This includes the state of any buttons on either the keyboard or the mouse, as well as the
4//! position of the mouse.
5//!
6//! It also includes which widgets, if any, are capturing the keyboard and mouse.
7//!
8//! This module exists mostly to support the `input::Provider` trait.
9
10use self::mouse::Mouse;
11use super::keyboard::ModifierKey;
12use fnv;
13use position::Point;
14use utils;
15use widget;
16
17/// Holds the current state of user input.
18///
19/// This includes the state of all buttons on the keyboard and mouse, as well as the position of
20/// the mouse.
21///
22/// It also includes which widgets, if any, are capturing keyboard and mouse input.
23#[derive(Clone, Debug, PartialEq)]
24pub struct State {
25    /// Mouse position and button state.
26    pub mouse: Mouse,
27    /// All in-progress touch interactions.
28    pub touch: fnv::FnvHashMap<super::touch::Id, self::touch::Touch>,
29    /// Which widget, if any, is currently capturing the keyboard
30    pub widget_capturing_keyboard: Option<widget::Id>,
31    /// Which widget, if any, is currently capturing the mouse
32    pub widget_capturing_mouse: Option<widget::Id>,
33    /// The widget that is currently under the mouse cursor.
34    ///
35    /// If the mouse is currently over multiple widgets, this index will represent the top-most,
36    /// non-graphic-child widget.
37    pub widget_under_mouse: Option<widget::Id>,
38    /// Which modifier keys are being held down.
39    pub modifiers: ModifierKey,
40}
41
42impl State {
43    /// Returns a fresh new input state
44    pub fn new() -> State {
45        State {
46            touch: fnv::FnvHashMap::default(),
47            mouse: Mouse::new(),
48            widget_capturing_keyboard: None,
49            widget_capturing_mouse: None,
50            widget_under_mouse: None,
51            modifiers: ModifierKey::NO_MODIFIER,
52        }
53    }
54
55    /// Returns a copy of the input::State relative to the given `position::Point`
56    pub fn relative_to(mut self, xy: Point) -> State {
57        self.mouse.xy = utils::vec2_sub(self.mouse.xy, xy);
58        self.mouse.buttons = self.mouse.buttons.relative_to(xy);
59        self
60    }
61}
62
63/// Touch specific state.
64pub mod touch {
65    use position::Point;
66    use widget;
67
68    /// State stored about the start of a `Touch` interaction.
69    #[derive(Copy, Clone, Debug, PartialEq)]
70    pub struct Start {
71        /// The time at which the `Touch` began.
72        pub time: instant::Instant,
73        /// The position at which the touch began.
74        pub xy: Point,
75        /// The widget under the beginning of the touch if there was one.
76        ///
77        /// This widget captures the `Touch` input source for its duration.
78        pub widget: Option<widget::Id>,
79    }
80
81    /// All state stored for a `Touch` interaction in progress.
82    #[derive(Copy, Clone, Debug, PartialEq)]
83    pub struct Touch {
84        /// The `Start` of the touch interaction.
85        pub start: Start,
86        /// The last recorded position of the finger on the window.
87        pub xy: Point,
88        /// The widget currently being touched.
89        pub widget: Option<widget::Id>,
90    }
91}
92
93/// Mouse specific state.
94pub mod mouse {
95    use position::Point;
96    use std;
97    use widget;
98
99    #[doc(inline)]
100    pub use input::MouseButton as Button;
101
102    /// The max total number of buttons on a mouse.
103    pub const NUM_BUTTONS: usize = 9;
104
105    /// The state of the `Mouse`, including it's position and button states.
106    #[derive(Copy, Clone, Debug, PartialEq)]
107    pub struct Mouse {
108        /// A map that stores the up/down state of each button.
109        ///
110        /// If the button is down, then it stores the position of the mouse when the button was first
111        /// pressed.
112        pub buttons: ButtonMap,
113        /// The current position of the mouse.
114        pub xy: Point,
115    }
116
117    /// Whether the button is up or down.
118    #[derive(Copy, Clone, Debug, PartialEq)]
119    pub enum ButtonPosition {
120        /// The button is up (i.e. pressed).
121        Up,
122        /// The button is down and was originally pressed down at the given `Point` over the widget
123        /// at the given widget::Id.
124        Down(Point, Option<widget::Id>),
125    }
126
127    /// Stores the state of all mouse buttons.
128    ///
129    /// If the mouse button is down, it stores the position of the mouse when the button was pressed
130    #[derive(Copy, Clone, Debug, PartialEq)]
131    pub struct ButtonMap {
132        buttons: [ButtonPosition; NUM_BUTTONS],
133    }
134
135    /// An iterator yielding all pressed buttons.
136    #[derive(Clone)]
137    pub struct PressedButtons<'a> {
138        buttons: ::std::iter::Enumerate<::std::slice::Iter<'a, ButtonPosition>>,
139    }
140
141    impl Mouse {
142        /// Construct a new default `Mouse`.
143        pub fn new() -> Self {
144            Mouse {
145                buttons: ButtonMap::new(),
146                xy: [0.0, 0.0],
147            }
148        }
149    }
150
151    impl ButtonPosition {
152        /// If the mouse button is down, return a new one with position relative to the given `xy`.
153        pub fn relative_to(self, xy: Point) -> Self {
154            match self {
155                ButtonPosition::Down(pos, widget) => {
156                    ButtonPosition::Down([pos[0] - xy[0], pos[1] - xy[1]], widget)
157                }
158                button_pos => button_pos,
159            }
160        }
161
162        /// Is the `ButtonPosition` down.
163        pub fn is_down(&self) -> bool {
164            match *self {
165                ButtonPosition::Down(_, _) => true,
166                _ => false,
167            }
168        }
169
170        /// Is the `ButtonPosition` up.
171        pub fn is_up(&self) -> bool {
172            match *self {
173                ButtonPosition::Up => true,
174                _ => false,
175            }
176        }
177
178        /// Returns the position at which the button was pressed along with the widget that was
179        /// under the mouse at the time of pressing if the position is `Down`.
180        pub fn if_down(&self) -> Option<(Point, Option<widget::Id>)> {
181            match *self {
182                ButtonPosition::Down(xy, widget) => Some((xy, widget)),
183                _ => None,
184            }
185        }
186
187        /// Returns the position at which the button was pressed if it's down.
188        pub fn xy_if_down(&self) -> Option<Point> {
189            match *self {
190                ButtonPosition::Down(xy, _) => Some(xy),
191                _ => None,
192            }
193        }
194    }
195
196    impl ButtonMap {
197        /// Returns a new button map with all states set to `None`
198        pub fn new() -> Self {
199            ButtonMap {
200                buttons: [ButtonPosition::Up; NUM_BUTTONS],
201            }
202        }
203
204        /// Returns a copy of the ButtonMap relative to the given `Point`
205        pub fn relative_to(self, xy: Point) -> Self {
206            self.buttons
207                .iter()
208                .enumerate()
209                .fold(ButtonMap::new(), |mut map, (idx, button_pos)| {
210                    map.buttons[idx] = button_pos.relative_to(xy);
211                    map
212                })
213        }
214
215        /// The state of the left mouse button.
216        pub fn left(&self) -> &ButtonPosition {
217            &self[Button::Left]
218        }
219
220        /// The state of the middle mouse button.
221        pub fn middle(&self) -> &ButtonPosition {
222            &self[Button::Middle]
223        }
224
225        /// The state of the right mouse button.
226        pub fn right(&self) -> &ButtonPosition {
227            &self[Button::Right]
228        }
229
230        /// Sets the `Button` in the `Down` position.
231        pub fn press(&mut self, button: Button, xy: Point, widget: Option<widget::Id>) {
232            self.buttons[button_to_idx(button)] = ButtonPosition::Down(xy, widget);
233        }
234
235        /// Set's the `Button` in the `Up` position.
236        pub fn release(&mut self, button: Button) {
237            self.buttons[button_to_idx(button)] = ButtonPosition::Up;
238        }
239
240        /// An iterator yielding all pressed mouse buttons along with the location at which they
241        /// were originally pressed.
242        pub fn pressed(&self) -> PressedButtons {
243            PressedButtons {
244                buttons: self.buttons.iter().enumerate(),
245            }
246        }
247    }
248
249    /// Converts a `Button` to its respective index within the `ButtonMap`.
250    fn button_to_idx(button: Button) -> usize {
251        let idx: u32 = button.into();
252        idx as usize
253    }
254
255    /// Converts a `ButtonMap` index to its respective `Button`.
256    fn idx_to_button(idx: usize) -> Button {
257        (idx as u32).into()
258    }
259
260    impl std::ops::Index<Button> for ButtonMap {
261        type Output = ButtonPosition;
262        fn index(&self, button: Button) -> &Self::Output {
263            &self.buttons[button_to_idx(button)]
264        }
265    }
266
267    impl<'a> Iterator for PressedButtons<'a> {
268        type Item = (Button, Point, Option<widget::Id>);
269        fn next(&mut self) -> Option<Self::Item> {
270            while let Some((idx, button_pos)) = self.buttons.next() {
271                if let ButtonPosition::Down(xy, widget) = *button_pos {
272                    return Some((idx_to_button(idx), xy, widget));
273                }
274            }
275            None
276        }
277    }
278}
279
280#[test]
281fn pressed_next_returns_none_if_no_buttons_are_pressed() {
282    let map = mouse::ButtonMap::new();
283    let pressed = map.pressed().next();
284    assert!(pressed.is_none());
285}
286
287#[test]
288fn pressed_next_should_return_first_pressed_button() {
289    let mut map = mouse::ButtonMap::new();
290
291    map.press(mouse::Button::Right, [3.0, 3.0], None);
292    map.press(mouse::Button::X1, [5.4, 4.5], None);
293
294    let pressed = map.pressed().next();
295    assert_eq!(Some((mouse::Button::Right, [3.0, 3.0], None)), pressed);
296}
297
298#[test]
299fn button_down_should_store_the_point() {
300    let mut map = mouse::ButtonMap::new();
301    let xy = [2.0, 5.0];
302    map.press(mouse::Button::Left, xy, None);
303
304    assert_eq!(
305        mouse::ButtonPosition::Down(xy, None),
306        map[mouse::Button::Left]
307    );
308}
309
310#[test]
311fn input_state_should_be_made_relative_to_a_given_point() {
312    let mut state = State::new();
313    state.mouse.xy = [50.0, -10.0];
314    state
315        .mouse
316        .buttons
317        .press(mouse::Button::Middle, [-20.0, -10.0], None);
318
319    let relative_state = state.relative_to([20.0, 20.0]);
320    assert_eq!([30.0, -30.0], relative_state.mouse.xy);
321    assert_eq!(
322        Some([-40.0, -30.0]),
323        relative_state.mouse.buttons[mouse::Button::Middle].xy_if_down()
324    );
325}