use std::{
collections::HashSet,
ops::{Deref, DerefMut},
};
use crossterm::event::{KeyCode, ModifierKeyCode, MouseButton};
use crate::pos::{Pos, Rect};
use super::{Event, FrameInput};
#[derive(Clone, Debug, Default)]
pub struct InputState {
pub keys: Keys,
pub buttons: HashSet<MouseButton>,
pub mouse: Option<Pos>,
}
impl InputState {
pub fn update(&mut self, event: &Event) {
match event {
Event::MouseMove(pos) => self.mouse = Some(*pos),
Event::MouseOutside => self.mouse = None,
Event::MouseUp(b, pos) => {
self.mouse = Some(*pos);
self.buttons.remove(b);
}
Event::MouseDown(b, pos) => {
self.mouse = Some(*pos);
self.buttons.insert(*b);
}
Event::KeyPress(k) => {
self.keys.insert(*k);
}
Event::KeyRelease(k) => {
self.keys.remove(k);
}
Event::Redraw | Event::Close | Event::Paste(_) => (),
}
}
}
#[derive(Clone, Debug)]
pub struct StateEvent<'s> {
pub(crate) event: Event,
pub(crate) state: &'s InputState,
pub(crate) rect: Rect,
}
crate::seal!({'s} StateEvent{'s});
impl StateEvent<'_> {
pub fn event(&self) -> &Event {
&self.event
}
pub fn keys(&self) -> &Keys {
&self.state.keys
}
pub fn buttons(&self) -> &HashSet<MouseButton> {
&self.state.buttons
}
pub fn mouse(&self) -> Option<Pos> {
self.rect.rel(self.state.mouse?)
}
}
macro_rules! split {
($fn:ident, $pos:ty) => {
fn $fn(self, mid: $pos) -> (Self, Self) {
let (e1, e2) = self.event.$fn(mid);
let (r1, r2) = self.rect.$fn(mid);
(
Self { event: e1, state: self.state, rect: r1 },
Self { event: e2, state: self.state, rect: r2 },
)
}
};
}
impl FrameInput for StateEvent<'_> {
split!(split_h, crate::pos::X);
split!(split_v, crate::pos::Y);
}
#[derive(Clone, Debug, Default)]
pub struct Keys(HashSet<KeyCode>);
impl Deref for Keys {
type Target = HashSet<KeyCode>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Keys {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
macro_rules! mod_methods {
($(
$(#[$doc:meta])*
$fn:ident: $($mcc:ident),*
);* $(;)?) => {
impl Keys { $(
$(#[$doc])*
pub fn $fn(&self) -> bool {
$(
self.contains(&KeyCode::Modifier(ModifierKeyCode::$mcc))
)||*
}
)* }
}
}
mod_methods! {
ctrl: LeftControl, RightControl;
alt: LeftAlt, RightAlt;
win: LeftSuper, RightSuper;
}