clean up mod command

This commit is contained in:
🪞👃🪞 2025-01-02 15:14:33 +01:00
parent 6663f4efcb
commit 6776e2ec55
4 changed files with 99 additions and 113 deletions

View file

@ -10,6 +10,13 @@ use crate::*;
}
}
pub trait Command<S>: Send + Sync + Sized {
fn execute (self, state: &mut S) -> Perhaps<Self>;
fn delegate <T> (self, state: &mut S, wrap: impl Fn(Self)->T) -> Perhaps<T> {
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<T> {
fn command (&mut self, command: T) -> Perhaps<T>;
}
pub trait Command<S>: Send + Sync + Sized {
fn execute (self, state: &mut S) -> Perhaps<Self>;
}
pub fn delegate <B, C: Command<S>, S> (
cmd: C,
wrap: impl Fn(C)->B,
state: &mut S,
) -> Perhaps<B> {
Ok(cmd.execute(state)?.map(wrap))
}
pub trait InputToCommand<E: Engine, S>: Command<S> + Sized {
fn input_to_command (state: &S, input: &E::Input) -> Option<Self>;
fn execute_with_state (state: &mut S, input: &E::Input) -> Perhaps<bool> {
@ -52,65 +38,38 @@ pub trait InputToCommand<E: Engine, S>: Command<S> + Sized {
})
}
}
pub struct MenuBar<E: Engine, S, C: Command<S>> {
pub menus: Vec<Menu<E, S, C>>,
pub index: usize,
}
impl<E: Engine, S, C: Command<S>> MenuBar<E, S, C> {
pub fn new () -> Self { Self { menus: vec![], index: 0 } }
pub fn add (mut self, menu: Menu<E, S, C>) -> Self {
self.menus.push(menu);
self
}
}
pub struct Menu<E: Engine, S, C: Command<S>> {
pub title: String,
pub items: Vec<MenuItem<E, S, C>>,
pub index: Option<usize>,
}
impl<E: Engine, S, C: Command<S>> Menu<E, S, C> {
pub fn new (title: impl AsRef<str>) -> Self {
Self {
title: title.as_ref().to_string(),
items: vec![],
index: None,
pub type KeyMapping<const N: usize, E, T, U> = [(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<U> {
for (binding, handler) in self.0.iter() {
if event == binding {
return Some(handler(context))
}
}
}
pub fn add (mut self, item: MenuItem<E, S, C>) -> 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<E: Engine, S, C: Command<S>> {
/// Unused.
__(PhantomData<E>, PhantomData<S>),
/// 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<E: Engine, S, C: Command<S>> MenuItem<E, S, C> {
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())?
});
}
}

View file

@ -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<const N: usize, E, T, U> = [(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<U> {
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())?
});
}
}

View file

@ -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::*;

63
src/menu.rs Normal file
View file

@ -0,0 +1,63 @@
use crate::*;
pub struct MenuBar<E: Engine, S, C: Command<S>> {
pub menus: Vec<Menu<E, S, C>>,
pub index: usize,
}
impl<E: Engine, S, C: Command<S>> MenuBar<E, S, C> {
pub fn new () -> Self { Self { menus: vec![], index: 0 } }
pub fn add (mut self, menu: Menu<E, S, C>) -> Self {
self.menus.push(menu);
self
}
}
pub struct Menu<E: Engine, S, C: Command<S>> {
pub title: String,
pub items: Vec<MenuItem<E, S, C>>,
pub index: Option<usize>,
}
impl<E: Engine, S, C: Command<S>> Menu<E, S, C> {
pub fn new (title: impl AsRef<str>) -> Self {
Self {
title: title.as_ref().to_string(),
items: vec![],
index: None,
}
}
pub fn add (mut self, item: MenuItem<E, S, C>) -> 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<E: Engine, S, C: Command<S>> {
/// Unused.
__(PhantomData<E>, PhantomData<S>),
/// 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<E: Engine, S, C: Command<S>> MenuItem<E, S, C> {
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)
}
}