From b0c936bda018fdc3f74c5ebfaff632bdd694ac05 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 2 May 2025 18:50:12 +0300 Subject: [PATCH] app: organize some commands --- crates/app/src/api.rs | 273 ++++++++++++++++++------------------------ 1 file changed, 118 insertions(+), 155 deletions(-) diff --git a/crates/app/src/api.rs b/crates/app/src/api.rs index 1dc8045e..45918077 100644 --- a/crates/app/src/api.rs +++ b/crates/app/src/api.rs @@ -32,6 +32,49 @@ expose!([self: Tek] (":scene-prev" self.selected.scene_prev()) (":track-next" self.selected.track_next(self.tracks.len())) (":track-prev" self.selected.track_prev()))); +provide!(bool: |self: MidiPool| {}); +provide!(MidiClip: |self: MidiPool| { + ":new-clip" => self.new_clip(), + ":cloned-clip" => self.cloned_clip(), +}); +provide!(PathBuf: |self: MidiPool| {}); +provide!(Arc: |self: MidiPool| {}); +provide!(usize: |self: MidiPool| { + ":current" => 0, + ":after" => 0, + ":previous" => 0, + ":next" => 0 +}); +provide!(ItemColor: |self: MidiPool| { + ":random-color" => ItemColor::random() +}); +provide!(bool: |self: MidiEditor| { + ":true" => true, + ":false" => false, + ":time-lock" => self.time_lock().get(), + ":time-lock-toggle" => !self.time_lock().get(), +}); +provide!(usize: |self: MidiEditor| { + ":note-length" => self.note_len(), + ":note-pos" => self.note_pos(), + ":note-pos-next" => self.note_pos() + 1, + ":note-pos-prev" => self.note_pos().saturating_sub(1), + ":note-pos-next-octave" => self.note_pos() + 12, + ":note-pos-prev-octave" => self.note_pos().saturating_sub(12), + ":note-len" => self.note_len(), + ":note-len-next" => self.note_len() + 1, + ":note-len-prev" => self.note_len().saturating_sub(1), + ":note-range" => self.note_axis().get(), + ":note-range-prev" => self.note_axis().get() + 1, + ":note-range-next" => self.note_axis().get().saturating_sub(1), + ":time-pos" => self.time_pos(), + ":time-pos-next" => self.time_pos() + self.time_zoom().get(), + ":time-pos-prev" => self.time_pos().saturating_sub(self.time_zoom().get()), + ":time-zoom" => self.time_zoom().get(), + ":time-zoom-next" => self.time_zoom().get() + 1, + ":time-zoom-prev" => self.time_zoom().get().saturating_sub(1).max(1), +}); + handle!(TuiIn: |self: Tek, input|Ok(if let Some(command) = self.keys.command(self, input) { let undo = command.execute(self)?; @@ -195,28 +238,6 @@ fn delegate_to_pool (app: &mut Tek, cmd: PoolCommand) -> Perhaps { }) } -provide!(bool: |self: MidiPool| {}); - -provide!(MidiClip: |self: MidiPool| { - ":new-clip" => self.new_clip(), - ":cloned-clip" => self.cloned_clip(), -}); - -provide!(PathBuf: |self: MidiPool| {}); - -provide!(Arc: |self: MidiPool| {}); - -provide!(usize: |self: MidiPool| { - ":current" => 0, - ":after" => 0, - ":previous" => 0, - ":next" => 0 -}); - -provide!(ItemColor: |self: MidiPool| { - ":random-color" => ItemColor::random() -}); - #[derive(Clone, PartialEq, Debug)] pub enum PoolCommand { /// Toggle visibility of pool Show(bool), @@ -272,25 +293,6 @@ command!(|self: PoolCommand, state: MidiPool|{ SetColor(usize, ItemColor), } -atom_command!(PoolClipCommand: |state: MidiPool| { - ("add" [i: usize, c: MidiClip] - Some(Self::Add(i.expect("no index"), c.expect("no clip")))) - ("delete" [i: usize] - Some(Self::Delete(i.expect("no index")))) - ("swap" [a: usize, b: usize] - Some(Self::Swap(a.expect("no index"), b.expect("no index")))) - ("import" [i: usize, p: PathBuf] - Some(Self::Import(i.expect("no index"), p.expect("no path")))) - ("export" [i: usize, p: PathBuf] - Some(Self::Export(i.expect("no index"), p.expect("no path")))) - ("set-name" [i: usize, n: Arc] - Some(Self::SetName(i.expect("no index"), n.expect("no name")))) - ("set-length" [i: usize, l: usize] - Some(Self::SetLength(i.expect("no index"), l.expect("no length")))) - ("set-color" [i: usize, c: ItemColor] - Some(Self::SetColor(i.expect("no index"), c.expect("no color")))) -}); - impl Command for PoolClipCommand { fn execute (self, model: &mut T) -> Perhaps { use PoolClipCommand::*; @@ -357,6 +359,81 @@ impl Command for PoolClipCommand { } } +atom_command!(ClipRenameCommand: |state: MidiPool| { + ("begin" [] Some(Self::Begin)) + ("cancel" [] Some(Self::Cancel)) + ("confirm" [] Some(Self::Confirm)) + ("set" [n: Arc] Some(Self::Set(n.expect("no name")))) +}); +atom_command!(ClipLengthCommand: |state: MidiPool| { + ("begin" [] Some(Self::Begin)) + ("cancel" [] Some(Self::Cancel)) + ("next" [] Some(Self::Next)) + ("prev" [] Some(Self::Prev)) + ("inc" [] Some(Self::Inc)) + ("dec" [] Some(Self::Dec)) + ("set" [l: usize] Some(Self::Set(l.expect("no length")))) +}); +atom_command!(FileBrowserCommand: |state: MidiPool| { + ("begin" [] Some(Self::Begin)) + ("cancel" [] Some(Self::Cancel)) + ("confirm" [] Some(Self::Confirm)) + ("select" [i: usize] Some(Self::Select(i.expect("no index")))) + ("chdir" [p: PathBuf] Some(Self::Chdir(p.expect("no path")))) + ("filter" [f: Arc] Some(Self::Filter(f.expect("no filter")))) +}); +atom_command!(MidiEditCommand: |state: MidiEditor| { + ("note/append" [] Some(Self::AppendNote)) + ("note/put" [] Some(Self::PutNote)) + ("note/del" [] Some(Self::DelNote)) + ("note/pos" [a: usize] Some(Self::SetNoteCursor(a.expect("no note cursor")))) + ("note/len" [a: usize] Some(Self::SetNoteLength(a.expect("no note length")))) + ("time/pos" [a: usize] Some(Self::SetTimeCursor(a.expect("no time cursor")))) + ("time/zoom" [a: usize] Some(Self::SetTimeZoom(a.expect("no time zoom")))) + ("time/lock" [a: bool] Some(Self::SetTimeLock(a.expect("no time lock")))) + ("time/lock" [] Some(Self::SetTimeLock(!state.time_lock().get()))) +}); +atom_command!(PoolClipCommand: |state: MidiPool| { + ("add" [i: usize, c: MidiClip] + Some(Self::Add(i.expect("no index"), c.expect("no clip")))) + ("delete" [i: usize] + Some(Self::Delete(i.expect("no index")))) + ("swap" [a: usize, b: usize] + Some(Self::Swap(a.expect("no index"), b.expect("no index")))) + ("import" [i: usize, p: PathBuf] + Some(Self::Import(i.expect("no index"), p.expect("no path")))) + ("export" [i: usize, p: PathBuf] + Some(Self::Export(i.expect("no index"), p.expect("no path")))) + ("set-name" [i: usize, n: Arc] + Some(Self::SetName(i.expect("no index"), n.expect("no name")))) + ("set-length" [i: usize, l: usize] + Some(Self::SetLength(i.expect("no index"), l.expect("no length")))) + ("set-color" [i: usize, c: ItemColor] + Some(Self::SetColor(i.expect("no index"), c.expect("no color")))) +}); +// TODO: 1-9 seek markers that by default start every 8th of the clip +defcom!([self, state: MidiEditor] + (MidiEditCommand + (AppendNote [] { state.put_note(true); None }) + (PutNote [] { state.put_note(false); None }) + (DelNote [] { None }) + (SetNoteCursor [x: usize] { state.set_note_pos(x.min(127)); None }) + (SetNoteLength [x: usize] { + let note_len = state.note_len(); + let time_zoom = state.time_zoom().get(); + state.set_note_len(x); + //if note_len / time_zoom != x / time_zoom { + state.redraw(); + //} + None + }) + (SetNoteScroll [x: usize] { state.note_lo().set(x.min(127)); None }) + (SetTimeCursor [x: usize] { state.set_time_pos(x); None }) + (SetTimeScroll [x: usize] { state.time_start().set(x); None }) + (SetTimeZoom [x: usize] { state.time_zoom().set(x); state.redraw(); None }) + (SetTimeLock [x: bool] { state.time_lock().set(x); None }) + (Show [x: MaybeClip] { state.set_clip(x.as_ref()); None }))); + #[derive(Clone, Debug, PartialEq)] pub enum ClipRenameCommand { Begin, Cancel, @@ -364,12 +441,6 @@ impl Command for PoolClipCommand { Set(Arc), } -atom_command!(ClipRenameCommand: |state: MidiPool| { - ("begin" [] Some(Self::Begin)) - ("cancel" [] Some(Self::Cancel)) - ("confirm" [] Some(Self::Confirm)) - ("set" [n: Arc] Some(Self::Set(n.expect("no name")))) -}); command!(|self: ClipRenameCommand, state: MidiPool|if let Some( PoolMode::Rename(clip, ref mut old_name) @@ -394,15 +465,6 @@ command!(|self: ClipRenameCommand, state: MidiPool|if let Some( unreachable!() }); -atom_command!(FileBrowserCommand: |state: MidiPool| { - ("begin" [] Some(Self::Begin)) - ("cancel" [] Some(Self::Cancel)) - ("confirm" [] Some(Self::Confirm)) - ("select" [i: usize] Some(Self::Select(i.expect("no index")))) - ("chdir" [p: PathBuf] Some(Self::Chdir(p.expect("no path")))) - ("filter" [f: Arc] Some(Self::Filter(f.expect("no filter")))) -}); - command!(|self: FileBrowserCommand, state: MidiPool|{ use PoolMode::*; use FileBrowserCommand::*; @@ -444,16 +506,6 @@ pub enum ClipLengthCommand { Dec, } -atom_command!(ClipLengthCommand: |state: MidiPool| { - ("begin" [] Some(Self::Begin)) - ("cancel" [] Some(Self::Cancel)) - ("next" [] Some(Self::Next)) - ("prev" [] Some(Self::Prev)) - ("inc" [] Some(Self::Inc)) - ("dec" [] Some(Self::Dec)) - ("set" [l: usize] Some(Self::Set(l.expect("no length")))) -}); - command!(|self: ClipLengthCommand, state: MidiPool|{ use ClipLengthCommand::*; use ClipLengthFocus::*; @@ -491,92 +543,3 @@ command!(|self: ClipLengthCommand, state: MidiPool|{ } None }); - -provide!(bool: |self: MidiEditor| { - ":true" => true, - ":false" => false, - ":time-lock" => self.time_lock().get(), - ":time-lock-toggle" => !self.time_lock().get(), -}); - -provide!(usize: |self: MidiEditor| { - ":note-length" => self.note_len(), - - ":note-pos" => self.note_pos(), - ":note-pos-next" => self.note_pos() + 1, - ":note-pos-prev" => self.note_pos().saturating_sub(1), - ":note-pos-next-octave" => self.note_pos() + 12, - ":note-pos-prev-octave" => self.note_pos().saturating_sub(12), - - ":note-len" => self.note_len(), - ":note-len-next" => self.note_len() + 1, - ":note-len-prev" => self.note_len().saturating_sub(1), - - ":note-range" => self.note_axis().get(), - ":note-range-prev" => self.note_axis().get() + 1, - ":note-range-next" => self.note_axis().get().saturating_sub(1), - - ":time-pos" => self.time_pos(), - ":time-pos-next" => self.time_pos() + self.time_zoom().get(), - ":time-pos-prev" => self.time_pos().saturating_sub(self.time_zoom().get()), - - ":time-zoom" => self.time_zoom().get(), - ":time-zoom-next" => self.time_zoom().get() + 1, - ":time-zoom-prev" => self.time_zoom().get().saturating_sub(1).max(1), -}); - -atom_command!(MidiEditCommand: |state: MidiEditor| { - ("note/append" [] Some(Self::AppendNote)) - ("note/put" [] Some(Self::PutNote)) - ("note/del" [] Some(Self::DelNote)) - ("note/pos" [a: usize] Some(Self::SetNoteCursor(a.expect("no note cursor")))) - ("note/len" [a: usize] Some(Self::SetNoteLength(a.expect("no note length")))) - ("time/pos" [a: usize] Some(Self::SetTimeCursor(a.expect("no time cursor")))) - ("time/zoom" [a: usize] Some(Self::SetTimeZoom(a.expect("no time zoom")))) - ("time/lock" [a: bool] Some(Self::SetTimeLock(a.expect("no time lock")))) - ("time/lock" [] Some(Self::SetTimeLock(!state.time_lock().get()))) -}); - -#[derive(Clone, Debug)] pub enum MidiEditCommand { - // TODO: 1-9 seek markers that by default start every 8th of the clip - AppendNote, - PutNote, - DelNote, - SetNoteCursor(usize), - SetNoteLength(usize), - SetNoteScroll(usize), - SetTimeCursor(usize), - SetTimeScroll(usize), - SetTimeZoom(usize), - SetTimeLock(bool), - Show(Option>>), -} - -impl Command for MidiEditCommand { - fn execute (self, state: &mut MidiEditor) -> Perhaps { - use MidiEditCommand::*; - match self { - Show(clip) => { state.set_clip(clip.as_ref()); }, - DelNote => {}, - PutNote => { state.put_note(false); }, - AppendNote => { state.put_note(true); }, - SetTimeZoom(x) => { state.time_zoom().set(x); state.redraw(); }, - SetTimeLock(x) => { state.time_lock().set(x); }, - SetTimeScroll(x) => { state.time_start().set(x); }, - SetNoteScroll(x) => { state.note_lo().set(x.min(127)); }, - SetNoteLength(x) => { - let note_len = state.note_len(); - let time_zoom = state.time_zoom().get(); - state.set_note_len(x); - //if note_len / time_zoom != x / time_zoom { - state.redraw(); - //} - }, - SetTimeCursor(x) => { state.set_time_pos(x); }, - SetNoteCursor(note) => { state.set_note_pos(note.min(127)); }, - //_ => todo!("{:?}", self) - } - Ok(None) - } -} -