wip: refactor pt.6, fixed tek_api

This commit is contained in:
🪞👃🪞 2024-11-10 14:35:20 +01:00
parent 5df08409e5
commit 869d92110d
29 changed files with 1678 additions and 1679 deletions

View file

@ -1,78 +1,35 @@
use crate::*;
#[derive(Clone, PartialEq)]
pub enum SequencerCommand {
pub enum SequencerAppCommand {
Focus(FocusCommand),
Transport(TransportCommand),
Phrases(PhrasePoolCommand),
Editor(PhraseEditorCommand),
}
#[derive(Clone, PartialEq)]
pub enum PhrasePoolCommand {
Prev,
Next,
MoveUp,
MoveDown,
Delete,
Append,
Insert,
Duplicate,
RandomColor,
Edit,
Import,
Export,
Rename(PhraseRenameCommand),
Length(PhraseLengthCommand),
impl Handle<Tui> for SequencerApp<Tui> {
fn handle (&mut self, i: &TuiInput) -> Perhaps<bool> {
if let Some(entered) = self.entered() {
use SequencerFocus::*;
if let Some(true) = match entered {
Transport => self.transport.as_mut().map(|t|t.handle(i)).transpose()?.flatten(),
PhrasePool => self.phrases.write().unwrap().handle(i)?,
PhraseEditor => self.editor.handle(i)?,
} {
return Ok(Some(true))
}
}
if let Some(command) = SequencerCommand::input_to_command(self, i) {
let _undo = command.execute(self)?;
return Ok(Some(true))
}
Ok(None)
}
}
#[derive(Clone, PartialEq)]
pub enum PhraseRenameCommand {
Begin,
Backspace,
Append(char),
Set(String),
Confirm,
Cancel,
}
#[derive(Clone, PartialEq)]
pub enum PhraseLengthCommand {
Begin,
Next,
Prev,
Inc,
Dec,
Set(usize),
Confirm,
Cancel,
}
#[derive(Clone, PartialEq)]
pub enum PhraseEditorCommand {
// TODO: 1-9 seek markers that by default start every 8th of the phrase
ToggleDirection,
EnterEditMode,
ExitEditMode,
NoteAppend,
NoteCursorDec,
NoteCursorInc,
NoteLengthDec,
NoteLengthInc,
NotePageDown,
NotePageUp,
NoteScrollDec,
NoteScrollInc,
NoteSet,
TimeCursorDec,
TimeCursorInc,
TimeScrollDec,
TimeScrollInc,
TimeZoomIn,
TimeZoomOut,
GoUp,
GoDown,
GoLeft,
GoRight,
}
impl<E: Engine> Command<Sequencer<E>> for SequencerCommand {
fn execute (self, state: &mut Sequencer<E>) -> Perhaps<Self> {
impl<E: Engine> Command<SequencerApp<E>> for SequencerAppCommand {
fn execute (self, state: &mut SequencerApp<E>) -> Perhaps<Self> {
match self {
Self::Focus(cmd) => {
return delegate(cmd, Self::Focus, state)
@ -90,197 +47,34 @@ impl<E: Engine> Command<Sequencer<E>> for SequencerCommand {
Ok(None)
}
}
impl<E: Engine> Command<PhrasePool<E>> for PhrasePoolCommand {
fn execute (self, state: &mut PhrasePool<E>) -> Perhaps<Self> {
use PhrasePoolCommand::*;
use PhraseRenameCommand as Rename;
use PhraseLengthCommand as Length;
match self {
Rename(Rename::Begin) => { state.begin_rename() },
Length(Length::Begin) => { state.begin_length() },
Prev => { state.select_prev() },
Next => { state.select_next() },
Delete => { state.delete_selected() },
Append => { state.append_new(None, None) },
Insert => { state.insert_new(None, None) },
Duplicate => { state.insert_dup() },
RandomColor => { state.randomize_color() },
MoveUp => { state.move_up() },
MoveDown => { state.move_down() },
_ => unreachable!(),
}
Ok(None)
}
}
impl<E: Engine> Command<PhrasePool<E>> for PhraseRenameCommand {
fn translate (self, state: &PhrasePool<E>) -> Self {
use PhraseRenameCommand::*;
if let Some(PhrasePoolMode::Rename(_, ref old_name)) = state.mode {
match self {
Backspace => {
let mut new_name = old_name.clone();
new_name.pop();
return Self::Set(new_name)
impl InputToCommand<Tui, SequencerApp<Tui>> for SequencerCommand {
fn input_to_command (state: &SequencerApp<Tui>, input: &TuiInput) -> Option<Self> {
use SequencerCommand::*;
use FocusCommand::*;
match input.event() {
key!(KeyCode::Tab) => Some(Focus(Next)),
key!(Shift-KeyCode::Tab) => Some(Focus(Prev)),
key!(KeyCode::BackTab) => Some(Focus(Prev)),
key!(Shift-KeyCode::BackTab) => Some(Focus(Prev)),
key!(KeyCode::Up) => Some(Focus(Up)),
key!(KeyCode::Down) => Some(Focus(Down)),
key!(KeyCode::Left) => Some(Focus(Left)),
key!(KeyCode::Right) => Some(Focus(Right)),
key!(KeyCode::Char(' ')) => Some(Transport(TransportCommand::PlayToggle)),
_ => match state.focused() {
SequencerFocus::Transport => if let Some(t) = state.transport.as_ref() {
TransportCommand::input_to_command(&*t.read().unwrap(), input).map(Transport)
} else {
None
},
Append(c) => {
let mut new_name = old_name.clone();
new_name.push(c);
return Self::Set(new_name)
},
_ => {}
SequencerFocus::PhrasePool =>
PhrasePoolCommand::input_to_command(&*state.phrases.read().unwrap(), input)
.map(Phrases),
SequencerFocus::PhraseEditor =>
PhraseEditorCommand::input_to_command(&state.editor, input)
.map(Editor),
}
} else if self != Begin {
unreachable!()
}
self
}
fn execute (self, state: &mut PhrasePool<E>) -> Perhaps<Self> {
use PhraseRenameCommand::*;
if let Some(PhrasePoolMode::Rename(phrase, ref mut old_name)) = state.mode {
match self {
Set(s) => {
state.phrases[phrase].write().unwrap().name = s.into();
return Ok(Some(Self::Set(old_name.clone())))
},
Confirm => {
let old_name = old_name.clone();
state.mode = None;
return Ok(Some(Self::Set(old_name)))
},
Cancel => {
let mut phrase = state.phrases[phrase].write().unwrap();
phrase.name = old_name.clone();
},
_ => unreachable!()
};
Ok(None)
} else if self == Begin {
todo!()
} else {
unreachable!()
}
}
}
impl<E: Engine> Command<PhrasePool<E>> for PhraseLengthCommand {
fn translate (self, state: &PhrasePool<E>) -> Self {
use PhraseLengthCommand::*;
if let Some(PhrasePoolMode::Length(_, length, _)) = state.mode {
match self {
Confirm => { return Self::Set(length) },
_ => self
}
} else if self == Begin {
todo!()
} else {
unreachable!()
}
}
fn execute (self, state: &mut PhrasePool<E>) -> Perhaps<Self> {
use PhraseLengthFocus::*;
use PhraseLengthCommand::*;
if let Some(PhrasePoolMode::Length(phrase, ref mut length, ref mut focus)) = state.mode {
match self {
Cancel => { state.mode = None; },
Prev => { focus.prev() },
Next => { focus.next() },
Inc => match focus {
Bar => { *length += 4 * PPQ },
Beat => { *length += PPQ },
Tick => { *length += 1 },
},
Dec => match focus {
Bar => { *length = length.saturating_sub(4 * PPQ) },
Beat => { *length = length.saturating_sub(PPQ) },
Tick => { *length = length.saturating_sub(1) },
},
Set(length) => {
let mut phrase = state.phrases[phrase].write().unwrap();
let old_length = phrase.length;
phrase.length = length;
state.mode = None;
return Ok(Some(Self::Set(old_length)))
},
_ => unreachable!()
}
Ok(None)
} else if self == Begin {
todo!()
} else {
unreachable!()
}
}
}
impl<E: Engine> Command<PhraseEditor<E>> for PhraseEditorCommand {
fn translate (self, state: &PhraseEditor<E>) -> Self {
use PhraseEditorCommand::*;
match self {
GoUp => match state.entered { true => NoteCursorInc, false => NoteScrollInc, },
GoDown => match state.entered { true => NoteCursorDec, false => NoteScrollDec, },
GoLeft => match state.entered { true => TimeCursorDec, false => TimeScrollDec, },
GoRight => match state.entered { true => TimeCursorInc, false => TimeScrollInc, },
_ => self
}
}
fn execute (self, state: &mut PhraseEditor<E>) -> Perhaps<Self> {
use PhraseEditorCommand::*;
match self.translate(state) {
ToggleDirection => { state.mode = !state.mode; },
EnterEditMode => { state.entered = true; },
ExitEditMode => { state.entered = false; },
TimeZoomOut => { state.time_zoom_out() },
TimeZoomIn => { state.time_zoom_in() },
TimeCursorDec => { state.time_cursor_dec() },
TimeCursorInc => { state.time_cursor_inc() },
TimeScrollDec => { state.time_scroll_dec() },
TimeScrollInc => { state.time_scroll_inc() },
NoteCursorDec => { state.note_cursor_dec() },
NoteCursorInc => { state.note_cursor_inc() },
NoteScrollDec => { state.note_scroll_dec() },
NoteScrollInc => { state.note_scroll_inc() },
NoteLengthDec => { state.note_length_dec() },
NoteLengthInc => { state.note_length_inc() },
NotePageUp => { state.note_page_up() },
NotePageDown => { state.note_page_down() },
NoteAppend => {
if state.entered {
state.put();
state.time_cursor_advance();
}
},
NoteSet => {
if state.entered { state.put(); }
},
_ => unreachable!()
}
Ok(None)
}
}
impl Handle<Tui> for PhraseEditor<Tui> {
fn handle (&mut self, from: &TuiInput) -> Perhaps<bool> {
PhraseEditorCommand::execute_with_state(self, from)
}
}
impl InputToCommand<Tui, PhraseEditor<Tui>> for PhraseEditorCommand {
fn input_to_command (_: &PhraseEditor<Tui>, from: &TuiInput) -> Option<Self> {
match from.event() {
key!(KeyCode::Char('`')) => Some(Self::ToggleDirection),
key!(KeyCode::Enter) => Some(Self::EnterEditMode),
key!(KeyCode::Esc) => Some(Self::ExitEditMode),
key!(KeyCode::Char('[')) => Some(Self::NoteLengthDec),
key!(KeyCode::Char(']')) => Some(Self::NoteLengthInc),
key!(KeyCode::Char('a')) => Some(Self::NoteAppend),
key!(KeyCode::Char('s')) => Some(Self::NoteSet),
key!(KeyCode::Char('-')) => Some(Self::TimeZoomOut),
key!(KeyCode::Char('_')) => Some(Self::TimeZoomOut),
key!(KeyCode::Char('=')) => Some(Self::TimeZoomIn),
key!(KeyCode::Char('+')) => Some(Self::TimeZoomIn),
key!(KeyCode::PageUp) => Some(Self::NotePageUp),
key!(KeyCode::PageDown) => Some(Self::NotePageDown),
key!(KeyCode::Up) => Some(Self::GoUp),
key!(KeyCode::Down) => Some(Self::GoDown),
key!(KeyCode::Left) => Some(Self::GoLeft),
key!(KeyCode::Right) => Some(Self::GoRight),
_ => None
}
}
}