use position::Point;
use self::mouse::Mouse;
use fnv;
use super::keyboard::ModifierKey;
use utils;
use widget;
#[derive(Clone, Debug, PartialEq)]
pub struct State {
pub mouse: Mouse,
pub touch: fnv::FnvHashMap<super::touch::Id, self::touch::Touch>,
pub widget_capturing_keyboard: Option<widget::Id>,
pub widget_capturing_mouse: Option<widget::Id>,
pub widget_under_mouse: Option<widget::Id>,
pub modifiers: ModifierKey,
}
impl State {
pub fn new() -> State {
State{
touch: fnv::FnvHashMap::default(),
mouse: Mouse::new(),
widget_capturing_keyboard: None,
widget_capturing_mouse: None,
widget_under_mouse: None,
modifiers: ModifierKey::NO_MODIFIER,
}
}
pub fn relative_to(mut self, xy: Point) -> State {
self.mouse.xy = utils::vec2_sub(self.mouse.xy, xy);
self.mouse.buttons = self.mouse.buttons.relative_to(xy);
self
}
}
pub mod touch {
use position::Point;
use widget;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Start {
pub time: instant::Instant,
pub xy: Point,
pub widget: Option<widget::Id>,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Touch {
pub start: Start,
pub xy: Point,
pub widget: Option<widget::Id>,
}
}
pub mod mouse {
use position::Point;
use std;
use widget;
#[doc(inline)]
pub use input::MouseButton as Button;
pub const NUM_BUTTONS: usize = 9;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Mouse {
pub buttons: ButtonMap,
pub xy: Point,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ButtonPosition {
Up,
Down(Point, Option<widget::Id>),
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct ButtonMap {
buttons: [ButtonPosition; NUM_BUTTONS]
}
#[derive(Clone)]
pub struct PressedButtons<'a> {
buttons: ::std::iter::Enumerate<::std::slice::Iter<'a, ButtonPosition>>,
}
impl Mouse {
pub fn new() -> Self {
Mouse {
buttons: ButtonMap::new(),
xy: [0.0, 0.0],
}
}
}
impl ButtonPosition {
pub fn relative_to(self, xy: Point) -> Self {
match self {
ButtonPosition::Down(pos, widget) =>
ButtonPosition::Down([pos[0] - xy[0], pos[1] - xy[1]], widget),
button_pos => button_pos,
}
}
pub fn is_down(&self) -> bool {
match *self {
ButtonPosition::Down(_, _) => true,
_ => false,
}
}
pub fn is_up(&self) -> bool {
match *self {
ButtonPosition::Up => true,
_ => false,
}
}
pub fn if_down(&self) -> Option<(Point, Option<widget::Id>)> {
match *self {
ButtonPosition::Down(xy, widget) => Some((xy, widget)),
_ => None,
}
}
pub fn xy_if_down(&self) -> Option<Point> {
match *self {
ButtonPosition::Down(xy, _) => Some(xy),
_ => None,
}
}
}
impl ButtonMap {
pub fn new() -> Self {
ButtonMap{
buttons: [ButtonPosition::Up; NUM_BUTTONS]
}
}
pub fn relative_to(self, xy: Point) -> Self {
self.buttons.iter().enumerate().fold(ButtonMap::new(), |mut map, (idx, button_pos)| {
map.buttons[idx] = button_pos.relative_to(xy);
map
})
}
pub fn left(&self) -> &ButtonPosition {
&self[Button::Left]
}
pub fn middle(&self) -> &ButtonPosition {
&self[Button::Middle]
}
pub fn right(&self) -> &ButtonPosition {
&self[Button::Right]
}
pub fn press(&mut self, button: Button, xy: Point, widget: Option<widget::Id>) {
self.buttons[button_to_idx(button)] = ButtonPosition::Down(xy, widget);
}
pub fn release(&mut self, button: Button) {
self.buttons[button_to_idx(button)] = ButtonPosition::Up;
}
pub fn pressed(&self) -> PressedButtons {
PressedButtons { buttons: self.buttons.iter().enumerate() }
}
}
fn button_to_idx(button: Button) -> usize {
let idx: u32 = button.into();
idx as usize
}
fn idx_to_button(idx: usize) -> Button {
(idx as u32).into()
}
impl std::ops::Index<Button> for ButtonMap {
type Output = ButtonPosition;
fn index(&self, button: Button) -> &Self::Output {
&self.buttons[button_to_idx(button)]
}
}
impl<'a> Iterator for PressedButtons<'a> {
type Item = (Button, Point, Option<widget::Id>);
fn next(&mut self) -> Option<Self::Item> {
while let Some((idx, button_pos)) = self.buttons.next() {
if let ButtonPosition::Down(xy, widget) = *button_pos {
return Some((idx_to_button(idx), xy, widget));
}
}
None
}
}
}
#[test]
fn pressed_next_returns_none_if_no_buttons_are_pressed() {
let map = mouse::ButtonMap::new();
let pressed = map.pressed().next();
assert!(pressed.is_none());
}
#[test]
fn pressed_next_should_return_first_pressed_button() {
let mut map = mouse::ButtonMap::new();
map.press(mouse::Button::Right, [3.0, 3.0], None);
map.press(mouse::Button::X1, [5.4, 4.5], None);
let pressed = map.pressed().next();
assert_eq!(Some((mouse::Button::Right, [3.0, 3.0], None)), pressed);
}
#[test]
fn button_down_should_store_the_point() {
let mut map = mouse::ButtonMap::new();
let xy = [2.0, 5.0];
map.press(mouse::Button::Left, xy, None);
assert_eq!(mouse::ButtonPosition::Down(xy, None), map[mouse::Button::Left]);
}
#[test]
fn input_state_should_be_made_relative_to_a_given_point() {
let mut state = State::new();
state.mouse.xy = [50.0, -10.0];
state.mouse.buttons.press(mouse::Button::Middle, [-20.0, -10.0], None);
let relative_state = state.relative_to([20.0, 20.0]);
assert_eq!([30.0, -30.0], relative_state.mouse.xy);
assert_eq!(Some([-40.0, -30.0]), relative_state.mouse.buttons[mouse::Button::Middle].xy_if_down());
}