mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
clean up mod command
This commit is contained in:
parent
6663f4efcb
commit
6776e2ec55
4 changed files with 99 additions and 113 deletions
113
src/command.rs
113
src/command.rs
|
|
@ -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 {
|
#[macro_export] macro_rules! input_to_command {
|
||||||
($Command:ty: <$Engine:ty>|$state:ident:$State:ty,$input:ident|$handler:expr) => {
|
($Command:ty: <$Engine:ty>|$state:ident:$State:ty,$input:ident|$handler:expr) => {
|
||||||
impl InputToCommand<$Engine, $State> for $Command {
|
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 {
|
pub trait InputToCommand<E: Engine, S>: Command<S> + Sized {
|
||||||
fn input_to_command (state: &S, input: &E::Input) -> Option<Self>;
|
fn input_to_command (state: &S, input: &E::Input) -> Option<Self>;
|
||||||
fn execute_with_state (state: &mut S, input: &E::Input) -> Perhaps<bool> {
|
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 type KeyMapping<const N: usize, E, T, U> = [(E, &'static dyn Fn(&T)->U);N];
|
||||||
pub index: usize,
|
|
||||||
}
|
pub struct EventMap<'a, const N: usize, E, T, U>(
|
||||||
impl<E: Engine, S, C: Command<S>> MenuBar<E, S, C> {
|
pub [(E, &'a dyn Fn(T) -> U); N],
|
||||||
pub fn new () -> Self { Self { menus: vec![], index: 0 } }
|
pub Option<&'a dyn Fn(T) -> U>,
|
||||||
pub fn add (mut self, menu: Menu<E, S, C>) -> Self {
|
);
|
||||||
self.menus.push(menu);
|
|
||||||
self
|
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() {
|
||||||
pub struct Menu<E: Engine, S, C: Command<S>> {
|
if event == binding {
|
||||||
pub title: String,
|
return Some(handler(context))
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
}
|
return 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.
|
#[macro_export] macro_rules! event_map {
|
||||||
__(PhantomData<E>, PhantomData<S>),
|
($events:expr) => {
|
||||||
/// A separator. Skip it.
|
EventMap($events, None)
|
||||||
Separator,
|
};
|
||||||
/// A menu item with command, description and hotkey.
|
($events:expr, $default: expr) => {
|
||||||
Command(&'static str, &'static str, C),
|
EventMap($events, $default)
|
||||||
/// 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 {
|
#[macro_export] macro_rules! event_map_input_to_command {
|
||||||
Self::Separator
|
($Engine:ty: $Model:ty: $Command:ty: $EventMap:expr) => {
|
||||||
}
|
input_to_command!($Command: <$Engine>|state: $Model, input|{
|
||||||
pub fn cmd (hotkey: &'static str, text: &'static str, command: C) -> Self {
|
event_map!($EventMap).handle(state, input.event())?
|
||||||
Self::Command(hotkey, text, command)
|
});
|
||||||
}
|
|
||||||
pub fn off (hotkey: &'static str, text: &'static str) -> Self {
|
|
||||||
Self::Disabled(hotkey, text)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
35
src/event.rs
35
src/event.rs
|
|
@ -1,36 +1 @@
|
||||||
use crate::*;
|
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())?
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,6 @@ pub mod border; pub use self::border::*;
|
||||||
pub mod clock; pub use self::clock::*;
|
pub mod clock; pub use self::clock::*;
|
||||||
pub mod color; pub use self::color::*;
|
pub mod color; pub use self::color::*;
|
||||||
pub mod command; pub use self::command::*;
|
pub mod command; pub use self::command::*;
|
||||||
pub mod event; pub use self::event::*;
|
|
||||||
pub mod file; pub use self::file::*;
|
pub mod file; pub use self::file::*;
|
||||||
pub mod focus; pub use self::focus::*;
|
pub mod focus; pub use self::focus::*;
|
||||||
pub mod groovebox; pub use self::groovebox::*;
|
pub mod groovebox; pub use self::groovebox::*;
|
||||||
|
|
|
||||||
63
src/menu.rs
Normal file
63
src/menu.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue