mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
240 lines
8.1 KiB
Rust
240 lines
8.1 KiB
Rust
use crate::*;
|
|
|
|
#[derive(Clone, PartialEq)]
|
|
pub enum SequencerCommand {
|
|
FocusNext,
|
|
FocusPrev,
|
|
FocusUp,
|
|
FocusDown,
|
|
FocusLeft,
|
|
FocusRight,
|
|
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),
|
|
}
|
|
#[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,
|
|
NoteLengthDec,
|
|
NoteLengthInc,
|
|
TimeZoomIn,
|
|
TimeZoomOut,
|
|
NoteAppend,
|
|
NoteSet,
|
|
NotePageUp,
|
|
NotePageDown,
|
|
GoUp,
|
|
GoDown,
|
|
GoLeft,
|
|
GoRight,
|
|
}
|
|
impl<E: Engine> Command<Sequencer<E>> for SequencerCommand {
|
|
fn run (&self, state: &mut Sequencer<E>) -> Perhaps<Self> {
|
|
use SequencerCommand::*;
|
|
match self {
|
|
FocusNext => { state.focus_next(); },
|
|
FocusPrev => { state.focus_prev(); },
|
|
FocusUp => { state.focus_up(); },
|
|
FocusDown => { state.focus_down(); },
|
|
FocusLeft => { state.focus_left(); },
|
|
FocusRight => { state.focus_right(); },
|
|
Transport(command) => if let Some(ref transport) = state.transport {
|
|
return command.run(&mut*transport.write().unwrap()).map(|x|x.map(Transport))
|
|
},
|
|
Phrases(command) => {
|
|
return command.run(&mut*state.phrases.write().unwrap()).map(|x|x.map(Phrases))
|
|
},
|
|
Editor(command) => {
|
|
return command.run(&mut state.editor).map(|x|x.map(Editor))
|
|
},
|
|
}
|
|
Ok(None)
|
|
}
|
|
}
|
|
impl<E: Engine> Command<PhrasePool<E>> for PhrasePoolCommand {
|
|
fn run (&self, state: &mut PhrasePool<E>) -> Perhaps<Self> {
|
|
use PhrasePoolCommand::*;
|
|
use PhraseRenameCommand as Rename;
|
|
use PhraseLengthCommand as Length;
|
|
match self {
|
|
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() },
|
|
Edit => { todo!(); }
|
|
RandomColor => { state.randomize_color() },
|
|
MoveUp => { state.move_up() },
|
|
MoveDown => { state.move_down() },
|
|
Rename(Rename::Begin) => { state.begin_rename() },
|
|
Rename(_) => { unreachable!() },
|
|
Length(Length::Begin) => { state.begin_length() },
|
|
Length(_) => { unreachable!() },
|
|
Import => todo!(),
|
|
Export => todo!(),
|
|
}
|
|
Ok(None)
|
|
}
|
|
}
|
|
impl<E: Engine> Command<PhrasePool<E>> for PhraseRenameCommand {
|
|
fn run (&self, state: &mut PhrasePool<E>) -> Perhaps<Self> {
|
|
use PhraseRenameCommand::*;
|
|
if let Some(PhrasePoolMode::Rename(phrase, ref mut old_name)) = state.mode {
|
|
match self {
|
|
Begin => { unreachable!(); },
|
|
Backspace => {
|
|
let mut phrase = state.phrases[phrase].write().unwrap();
|
|
let old_name = phrase.name.clone();
|
|
phrase.name.pop();
|
|
return Ok(Some(Self::Set(old_name)))
|
|
},
|
|
Append(c) => {
|
|
let mut phrase = state.phrases[phrase].write().unwrap();
|
|
let old_name = phrase.name.clone();
|
|
phrase.name.push(*c);
|
|
return Ok(Some(Self::Set(old_name)))
|
|
},
|
|
Set(s) => {
|
|
let mut phrase = state.phrases[phrase].write().unwrap();
|
|
phrase.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();
|
|
}
|
|
};
|
|
Ok(None)
|
|
} else if *self == Begin {
|
|
todo!()
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
impl<E: Engine> Command<PhrasePool<E>> for PhraseLengthCommand {
|
|
fn run (&self, state: &mut PhrasePool<E>) -> Perhaps<Self> {
|
|
use PhraseLengthCommand::*;
|
|
if let Some(PhrasePoolMode::Length(phrase, ref mut length, ref mut focus)) = state.mode {
|
|
match self {
|
|
Begin => { unreachable!(); },
|
|
Cancel => { state.mode = None; },
|
|
Confirm => { return Self::Set(*length).run(state) },
|
|
Prev => { focus.prev() },
|
|
Next => { focus.next() },
|
|
Inc => {
|
|
use PhraseLengthFocus::*;
|
|
match focus {
|
|
Bar => { *length += 4 * PPQ },
|
|
Beat => { *length += PPQ },
|
|
Tick => { *length += 1 },
|
|
}
|
|
},
|
|
Dec => {
|
|
use PhraseLengthFocus::*;
|
|
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)))
|
|
},
|
|
}
|
|
Ok(None)
|
|
} else if *self == Begin {
|
|
todo!()
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
impl<E: Engine> Command<PhraseEditor<E>> for PhraseEditorCommand {
|
|
fn run (&self, state: &mut PhraseEditor<E>) -> Perhaps<Self> {
|
|
use PhraseEditorCommand::*;
|
|
match self {
|
|
ToggleDirection => { state.mode = !state.mode; },
|
|
EnterEditMode => { state.entered = true; },
|
|
ExitEditMode => { state.entered = false; },
|
|
TimeZoomOut => { state.time_zoom_out() },
|
|
TimeZoomIn => { state.time_zoom_in() },
|
|
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(); },
|
|
GoUp => match state.entered {
|
|
true => state.note_cursor_inc(),
|
|
false => state.note_scroll_inc(),
|
|
},
|
|
GoDown => match state.entered {
|
|
true => state.note_cursor_dec(),
|
|
false => state.note_scroll_dec(),
|
|
},
|
|
GoLeft => match state.entered {
|
|
true => state.time_cursor_dec(),
|
|
false => state.time_scroll_dec(),
|
|
},
|
|
GoRight => match state.entered {
|
|
true => state.time_cursor_inc(),
|
|
false => state.time_scroll_inc(),
|
|
},
|
|
}
|
|
Ok(None)
|
|
}
|
|
}
|