mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 12:46:42 +01:00
wip: refactor pt.6, fixed tek_api
This commit is contained in:
parent
5df08409e5
commit
869d92110d
29 changed files with 1678 additions and 1679 deletions
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue