From 70794e3cb9b5a945feca32a56733cf034eabe92b Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 14 Dec 2024 19:37:00 +0100 Subject: [PATCH] simplify sequencer input delegation --- crates/tek/src/tui/app_sequencer.rs | 53 ++++++------- crates/tek/src/tui/phrase_editor.rs | 119 +++++++++++++++------------- crates/tek/src/tui/tui_input.rs | 36 ++++----- 3 files changed, 103 insertions(+), 105 deletions(-) diff --git a/crates/tek/src/tui/app_sequencer.rs b/crates/tek/src/tui/app_sequencer.rs index ee2a88e4..14354b0d 100644 --- a/crates/tek/src/tui/app_sequencer.rs +++ b/crates/tek/src/tui/app_sequencer.rs @@ -125,19 +125,15 @@ pub fn to_sequencer_command (state: &SequencerTui, input: &TuiInput) -> Option match state.focus { - PhraseEditor => SequencerCommand::Focus(FocusCommand::Set(PhraseList)), - _ => SequencerCommand::Focus(FocusCommand::Set(PhraseEditor)), - } - // Enqueue currently edited phrase - key_pat!(Char('q')) => - Enqueue(Some(state.phrases.phrases[state.phrases.phrase.load(Ordering::Relaxed)].clone())), + key_pat!(Char('q')) => Enqueue(Some( + state.phrases.phrases[state.phrases.phrase.load(Ordering::Relaxed)].clone() + )), // 0: Enqueue phrase 0 (stop all) - key_pat!(Char('0')) => - Enqueue(Some(state.phrases.phrases[0].clone())), + key_pat!(Char('0')) => Enqueue(Some( + state.phrases.phrases[0].clone() + )), // E: Toggle between editing currently playing or other phrase key_pat!(Char('e')) => if let Some((_, Some(playing_phrase))) = state.player.play_phrase() { @@ -155,29 +151,26 @@ pub fn to_sequencer_command (state: &SequencerTui, input: &TuiInput) -> Option - Clock(if state.clock().is_stopped() { Play(None) } else { Pause(None) }), + key_pat!(Char(' ')) => Clock(if state.clock().is_stopped() { + Play(None) + } else { + Pause(None) + }), // Transport: Play from start or rewind to start - key_pat!(Shift-Char(' ')) => - Clock(if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }), + key_pat!(Shift-Char(' ')) => Clock(if state.clock().is_stopped() { + Play(Some(0)) + } else { + Pause(Some(0)) + }), - // Editor: zoom - key_pat!(Char('z')) | key_pat!(Char('-')) | key_pat!(Char('_'))| key_pat!(Char('=')) | key_pat!(Char('+')) => - Editor(PhraseCommand::input_to_command(&state.editor, input)?), - - // List: select phrase to edit, change color - key_pat!(Char('[')) | key_pat!(Char(']')) | key_pat!(Char('c')) | key_pat!(Shift-Char('A')) | key_pat!(Shift-Char('D')) => - Phrases(PhrasesCommand::input_to_command(&state.phrases, input)?), - - // Delegate to focused control: - _ => match state.focus { - PhraseEditor => Editor(PhraseCommand::input_to_command(&state.editor, input)?), - PhraseList => Phrases(PhrasesCommand::input_to_command(&state.phrases, input)?), - Transport(_) => match to_transport_command(state, input)? { - TransportCommand::Clock(command) => Clock(command), - _ => return None, - }, + // Delegate to components: + _ => if let Some(command) = PhraseCommand::input_to_command(&state.editor, input) { + Editor(command) + } else if let Some(command) = PhrasesCommand::input_to_command(&state.phrases, input) { + Phrases(command) + } else { + return None } }) diff --git a/crates/tek/src/tui/phrase_editor.rs b/crates/tek/src/tui/phrase_editor.rs index 0f001e24..8d2f3a60 100644 --- a/crates/tek/src/tui/phrase_editor.rs +++ b/crates/tek/src/tui/phrase_editor.rs @@ -1,5 +1,7 @@ use crate::*; use Ordering::Relaxed; +use KeyCode::{Char, Up, Down, Left, Right}; +use PhraseCommand::*; pub trait HasEditor { fn editor (&self) -> &PhraseEditorModel; @@ -18,61 +20,64 @@ pub enum PhraseCommand { SetTimeCursor(usize), SetTimeScroll(usize), SetTimeZoom(usize), - SetTimeZoomLock(bool), + SetTimeLock(bool), Show(Option>>), ToggleDirection, } impl InputToCommand for PhraseCommand { fn input_to_command (state: &PhraseEditorModel, from: &TuiInput) -> Option { - use PhraseCommand::*; - use KeyCode::{Char, Up, Down, PageUp, PageDown, Left, Right}; - let point = state.point(); - let note_point = point.note_point.load(Relaxed); - let time_point = point.time_point.load(Relaxed); - let note_len = point.note_len.load(Relaxed); - let range = state.range(); - let note_lo = range.note_lo.load(Relaxed); - let time_start = range.time_start.load(Relaxed); - let time_zoom = range.time_zoom(); - let length = state.phrase().read().unwrap().as_ref() - .map(|p|p.read().unwrap().length).unwrap_or(1); - Some(match from.event() { - key_pat!(Char('`')) => ToggleDirection, - key_pat!(Char('z')) => SetTimeZoomLock(!state.range().time_lock()), - key_pat!(Char('-')) => SetTimeZoom(next_note_length(time_zoom)), - key_pat!(Char('_')) => SetTimeZoom(next_note_length(time_zoom)), - key_pat!(Char('=')) => SetTimeZoom(prev_note_length(time_zoom)), - key_pat!(Char('+')) => SetTimeZoom(prev_note_length(time_zoom)), - key_pat!(Char('a')) => AppendNote, - key_pat!(Char('s')) => PutNote, - // TODO: no triplet/dotted - key_pat!(Char(',')) => SetNoteLength(prev_note_length(note_len)), - key_pat!(Char('.')) => SetNoteLength(next_note_length(note_len)), - // TODO: with triplet/dotted - key_pat!(Char('<')) => SetNoteLength(prev_note_length(note_len)), - key_pat!(Char('>')) => SetNoteLength(next_note_length(note_len)), - // TODO: '/' set triplet, '?' set dotted - _ => match from.event() { - 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!(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!(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!(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), - _ => return None - }, + let length = ||state + .phrase() + .read() + .unwrap() + .as_ref() + .map(|p|p.read().unwrap().length) + .unwrap_or(1); + + let range = state.range(); + let note_lo = ||range.note_lo.load(Relaxed); + let time_start = ||range.time_start.load(Relaxed); + let time_zoom = ||range.time_zoom(); + + let point = state.point(); + let note_point = ||point.note_point(); + let time_point = ||point.time_point(); + let note_len = ||point.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(!state.range().time_lock()), + key_pat!(Char('-')) => SetTimeZoom(next_note_length(time_zoom())), + key_pat!(Char('_')) => SetTimeZoom(next_note_length(time_zoom())), + key_pat!(Char('=')) => SetTimeZoom(prev_note_length(time_zoom())), + key_pat!(Char('+')) => SetTimeZoom(prev_note_length(time_zoom())), + key_pat!(Char('a')) => AppendNote, + key_pat!(Char('s')) => PutNote, + key_pat!(Char(',')) => SetNoteLength(prev_note_length(note_len())), // TODO: no 3plet + key_pat!(Char('.')) => SetNoteLength(next_note_length(note_len())), + key_pat!(Char('<')) => SetNoteLength(prev_note_length(note_len())), // TODO: 3plet + key_pat!(Char('>')) => SetNoteLength(next_note_length(note_len())), + // TODO: key_pat!(Char('/')) => // toggle 3plet + // TODO: key_pat!(Char('?')) => // toggle dotted + _ => return None }) } } @@ -83,15 +88,15 @@ impl Command for PhraseCommand { let range = state.range(); let point = state.point(); match self { - Show(phrase) => { state.set_phrase(phrase); }, - PutNote => { state.put_note(false); }, - AppendNote => { state.put_note(true); }, - SetTimeZoom(x) => { range.set_time_zoom(x); }, - SetTimeZoomLock(x) => { range.set_time_lock(x); }, - SetTimeScroll(x) => { range.set_time_start(x); }, - SetNoteScroll(x) => { range.set_note_lo(x); }, - SetNoteLength(x) => { point.set_note_len(x); }, - SetTimeCursor(x) => { point.set_time_point(x); }, + Show(phrase) => { state.set_phrase(phrase); }, + PutNote => { state.put_note(false); }, + AppendNote => { state.put_note(true); }, + SetTimeZoom(x) => { range.set_time_zoom(x); }, + SetTimeLock(x) => { range.set_time_lock(x); }, + SetTimeScroll(x) => { range.set_time_start(x); }, + SetNoteScroll(x) => { range.set_note_lo(x); }, + SetNoteLength(x) => { point.set_note_len(x); }, + SetTimeCursor(x) => { point.set_time_point(x); }, SetNoteCursor(note) => { let note = 127.min(note); let start = range.note_lo.load(Relaxed); diff --git a/crates/tek/src/tui/tui_input.rs b/crates/tek/src/tui/tui_input.rs index 96b7a88e..958a8b16 100644 --- a/crates/tek/src/tui/tui_input.rs +++ b/crates/tek/src/tui/tui_input.rs @@ -29,14 +29,6 @@ impl Input for TuiInput { } #[macro_export] macro_rules! key_event_pat { - ($code:pat, $modifiers: pat) => { - TuiEvent::Input(crossterm::event::Event::Key(KeyEvent { - code: $code, - modifiers: $modifiers, - kind: KeyEventKind::Press, - state: KeyEventState::NONE - })) - }; ($code:pat) => { TuiEvent::Input(crossterm::event::Event::Key(KeyEvent { code: $code, @@ -45,10 +37,7 @@ impl Input for TuiInput { state: KeyEventState::NONE })) }; -} - -#[macro_export] macro_rules! key_event_expr { - ($code:expr, $modifiers: expr) => { + ($code:pat, $modifiers: pat) => { TuiEvent::Input(crossterm::event::Event::Key(KeyEvent { code: $code, modifiers: $modifiers, @@ -56,7 +45,18 @@ impl Input for TuiInput { state: KeyEventState::NONE })) }; - ($code:expr) => { +} + +#[macro_export] macro_rules! key_event_expr { + ($code:ident, $modifiers: expr) => { + TuiEvent::Input(crossterm::event::Event::Key(KeyEvent { + code: $code, + modifiers: $modifiers, + kind: KeyEventKind::Press, + state: KeyEventState::NONE + })) + }; + ($code:ident) => { TuiEvent::Input(crossterm::event::Event::Key(KeyEvent { code: $code, modifiers: KeyModifiers::NONE, @@ -75,11 +75,11 @@ impl Input for TuiInput { } #[macro_export] macro_rules! key_expr { - (Ctrl-Alt-$code:expr) => { key_event_expr!($code, KeyModifiers::CONTROL | KeyModifiers::ALT) }; - (Ctrl-$code:expr) => { key_event_expr!($code, KeyModifiers::CONTROL) }; - (Alt-$code:expr) => { key_event_expr!($code, KeyModifiers::ALT) }; - (Shift-$code:expr) => { key_event_expr!($code, KeyModifiers::SHIFT) }; - ($code:expr) => { key_event_expr!($code) }; + (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) }; } /*