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 KeyCode::{Char, Up, Down, Left, Right};
use KeyCode::{Char, Up, Down, Left, Right, Enter};
use PhraseCommand::*;
pub trait HasEditor {
@ -30,68 +30,46 @@ pub enum PhraseCommand {
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 {
fn to_editor_command (&self, from: &TuiInput) -> Option<PhraseCommand> {
EventMap([
(&key_expr!(Ctrl-Alt-Up),
&|q: &Self|SetNoteScroll(q.note_point() + 3)),
(&key_expr!(Ctrl-Alt-Down),
&|q: &Self|SetNoteScroll(q.note_point().saturating_sub(3))),
(&key_expr!(Ctrl-Alt-Left),
&|q: &Self|SetTimeScroll(q.time_point().saturating_sub(q.time_zoom().get()))),
(&key_expr!(Ctrl-Alt-Right),
&|q: &Self|SetTimeScroll((q.time_point() + q.time_zoom()) % q.phrase_length().get())),
(&key_expr!(Ctrl-Up),
&|q: &Self|SetNoteScroll(q.note_lo().get() + 1)),
(&key_expr!(Ctrl-Down),
&|q: &Self|SetNoteScroll(q.note_lo().get().saturating_sub(1))),
(&key_expr!(Ctrl-Left),
&|q: &Self|SetTimeScroll(q.time_start().get().saturating_sub(q.note_len()))),
(&key_expr!(Ctrl-Right),
&|q: &Self|SetTimeScroll(q.time_start().get() + q.note_len())),
(&key_expr!(Alt-Up),
&|q: &Self|SetNoteCursor(q.note_point().get() + 3)),
(&key_expr!(Alt-Down),
&|q: &Self|SetNoteCursor(q.note_point().get().saturating_sub(3))),
(&key_expr!(Alt-Left),
&|q: &Self|SetTimeCursor(q.time_point().get().saturating_sub(q.time_zoom()))),
(&key_expr!(Alt-Right),
&|q: &Self|SetTimeCursor((q.time_point().get() + q.time_zoom().get()) % q.phrase_length().get())),
(&key_expr!(Up),
&|q: &Self|SetNoteCursor(q.note_point().get() + 1)),
(&key_expr!(Down),
&|q: &Self|SetNoteCursor(q.note_point().get().saturating_sub(1))),
(&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()))),
event_map!([
(kexp!(Ctrl-Alt-Up), &|state: &Self|SetNoteScroll(state.note_point() + 3)),
(kexp!(Ctrl-Alt-Down), &|state: &Self|SetNoteScroll(state.note_point().saturating_sub(3))),
(kexp!(Ctrl-Alt-Left), &|state: &Self|SetTimeScroll(state.time_point().saturating_sub(state.time_zoom().get()))),
(kexp!(Ctrl-Alt-Right), &|state: &Self|SetTimeScroll((state.time_point() + state.time_zoom().get()) % state.phrase_length().get())),
(kexp!(Ctrl-Up), &|state: &Self|SetNoteScroll(state.note_lo().get() + 1)),
(kexp!(Ctrl-Down), &|state: &Self|SetNoteScroll(state.note_lo().get().saturating_sub(1))),
(kexp!(Ctrl-Left), &|state: &Self|SetTimeScroll(state.time_start().get().saturating_sub(state.note_len()))),
(kexp!(Ctrl-Right), &|state: &Self|SetTimeScroll(state.time_start().get() + state.note_len())),
(kexp!(Alt-Up), &|state: &Self|SetNoteCursor(state.note_point().get() + 3)),
(kexp!(Alt-Down), &|state: &Self|SetNoteCursor(state.note_point().get().saturating_sub(3))),
(kexp!(Alt-Left), &|state: &Self|SetTimeCursor(state.time_point().get().saturating_sub(state.time_zoom()))),
(kexp!(Alt-Right), &|state: &Self|SetTimeCursor((state.time_point().get() + state.time_zoom().get()) % state.phrase_length().get())),
(kexp!(Up), &|state: &Self|SetNoteCursor(state.note_point().get() + 1)),
(kexp!(Down), &|state: &Self|SetNoteCursor(state.note_point().get().saturating_sub(1))),
(kexp!(Left), &|state: &Self|SetTimeCursor(state.time_point().get().saturating_sub(state.note_len()))),
(kexp!(Right), &|state: &Self|SetTimeCursor((state.time_point().get() + state.note_len().get()) % state.phrase_length().get())),
(kexp!(Char('z')), &|state: &Self|SetTimeLock(!state.time_lock().get())),
(kexp!(Char('-')), &|state: &Self|SetTimeZoom(Note::next(state.time_zoom().get()))),
(kexp!(Char('_')), &|state: &Self|SetTimeZoom(Note::next(state.time_zoom().get()))),
(kexp!(Char('=')), &|state: &Self|SetTimeZoom(Note::prev(state.time_zoom().get()))),
(kexp!(Char('+')), &|state: &Self|SetTimeZoom(Note::prev(state.time_zoom().get()))),
(kexp!(Enter), &|state: &Self|PutNote),
(kexp!(Ctrl-Enter), &|state: &Self|AppendNote),
(kexp!(Char(',')), &|state: &Self|SetNoteLength(Note::prev(state.note_len().get()))), // TODO: no 3plet
(kexp!(Char('.')), &|state: &Self|SetNoteLength(Note::next(state.note_len().get()))),
(kexp!(Char('<')), &|state: &Self|SetNoteLength(Note::prev(state.note_len().get()))), // TODO: 3plet
(kexp!(Char('>')), &|state: &Self|SetNoteLength(Note::next(state.note_len().get()))),
//key_pat!(Char('`')) -> ToggleDirection,
//// TODO: key_pat!(Char('/')) => // toggle 3plet
//// 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 {
(Ctrl-Alt-$code:ident) => { key_event_expr!($code, KeyModifiers::CONTROL | KeyModifiers::ALT) };
(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 {
($code:ident, $modifiers: expr) => {
($code:expr, $modifiers: expr) => {
TuiEvent::Input(crossterm::event::Event::Key(KeyEvent {
code: $code,
modifiers: $modifiers,
@ -77,7 +108,7 @@ impl Input<Tui> for TuiInput {
state: KeyEventState::NONE
}))
};
($code:ident) => {
($code:expr) => {
TuiEvent::Input(crossterm::event::Event::Key(KeyEvent {
code: $code,
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 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
}
}