unify command definitions and implementations

This commit is contained in:
🪞👃🪞 2025-04-24 01:32:36 +03:00
parent 5db97825cc
commit 85616f7338

View file

@ -26,89 +26,113 @@ 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<bool>)
Editor(MidiEditCommand)
Enqueue(Option<Arc<RwLock<MidiClip>>>)
History(isize)
Input(InputCommand)
Launch
Output(OutputCommand)
Pool(PoolCommand)
Sampler(SamplerCommand)
Scene(SceneCommand)
Select(Selection)
StopAll
Track(TrackCommand)
Zoom(Option<usize>)
}
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<Arc<RwLock<MidiClip>>>)
Enqueue(usize, usize)
Edit(Option<Arc<RwLock<MidiClip>>>)
SetLoop(usize, usize, bool)
SetColor(usize, usize, ItemPalette)
}
Sampler(cmd: SamplerCommand) => {
println!("\n\rtodo: {cmd:?}");
None
}
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
});
}
Enqueue(clip: Option<Arc<RwLock<MidiClip>>>) => {
println!("\n\rtodo: enqueue {clip:?}");
None
}
History(delta: isize) => {
println!("\n\rtodo: {self:?}");
None
}
Zoom(zoom: Option<usize>) => {
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 {
None
}
Color(palette: ItemPalette) => {
use Selection::*;
Some(Self::Color(match app.selected {
Mix => {
let old = app.color;
app.color = palette;
old
},
Self::Edit(value) => {
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<bool>) => {
if let Some(value) = value {
if app.is_editing() != value {
app.editing.store(value, Relaxed);
@ -143,20 +167,9 @@ command!(|self: TekCommand, app: Tek|match self {
}
}
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 => {
}
Launch => {
use Selection::*;
match app.selected {
Track(t) => app.tracks[t].player.enqueue_next(None),
@ -169,72 +182,64 @@ command!(|self: TekCommand, app: Tek|match self {
_ => {}
};
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
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
});
}
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)
None
}
}
}))
},
Self::StopAll => {
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()),
_ => {}
}
};
undo
} else {
None
},
_ => todo!("{self:?}")
});
command!(|self: InputCommand, app: Tek|match self {
Self::Add => {
}
InputCommand {
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 => {
}
}
OutputCommand {
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 => {
}
}
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 {
@ -243,36 +248,53 @@ command!(|self: TrackCommand, app: Tek|match self {
_ => 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) => {
}
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))
},
Self::TogglePlay => {
}
TogglePlay => {
Some(Self::TogglePlay)
},
Self::ToggleSolo => {
}
ToggleSolo => {
Some(Self::ToggleSolo)
},
Self::ToggleRecord => {
}
ToggleRecord => {
if let Some(t) = app.selected.track() {
app.tracks[t-1].player.recording = !app.tracks[t-1].player.recording;
}
Some(Self::ToggleRecord)
},
Self::ToggleMonitor => {
}
ToggleMonitor => {
if let Some(t) = app.selected.track() {
app.tracks[t-1].player.monitoring = !app.tracks[t-1].player.monitoring;
}
Some(Self::ToggleMonitor)
},
_ => None
});
command!(|self: SceneCommand, app: Tek|match self {
Self::Add => {
}
}
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 {
@ -281,33 +303,46 @@ command!(|self: SceneCommand, app: Tek|match self {
_ => app.selected
};
Some(Self::Del(index))
},
Self::Del(index) => { app.scene_del(index); None },
Self::SetColor(index, color) => {
}
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))
},
Self::Enqueue(scene) => {
}
Enqueue(scene: usize) => {
for track in 0..app.tracks.len() {
app.tracks[track].player.enqueue_next(app.scenes[scene].clips[track].as_ref());
}
None
},
_ => None
});
command!(|self: ClipCommand, app: Tek|match self {
Self::Get(track, scene) => { todo!() },
Self::Put(track, scene, clip) => {
}
}
ClipCommand {
Get(a: usize, b: usize) => {
println!("\n\rtodo: {self:?}");
None
}
Edit(clip: Option<Arc<RwLock<MidiClip>>>) => {
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<Arc<RwLock<MidiClip>>>) => {
let old = app.scenes[scene].clips[track].clone();
app.scenes[scene].clips[track] = clip;
Some(Self::Put(track, scene, old))
},
Self::Enqueue(track, scene) => {
}
Enqueue(track: usize, scene: usize) => {
app.tracks[track].player.enqueue_next(app.scenes[scene].clips[track].as_ref());
None
},
Self::SetColor(track, scene, color) => {
}
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();
@ -315,6 +350,6 @@ command!(|self: ClipCommand, app: Tek|match self {
panic!("{color:?} {old:?}");
Self::SetColor(track, scene, old)
})
},
_ => None
});
}
}
}