use std::any::Any;
use crossterm::event::{
KeyEvent, KeyEventKind, KeyEventState, KeyModifiers, MouseButton, MouseEvent, MouseEventKind,
};
pub use crossterm::event::KeyCode;
pub struct Msg {
msg: Box<dyn Any + Send>,
}
impl Msg {
pub fn new<M: Message + 'static>(msg: M) -> Self {
Self { msg: Box::new(msg) }
}
pub fn cast<M: Message + 'static>(&self) -> Option<&M> {
self.msg.downcast_ref::<M>()
}
pub fn is<M: Message + 'static>(&self) -> bool {
self.msg.is::<M>()
}
}
pub trait Message: Send {}
macro_rules! matches_method {
($method:ident, $field:ident, $value:pat) => {
pub fn $method(&self) -> bool {
matches!(self.$field, $value)
}
};
}
macro_rules! bitflags_method {
($method:ident, $field:ident, $flags:ident, $constant:ident) => {
pub fn $method(&self) -> bool {
self.$field.contains($flags::$constant)
}
};
}
#[derive(Debug)]
pub struct Quit;
impl Message for Quit {}
#[derive(Debug)]
pub struct Key {
pub code: KeyCode,
modifiers: KeyModifiers,
kind: KeyEventKind,
state: KeyEventState,
}
impl Message for Key {}
impl Key {
matches_method! { is_press, kind, KeyEventKind::Press }
matches_method! { is_release, kind, KeyEventKind::Release }
matches_method! { is_repeat, kind, KeyEventKind::Repeat }
bitflags_method! { with_shift, modifiers, KeyModifiers, SHIFT }
bitflags_method! { with_control, modifiers, KeyModifiers, CONTROL }
bitflags_method! { with_alt, modifiers, KeyModifiers, ALT }
bitflags_method! { with_super, modifiers, KeyModifiers, SUPER }
bitflags_method! { with_hyper, modifiers, KeyModifiers, HYPER }
bitflags_method! { with_meta, modifiers, KeyModifiers, META }
bitflags_method! { from_keypad, state, KeyEventState, KEYPAD }
bitflags_method! { with_capslock, state, KeyEventState, CAPS_LOCK }
bitflags_method! { with_numlock, state, KeyEventState, NUM_LOCK }
}
impl From<KeyEvent> for Key {
fn from(value: KeyEvent) -> Self {
Self {
code: value.code,
modifiers: value.modifiers,
kind: value.kind,
state: value.state,
}
}
}
#[derive(Debug)]
pub struct Mouse {
kind: MouseEventKind,
modifiers: KeyModifiers,
pub column: u16,
pub row: u16,
}
impl Message for Mouse {}
impl Mouse {
pub fn is_left(&self) -> bool {
matches!(
self.kind,
MouseEventKind::Down(MouseButton::Left)
| MouseEventKind::Up(MouseButton::Left)
| MouseEventKind::Drag(MouseButton::Left)
)
}
pub fn is_right(&self) -> bool {
matches!(
self.kind,
MouseEventKind::Down(MouseButton::Right)
| MouseEventKind::Up(MouseButton::Right)
| MouseEventKind::Drag(MouseButton::Right)
)
}
pub fn is_middle(&self) -> bool {
matches!(
self.kind,
MouseEventKind::Down(MouseButton::Middle)
| MouseEventKind::Up(MouseButton::Middle)
| MouseEventKind::Drag(MouseButton::Middle)
)
}
pub fn is_scroll(&self) -> bool {
use MouseEventKind::*;
matches!(self.kind, ScrollUp | ScrollDown | ScrollLeft | ScrollRight)
}
matches_method! { is_press, kind, MouseEventKind::Down(_) }
matches_method! { is_release, kind, MouseEventKind::Up(_) }
matches_method! { is_drag, kind, MouseEventKind::Drag(_) }
matches_method! { is_move, kind, MouseEventKind::Moved }
matches_method! { is_scroll_up, kind, MouseEventKind::ScrollUp }
matches_method! { is_scroll_down, kind, MouseEventKind::ScrollDown }
matches_method! { is_scroll_left, kind, MouseEventKind::ScrollLeft }
matches_method! { is_scroll_right, kind, MouseEventKind::ScrollRight }
bitflags_method! { with_shift, modifiers, KeyModifiers, SHIFT }
bitflags_method! { with_control, modifiers, KeyModifiers, CONTROL }
bitflags_method! { with_alt, modifiers, KeyModifiers, ALT }
bitflags_method! { with_super, modifiers, KeyModifiers, SUPER }
bitflags_method! { with_hyper, modifiers, KeyModifiers, HYPER }
bitflags_method! { with_meta, modifiers, KeyModifiers, META }
}
impl From<MouseEvent> for Mouse {
fn from(value: MouseEvent) -> Self {
Self {
kind: value.kind,
column: value.column,
row: value.row,
modifiers: value.modifiers,
}
}
}
#[derive(Debug)]
pub enum Focus {
Gained,
Lost,
}
impl Message for Focus {}
#[cfg(feature = "paste")]
pub struct Paste(pub String);
#[cfg(feature = "paste")]
impl Message for Paste {}
pub struct Resize {
pub width: u16,
pub height: u16,
}
impl Message for Resize {}