mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
simplify sequencer input delegation
This commit is contained in:
parent
29abe29504
commit
70794e3cb9
3 changed files with 103 additions and 105 deletions
|
|
@ -125,19 +125,15 @@ pub fn to_sequencer_command (state: &SequencerTui, input: &TuiInput) -> Option<S
|
||||||
use super::app_transport::TransportCommand;
|
use super::app_transport::TransportCommand;
|
||||||
Some(match input.event() {
|
Some(match input.event() {
|
||||||
|
|
||||||
// Switch between editor and list
|
|
||||||
key_pat!(Tab) | key_pat!(BackTab) | key_pat!(Shift-Tab) | key_pat!(Shift-BackTab) => match state.focus {
|
|
||||||
PhraseEditor => SequencerCommand::Focus(FocusCommand::Set(PhraseList)),
|
|
||||||
_ => SequencerCommand::Focus(FocusCommand::Set(PhraseEditor)),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enqueue currently edited phrase
|
// Enqueue currently edited phrase
|
||||||
key_pat!(Char('q')) =>
|
key_pat!(Char('q')) => Enqueue(Some(
|
||||||
Enqueue(Some(state.phrases.phrases[state.phrases.phrase.load(Ordering::Relaxed)].clone())),
|
state.phrases.phrases[state.phrases.phrase.load(Ordering::Relaxed)].clone()
|
||||||
|
)),
|
||||||
|
|
||||||
// 0: Enqueue phrase 0 (stop all)
|
// 0: Enqueue phrase 0 (stop all)
|
||||||
key_pat!(Char('0')) =>
|
key_pat!(Char('0')) => Enqueue(Some(
|
||||||
Enqueue(Some(state.phrases.phrases[0].clone())),
|
state.phrases.phrases[0].clone()
|
||||||
|
)),
|
||||||
|
|
||||||
// E: Toggle between editing currently playing or other phrase
|
// E: Toggle between editing currently playing or other phrase
|
||||||
key_pat!(Char('e')) => if let Some((_, Some(playing_phrase))) = state.player.play_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<S
|
||||||
},
|
},
|
||||||
|
|
||||||
// Transport: Play/pause
|
// Transport: Play/pause
|
||||||
key_pat!(Char(' ')) =>
|
key_pat!(Char(' ')) => Clock(if state.clock().is_stopped() {
|
||||||
Clock(if state.clock().is_stopped() { Play(None) } else { Pause(None) }),
|
Play(None)
|
||||||
|
} else {
|
||||||
|
Pause(None)
|
||||||
|
}),
|
||||||
|
|
||||||
// Transport: Play from start or rewind to start
|
// Transport: Play from start or rewind to start
|
||||||
key_pat!(Shift-Char(' ')) =>
|
key_pat!(Shift-Char(' ')) => Clock(if state.clock().is_stopped() {
|
||||||
Clock(if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }),
|
Play(Some(0))
|
||||||
|
} else {
|
||||||
|
Pause(Some(0))
|
||||||
|
}),
|
||||||
|
|
||||||
// Editor: zoom
|
// Delegate to components:
|
||||||
key_pat!(Char('z')) | key_pat!(Char('-')) | key_pat!(Char('_'))| key_pat!(Char('=')) | key_pat!(Char('+')) =>
|
_ => if let Some(command) = PhraseCommand::input_to_command(&state.editor, input) {
|
||||||
Editor(PhraseCommand::input_to_command(&state.editor, input)?),
|
Editor(command)
|
||||||
|
} else if let Some(command) = PhrasesCommand::input_to_command(&state.phrases, input) {
|
||||||
// List: select phrase to edit, change color
|
Phrases(command)
|
||||||
key_pat!(Char('[')) | key_pat!(Char(']')) | key_pat!(Char('c')) | key_pat!(Shift-Char('A')) | key_pat!(Shift-Char('D')) =>
|
} else {
|
||||||
Phrases(PhrasesCommand::input_to_command(&state.phrases, input)?),
|
return None
|
||||||
|
|
||||||
// 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,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use Ordering::Relaxed;
|
use Ordering::Relaxed;
|
||||||
|
use KeyCode::{Char, Up, Down, Left, Right};
|
||||||
|
use PhraseCommand::*;
|
||||||
|
|
||||||
pub trait HasEditor {
|
pub trait HasEditor {
|
||||||
fn editor (&self) -> &PhraseEditorModel;
|
fn editor (&self) -> &PhraseEditorModel;
|
||||||
|
|
@ -18,61 +20,64 @@ pub enum PhraseCommand {
|
||||||
SetTimeCursor(usize),
|
SetTimeCursor(usize),
|
||||||
SetTimeScroll(usize),
|
SetTimeScroll(usize),
|
||||||
SetTimeZoom(usize),
|
SetTimeZoom(usize),
|
||||||
SetTimeZoomLock(bool),
|
SetTimeLock(bool),
|
||||||
Show(Option<Arc<RwLock<Phrase>>>),
|
Show(Option<Arc<RwLock<Phrase>>>),
|
||||||
ToggleDirection,
|
ToggleDirection,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputToCommand<Tui, PhraseEditorModel> for PhraseCommand {
|
impl InputToCommand<Tui, PhraseEditorModel> for PhraseCommand {
|
||||||
fn input_to_command (state: &PhraseEditorModel, from: &TuiInput) -> Option<Self> {
|
fn input_to_command (state: &PhraseEditorModel, from: &TuiInput) -> Option<Self> {
|
||||||
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),
|
let length = ||state
|
||||||
key_pat!(Ctrl-Down) => SetNoteScroll(note_lo.saturating_sub(1)),
|
.phrase()
|
||||||
key_pat!(Ctrl-Left) => SetTimeScroll(time_start.saturating_sub(note_len)),
|
.read()
|
||||||
key_pat!(Ctrl-Right) => SetTimeScroll(time_start + note_len),
|
.unwrap()
|
||||||
key_pat!(Ctrl-Alt-Up) => SetNoteScroll(note_point + 3),
|
.as_ref()
|
||||||
key_pat!(Ctrl-Alt-Down) => SetNoteScroll(note_point.saturating_sub(3)),
|
.map(|p|p.read().unwrap().length)
|
||||||
key_pat!(Ctrl-Alt-Left) => SetTimeScroll(time_point.saturating_sub(time_zoom)),
|
.unwrap_or(1);
|
||||||
key_pat!(Ctrl-Alt-Right) => SetTimeScroll((time_point + time_zoom) % length),
|
|
||||||
_ => return None
|
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<PhraseEditorModel> for PhraseCommand {
|
||||||
let range = state.range();
|
let range = state.range();
|
||||||
let point = state.point();
|
let point = state.point();
|
||||||
match self {
|
match self {
|
||||||
Show(phrase) => { state.set_phrase(phrase); },
|
Show(phrase) => { state.set_phrase(phrase); },
|
||||||
PutNote => { state.put_note(false); },
|
PutNote => { state.put_note(false); },
|
||||||
AppendNote => { state.put_note(true); },
|
AppendNote => { state.put_note(true); },
|
||||||
SetTimeZoom(x) => { range.set_time_zoom(x); },
|
SetTimeZoom(x) => { range.set_time_zoom(x); },
|
||||||
SetTimeZoomLock(x) => { range.set_time_lock(x); },
|
SetTimeLock(x) => { range.set_time_lock(x); },
|
||||||
SetTimeScroll(x) => { range.set_time_start(x); },
|
SetTimeScroll(x) => { range.set_time_start(x); },
|
||||||
SetNoteScroll(x) => { range.set_note_lo(x); },
|
SetNoteScroll(x) => { range.set_note_lo(x); },
|
||||||
SetNoteLength(x) => { point.set_note_len(x); },
|
SetNoteLength(x) => { point.set_note_len(x); },
|
||||||
SetTimeCursor(x) => { point.set_time_point(x); },
|
SetTimeCursor(x) => { point.set_time_point(x); },
|
||||||
SetNoteCursor(note) => {
|
SetNoteCursor(note) => {
|
||||||
let note = 127.min(note);
|
let note = 127.min(note);
|
||||||
let start = range.note_lo.load(Relaxed);
|
let start = range.note_lo.load(Relaxed);
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,6 @@ impl Input<Tui> for TuiInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export] macro_rules! key_event_pat {
|
#[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) => {
|
($code:pat) => {
|
||||||
TuiEvent::Input(crossterm::event::Event::Key(KeyEvent {
|
TuiEvent::Input(crossterm::event::Event::Key(KeyEvent {
|
||||||
code: $code,
|
code: $code,
|
||||||
|
|
@ -45,10 +37,7 @@ impl Input<Tui> for TuiInput {
|
||||||
state: KeyEventState::NONE
|
state: KeyEventState::NONE
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
}
|
($code:pat, $modifiers: pat) => {
|
||||||
|
|
||||||
#[macro_export] macro_rules! key_event_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,
|
||||||
|
|
@ -56,7 +45,18 @@ impl Input<Tui> for TuiInput {
|
||||||
state: KeyEventState::NONE
|
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 {
|
TuiEvent::Input(crossterm::event::Event::Key(KeyEvent {
|
||||||
code: $code,
|
code: $code,
|
||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
|
|
@ -75,11 +75,11 @@ impl Input<Tui> for TuiInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export] macro_rules! key_expr {
|
#[macro_export] macro_rules! key_expr {
|
||||||
(Ctrl-Alt-$code:expr) => { key_event_expr!($code, KeyModifiers::CONTROL | KeyModifiers::ALT) };
|
(Ctrl-Alt-$code:ident) => { key_event_expr!($code, KeyModifiers::CONTROL | KeyModifiers::ALT) };
|
||||||
(Ctrl-$code:expr) => { key_event_expr!($code, KeyModifiers::CONTROL) };
|
(Ctrl-$code:ident) => { key_event_expr!($code, KeyModifiers::CONTROL) };
|
||||||
(Alt-$code:expr) => { key_event_expr!($code, KeyModifiers::ALT) };
|
(Alt-$code:ident) => { key_event_expr!($code, KeyModifiers::ALT) };
|
||||||
(Shift-$code:expr) => { key_event_expr!($code, KeyModifiers::SHIFT) };
|
(Shift-$code:ident) => { key_event_expr!($code, KeyModifiers::SHIFT) };
|
||||||
($code:expr) => { key_event_expr!($code) };
|
($code:ident) => { key_event_expr!($code) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue