diff --git a/src/command.rs b/src/command.rs index 8740193b..fc4dcc32 100644 --- a/src/command.rs +++ b/src/command.rs @@ -10,6 +10,13 @@ use crate::*; } } +pub trait Command: Send + Sync + Sized { + fn execute (self, state: &mut S) -> Perhaps; + fn delegate (self, state: &mut S, wrap: impl Fn(Self)->T) -> Perhaps { + Ok(self.execute(state)?.map(wrap)) + } +} + #[macro_export] macro_rules! input_to_command { ($Command:ty: <$Engine:ty>|$state:ident:$State:ty,$input:ident|$handler:expr) => { impl InputToCommand<$Engine, $State> for $Command { @@ -20,27 +27,6 @@ use crate::*; } } -#[derive(Clone)] -pub enum NextPrev { - Next, - Prev, -} - -pub trait Execute { - fn command (&mut self, command: T) -> Perhaps; -} - -pub trait Command: Send + Sync + Sized { - fn execute (self, state: &mut S) -> Perhaps; -} -pub fn delegate , S> ( - cmd: C, - wrap: impl Fn(C)->B, - state: &mut S, -) -> Perhaps { - Ok(cmd.execute(state)?.map(wrap)) -} - pub trait InputToCommand: Command + Sized { fn input_to_command (state: &S, input: &E::Input) -> Option; fn execute_with_state (state: &mut S, input: &E::Input) -> Perhaps { @@ -52,65 +38,38 @@ pub trait InputToCommand: Command + Sized { }) } } -pub struct MenuBar> { - pub menus: Vec>, - pub index: usize, -} -impl> MenuBar { - pub fn new () -> Self { Self { menus: vec![], index: 0 } } - pub fn add (mut self, menu: Menu) -> Self { - self.menus.push(menu); - self - } -} -pub struct Menu> { - pub title: String, - pub items: Vec>, - pub index: Option, -} -impl> Menu { - pub fn new (title: impl AsRef) -> Self { - Self { - title: title.as_ref().to_string(), - items: vec![], - index: None, + +pub type KeyMapping = [(E, &'static dyn Fn(&T)->U);N]; + +pub struct EventMap<'a, const N: usize, E, T, U>( + pub [(E, &'a dyn Fn(T) -> U); N], + pub Option<&'a dyn Fn(T) -> U>, +); + +impl<'a, const N: usize, E: PartialEq, T, U> EventMap<'a, N, E, T, U> { + pub fn handle (&self, context: T, event: &E) -> Option { + for (binding, handler) in self.0.iter() { + if event == binding { + return Some(handler(context)) + } } - } - pub fn add (mut self, item: MenuItem) -> Self { - self.items.push(item); - self - } - pub fn sep (mut self) -> Self { - self.items.push(MenuItem::sep()); - self - } - pub fn cmd (mut self, hotkey: &'static str, text: &'static str, command: C) -> Self { - self.items.push(MenuItem::cmd(hotkey, text, command)); - self - } - pub fn off (mut self, hotkey: &'static str, text: &'static str) -> Self { - self.items.push(MenuItem::off(hotkey, text)); - self + return None } } -pub enum MenuItem> { - /// Unused. - __(PhantomData, PhantomData), - /// A separator. Skip it. - Separator, - /// A menu item with command, description and hotkey. - Command(&'static str, &'static str, C), - /// A menu item that can't be activated but has description and hotkey - Disabled(&'static str, &'static str) + +#[macro_export] macro_rules! event_map { + ($events:expr) => { + EventMap($events, None) + }; + ($events:expr, $default: expr) => { + EventMap($events, $default) + }; } -impl> MenuItem { - pub fn sep () -> Self { - Self::Separator - } - pub fn cmd (hotkey: &'static str, text: &'static str, command: C) -> Self { - Self::Command(hotkey, text, command) - } - pub fn off (hotkey: &'static str, text: &'static str) -> Self { - Self::Disabled(hotkey, text) + +#[macro_export] macro_rules! event_map_input_to_command { + ($Engine:ty: $Model:ty: $Command:ty: $EventMap:expr) => { + input_to_command!($Command: <$Engine>|state: $Model, input|{ + event_map!($EventMap).handle(state, input.event())? + }); } } diff --git a/src/event.rs b/src/event.rs index 16f47f07..c7b7e813 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,36 +1 @@ use crate::*; - -pub struct EventMap<'a, const N: usize, E, T, U>( - pub [(E, &'a dyn Fn(T) -> U); N], - pub Option<&'a dyn Fn(T) -> U>, -); - -pub type KeyMapping = [(E, &'static dyn Fn(&T)->U);N]; - -impl<'a, const N: usize, E: PartialEq, T, U> EventMap<'a, N, E, T, U> { - pub fn handle (&self, context: T, event: &E) -> Option { - for (binding, handler) in self.0.iter() { - if event == binding { - return Some(handler(context)) - } - } - return None - } -} - -#[macro_export] macro_rules! event_map { - ($events:expr) => { - EventMap($events, None) - }; - ($events:expr, $default: expr) => { - EventMap($events, $default) - }; -} - -#[macro_export] macro_rules! event_map_input_to_command { - ($Engine:ty: $Model:ty: $Command:ty: $EventMap:expr) => { - input_to_command!($Command: <$Engine>|state: $Model, input|{ - event_map!($EventMap).handle(state, input.event())? - }); - } -} diff --git a/src/lib.rs b/src/lib.rs index fd331761..063e14fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,6 @@ pub mod border; pub use self::border::*; pub mod clock; pub use self::clock::*; pub mod color; pub use self::color::*; pub mod command; pub use self::command::*; -pub mod event; pub use self::event::*; pub mod file; pub use self::file::*; pub mod focus; pub use self::focus::*; pub mod groovebox; pub use self::groovebox::*; diff --git a/src/menu.rs b/src/menu.rs new file mode 100644 index 00000000..3ce55383 --- /dev/null +++ b/src/menu.rs @@ -0,0 +1,63 @@ +use crate::*; +pub struct MenuBar> { + pub menus: Vec>, + pub index: usize, +} +impl> MenuBar { + pub fn new () -> Self { Self { menus: vec![], index: 0 } } + pub fn add (mut self, menu: Menu) -> Self { + self.menus.push(menu); + self + } +} +pub struct Menu> { + pub title: String, + pub items: Vec>, + pub index: Option, +} +impl> Menu { + pub fn new (title: impl AsRef) -> Self { + Self { + title: title.as_ref().to_string(), + items: vec![], + index: None, + } + } + pub fn add (mut self, item: MenuItem) -> Self { + self.items.push(item); + self + } + pub fn sep (mut self) -> Self { + self.items.push(MenuItem::sep()); + self + } + pub fn cmd (mut self, hotkey: &'static str, text: &'static str, command: C) -> Self { + self.items.push(MenuItem::cmd(hotkey, text, command)); + self + } + pub fn off (mut self, hotkey: &'static str, text: &'static str) -> Self { + self.items.push(MenuItem::off(hotkey, text)); + self + } +} +pub enum MenuItem> { + /// Unused. + __(PhantomData, PhantomData), + /// A separator. Skip it. + Separator, + /// A menu item with command, description and hotkey. + Command(&'static str, &'static str, C), + /// A menu item that can't be activated but has description and hotkey + Disabled(&'static str, &'static str) +} +impl> MenuItem { + pub fn sep () -> Self { + Self::Separator + } + pub fn cmd (hotkey: &'static str, text: &'static str, command: C) -> Self { + Self::Command(hotkey, text, command) + } + pub fn off (hotkey: &'static str, text: &'static str) -> Self { + Self::Disabled(hotkey, text) + } +}