use std::intrinsics::{ get_tydesc, TypeId };
use std::fmt::Show;
use input::{
Button,
Input,
Motion,
};
use {
FocusEvent,
MouseCursorEvent,
MouseRelativeEvent,
MouseScrollEvent,
PressEvent,
ReleaseEvent,
ResizeEvent,
TextEvent,
};
use ptr::Ptr;
pub trait GenericEvent {
fn from_event(event_trait_id: TypeId, args: &Ptr) -> Option<Self>;
fn with_event<U>(&self, event_trait_id: TypeId, f: |&Ptr| -> U) -> Option<U>;
}
pub fn assert_event_trait<
E: GenericEvent + PartialEq + Show,
T: 'static
>(e: &E) {
let name = unsafe { (*get_tydesc::<T>()).name };
let id = TypeId::of::<T>();
let mut tested_equal = false;
e.with_event(id, |ev| {
let new_e: E = GenericEvent::from_event(id, ev).expect(
format!(
"Could not construct event of event trait '{}' from '{}'",
name, e
).as_slice()
);
assert_eq!(*e, new_e);
tested_equal = true;
});
if !tested_equal {
panic!("Expected event trait '{}', found '{}'", name, e);
}
}
impl GenericEvent for Input {
#[inline(always)]
fn from_event(event_trait_id: TypeId, args: &Ptr) -> Option<Input> {
let press = TypeId::of::<Box<PressEvent>>();
let release = TypeId::of::<Box<ReleaseEvent>>();
let mouse_cursor = TypeId::of::<Box<MouseCursorEvent>>();
let mouse_relative = TypeId::of::<Box<MouseRelativeEvent>>();
let mouse_scroll = TypeId::of::<Box<MouseScrollEvent>>();
let text = TypeId::of::<Box<TextEvent>>();
let resize = TypeId::of::<Box<ResizeEvent>>();
let focus = TypeId::of::<Box<FocusEvent>>();
match event_trait_id {
x if x == press => {
Some(Input::Press(*args.expect::<Button>()))
}
x if x == release => {
Some(Input::Release(*args.expect::<Button>()))
}
x if x == mouse_cursor => {
let &(x, y) = args.expect::<(f64, f64)>();
Some(Input::Move(Motion::MouseCursor(x, y)))
}
x if x == mouse_relative => {
let &(x, y) = args.expect::<(f64, f64)>();
Some(Input::Move(Motion::MouseRelative(x, y)))
}
x if x == mouse_scroll => {
let &(x, y) = args.expect::<(f64, f64)>();
Some(Input::Move(Motion::MouseScroll(x, y)))
}
x if x == text => {
let text = args.expect_str();
Some(Input::Text(text.to_string()))
}
x if x == resize => {
let &(w, h) = args.expect::<(u32, u32)>();
Some(Input::Resize(w, h))
}
x if x == focus => {
Some(Input::Focus(*args.expect::<bool>()))
}
_ => None
}
}
#[inline(always)]
fn with_event<U>(&self, event_trait_id: TypeId, f: |&Ptr| -> U) -> Option<U> {
let press = TypeId::of::<Box<PressEvent>>();
let release = TypeId::of::<Box<ReleaseEvent>>();
let mouse_cursor = TypeId::of::<Box<MouseCursorEvent>>();
let mouse_relative = TypeId::of::<Box<MouseRelativeEvent>>();
let mouse_scroll = TypeId::of::<Box<MouseScrollEvent>>();
let text = TypeId::of::<Box<TextEvent>>();
let resize = TypeId::of::<Box<ResizeEvent>>();
let focus = TypeId::of::<Box<FocusEvent>>();
match event_trait_id {
x if x == press => {
match *self {
Input::Press(ref button) =>
Some(Ptr::with_ref(button, f)),
_ => None
}
}
x if x == release => {
match *self {
Input::Release(ref button) =>
Some(Ptr::with_ref(button, f)),
_ => None
}
}
x if x == mouse_cursor => {
match *self {
Input::Move(Motion::MouseCursor(x, y)) =>
Some(Ptr::with_ref(&(x, y), f)),
_ => None
}
}
x if x == mouse_relative => {
match *self {
Input::Move(Motion::MouseRelative(x, y)) =>
Some(Ptr::with_ref(&(x, y), f)),
_ => None
}
}
x if x == mouse_scroll => {
match *self {
Input::Move(Motion::MouseScroll(x, y)) =>
Some(Ptr::with_ref(&(x, y), f)),
_ => None
}
}
x if x == text => {
match *self {
Input::Text(ref text) =>
Some(Ptr::with_str(text.as_slice(), f)),
_ => None
}
}
x if x == resize => {
match *self {
Input::Resize(w, h) =>
Some(Ptr::with_ref(&(w, h), f)),
_ => None
}
}
x if x == focus => {
match *self {
Input::Focus(focused) =>
Some(Ptr::with_ref(&focused, f)),
_ => None
}
}
_ => None
}
}
}
#[test]
fn test_input_event() {
use input::Button::Keyboard;
use input::Key;
let ref e = PressEvent::from_button(Keyboard(Key::A)).unwrap();
assert_event_trait::<Input, Box<PressEvent>>(e);
let ref e = ReleaseEvent::from_button(Keyboard(Key::B)).unwrap();
assert_event_trait::<Input, Box<ReleaseEvent>>(e);
let ref e = MouseCursorEvent::from_xy(1.0, 0.0).unwrap();
assert_event_trait::<Input, Box<MouseCursorEvent>>(e);
let ref e = MouseRelativeEvent::from_xy(0.0, 1.0).unwrap();
assert_event_trait::<Input, Box<MouseRelativeEvent>>(e);
let ref e = MouseScrollEvent::from_xy(-1.0, 0.0).unwrap();
assert_event_trait::<Input, Box<MouseScrollEvent>>(e);
let ref e = TextEvent::from_text("hello").unwrap();
assert_event_trait::<Input, Box<TextEvent>>(e);
let ref e = ResizeEvent::from_width_height(30, 33).unwrap();
assert_event_trait::<Input, Box<ResizeEvent>>(e);
let ref e = FocusEvent::from_focused(true).unwrap();
assert_event_trait::<Input, Box<FocusEvent>>(e);
}