From 85616f7338aceced606efb26ee893005f4bf9132 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 24 Apr 2025 01:32:36 +0300 Subject: [PATCH] unify command definitions and implementations --- crates/app/src/keys.rs | 571 ++++++++++++++++++++++------------------- 1 file changed, 303 insertions(+), 268 deletions(-) diff --git a/crates/app/src/keys.rs b/crates/app/src/keys.rs index 3a34135c..30f4daf0 100644 --- a/crates/app/src/keys.rs +++ b/crates/app/src/keys.rs @@ -26,295 +26,330 @@ handle!(TuiIn: |self: Tek, input|Ok({ })); macro_rules! defcom { - ($($Command:ident { $( - $Variant:ident $(($($Param:ty),+))? + (|$self:ident, $app:ident:$App:ty| $($Command:ident { $( + $Variant:ident $(($($param:ident: $Param:ty),+))? => $expr:expr )* $(,)? })*) => { $(#[derive(Clone, Debug)] pub enum $Command { $($Variant $(($($Param),+))?),* })* + $(command!(|$self: $Command, $app: $App|match $self { + $($Command::$Variant $(($($param),+))? => $expr),* + });)* } } -defcom! { +defcom! { |self, app: Tek| + TekCommand { - Clip(ClipCommand) - Clock(ClockCommand) - Color(ItemPalette) - Edit(Option) - Editor(MidiEditCommand) - Enqueue(Option>>) - History(isize) - Input(InputCommand) - Launch - Output(OutputCommand) - Pool(PoolCommand) - Sampler(SamplerCommand) - Scene(SceneCommand) - Select(Selection) - StopAll - Track(TrackCommand) - Zoom(Option) - } - InputCommand { - Add - } - OutputCommand { - Add - } - TrackCommand { - Add - Del(usize) - Stop(usize) - Swap(usize, usize) - SetSize(usize) - SetZoom(usize) - SetColor(usize, ItemPalette) - TogglePlay - ToggleSolo - ToggleRecord - ToggleMonitor - } - SceneCommand { - Add - Del(usize) - Swap(usize, usize) - SetSize(usize) - SetZoom(usize) - SetColor(usize, ItemPalette) - Enqueue(usize) - } - ClipCommand { - Get(usize, usize) - Put(usize, usize, Option>>) - Enqueue(usize, usize) - Edit(Option>>) - SetLoop(usize, usize, bool) - SetColor(usize, usize, ItemPalette) - } -} -command!(|self: TekCommand, app: Tek|match self { - Self::Zoom(_) => { println!("\n\rtodo: global zoom"); None }, - Self::History(delta) => { println!("\n\rtodo: undo/redo"); None }, - Self::Select(s) => { - app.selected = s; - // autoedit: load focused clip in editor. - if let Some(ref mut editor) = app.editor { - editor.set_clip(match app.selected { - Selection::Clip(t, s) if let Some(Some(Some(clip))) = app - .scenes.get(s).map(|s|s.clips.get(t)) => Some(clip), - _ => None - }); + Sampler(cmd: SamplerCommand) => { + println!("\n\rtodo: {cmd:?}"); + None } - None - }, - Self::Edit(value) => { - if let Some(value) = value { - if app.is_editing() != value { - app.editing.store(value, Relaxed); - } + + Enqueue(clip: Option>>) => { + println!("\n\rtodo: enqueue {clip:?}"); + None + } + + History(delta: isize) => { + println!("\n\rtodo: {self:?}"); + None + } + + Zoom(zoom: Option) => { + println!("\n\rtodo: {self:?}"); + None + } + + Scene(cmd: SceneCommand) => + cmd.delegate(app, Self::Scene)? + + Track(cmd: TrackCommand) => + cmd.delegate(app, Self::Track)? + + Output(cmd: OutputCommand) => + cmd.delegate(app, Self::Output)? + + Input(cmd: InputCommand) => + cmd.delegate(app, Self::Input)? + + Clip(cmd: ClipCommand) => + cmd.delegate(app, Self::Clip)? + + Clock(cmd: ClockCommand) => + cmd.delegate(app, Self::Clock)? + + Editor(cmd: MidiEditCommand) => app.editor.as_mut() + .map(|editor|cmd.delegate(editor, Self::Editor)) + .transpose()? + .flatten() + + Pool(cmd: PoolCommand) => if let Some(pool) = app.pool.as_mut() { + let undo = cmd.clone().delegate(pool, Self::Pool)?; + if let Some(editor) = app.editor.as_mut() { + match cmd { + // autoselect: automatically load selected clip in editor + // autocolor: update color in all places simultaneously + PoolCommand::Select(_) | PoolCommand::Clip(PoolClipCommand::SetColor(_, _)) => + editor.set_clip(pool.clip().as_ref()), + _ => {} + } + }; + undo } else { - app.editing.store(!app.is_editing(), Relaxed); - }; - // autocreate: create new clip from pool when entering empty cell - if let Some(ref pool) = app.pool { - if app.is_editing() { - if let Selection::Clip(t, s) = app.selected { - if let Some(scene) = app.scenes.get_mut(s) { - if let Some(slot) = scene.clips.get_mut(t) { - if slot.is_none() { - let (index, mut clip) = pool.add_new_clip(); - // autocolor: new clip colors from scene and track color - clip.write().unwrap().color = ItemColor::random_near( - app.tracks[t].color.base.mix( - scene.color.base, - 0.5 - ), - 0.2 - ).into(); - if let Some(ref mut editor) = app.editor { - editor.set_clip(Some(&clip)); + None + } + + Color(palette: ItemPalette) => { + use Selection::*; + Some(Self::Color(match app.selected { + Mix => { + let old = app.color; + app.color = palette; + old + }, + Track(t) => { + let old = app.tracks[t].color; + app.tracks[t].color = palette; + old + } + Scene(s) => { + let old = app.scenes[s].color; + app.scenes[s].color = palette; + old + } + Clip(t, s) => { + if let Some(ref clip) = app.scenes[s].clips[t] { + let mut clip = clip.write().unwrap(); + let old = clip.color; + clip.color = palette; + old + } else { + return Ok(None) + } + } + })) + } + + Edit(value: Option) => { + if let Some(value) = value { + if app.is_editing() != value { + app.editing.store(value, Relaxed); + } + } else { + app.editing.store(!app.is_editing(), Relaxed); + }; + // autocreate: create new clip from pool when entering empty cell + if let Some(ref pool) = app.pool { + if app.is_editing() { + if let Selection::Clip(t, s) = app.selected { + if let Some(scene) = app.scenes.get_mut(s) { + if let Some(slot) = scene.clips.get_mut(t) { + if slot.is_none() { + let (index, mut clip) = pool.add_new_clip(); + // autocolor: new clip colors from scene and track color + clip.write().unwrap().color = ItemColor::random_near( + app.tracks[t].color.base.mix( + scene.color.base, + 0.5 + ), + 0.2 + ).into(); + if let Some(ref mut editor) = app.editor { + editor.set_clip(Some(&clip)); + } + *slot = Some(clip); } - *slot = Some(clip); } } } } } + None } - None - }, - Self::Clock(cmd) => cmd.delegate(app, Self::Clock)?, - Self::Scene(cmd) => cmd.delegate(app, Self::Scene)?, - Self::Track(cmd) => cmd.delegate(app, Self::Track)?, - Self::Input(cmd) => cmd.delegate(app, Self::Input)?, - Self::Output(cmd) => cmd.delegate(app, Self::Output)?, - Self::Clip(cmd) => cmd.delegate(app, Self::Clip)?, - Self::Editor(cmd) => app.editor.as_mut() - .map(|editor|cmd.delegate(editor, Self::Editor)).transpose()?.flatten(), - //Self::Sampler(cmd) => app.sampler.as_mut() - //.map(|sampler|cmd.delegate(sampler, Self::Sampler)).transpose()?.flatten(), - //Self::Enqueue(clip) => app.player.as_mut() - //.map(|player|{player.enqueue_next(clip.as_ref());None}).flatten(), - Self::Launch => { - use Selection::*; - match app.selected { - Track(t) => app.tracks[t].player.enqueue_next(None), - Clip(t, s) => app.tracks[t].player.enqueue_next(app.scenes[s].clips[t].as_ref()), - Scene(s) => { - for t in 0..app.tracks.len() { - app.tracks[t].player.enqueue_next(app.scenes[s].clips[t].as_ref()) - } - }, - _ => {} - }; - None - }, - Self::Color(palette) => { - use Selection::*; - Some(Self::Color(match app.selected { - Mix => { - let old = app.color; - app.color = palette; - old - }, - Track(t) => { - let old = app.tracks[t].color; - app.tracks[t].color = palette; - old - } - Scene(s) => { - let old = app.scenes[s].color; - app.scenes[s].color = palette; - old - } - Clip(t, s) => { - if let Some(ref clip) = app.scenes[s].clips[t] { - let mut clip = clip.write().unwrap(); - let old = clip.color; - clip.color = palette; - old - } else { - return Ok(None) - } - } - })) - }, - Self::StopAll => { - for track in 0..app.tracks.len(){app.tracks[track].player.enqueue_next(None);} - None - }, - Self::Pool(cmd) => if let Some(pool) = app.pool.as_mut() { - let undo = cmd.clone().delegate(pool, Self::Pool)?; - if let Some(editor) = app.editor.as_mut() { - match cmd { - // autoselect: automatically load selected clip in editor - // autocolor: update color in all places simultaneously - PoolCommand::Select(_) | PoolCommand::Clip(PoolClipCommand::SetColor(_, _)) => - editor.set_clip(pool.clip().as_ref()), + + Launch => { + use Selection::*; + match app.selected { + Track(t) => app.tracks[t].player.enqueue_next(None), + Clip(t, s) => app.tracks[t].player.enqueue_next(app.scenes[s].clips[t].as_ref()), + Scene(s) => { + for t in 0..app.tracks.len() { + app.tracks[t].player.enqueue_next(app.scenes[s].clips[t].as_ref()) + } + }, _ => {} + }; + None + } + + Select(s: Selection) => { + app.selected = s; + // autoedit: load focused clip in editor. + if let Some(ref mut editor) = app.editor { + editor.set_clip(match app.selected { + Selection::Clip(t, s) if let Some(Some(Some(clip))) = app + .scenes.get(s).map(|s|s.clips.get(t)) => Some(clip), + _ => None + }); } - }; - undo - } else { - None - }, - _ => todo!("{self:?}") -}); -command!(|self: InputCommand, app: Tek|match self { - Self::Add => { - app.midi_ins.push(JackMidiIn::new(&app.jack, &format!("M/{}", app.midi_ins.len()), &[])?); - None - }, -}); -command!(|self: OutputCommand, app: Tek|match self { - Self::Add => { - app.midi_outs.push(JackMidiOut::new(&app.jack, &format!("{}/M", app.midi_outs.len()), &[])?); - None - }, -}); -command!(|self: TrackCommand, app: Tek|match self { - Self::Add => { - use Selection::*; - let index = app.track_add(None, None, &[], &[])?.0; - app.selected = match app.selected { - Track(t) => Track(index), - Clip(t, s) => Clip(index, s), - _ => app.selected - }; - Some(Self::Del(index)) - }, - Self::Del(index) => { app.track_del(index); None }, - Self::Stop(track) => { app.tracks[track].player.enqueue_next(None); None }, - Self::SetColor(index, color) => { - let old = app.tracks[index].color; - app.tracks[index].color = color; - Some(Self::SetColor(index, old)) - }, - Self::TogglePlay => { - Some(Self::TogglePlay) - }, - Self::ToggleSolo => { - Some(Self::ToggleSolo) - }, - Self::ToggleRecord => { - if let Some(t) = app.selected.track() { - app.tracks[t-1].player.recording = !app.tracks[t-1].player.recording; + None } - Some(Self::ToggleRecord) - }, - Self::ToggleMonitor => { - if let Some(t) = app.selected.track() { - app.tracks[t-1].player.monitoring = !app.tracks[t-1].player.monitoring; + + StopAll => { + for track in 0..app.tracks.len(){app.tracks[track].player.enqueue_next(None);} + None } - Some(Self::ToggleMonitor) - }, - _ => None -}); -command!(|self: SceneCommand, app: Tek|match self { - Self::Add => { - use Selection::*; - let index = app.scene_add(None, None)?.0; - app.selected = match app.selected { - Scene(s) => Scene(index), - Clip(t, s) => Clip(t, index), - _ => app.selected - }; - Some(Self::Del(index)) - }, - Self::Del(index) => { app.scene_del(index); None }, - Self::SetColor(index, color) => { - let old = app.scenes[index].color; - app.scenes[index].color = color; - Some(Self::SetColor(index, old)) - }, - Self::Enqueue(scene) => { - for track in 0..app.tracks.len() { + + } + + InputCommand { + + Add => { + app.midi_ins.push(JackMidiIn::new(&app.jack, &format!("M/{}", app.midi_ins.len()), &[])?); + None + } + + } + + OutputCommand { + + Add => { + app.midi_outs.push(JackMidiOut::new(&app.jack, &format!("{}/M", app.midi_outs.len()), &[])?); + None + } + + } + + TrackCommand { + + Swap(a: usize, b: usize) => { + println!("\n\rtodo: {self:?}"); + None + } + + SetSize(t: usize) => { + println!("\n\rtodo: {self:?}"); + None + } + + SetZoom(z: usize) => { + println!("\n\rtodo: {self:?}"); + None + } + + Add => { + use Selection::*; + let index = app.track_add(None, None, &[], &[])?.0; + app.selected = match app.selected { + Track(t) => Track(index), + Clip(t, s) => Clip(index, s), + _ => app.selected + }; + Some(Self::Del(index)) + } + Del(index: usize) => { + app.track_del(index); + None + } + Stop(index: usize) => { + app.tracks[index].player.enqueue_next(None); + None + } + SetColor(index: usize, color: ItemPalette) => { + let old = app.tracks[index].color; + app.tracks[index].color = color; + Some(Self::SetColor(index, old)) + } + TogglePlay => { + Some(Self::TogglePlay) + } + ToggleSolo => { + Some(Self::ToggleSolo) + } + ToggleRecord => { + if let Some(t) = app.selected.track() { + app.tracks[t-1].player.recording = !app.tracks[t-1].player.recording; + } + Some(Self::ToggleRecord) + } + ToggleMonitor => { + if let Some(t) = app.selected.track() { + app.tracks[t-1].player.monitoring = !app.tracks[t-1].player.monitoring; + } + Some(Self::ToggleMonitor) + } + } + SceneCommand { + Swap(a: usize, b: usize) => { + println!("\n\rtodo: {self:?}"); + None + } + SetSize(index: usize) => { + println!("\n\rtodo: {self:?}"); + None + } + SetZoom(zoom: usize) => { + println!("\n\rtodo: {self:?}"); + None + } + Add => { + use Selection::*; + let index = app.scene_add(None, None)?.0; + app.selected = match app.selected { + Scene(s) => Scene(index), + Clip(t, s) => Clip(t, index), + _ => app.selected + }; + Some(Self::Del(index)) + } + Del(index: usize) => { + app.scene_del(index); + None + } + SetColor(index: usize, color: ItemPalette) => { + let old = app.scenes[index].color; + app.scenes[index].color = color; + Some(Self::SetColor(index, old)) + } + Enqueue(scene: usize) => { + for track in 0..app.tracks.len() { + app.tracks[track].player.enqueue_next(app.scenes[scene].clips[track].as_ref()); + } + None + } + } + ClipCommand { + Get(a: usize, b: usize) => { + println!("\n\rtodo: {self:?}"); + None + } + Edit(clip: Option>>) => { + println!("\n\rtodo: edit {clip:?}"); + None + } + SetLoop(track: usize, scene: usize, looped: bool) => { + println!("\n\rtodo: {self:?}"); + None + } + Put(track: usize, scene: usize, clip: Option>>) => { + let old = app.scenes[scene].clips[track].clone(); + app.scenes[scene].clips[track] = clip; + Some(Self::Put(track, scene, old)) + } + Enqueue(track: usize, scene: usize) => { app.tracks[track].player.enqueue_next(app.scenes[scene].clips[track].as_ref()); + None } - None - }, - _ => None -}); -command!(|self: ClipCommand, app: Tek|match self { - Self::Get(track, scene) => { todo!() }, - Self::Put(track, scene, clip) => { - let old = app.scenes[scene].clips[track].clone(); - app.scenes[scene].clips[track] = clip; - Some(Self::Put(track, scene, old)) - }, - Self::Enqueue(track, scene) => { - app.tracks[track].player.enqueue_next(app.scenes[scene].clips[track].as_ref()); - None - }, - Self::SetColor(track, scene, color) => { - app.scenes[scene].clips[track].as_ref().map(|clip|{ - let mut clip = clip.write().unwrap(); - let old = clip.color.clone(); - clip.color = color.clone(); - panic!("{color:?} {old:?}"); - Self::SetColor(track, scene, old) - }) - }, - _ => None -}); + SetColor(track: usize, scene: usize, color: ItemPalette) => { + app.scenes[scene].clips[track].as_ref().map(|clip|{ + let mut clip = clip.write().unwrap(); + let old = clip.color.clone(); + clip.color = color.clone(); + panic!("{color:?} {old:?}"); + Self::SetColor(track, scene, old) + }) + } + } +}