wip: acceptable event_map

This commit is contained in:
🪞👃🪞 2024-12-21 22:13:12 +01:00
parent 8df00dada6
commit 3d14256d5e
2 changed files with 70 additions and 74 deletions

View file

@ -1,5 +1,5 @@
use crate::*; use crate::*;
use KeyCode::{Char, Up, Down, Left, Right}; use KeyCode::{Char, Up, Down, Left, Right, Enter};
use PhraseCommand::*; use PhraseCommand::*;
pub trait HasEditor { pub trait HasEditor {
@ -30,68 +30,46 @@ pub enum PhraseCommand {
ToggleDirection, ToggleDirection,
} }
impl InputToCommand<Tui, PhraseEditorModel> for PhraseCommand {
fn input_to_command (state: &PhraseEditorModel, from: &TuiInput) -> Option<Self> {
return state.to_editor_command(from)
}
}
impl PhraseEditorModel { impl PhraseEditorModel {
fn to_editor_command (&self, from: &TuiInput) -> Option<PhraseCommand> { fn to_editor_command (&self, from: &TuiInput) -> Option<PhraseCommand> {
EventMap([ event_map!([
(&key_expr!(Ctrl-Alt-Up), (kexp!(Ctrl-Alt-Up), &|state: &Self|SetNoteScroll(state.note_point() + 3)),
&|q: &Self|SetNoteScroll(q.note_point() + 3)), (kexp!(Ctrl-Alt-Down), &|state: &Self|SetNoteScroll(state.note_point().saturating_sub(3))),
(&key_expr!(Ctrl-Alt-Down), (kexp!(Ctrl-Alt-Left), &|state: &Self|SetTimeScroll(state.time_point().saturating_sub(state.time_zoom().get()))),
&|q: &Self|SetNoteScroll(q.note_point().saturating_sub(3))), (kexp!(Ctrl-Alt-Right), &|state: &Self|SetTimeScroll((state.time_point() + state.time_zoom().get()) % state.phrase_length().get())),
(&key_expr!(Ctrl-Alt-Left), (kexp!(Ctrl-Up), &|state: &Self|SetNoteScroll(state.note_lo().get() + 1)),
&|q: &Self|SetTimeScroll(q.time_point().saturating_sub(q.time_zoom().get()))), (kexp!(Ctrl-Down), &|state: &Self|SetNoteScroll(state.note_lo().get().saturating_sub(1))),
(&key_expr!(Ctrl-Alt-Right), (kexp!(Ctrl-Left), &|state: &Self|SetTimeScroll(state.time_start().get().saturating_sub(state.note_len()))),
&|q: &Self|SetTimeScroll((q.time_point() + q.time_zoom()) % q.phrase_length().get())), (kexp!(Ctrl-Right), &|state: &Self|SetTimeScroll(state.time_start().get() + state.note_len())),
(&key_expr!(Ctrl-Up), (kexp!(Alt-Up), &|state: &Self|SetNoteCursor(state.note_point().get() + 3)),
&|q: &Self|SetNoteScroll(q.note_lo().get() + 1)), (kexp!(Alt-Down), &|state: &Self|SetNoteCursor(state.note_point().get().saturating_sub(3))),
(&key_expr!(Ctrl-Down), (kexp!(Alt-Left), &|state: &Self|SetTimeCursor(state.time_point().get().saturating_sub(state.time_zoom()))),
&|q: &Self|SetNoteScroll(q.note_lo().get().saturating_sub(1))), (kexp!(Alt-Right), &|state: &Self|SetTimeCursor((state.time_point().get() + state.time_zoom().get()) % state.phrase_length().get())),
(&key_expr!(Ctrl-Left), (kexp!(Up), &|state: &Self|SetNoteCursor(state.note_point().get() + 1)),
&|q: &Self|SetTimeScroll(q.time_start().get().saturating_sub(q.note_len()))), (kexp!(Down), &|state: &Self|SetNoteCursor(state.note_point().get().saturating_sub(1))),
(&key_expr!(Ctrl-Right), (kexp!(Left), &|state: &Self|SetTimeCursor(state.time_point().get().saturating_sub(state.note_len()))),
&|q: &Self|SetTimeScroll(q.time_start().get() + q.note_len())), (kexp!(Right), &|state: &Self|SetTimeCursor((state.time_point().get() + state.note_len().get()) % state.phrase_length().get())),
(&key_expr!(Alt-Up), (kexp!(Char('z')), &|state: &Self|SetTimeLock(!state.time_lock().get())),
&|q: &Self|SetNoteCursor(q.note_point().get() + 3)), (kexp!(Char('-')), &|state: &Self|SetTimeZoom(Note::next(state.time_zoom().get()))),
(&key_expr!(Alt-Down), (kexp!(Char('_')), &|state: &Self|SetTimeZoom(Note::next(state.time_zoom().get()))),
&|q: &Self|SetNoteCursor(q.note_point().get().saturating_sub(3))), (kexp!(Char('=')), &|state: &Self|SetTimeZoom(Note::prev(state.time_zoom().get()))),
(&key_expr!(Alt-Left), (kexp!(Char('+')), &|state: &Self|SetTimeZoom(Note::prev(state.time_zoom().get()))),
&|q: &Self|SetTimeCursor(q.time_point().get().saturating_sub(q.time_zoom()))), (kexp!(Enter), &|state: &Self|PutNote),
(&key_expr!(Alt-Right), (kexp!(Ctrl-Enter), &|state: &Self|AppendNote),
&|q: &Self|SetTimeCursor((q.time_point().get() + q.time_zoom().get()) % q.phrase_length().get())), (kexp!(Char(',')), &|state: &Self|SetNoteLength(Note::prev(state.note_len().get()))), // TODO: no 3plet
(&key_expr!(Up), (kexp!(Char('.')), &|state: &Self|SetNoteLength(Note::next(state.note_len().get()))),
&|q: &Self|SetNoteCursor(q.note_point().get() + 1)), (kexp!(Char('<')), &|state: &Self|SetNoteLength(Note::prev(state.note_len().get()))), // TODO: 3plet
(&key_expr!(Down), (kexp!(Char('>')), &|state: &Self|SetNoteLength(Note::next(state.note_len().get()))),
&|q: &Self|SetNoteCursor(q.note_point().get().saturating_sub(1))), //key_pat!(Char('`')) -> ToggleDirection,
(&key_expr!(Left),
&|q: &Self|SetTimeCursor(q.time_point().get().saturating_sub(q.note_len()))),
(&key_expr!(Right),
&|q: &Self|SetTimeCursor((q.time_point().get() + q.note_len().get()) % q.phrase_length().get())),
(&key_pat!(Char('`')),
&|q: &Self|ToggleDirection),
(&key_pat!(Char('z')),
&|q: &Self|SetTimeLock(!q.time_lock().get())),
(&key_pat!(Char('-')),
&|q: &Self|SetTimeZoom(Note::next(q.time_zoom().get()))),
(&key_pat!(Char('_')),
&|q: &Self|SetTimeZoom(Note::next(q.time_zoom().get()))),
(&key_pat!(Char('=')),
&|q: &Self|SetTimeZoom(Note::prev(q.time_zoom().get()))),
(&key_pat!(Char('+')),
&|q: &Self|SetTimeZoom(Note::prev(q.time_zoom().get()))),
(&key_expr!(Enter),
&|q: &Self|PutNote),
(&key_expr!(Ctrl-Enter),
&|q: &Self|AppendNote),
(&key_pat!(Char(',')),
&|q: &Self|SetNoteLength(Note::prev(q.note_len().get()))), // TODO: no 3plet
(&key_pat!(Char('.')),
&|q: &Self|SetNoteLength(Note::next(q.note_len().get()))),
(&key_pat!(Char('<')),
&|q: &Self|SetNoteLength(Note::prev(q.note_len().get()))), // TODO: 3plet
(&key_pat!(Char('>')),
&|q: &Self|SetNoteLength(Note::next(q.note_len().get()))),
//// TODO: key_pat!(Char('/')) => // toggle 3plet //// TODO: key_pat!(Char('/')) => // toggle 3plet
//// TODO: key_pat!(Char('?')) => // toggle dotted //// TODO: key_pat!(Char('?')) => // toggle dotted
]).handle(state, from.event()) ]).handle(self, from.event())
} }
} }

View file

@ -60,6 +60,37 @@ impl Input<Tui> for TuiInput {
}; };
} }
pub struct EventMap<'a, const N: usize, E, T, U>(pub [(E, &'a 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)
};
(|$state:ident|{$([$char:expr] = [$handler:expr]),*}) => {
EventMap([$((&$char, &|$state|$handler),),*])
}
}
#[macro_export] macro_rules! kexp {
(Ctrl-Alt-$code:ident) => { key_event_expr!($code, KeyModifiers::CONTROL | KeyModifiers::ALT) };
(Ctrl-$code:ident) => { key_event_expr!($code, KeyModifiers::CONTROL) };
(Alt-$code:ident) => { key_event_expr!($code, KeyModifiers::ALT) };
(Shift-$code:ident) => { key_event_expr!($code, KeyModifiers::SHIFT) };
($code:ident) => { key_event_expr!($code) };
($code:expr) => { key_event_expr!($code) };
}
#[macro_export] macro_rules! key_expr { #[macro_export] macro_rules! key_expr {
(Ctrl-Alt-$code:ident) => { key_event_expr!($code, KeyModifiers::CONTROL | KeyModifiers::ALT) }; (Ctrl-Alt-$code:ident) => { key_event_expr!($code, KeyModifiers::CONTROL | KeyModifiers::ALT) };
(Ctrl-$code:ident) => { key_event_expr!($code, KeyModifiers::CONTROL) }; (Ctrl-$code:ident) => { key_event_expr!($code, KeyModifiers::CONTROL) };
@ -69,7 +100,7 @@ impl Input<Tui> for TuiInput {
} }
#[macro_export] macro_rules! key_event_expr { #[macro_export] macro_rules! key_event_expr {
($code:ident, $modifiers: expr) => { ($code:expr, $modifiers: expr) => {
TuiEvent::Input(crossterm::event::Event::Key(KeyEvent { TuiEvent::Input(crossterm::event::Event::Key(KeyEvent {
code: $code, code: $code,
modifiers: $modifiers, modifiers: $modifiers,
@ -77,7 +108,7 @@ impl Input<Tui> for TuiInput {
state: KeyEventState::NONE state: KeyEventState::NONE
})) }))
}; };
($code:ident) => { ($code:expr) => {
TuiEvent::Input(crossterm::event::Event::Key(KeyEvent { TuiEvent::Input(crossterm::event::Event::Key(KeyEvent {
code: $code, code: $code,
modifiers: KeyModifiers::NONE, modifiers: KeyModifiers::NONE,
@ -148,16 +179,3 @@ pub type KeyBinding<T> = (KeyCode, KeyModifiers, &'static str, &'static str, Key
pub type KeyMap<T> = [KeyBinding<T>]; pub type KeyMap<T> = [KeyBinding<T>];
*/ */
pub struct EventMap<'a, const N: usize, E, T, U>(pub [(E, &'a dyn Fn(T) -> U); N]);
impl<'a, const N: usize, E, 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
}
}