use webcore::value::Reference;
use webcore::try_from::TryInto;
use webapi::event_target::EventTarget;
use webapi::event::{IEvent, IUiEvent, UiEvent, Event};
use webapi::events::keyboard::{ModifierKey, get_event_modifier_state};
pub trait IMouseEvent: IUiEvent {
#[inline]
fn alt_key( &self ) -> bool {
js!(
return @{self.as_ref()}.altKey;
).try_into().unwrap()
}
fn button( &self ) -> MouseButton {
match js!(
return @{self.as_ref()}.button;
).try_into().unwrap() {
0 => MouseButton::Left,
1 => MouseButton::Wheel,
2 => MouseButton::Right,
3 => MouseButton::Button4,
4 => MouseButton::Button5,
_ => unreachable!("Unexpected MouseEvent.button value"),
}
}
fn buttons( &self ) -> MouseButtonsState {
MouseButtonsState(
js!(
return @{self.as_ref()}.buttons;
).try_into().unwrap()
)
}
#[inline]
fn client_x( &self ) -> i32 {
js!(
return @{self.as_ref()}.clientX;
).try_into().unwrap()
}
#[inline]
fn client_y( &self ) -> i32 {
js!(
return @{self.as_ref()}.clientY;
).try_into().unwrap()
}
#[inline]
fn offset_x( &self ) -> f64 {
js!(
return @{self.as_ref()}.offsetX;
).try_into().unwrap()
}
#[inline]
fn offset_y( &self ) -> f64 {
js!(
return @{self.as_ref()}.offsetY;
).try_into().unwrap()
}
#[inline]
fn ctrl_key( &self ) -> bool {
js!(
return @{self.as_ref()}.ctrlKey;
).try_into().unwrap()
}
#[inline]
fn get_modifier_state( &self, key: ModifierKey ) -> bool {
get_event_modifier_state( self, key )
}
#[inline]
fn meta_key( &self ) -> bool {
js!(
return @{self.as_ref()}.metaKey;
).try_into().unwrap()
}
#[inline]
fn movement_x( &self ) -> i32 {
js!(
return @{self.as_ref()}.movementX;
).try_into().unwrap()
}
#[inline]
fn movement_y( &self ) -> i32 {
js!(
return @{self.as_ref()}.movementY;
).try_into().unwrap()
}
#[inline]
fn region( &self ) -> Option< String > {
js!(
return @{self.as_ref()}.region;
).try_into().ok()
}
#[inline]
fn related_target( &self ) -> Option< EventTarget > {
js!(
return @{self.as_ref()}.relatedTarget;
).try_into().ok()
}
#[inline]
fn screen_x( &self ) -> i32 {
js!(
return @{self.as_ref()}.screenX;
).try_into().unwrap()
}
#[inline]
fn screen_y( &self ) -> i32 {
js!(
return @{self.as_ref()}.screenY;
).try_into().unwrap()
}
#[inline]
fn shift_key( &self ) -> bool {
js!(
return @{self.as_ref()}.shiftKey;
).try_into().unwrap()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MouseButton {
Left,
Wheel,
Right,
Button4,
Button5,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct MouseButtonsState(u8);
impl MouseButtonsState {
pub fn is_down(&self, button: MouseButton) -> bool {
match button {
MouseButton::Left => self.0 & 0b1 != 0,
MouseButton::Right => self.0 & 0b10 != 0,
MouseButton::Wheel => self.0 & 0b100 != 0,
MouseButton::Button4 => self.0 & 0b1000 != 0,
MouseButton::Button5 => self.0 & 0b1_0000 != 0,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(subclass_of(Event, UiEvent))]
pub struct MouseEvent( Reference );
impl IEvent for MouseEvent {}
impl IUiEvent for MouseEvent {}
impl IMouseEvent for MouseEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(event = "click")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct ClickEvent( Reference );
impl IEvent for ClickEvent {}
impl IUiEvent for ClickEvent {}
impl IMouseEvent for ClickEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(event = "auxclick")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct AuxClickEvent( Reference );
impl IEvent for AuxClickEvent {}
impl IUiEvent for AuxClickEvent {}
impl IMouseEvent for AuxClickEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(event = "contextmenu")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct ContextMenuEvent( Reference );
impl IEvent for ContextMenuEvent {}
impl IUiEvent for ContextMenuEvent {}
impl IMouseEvent for ContextMenuEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(event = "dblclick")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct DoubleClickEvent( Reference );
impl IEvent for DoubleClickEvent {}
impl IUiEvent for DoubleClickEvent {}
impl IMouseEvent for DoubleClickEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(event = "mousedown")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct MouseDownEvent( Reference );
impl IEvent for MouseDownEvent {}
impl IUiEvent for MouseDownEvent {}
impl IMouseEvent for MouseDownEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(event = "mouseup")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct MouseUpEvent( Reference );
impl IEvent for MouseUpEvent {}
impl IUiEvent for MouseUpEvent {}
impl IMouseEvent for MouseUpEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(event = "mousemove")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct MouseMoveEvent( Reference );
impl IEvent for MouseMoveEvent {}
impl IUiEvent for MouseMoveEvent {}
impl IMouseEvent for MouseMoveEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(event = "mouseover")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct MouseOverEvent( Reference );
impl IEvent for MouseOverEvent {}
impl IUiEvent for MouseOverEvent {}
impl IMouseEvent for MouseOverEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(event = "mouseout")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct MouseOutEvent( Reference );
impl IEvent for MouseOutEvent {}
impl IUiEvent for MouseOutEvent {}
impl IMouseEvent for MouseOutEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(event = "mouseenter")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct MouseEnterEvent( Reference );
impl IEvent for MouseEnterEvent {}
impl IUiEvent for MouseEnterEvent {}
impl IMouseEvent for MouseEnterEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(event = "mouseleave")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct MouseLeaveEvent( Reference );
impl IEvent for MouseLeaveEvent {}
impl IUiEvent for MouseLeaveEvent {}
impl IMouseEvent for MouseLeaveEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MouseEvent")]
#[reference(event = "wheel")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct MouseWheelEvent( Reference );
impl IEvent for MouseWheelEvent {}
impl IUiEvent for MouseWheelEvent {}
impl IMouseEvent for MouseWheelEvent {}
impl MouseWheelEvent {
pub fn delta_x(&self) -> f64 {
js! (
return @{self}.deltaX;
).try_into().unwrap()
}
pub fn delta_y(&self) -> f64 {
js! (
return @{self}.deltaY;
).try_into().unwrap()
}
pub fn delta_z(&self) -> f64 {
js! (
return @{self}.deltaZ;
).try_into().unwrap()
}
pub fn delta_mode(&self) -> MouseWheelDeltaMode {
let mode: u32 = js! (
return @{self}.deltaMode;
).try_into().unwrap();
match mode {
0 => MouseWheelDeltaMode::Pixel,
1 => MouseWheelDeltaMode::Line,
2 => MouseWheelDeltaMode::Page,
_ => unreachable!()
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MouseWheelDeltaMode {
Pixel,
Line,
Page
}
#[cfg(all(test, feature = "web_test"))]
mod tests {
use super::*;
use webapi::event::ConcreteEvent;
#[test]
fn test_mouse_event() {
let event: MouseEvent = js!(
return new MouseEvent(
@{ClickEvent::EVENT_TYPE},
{
altKey: false,
button: 2,
buttons: 6,
clientX: 3,
clientY: 4,
ctrlKey: true,
metaKey: false,
screenX: 1,
screenY: 2,
shiftKey: true
}
);
).try_into().unwrap();
assert_eq!( event.event_type(), ClickEvent::EVENT_TYPE );
assert_eq!( event.alt_key(), false );
assert_eq!( event.button(), MouseButton::Right );
assert!( !event.buttons().is_down( MouseButton::Left ) );
assert!( event.buttons().is_down( MouseButton::Right ) );
assert!( event.buttons().is_down( MouseButton::Wheel ) );
assert_eq!( event.client_x(), 3 );
assert_eq!( event.client_y(), 4 );
assert!( event.ctrl_key() );
assert!( !event.get_modifier_state( ModifierKey::Alt ) );
assert!( event.get_modifier_state( ModifierKey::Ctrl ) );
assert!( event.get_modifier_state( ModifierKey::Shift ) );
assert!( !event.meta_key() );
assert_eq!( event.movement_x(), 0 );
assert_eq!( event.movement_y(), 0 );
assert!( event.region().is_none() );
assert!( event.related_target().is_none() );
assert_eq!( event.screen_x(), 1 );
assert_eq!( event.screen_y(), 2 );
assert!( event.shift_key() );
}
#[test]
fn test_click_event() {
let event: ClickEvent = js!(
return new MouseEvent( @{ClickEvent::EVENT_TYPE} );
).try_into().unwrap();
assert_eq!( event.event_type(), ClickEvent::EVENT_TYPE );
}
#[test]
fn test_aux_click_event() {
let event: AuxClickEvent = js!(
return new MouseEvent( @{AuxClickEvent::EVENT_TYPE} );
).try_into()
.unwrap();
assert_eq!( event.event_type(), AuxClickEvent::EVENT_TYPE );
}
#[test]
fn test_context_menu_event() {
let event: ContextMenuEvent = js!(
return new MouseEvent( @{ContextMenuEvent::EVENT_TYPE} );
).try_into().unwrap();
assert_eq!( event.event_type(), ContextMenuEvent::EVENT_TYPE );
}
#[test]
fn test_double_click_event() {
let event: DoubleClickEvent = js!(
return new MouseEvent( @{DoubleClickEvent::EVENT_TYPE} );
).try_into().unwrap();
assert_eq!( event.event_type(), DoubleClickEvent::EVENT_TYPE );
}
#[test]
fn test_mouse_down_event() {
let event: MouseDownEvent = js!(
return new MouseEvent( @{MouseDownEvent::EVENT_TYPE} );
).try_into().unwrap();
assert_eq!( event.event_type(), MouseDownEvent::EVENT_TYPE );
}
#[test]
fn test_mouse_up_event() {
let event: MouseUpEvent = js!(
return new MouseEvent( @{MouseUpEvent::EVENT_TYPE} );
).try_into().unwrap();
assert_eq!( event.event_type(), MouseUpEvent::EVENT_TYPE );
}
#[test]
fn test_mouse_move_event() {
let event: MouseMoveEvent = js!(
return new MouseEvent( @{MouseMoveEvent::EVENT_TYPE} );
).try_into().unwrap();
assert_eq!( event.event_type(), MouseMoveEvent::EVENT_TYPE );
}
#[test]
fn test_mouse_over_event() {
let event: MouseOverEvent = js!(
return new MouseEvent( @{MouseOverEvent::EVENT_TYPE} );
).try_into().unwrap();
assert_eq!( event.event_type(), MouseOverEvent::EVENT_TYPE );
}
#[test]
fn test_mouse_out_event() {
let event: MouseOutEvent = js!(
return new MouseEvent( @{MouseOutEvent::EVENT_TYPE} );
).try_into().unwrap();
assert_eq!( event.event_type(), MouseOutEvent::EVENT_TYPE );
}
#[test]
fn test_mouse_enter_event() {
let event: MouseEnterEvent = js!(
return new MouseEvent( @{MouseEnterEvent::EVENT_TYPE} );
).try_into()
.unwrap();
assert_eq!( event.event_type(), MouseEnterEvent::EVENT_TYPE );
}
#[test]
fn test_mouse_leave_event() {
let event: MouseLeaveEvent = js!(
return new MouseEvent( @{MouseLeaveEvent::EVENT_TYPE} );
).try_into()
.unwrap();
assert_eq!( event.event_type(), MouseLeaveEvent::EVENT_TYPE );
}
#[test]
fn test_mouse_wheel_event() {
let event: MouseWheelEvent = js!(
return new MouseEvent( @{MouseWheelEvent::EVENT_TYPE} );
).try_into()
.unwrap();
assert_eq!( event.event_type(), MouseWheelEvent::EVENT_TYPE );
}
}