use crate::layout::Scale;
use crate::Context;
use std::fmt::Debug;
use maverick_os::window::{Input, TouchPhase, ElementState, MouseScrollDelta, Touch};
pub use maverick_os::window::{NamedKey, Key, SmolStr};
use downcast_rs::{Downcast, impl_downcast};
pub type Events = std::collections::VecDeque<Box<dyn Event>>;
pub trait OnEvent: Debug + Downcast {
fn on_event(&mut self, _ctx: &mut Context, event: Box<dyn Event>) -> Vec<Box<dyn Event>> {vec![event]}
}
type EventChildren = Vec<((f32, f32), (f32, f32))>;
pub trait Event: Debug + Downcast {
fn pass(
self: Box<Self>,
_ctx: &mut Context,
children: &EventChildren,
) -> Vec<Option<Box<dyn Event>>>;
}
impl_downcast!(Event);
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MouseState {
Pressed,
Moved,
Released,
Scroll(f32, f32),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyboardState {
Pressed,
Released,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct MouseEvent {
pub position: Option<(f32, f32)>,
pub state: MouseState,
}
impl Event for MouseEvent {
fn pass(self: Box<Self>, _ctx: &mut Context, children: &Vec<((f32, f32), (f32, f32))>) -> Vec<Option<Box<dyn Event>>> {
let mut passed = false;
children.iter().rev().map(|(offset, size)| { let position = self.position.and_then(|position| (!passed).then(|| (
position.0 > offset.0 &&
position.0 < offset.0+size.0 &&
position.1 > offset.1 &&
position.1 < offset.1+size.1
).then(|| {
passed = true;
(position.0 - offset.0, position.1 - offset.1)
})).flatten());
Some(Box::new(MouseEvent{position, state: self.state}) as Box<dyn Event>)
}).collect::<Vec<_>>().into_iter().rev().collect()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KeyboardEvent {
pub key: Key,
pub state: KeyboardState,
}
impl Event for KeyboardEvent {
fn pass(self: Box<Self>, _ctx: &mut Context, children: &Vec<((f32, f32), (f32, f32))>) -> Vec<Option<Box<dyn Event>>> {
children.iter().map(|_| Some(self.clone() as Box<dyn Event>)).collect()
}
}
#[derive(Debug, Clone, Copy)]
pub struct TickEvent;
impl Event for TickEvent {
fn pass(self: Box<Self>, _ctx: &mut Context, children: &Vec<((f32, f32), (f32, f32))>) -> Vec<Option<Box<dyn Event>>> {
children.iter().map(|_| Some(Box::new(*self) as Box<dyn Event>)).collect()
}
}
pub(crate) struct EventHandler {
touching: bool,
mouse: (f32, f32),
scroll: Option<(f32, f32)>,
}
impl EventHandler {
pub fn new() -> Self {EventHandler{
touching: false,
mouse: (0.0, 0.0),
scroll: None,
}}
pub fn on_input(&mut self, scale: &Scale, input: Input) -> Option<Box<dyn Event>> {
match input {
Input::Touch(Touch { location, phase, .. }) => {
let location = (location.x as f32, location.y as f32);
let position = (scale.logical(location.0), scale.logical(location.1));
let event = match phase {
TouchPhase::Started => {
self.scroll = Some(position);
self.touching = true;
Some(MouseState::Pressed)
},
TouchPhase::Ended | TouchPhase::Cancelled => {
self.touching = false;
Some(MouseState::Released)
},
TouchPhase::Moved => {
self.scroll.and_then(|(prev_x, prev_y)| {
self.scroll = Some(position);
let dx = position.0 - prev_x;
let dy = position.1 - prev_y;
let scroll_x = -dx * 1.0;
let scroll_y = -dy * 1.0;
(scroll_x.abs() > 0.01 || scroll_y.abs() > 0.01).then_some(
MouseState::Scroll(scroll_x, scroll_y)
)
})
}
}.map(|state| Box::new(MouseEvent{position: Some(position), state}) as Box<dyn Event>);
self.mouse = position;
event
},
Input::CursorMoved{position, ..} => {
let position = (scale.logical(position.0 as f32), scale.logical(position.1 as f32));
(self.mouse != position).then_some({
self.mouse = position;
Box::new(MouseEvent{position: Some(position), state: MouseState::Moved})
})
},
Input::Mouse{state, ..} => {
Some(Box::new(MouseEvent{position: Some(self.mouse), state: match state {
ElementState::Pressed => MouseState::Pressed,
ElementState::Released => MouseState::Released,
}}))
},
Input::MouseWheel{delta, phase, ..} => {
match phase {
TouchPhase::Started => {
self.scroll = Some((0.0, 0.0));
None
}
TouchPhase::Moved => {
self.scroll.map(|(prev_x, prev_y)| {
let pos = match delta {
MouseScrollDelta::LineDelta(x, y) => (x.signum(), y.signum()),
MouseScrollDelta::PixelDelta(p) => (p.x as f32, p.y as f32),
};
let scroll_x = prev_x + (-pos.0 * 0.2);
let scroll_y = prev_y + (-pos.1 * 0.2);
Some(Box::new(MouseEvent{position: Some(self.mouse), state: MouseState::Scroll(scroll_x, scroll_y)}) as Box<dyn Event>)
})?
},
_ => None
}
},
Input::Keyboard{event, ..} => {
Some(Box::new(KeyboardEvent{
key: event.logical_key, state: match event.state {
ElementState::Pressed => KeyboardState::Pressed,
ElementState::Released => KeyboardState::Released,
}}))
},
_ => None
}
}
}
#[macro_export]
macro_rules! events {
( $( $x:expr ),* $(,)? ) => {
{
vec![
$(Box::new($x) as Box<dyn Event>),*
]
}
};
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Button {
Pressed(bool),
Hover(bool),
}
impl Event for Button {
fn pass(self: Box<Self>, _ctx: &mut Context, children: &Vec<((f32, f32), (f32, f32))>) -> Vec<Option<Box<dyn Event>>> {
children.iter().map(|_| Some(self.clone() as Box<dyn Event>)).collect()
}
}
#[derive(Debug, Copy, Clone)]
pub enum Selectable {
Pressed(uuid::Uuid, uuid::Uuid),
Selected(bool)
}
impl Event for Selectable {
fn pass(self: Box<Self>, _ctx: &mut Context, children: &Vec<((f32, f32), (f32, f32))>) -> Vec<Option<Box<dyn Event>>> {
children.iter().map(|_| Some(self.clone() as Box<dyn Event>)).collect()
}
}
#[derive(Debug, Clone, Copy)]
pub enum Slider {
Start(f32),
Moved(f32),
}
impl Event for Slider {
fn pass(self: Box<Self>, _ctx: &mut Context, children: &Vec<((f32, f32), (f32, f32))>) -> Vec<Option<Box<dyn Event>>> {
children.iter().map(|_| Some(self.clone() as Box<dyn Event>)).collect()
}
}
#[derive(Debug, Clone)]
pub enum TextInput {
Hover(bool),
Focused(bool),
}
impl Event for TextInput {
fn pass(self: Box<Self>, _ctx: &mut Context, children: &Vec<((f32, f32), (f32, f32))>) -> Vec<Option<Box<dyn Event>>> {
children.iter().map(|_| Some(self.clone() as Box<dyn Event>)).collect()
}
}