use rin_math::{Pnt2, Vec2, Rect, InsideRect, vec2};
use seitan::*;
use std::path::PathBuf;
#[cfg(feature="stdweb_window")]
#[derive(Clone,Debug,PartialEq)]
pub struct WebFile {
pub data: Vec<u8>,
pub name: String,
pub mime: String,
pub last_modified: std::time::Duration,
}
#[derive(Clone,Debug,PartialEq)]
pub enum Event{
MousePressed{ pos: Pnt2<f64>, button: MouseButton, mods: KeyModifiers },
MouseReleased{ pos: Pnt2<f64>, button: MouseButton, mods: KeyModifiers },
MouseMoved{ pos: Pnt2<f64> },
Scroll{ scroll: Vec2<f64> },
KeyPressed{ key: Key, mods: KeyModifiers, repeat: bool },
KeyReleased{ key: Key },
Char{character: char},
WindowMoved{ pos: Pnt2<i32> },
WindowResized{ size: Vec2<i32> },
WindowClosing,
Dropped{paths: Vec<PathBuf>},
#[cfg(feature="stdweb_window")]
DroppedWebFile{file: WebFile},
Update{delta: f64},
FocusLost,
FocusGained,
#[cfg(target_os="android")]
Pause,
#[cfg(target_os="android")]
Stop,
#[cfg(target_os="android")]
Resume,
#[cfg(target_os="android")]
Destroy
}
#[derive(Clone,Debug,Copy,Eq,PartialEq)]
pub enum MouseButton{
Left=0,
Right,
Middle,
Button4,
Button5,
Button6,
Button7,
Button8,
Any
}
#[derive(Clone,Debug,Copy,Eq,PartialEq)]
pub enum Key{
World1,
World2,
Escape,
Enter,
Tab,
Backspace,
Insert,
Delete,
Right,
Left,
Down,
Up,
PageUp,
PageDown,
Home,
End,
CapsLock,
ScrollLock,
NumLock,
PrintScreen,
Pause,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
F17,
F18,
F19,
F20,
F21,
F22,
F23,
F24,
F25,
Kp0,
Kp1,
Kp2,
Kp3,
Kp4,
Kp5,
Kp6,
Kp7,
Kp8,
Kp9,
KpDecimal,
KpDivide,
KpMultiply,
KpSubtract,
KpAdd,
KpEnter,
KpEqual,
LeftShift,
LeftControl,
LeftAlt,
LeftSuper,
RightShift,
RightControl,
RightAlt,
RightSuper,
Menu,
Unknown,
Codepoint(char)
}
impl From<char> for Key{
fn from(c: char) -> Key{
Key::Codepoint(c)
}
}
bitflags::bitflags! {
pub struct KeyModifiers: i32 {
const NONE = 0x0000;
const SHIFT = 0x0001;
const CONTROL = 0x0002;
const ALT = 0x0004;
const SUPER = 0x0008;
}
}
#[derive(Clone,Debug,Copy,PartialEq)]
pub enum MouseEvent{
Pressed{ pos: Pnt2<f64>, button: MouseButton, mods: KeyModifiers },
Released{ pos: Pnt2<f64>, button: MouseButton, mods: KeyModifiers },
Moved{ pos: Pnt2<f64> },
Scrolled{ scroll: Vec2<f64> },
}
impl MouseEvent{
pub fn is_mouse_pressed_event(&self) -> bool {
match self {
MouseEvent::Pressed{..} => true,
_ => false,
}
}
pub fn is_mouse_released_event(&self) -> bool {
match self {
MouseEvent::Released{..} => true,
_ => false,
}
}
pub fn is_mouse_moved_event(&self) -> bool {
match self {
MouseEvent::Moved{..} => true,
_ => false,
}
}
pub fn is_mouse_scrolled_event(&self) -> bool {
match self {
MouseEvent::Scrolled{..} => true,
_ => false,
}
}
pub fn into_event(self) -> Event{
match self {
MouseEvent::Moved{pos} => Event::MouseMoved{pos},
MouseEvent::Pressed{pos, button, mods} => Event::MousePressed{pos, button, mods},
MouseEvent::Released{pos, button, mods} => Event::MouseReleased{pos, button, mods},
MouseEvent::Scrolled{scroll} => Event::Scroll{scroll}
}
}
}
#[derive(Clone,Debug,Copy,PartialEq)]
pub enum KeyEvent{
Pressed{ key: Key, mods: KeyModifiers, repeat: bool },
Released{ key: Key },
Char{ character: char }
}
impl KeyEvent{
pub fn is_key_pressed_event(&self) -> bool {
match self {
KeyEvent::Pressed{..} => true,
_ => false,
}
}
pub fn is_key_released_event(&self) -> bool {
match self {
KeyEvent::Released{..} => true,
_ => false,
}
}
pub fn is_char_event(&self) -> bool {
match self {
KeyEvent::Char{..} => true,
_ => false,
}
}
pub fn into_event(self) -> Event{
match self {
KeyEvent::Pressed{key, mods, repeat} => Event::KeyPressed{key, mods, repeat},
KeyEvent::Released{key} => Event::KeyReleased{key},
KeyEvent::Char{character} => Event::Char{character},
}
}
}
#[derive(Clone,Debug,Copy,PartialEq,Eq)]
pub enum WindowEvent{
Moved{ pos: Pnt2<i32> },
Resized{ size: Vec2<i32> },
Closing,
}
impl WindowEvent{
pub fn is_window_moved_event(&self) -> bool {
match self {
WindowEvent::Moved{..} => true,
_ => false,
}
}
pub fn is_window_resized_event(&self) -> bool {
match self {
WindowEvent::Resized{..} => true,
_ => false,
}
}
pub fn is_closing_event(&self) -> bool {
match self {
WindowEvent::Closing{..} => true,
_ => false,
}
}
pub fn into_event(self) -> Event{
match self {
WindowEvent::Moved{pos} => Event::WindowMoved{pos},
WindowEvent::Resized{size} => Event::WindowResized{size},
WindowEvent::Closing => Event::WindowClosing,
}
}
}
impl Event{
pub fn is_key_event(&self) -> bool{
match self{
&Event::KeyPressed{..} | &Event::KeyReleased{..} => true,
&Event::Char{..} => true,
_ => false,
}
}
pub fn is_key_pressed_event(&self) -> bool {
match self{
&Event::KeyPressed{..} => true,
_ => false,
}
}
pub fn is_key_released_event(&self) -> bool {
match self{
&Event::KeyReleased{..} => true,
_ => false,
}
}
pub fn is_char_event(&self) -> bool {
match self{
&Event::Char{..} => true,
_ => false,
}
}
pub fn is_mouse_event(&self) -> bool{
match self{
&Event::MousePressed{..} | &Event::MouseReleased{..} => true,
&Event::MouseMoved{..} => true,
&Event::Scroll{..} => true,
_ => false
}
}
pub fn is_mouse_pressed_event(&self) -> bool {
match self{
&Event::MousePressed{..} => true,
_ => false,
}
}
pub fn is_mouse_released_event(&self) -> bool {
match self{
&Event::MouseReleased{..} => true,
_ => false,
}
}
pub fn is_mouse_moved_event(&self) -> bool {
match self{
&Event::MouseMoved{..} => true,
_ => false,
}
}
pub fn is_scroll_event(&self) -> bool {
match self{
&Event::Scroll{..} => true,
_ => false,
}
}
pub fn is_window_event(&self) -> bool{
match self{
&Event::WindowMoved{..} => true,
&Event::WindowResized{..} => true,
&Event::WindowClosing => true,
_ => false
}
}
pub fn is_window_moved_event(&self) -> bool {
match self{
&Event::WindowMoved{..} => true,
_ => false,
}
}
pub fn is_window_resized_event(&self) -> bool {
match self{
&Event::WindowResized{..} => true,
_ => false,
}
}
pub fn is_window_closing_event(&self) -> bool {
match self{
&Event::WindowClosing{..} => true,
_ => false,
}
}
pub fn is_update_event(&self) -> bool{
match self{
&Event::Update{..} => true,
_ => false,
}
}
pub fn is_dropped_event(&self) ->bool{
match self{
&Event::Dropped{..} => true,
_ => false,
}
}
#[cfg(feature="stdweb_window")]
pub fn is_dropped_web_file_event(&self) ->bool{
match self{
&Event::DroppedWebFile{..} => true,
_ => false,
}
}
}
pub trait Events<'a>{
fn keys(self) -> Stream<'a, KeyEvent>;
fn keys_partition(self) -> (Stream<'a, KeyEvent>, Stream<'a, Event>);
fn mouse(self) -> Stream<'a, MouseEvent>;
fn mouse_partition(self) -> (Stream<'a, MouseEvent>, Stream<'a, Event>);
fn window(self) -> Stream<'a, WindowEvent>;
fn window_partition(self) -> (Stream<'a, WindowEvent>, Stream<'a, Event>);
fn update(self) -> Stream<'a, f64>;
fn update_partition(self) -> (Stream<'a, f64>, Stream<'a, Event>);
fn dropped(self) -> Stream<'a, Vec<PathBuf>>;
fn dropped_partition(self) -> (Stream<'a, Vec<PathBuf>>, Stream<'a, Event>);
#[cfg(feature = "stdweb_window")]
fn dropped_web_file(self) -> Stream<'a, WebFile>;
#[cfg(feature = "stdweb_window")]
fn dropped_web_file_partition(self) -> (Stream<'a, WebFile>, Stream<'a, Event>);
fn with_viewport(self, viewport: Property<'a, Rect<i32>>) -> Stream<'a, Event>;
}
impl<'a, S: StreamExt<'a, Event>> Events<'a> for S{
fn keys(self) -> Stream<'a, KeyEvent>{
self.filter_map(|event|
match event{
Event::KeyPressed{key,mods,repeat} => Some(KeyEvent::Pressed{key, mods, repeat}),
Event::KeyReleased{key} => Some(KeyEvent::Released{key}),
Event::Char{character} => Some(KeyEvent::Char{character}),
_ => None,
}
)
}
fn keys_partition(self) -> (Stream<'a, KeyEvent>, Stream<'a, Event>){
self.partition_map(|event|
match event{
Event::KeyPressed{key,mods,repeat} => Either::Left(KeyEvent::Pressed{key, mods, repeat}),
Event::KeyReleased{key} => Either::Left(KeyEvent::Released{key}),
Event::Char{character} => Either::Left(KeyEvent::Char{character}),
_ => Either::Right(event),
}
)
}
fn mouse(self) -> Stream<'a, MouseEvent> {
self.filter_map(|event|
match event{
Event::MousePressed{pos,button,mods} => Some(MouseEvent::Pressed{pos, button, mods}),
Event::MouseReleased{pos,button,mods} => Some(MouseEvent::Released{pos, button, mods}),
Event::MouseMoved{pos} => Some(MouseEvent::Moved{pos}),
Event::Scroll{scroll} => Some(MouseEvent::Scrolled{scroll}),
_ => None
}
)
}
fn mouse_partition(self) -> (Stream<'a, MouseEvent>, Stream<'a, Event>){
self.partition_map(|event|
match event{
Event::MousePressed{pos,button,mods}
=> Either::Left(MouseEvent::Pressed{pos, button, mods}),
Event::MouseReleased{pos,button,mods}
=> Either::Left(MouseEvent::Released{pos, button, mods}),
Event::MouseMoved{pos}
=> Either::Left(MouseEvent::Moved{pos}),
Event::Scroll{scroll}
=> Either::Left(MouseEvent::Scrolled{scroll}),
_ => Either::Right(event)
}
)
}
fn window(self) -> Stream<'a, WindowEvent>{
self.filter_map(|event|
match event{
Event::WindowMoved{pos} => Some(WindowEvent::Moved{pos}),
Event::WindowResized{size} => Some(WindowEvent::Resized{size}),
Event::WindowClosing => Some(WindowEvent::Closing),
_ => None
}
)
}
fn window_partition(self) -> (Stream<'a, WindowEvent>, Stream<'a, Event>){
self.partition_map(|event|
match event{
Event::WindowMoved{pos}
=> Either::Left(WindowEvent::Moved{pos}),
Event::WindowResized{size}
=> Either::Left(WindowEvent::Resized{size}),
Event::WindowClosing
=> Either::Left(WindowEvent::Closing),
_ => Either::Right(event)
}
)
}
fn update(self) -> Stream<'a, f64>{
self.filter_map(|event|
match event{
Event::Update{delta} => Some(delta),
_ => None,
}
)
}
fn update_partition(self) -> (Stream<'a, f64>, Stream<'a, Event>){
self.partition_map(|event|
match event{
Event::Update{delta} => Either::Left(delta),
_ => Either::Right(event),
}
)
}
fn dropped(self) -> Stream<'a, Vec<PathBuf>>{
self.filter_map(|event|
match event{
Event::Dropped{paths} => Some(paths),
_ => None,
}
)
}
fn dropped_partition(self) -> (Stream<'a, Vec<PathBuf>>, Stream<'a, Event>){
self.partition_map(|event|
match event{
Event::Dropped{paths} => Either::Left(paths),
_ => Either::Right(event),
}
)
}
#[cfg(feature = "stdweb_window")]
fn dropped_web_file(self) -> Stream<'a, WebFile>{
self.filter_map(|event|
match event{
Event::DroppedWebFile{file} => Some(file),
_ => None,
}
)
}
#[cfg(feature = "stdweb_window")]
fn dropped_web_file_partition(self) -> (Stream<'a, WebFile>, Stream<'a, Event>){
self.partition_map(|event|
match event{
Event::DroppedWebFile{file} => Either::Left(file),
_ => Either::Right(event),
}
)
}
fn with_viewport(self, viewport: Property<'a, Rect<i32>>) -> Stream<'a, Event>{
self.filter_map(move |event|{
let offset = -vec2(viewport.get().pos.x as f64, viewport.as_ref().pos.y as f64);
match event{
Event::MouseMoved{pos} => Some(Event::MouseMoved{
pos: pos + offset
}),
Event::MousePressed{pos, button, mods} => Some(Event::MousePressed{
pos: pos + offset,
button,
mods
}),
Event::MouseReleased{pos, button, mods} => Some(Event::MouseReleased {
pos: pos + offset,
button,
mods,
}),
event => Some(event),
}
})
}
}
pub trait MouseEvents<'a>{
fn pressed(self, b: MouseButton) -> Stream<'a,(Pnt2<f64>,MouseButton)>;
fn released(self, b: MouseButton) -> Stream<'a,(Pnt2<f64>,MouseButton)>;
fn pressed_with_mods(self, b: MouseButton, mods: KeyModifiers) -> Stream<'a,(Pnt2<f64>,MouseButton,KeyModifiers)>;
fn released_with_mods(self, b: MouseButton, mods: KeyModifiers) -> Stream<'a,(Pnt2<f64>,MouseButton,KeyModifiers)>;
fn pressed_and_mods(self, b: MouseButton) -> Stream<'a,(Pnt2<f64>,MouseButton,KeyModifiers)>;
fn released_and_mods(self, b: MouseButton) -> Stream<'a,(Pnt2<f64>,MouseButton,KeyModifiers)>;
fn moved(self) -> Stream<'a,Pnt2<f64>>;
fn scrolled(self) -> Stream<'a,Vec2<f64>>;
fn is_pressed(self, b: MouseButton) -> Stream<'a,bool>;
fn with_viewport(self, viewport: Property<'a, Rect<i32>>) -> Stream<'a, MouseEvent>;
}
impl<'a, S: StreamExt<'a, MouseEvent>> MouseEvents<'a> for S{
fn pressed(self, b: MouseButton) -> Stream<'a,(Pnt2<f64>,MouseButton)>{
self.filter_map(move |event|
match event{
MouseEvent::Pressed{pos, button, ..} => {
if b==button || b==MouseButton::Any {
Some((pos,button))
}else{
None
}
}
_ => None
}
)
}
fn released(self, b: MouseButton) -> Stream<'a,(Pnt2<f64>,MouseButton)>{
self.filter_map(move |event|
match event{
MouseEvent::Released{pos,button,..} => {
if b==button || b==MouseButton::Any{
Some((pos,button))
}else{
None
}
}
_ => None
}
)
}
fn pressed_with_mods(self, b: MouseButton, keymods: KeyModifiers) -> Stream<'a,(Pnt2<f64>,MouseButton,KeyModifiers)>{
self.filter_map(move |event|
match event{
MouseEvent::Pressed{pos, button, mods} => {
if (b==button || b==MouseButton::Any) && mods == keymods {
Some((pos,button,mods))
}else{
None
}
}
_ => None
}
)
}
fn released_with_mods(self, b: MouseButton, keymods: KeyModifiers) -> Stream<'a,(Pnt2<f64>,MouseButton,KeyModifiers)>{
self.filter_map(move |event|
match event{
MouseEvent::Released{pos,button,mods} => {
if (b==button || b==MouseButton::Any) && mods == keymods {
Some((pos,button,mods))
}else{
None
}
}
_ => None
}
)
}
fn pressed_and_mods(self, b: MouseButton) -> Stream<'a,(Pnt2<f64>,MouseButton,KeyModifiers)>{
self.filter_map(move |event|
match event{
MouseEvent::Pressed{pos,button,mods} => {
if b==button || b==MouseButton::Any {
Some((pos,button,mods))
}else{
None
}
}
_ => None
}
)
}
fn released_and_mods(self, b: MouseButton) -> Stream<'a,(Pnt2<f64>,MouseButton,KeyModifiers)>{
self.filter_map(move |event|
match event{
MouseEvent::Released{pos,button,mods} => {
if b==button || b==MouseButton::Any {
Some((pos,button,mods))
}else{
None
}
}
_ => None
}
)
}
fn moved(self) -> Stream<'a,Pnt2<f64>>{
self.filter_map(|event|
match event{
MouseEvent::Moved{pos} => Some(pos),
_ => None
}
)
}
fn scrolled(self) -> Stream<'a,Vec2<f64>>{
self.filter_map(|event|
match event{
MouseEvent::Scrolled{scroll} => Some(scroll),
_ => None
}
)
}
fn is_pressed(self, b: MouseButton) -> Stream<'a, bool>{
self.filter_map(move |event|
match event{
MouseEvent::Pressed{button,..} => {
if b==button || b==MouseButton::Any{
Some(true)
}else{
None
}
}
MouseEvent::Released{button,..} => {
if b==button || b==MouseButton::Any{
Some(false)
}else{
None
}
}
_ => None
}
)
}
fn with_viewport(self, viewport: Property<'a, Rect<i32>>) -> Stream<'a, MouseEvent>{
self.map(move |event|{
let offset = -vec2(viewport.get().pos.x as f64, viewport.as_ref().pos.y as f64);
match event{
MouseEvent::Moved{pos} => MouseEvent::Moved{
pos: pos + offset
},
MouseEvent::Pressed{pos, button, mods} => MouseEvent::Pressed{
pos: pos + offset,
button,
mods
},
MouseEvent::Released{pos, button, mods} => MouseEvent::Released {
pos: pos + offset,
button,
mods,
},
scrolled @ MouseEvent::Scrolled{..} => scrolled,
}
})
}
}
pub trait MouseButtonEvents<'a>{
fn over(self, area: Rect<f64>) -> Stream<'a,(Pnt2<f64>,MouseButton)>;
fn is_over(self, area: Rect<f64>) -> Stream<'a,bool>;
}
impl<'a, S: StreamExt<'a,(Pnt2<f64>,MouseButton)>> MouseButtonEvents<'a> for S {
fn over(self, area: Rect<f64>) -> Stream<'a,(Pnt2<f64>,MouseButton)>{
self.filter(move |(pos, _button)| pos.inside(&area))
}
fn is_over(self, area: Rect<f64>) -> Stream<'a,bool>{
self.map(move |(pos, _button)| pos.inside(&area))
}
}
pub trait MouseMovedEvents<'a>{
fn over(self, area: Rect<f64>) -> Stream<'a, Pnt2<f64>>;
fn is_over(self, area: Rect<f64>) -> Stream<'a,bool>;
}
impl<'a, S:StreamExt<'a,Pnt2<f64>>> MouseMovedEvents<'a> for S{
fn over(self, area: Rect<f64>) -> Stream<'a,Pnt2<f64>>{
self.filter(move |pos| pos.inside(&area))
}
fn is_over(self, area: Rect<f64>) -> Stream<'a,bool>{
self.map(move |pos| pos.inside(&area))
}
}
pub trait KeyEvents<'a>{
fn pressed<K: Into<Key>>(self, k: K) -> Stream<'a,Key>;
fn released<K: Into<Key>>(self, k: K) -> Stream<'a,Key>;
fn pressed_with_mods<K: Into<Key>>(self, k: K, modifers: KeyModifiers) -> Stream<'a,Key>;
fn pressed_any(self) -> Stream<'a,Key>;
fn released_any(self) -> Stream<'a,Key>;
fn character(self, c: char) -> Stream<'a,char>;
fn character_any(self) -> Stream<'a,char>;
fn is_pressed<K: Into<Key> + 'a>(self, k: K) -> Stream<'a, bool>;
}
impl<'a, S: StreamExt<'a,KeyEvent>> KeyEvents<'a> for S{
fn pressed<K: Into<Key>>(self, k: K) -> Stream<'a,Key>{
let k = k.into();
self.filter_map(move |event|
match event{
KeyEvent::Pressed{key, ..} => {
if k==key {
Some(key)
}else{
None
}
}
_ => None
}
)
}
fn pressed_with_mods<K: Into<Key>>(self, k: K, modifers: KeyModifiers) -> Stream<'a,Key>{
let k = k.into();
self.filter_map(move |event|
match event{
KeyEvent::Pressed{key, mods, ..} => {
if k==key && mods == modifers {
Some(key)
}else{
None
}
}
_ => None
}
)
}
fn released<K: Into<Key>>(self, k: K) -> Stream<'a,Key>{
let k = k.into();
self.filter_map(move |event|
match event{
KeyEvent::Released{key} => {
if k==key {
Some(key)
}else{
None
}
}
_ => None
}
)
}
fn pressed_any(self) -> Stream<'a,Key>{
self.filter_map(|event|
match event{
KeyEvent::Pressed{key, ..} => Some(key),
_ => None
}
)
}
fn released_any(self) -> Stream<'a,Key>{
self.filter_map(|event|
match event{
KeyEvent::Released{key} => Some(key),
_ => None
}
)
}
fn character(self, c: char) -> Stream<'a,char>{
self.filter_map(move |event|
match event{
KeyEvent::Char{character} => {
if c==character {
Some(character)
}else{
None
}
}
_ => None
}
)
}
fn character_any(self) -> Stream<'a,char>{
self.filter_map(|event|
match event{
KeyEvent::Char{character} => Some(character),
_ => None
}
)
}
fn is_pressed<K: Into<Key> + 'a>(self, k: K) -> Stream<'a, bool>{
let k = k.into();
self.filter_map(move |event|
match event{
KeyEvent::Pressed{key, ..} => {
if k == key{
Some(true)
}else{
None
}
}
KeyEvent::Released{key, ..} => {
if k == key{
Some(false)
}else{
None
}
}
_ => None
}
)
}
}
pub trait WindowEvents<'a>{
fn resized(self) -> Stream<'a,Vec2<i32>>;
fn moved(self) -> Stream<'a,Pnt2<i32>>;
fn closing(self) -> Stream<'a,bool>;
}
impl<'a, S: StreamExt<'a,WindowEvent>> WindowEvents<'a> for S{
fn resized(self) -> Stream<'a,Vec2<i32>>{
self.filter_map(|e|
if let WindowEvent::Resized{size} = e{
Some(size)
}else{
None
}
)
}
fn moved(self) -> Stream<'a,Pnt2<i32>>{
self.filter_map(|e|
if let WindowEvent::Moved{pos} = e{
Some(pos)
}else{
None
}
)
}
fn closing(self) -> Stream<'a,bool>{
self.filter_map(|e|
if let WindowEvent::Closing = e{
Some(true)
}else{
None
}
)
}
}