From 8df00dada68d755c3cf049a467b13eec918f14f7 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 21 Dec 2024 21:24:25 +0100 Subject: [PATCH] wip: static KeyMap --- crates/tek/src/tui/phrase_editor.rs | 107 ++++++++++++++++------------ crates/tek/src/tui/tui_input.rs | 50 ++++++++----- 2 files changed, 96 insertions(+), 61 deletions(-) diff --git a/crates/tek/src/tui/phrase_editor.rs b/crates/tek/src/tui/phrase_editor.rs index 9c325d54..0ab2d568 100644 --- a/crates/tek/src/tui/phrase_editor.rs +++ b/crates/tek/src/tui/phrase_editor.rs @@ -30,51 +30,68 @@ pub enum PhraseCommand { ToggleDirection, } -impl InputToCommand for PhraseCommand { - fn input_to_command (state: &PhraseEditorModel, from: &TuiInput) -> Option { - let length = ||state.phrase().as_ref().map(|p|p.read().unwrap().length).unwrap_or(1); - - let note_lo = ||state.note_lo().get(); - let time_start = ||state.time_start().get(); - let time_zoom = ||state.time_zoom().get(); - let time_lock = ||state.time_lock().get(); - - let note_point = ||state.note_point(); - let time_point = ||state.time_point(); - let note_len = ||state.note_len(); - Some(match from.event() { - key_pat!(Ctrl-Alt-Up) => SetNoteScroll(note_point() + 3), - key_pat!(Ctrl-Alt-Down) => SetNoteScroll(note_point().saturating_sub(3)), - key_pat!(Ctrl-Alt-Left) => SetTimeScroll(time_point().saturating_sub(time_zoom())), - key_pat!(Ctrl-Alt-Right) => SetTimeScroll((time_point() + time_zoom()) % length()), - key_pat!(Ctrl-Up) => SetNoteScroll(note_lo() + 1), - key_pat!(Ctrl-Down) => SetNoteScroll(note_lo().saturating_sub(1)), - key_pat!(Ctrl-Left) => SetTimeScroll(time_start().saturating_sub(note_len())), - key_pat!(Ctrl-Right) => SetTimeScroll(time_start() + note_len()), - key_pat!(Alt-Up) => SetNoteCursor(note_point() + 3), - key_pat!(Alt-Down) => SetNoteCursor(note_point().saturating_sub(3)), - key_pat!(Alt-Left) => SetTimeCursor(time_point().saturating_sub(time_zoom())), - key_pat!(Alt-Right) => SetTimeCursor((time_point() + time_zoom()) % length()), - key_pat!(Up) => SetNoteCursor(note_point() + 1), - key_pat!(Down) => SetNoteCursor(note_point().saturating_sub(1)), - key_pat!(Left) => SetTimeCursor(time_point().saturating_sub(note_len())), - key_pat!(Right) => SetTimeCursor((time_point() + note_len()) % length()), - key_pat!(Char('`')) => ToggleDirection, - key_pat!(Char('z')) => SetTimeLock(!time_lock()), - key_pat!(Char('-')) => SetTimeZoom(Note::next(time_zoom())), - key_pat!(Char('_')) => SetTimeZoom(Note::next(time_zoom())), - key_pat!(Char('=')) => SetTimeZoom(Note::prev(time_zoom())), - key_pat!(Char('+')) => SetTimeZoom(Note::prev(time_zoom())), - key_pat!(Enter) => PutNote, - key_pat!(Ctrl-Enter) => AppendNote, - key_pat!(Char(',')) => SetNoteLength(Note::prev(note_len())), // TODO: no 3plet - key_pat!(Char('.')) => SetNoteLength(Note::next(note_len())), - key_pat!(Char('<')) => SetNoteLength(Note::prev(note_len())), // TODO: 3plet - key_pat!(Char('>')) => SetNoteLength(Note::next(note_len())), - // TODO: key_pat!(Char('/')) => // toggle 3plet - // TODO: key_pat!(Char('?')) => // toggle dotted - _ => return None - }) +impl PhraseEditorModel { + fn to_editor_command (&self, from: &TuiInput) -> Option { + 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()))), + //// TODO: key_pat!(Char('/')) => // toggle 3plet + //// TODO: key_pat!(Char('?')) => // toggle dotted + ]).handle(state, from.event()) } } diff --git a/crates/tek/src/tui/tui_input.rs b/crates/tek/src/tui/tui_input.rs index 958a8b16..9b4dae57 100644 --- a/crates/tek/src/tui/tui_input.rs +++ b/crates/tek/src/tui/tui_input.rs @@ -28,6 +28,19 @@ impl Input for TuiInput { } } +#[macro_export] macro_rules! key_pat { + (Ctrl-Alt-$code:pat) => { key_event_pat!($code, KeyModifiers::CONTROL | KeyModifiers::ALT) }; + (Ctrl-$code:pat) => { key_event_pat!($code, KeyModifiers::CONTROL) }; + (Alt-$code:pat) => { key_event_pat!($code, KeyModifiers::ALT) }; + (Shift-$code:pat) => { key_event_pat!($code, KeyModifiers::SHIFT) }; + ($code:pat) => { TuiEvent::Input(crossterm::event::Event::Key(KeyEvent { + code: $code, + modifiers: KeyModifiers::NONE, + kind: KeyEventKind::Press, + state: KeyEventState::NONE + })) }; +} + #[macro_export] macro_rules! key_event_pat { ($code:pat) => { TuiEvent::Input(crossterm::event::Event::Key(KeyEvent { @@ -47,6 +60,14 @@ impl Input for TuiInput { }; } +#[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) }; + (Alt-$code:ident) => { key_event_expr!($code, KeyModifiers::ALT) }; + (Shift-$code:ident) => { key_event_expr!($code, KeyModifiers::SHIFT) }; + ($code:ident) => { key_event_expr!($code) }; +} + #[macro_export] macro_rules! key_event_expr { ($code:ident, $modifiers: expr) => { TuiEvent::Input(crossterm::event::Event::Key(KeyEvent { @@ -66,22 +87,6 @@ impl Input for TuiInput { }; } -#[macro_export] macro_rules! key_pat { - (Ctrl-Alt-$code:pat) => { key_event_pat!($code, KeyModifiers::CONTROL | KeyModifiers::ALT) }; - (Ctrl-$code:pat) => { key_event_pat!($code, KeyModifiers::CONTROL) }; - (Alt-$code:pat) => { key_event_pat!($code, KeyModifiers::ALT) }; - (Shift-$code:pat) => { key_event_pat!($code, KeyModifiers::SHIFT) }; - ($code:pat) => { key_event_pat!($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) }; - (Alt-$code:ident) => { key_event_expr!($code, KeyModifiers::ALT) }; - (Shift-$code:ident) => { key_event_expr!($code, KeyModifiers::SHIFT) }; - ($code:ident) => { key_event_expr!($code) }; -} - /* /// Define a key pub const fn key (code: KeyCode) -> KeyEvent { @@ -143,3 +148,16 @@ pub type KeyBinding = (KeyCode, KeyModifiers, &'static str, &'static str, Key pub type KeyMap = [KeyBinding]; */ + +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 { + for (binding, handler) in self.0.iter() { + if event == binding { + return Some(handler(context)) + } + } + return None + } +}