#![deny(missing_docs)]
extern crate vecmath;
extern crate input;
use std::time::Instant;
use math::{Matrix2d, Rectangle};
use input::GenericEvent;
pub mod math;
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ButtonEvent {
MouseEnter,
MouseLeave,
Press,
Click,
Cancel,
}
pub struct ButtonController {
pub mouse_cursor_inside: bool,
pub was_inside: bool,
pub pressed: bool,
pub pressed_instant: Option<Instant>,
pub events: Vec<ButtonEvent>,
}
impl ButtonController {
pub fn new() -> ButtonController {
ButtonController {
mouse_cursor_inside: false,
was_inside: false,
pressed: false,
pressed_instant: None,
events: vec![],
}
}
pub fn event<E: GenericEvent>(&mut self, layout: Rectangle, transform: Matrix2d, e: &E) {
use math::is_inside;
use input::MouseButton;
self.events.clear();
if let Some(pos) = e.mouse_cursor_args() {
let inside = is_inside(pos, transform, layout);
if inside {
if !self.mouse_cursor_inside {
self.mouse_cursor_inside = true;
self.events.push(ButtonEvent::MouseEnter);
}
} else {
if self.mouse_cursor_inside {
self.mouse_cursor_inside = false;
self.events.push(ButtonEvent::MouseLeave);
}
}
}
if let Some(input::Button::Mouse(MouseButton::Left)) = e.press_args() {
if self.mouse_cursor_inside {
self.pressed = true;
self.was_inside = true;
self.events.push(ButtonEvent::Press);
self.pressed_instant = Some(Instant::now());
}
}
if let Some(input::Button::Mouse(MouseButton::Left)) = e.release_args() {
self.pressed = false;
if self.mouse_cursor_inside {
self.events.push(ButtonEvent::Click);
} else if self.was_inside {
self.events.push(ButtonEvent::Cancel);
}
self.was_inside = false;
}
}
pub fn touch_event<E: GenericEvent, S: Into<[u32; 2]>>(&mut self,
layout: Rectangle,
transform: Matrix2d,
window_size: S,
e: &E) {
use input::Touch;
use math::is_inside;
self.events.clear();
let window_size = window_size.into();
if let Some(args) = e.touch_args() {
let pos = args.position();
let pos = [pos[0] * window_size[0] as f64, pos[1] * window_size[1] as f64];
let inside = is_inside(pos, transform, layout);
match args.touch {
Touch::Start => {
if inside {
self.pressed = true;
self.was_inside = true;
self.mouse_cursor_inside = true;
self.events.push(ButtonEvent::Press);
self.pressed_instant = Some(Instant::now());
}
}
Touch::Move => {
if inside {
if !self.mouse_cursor_inside {
self.mouse_cursor_inside = true;
self.events.push(ButtonEvent::MouseEnter);
}
} else {
if self.mouse_cursor_inside {
self.mouse_cursor_inside = false;
self.events.push(ButtonEvent::MouseLeave);
}
}
}
Touch::End => {
self.pressed = false;
if self.mouse_cursor_inside {
self.events.push(ButtonEvent::Click);
} else if self.was_inside {
self.events.push(ButtonEvent::Cancel);
}
self.was_inside = false;
self.mouse_cursor_inside = false;
}
Touch::Cancel => {}
}
}
}
pub fn appear_pressed(&self, pressed_duration_secs: f64) -> bool {
if let Some(ref instant) = self.pressed_instant {
if math::duration_to_secs(&instant.elapsed()) < pressed_duration_secs {
true
} else {
self.pressed
}
} else {
self.pressed
}
}
pub fn state(&self, pressed_duration_secs: f64) -> ButtonState {
ButtonVisual {
appear_pressed: self.appear_pressed(pressed_duration_secs),
mouse_cursor_inside: self.mouse_cursor_inside,
}.state()
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ButtonState {
Inactive,
Hover,
Press,
Cancel,
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct ButtonVisual {
pub appear_pressed: bool,
pub mouse_cursor_inside: bool,
}
impl ButtonVisual {
pub fn state(&self) -> ButtonState {
use ButtonState as S;
match (self.appear_pressed, self.mouse_cursor_inside) {
(true, true) => S::Press,
(true, false) => S::Cancel,
(false, false) => S::Inactive,
(false, true) => S::Hover,
}
}
}