From 38fb348d1969f6534c9ee08ccaa1d765c479e49e Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 26 Apr 2025 15:58:35 +0300 Subject: [PATCH] wip: add overlay for help/menu modals --- crates/app/edn/arranger_keys.edn | 3 + crates/app/edn/groovebox_keys.edn | 8 + crates/app/src/api.rs | 277 ++++++++++++++---------------- crates/app/src/model.rs | 149 +++++++++++----- crates/app/src/view.rs | 30 +++- crates/cli/edn/arranger.edn | 11 +- crates/cli/edn/groovebox.edn | 13 +- crates/cli/edn/sampler.edn | 7 +- crates/cli/edn/sequencer.edn | 11 +- crates/cli/tek.rs | 48 +++--- 10 files changed, 323 insertions(+), 234 deletions(-) diff --git a/crates/app/edn/arranger_keys.edn b/crates/app/edn/arranger_keys.edn index 46060ffd..fcb88e93 100644 --- a/crates/app/edn/arranger_keys.edn +++ b/crates/app/edn/arranger_keys.edn @@ -1,3 +1,6 @@ +(@esc menu) +(@f1 help) + (@u undo 1) (@shift-u redo 1) (@space clock toggle) diff --git a/crates/app/edn/groovebox_keys.edn b/crates/app/edn/groovebox_keys.edn index d03d652e..ba69dbb0 100644 --- a/crates/app/edn/groovebox_keys.edn +++ b/crates/app/edn/groovebox_keys.edn @@ -1,9 +1,17 @@ +(@esc menu) +(@f1 help) + (@u undo 1) (@shift-u redo 1) + (@space clock toggle) (@shift-space clock toggle 0) + (@c color) + (@q launch) + (@shift-I input add) (@shift-O output add) + (@r record/begin :sample) diff --git a/crates/app/src/api.rs b/crates/app/src/api.rs index 8d5863c2..fc0d3a96 100644 --- a/crates/app/src/api.rs +++ b/crates/app/src/api.rs @@ -30,45 +30,141 @@ expose!([self: Tek] { } } [Selection] => { - ":scene-next" => match self.selected { - Selection::Mix => Selection::Scene(0), - Selection::Track(t) => Selection::Clip(t, 0), - Selection::Scene(s) if s + 1 < self.scenes.len() => Selection::Scene(s + 1), - Selection::Scene(s) => Selection::Mix, - Selection::Clip(t, s) if s + 1 < self.scenes.len() => Selection::Clip(t, s + 1), - Selection::Clip(t, s) => Selection::Track(t), - }, - ":scene-prev" => match self.selected { - Selection::Mix => Selection::Mix, - Selection::Track(t) => Selection::Track(t), - Selection::Scene(0) => Selection::Mix, - Selection::Scene(s) => Selection::Scene(s - 1), - Selection::Clip(t, 0) => Selection::Track(t), - Selection::Clip(t, s) => Selection::Clip(t, s - 1), - }, - ":track-next" => match self.selected { - Selection::Mix => Selection::Track(0), - Selection::Track(t) if t + 1 < self.tracks.len() => Selection::Track(t + 1), - Selection::Track(t) => Selection::Mix, - Selection::Scene(s) => Selection::Clip(0, s), - Selection::Clip(t, s) if t + 1 < self.tracks.len() => Selection::Clip(t + 1, s), - Selection::Clip(t, s) => Selection::Scene(s), - }, - ":track-prev" => match self.selected { - Selection::Mix => Selection::Mix, - Selection::Scene(s) => Selection::Scene(s), - Selection::Track(0) => Selection::Mix, - Selection::Track(t) => Selection::Track(t - 1), - Selection::Clip(0, s) => Selection::Scene(s), - Selection::Clip(t, s) => Selection::Clip(t - 1, s), - }, + ":scene-next" => self.selected.scene_next(self.scenes.len()), + ":scene-prev" => self.selected.scene_prev(), + ":track-next" => self.selected.track_next(self.tracks.len()), + ":track-prev" => self.selected.track_prev(), } }); +impose!([app: Tek] { + + TekCommand => { + ("help" [] + Some(Self::ToggleHelp)) + ("stop" [] + Some(Self::StopAll)) + ("undo" [d: usize] + Some(Self::History(-(d.unwrap_or(0)as isize)))) + ("redo" [d: usize] + Some(Self::History(d.unwrap_or(0) as isize))) + ("zoom" [z: usize] + Some(Self::Zoom(z))) + ("edit" [] + Some(Self::Edit(None))) + ("edit" [c: bool] + Some(Self::Edit(c))) + ("color" [] + Some(Self::Color(ItemPalette::random()))) + ("color" [c: Color] + Some(Self::Color(c.map(ItemPalette::from).expect("no color")))) + ("enqueue" [c: Arc>] + Some(Self::Enqueue(c))) + ("launch" [] + Some(Self::Launch)) + ("clip" [,..a] + ClipCommand::try_from_expr(app, a).map(Self::Clip)) + ("clock" [,..a] + ClockCommand::try_from_expr(app.clock(), a).map(Self::Clock)) + ("editor" [,..a] + MidiEditCommand::try_from_expr(app.editor.as_ref().expect("no editor"), a).map(Self::Editor)) + ("pool" [,..a] + PoolCommand::try_from_expr(app.pool.as_ref().expect("no pool"), a).map(Self::Pool)) + //("sampler" [,..a] + // Self::Sampler( //SamplerCommand::try_from_expr(app.sampler().as_ref().expect("no sampler"), a).expect("invalid command"))) + ("scene" [,..a] + SceneCommand::try_from_expr(app, a).map(Self::Scene)) + ("track" [,..a] + TrackCommand::try_from_expr(app, a).map(Self::Track)) + ("input" [,..a] + InputCommand::try_from_expr(app, a).map(Self::Input)) + ("output" [,..a] + OutputCommand::try_from_expr(app, a).map(Self::Output)) + ("select" [t: Selection] + Some(t.map(Self::Select).expect("no selection"))) + ("select" [t: usize, s: usize] + Some(match (t.expect("no track"), s.expect("no scene")) { + (0, 0) => Self::Select(Selection::Mix), + (t, 0) => Self::Select(Selection::Track(t)), + (0, s) => Self::Select(Selection::Scene(s)), + (t, s) => Self::Select(Selection::Clip(t, s)), + })) + } + + ClipCommand => { + ("get" [a: usize, b: usize] + Some(Self::Get(a.unwrap(), b.unwrap()))) + ("put" [a: usize, b: usize, c: Option>>] + Some(Self::Put(a.unwrap(), b.unwrap(), c.unwrap()))) + ("enqueue" [a: usize, b: usize] + Some(Self::Enqueue(a.unwrap(), b.unwrap()))) + ("edit" [a: Option>>] + Some(Self::Edit(a.unwrap()))) + ("loop" [a: usize, b: usize, c: bool] + Some(Self::SetLoop(a.unwrap(), b.unwrap(), c.unwrap()))) + ("color" [a: usize, b: usize] + Some(Self::SetColor(a.unwrap(), b.unwrap(), ItemPalette::random()))) + } + + InputCommand => { + ("add" [] Some(Self::Add)) + } + + OutputCommand => { + ("add" [] Some(Self::Add)) + } + + SceneCommand => { + ("add" [] + Some(Self::Add)) + ("del" [a: usize] + Some(Self::Del(0))) + ("zoom" [a: usize] + Some(Self::SetZoom(a.unwrap()))) + ("color" [a: usize] + Some(Self::SetColor(a.unwrap(), ItemPalette::G[128]))) + ("enqueue" [a: usize] + Some(Self::Enqueue(a.unwrap()))) + ("swap" [a: usize, b: usize] + Some(Self::Swap(a.unwrap(), b.unwrap()))) + } + + TrackCommand => { + ("add" [] + Some(Self::Add)) + ("size" [a: usize] + Some(Self::SetSize(a.unwrap()))) + ("zoom" [a: usize] + Some(Self::SetZoom(a.unwrap()))) + ("color" [a: usize] + Some(Self::SetColor(a.unwrap(), ItemPalette::random()))) + ("del" [a: usize] + Some(Self::Del(a.unwrap()))) + ("stop" [a: usize] + Some(Self::Stop(a.unwrap()))) + ("swap" [a: usize, b: usize] + Some(Self::Swap(a.unwrap(), b.unwrap()))) + ("play" [] + Some(Self::TogglePlay)) + ("solo" [] + Some(Self::ToggleSolo)) + ("rec" [] + Some(Self::ToggleRecord)) + ("mon" [] + Some(Self::ToggleMonitor)) + } + +}); + defcom! { |self, app: Tek| TekCommand { + ToggleHelp => { + app.modal = Some(Modal::Help); + None + } + Sampler(cmd: SamplerCommand) => { println!("\n\rtodo: {cmd:?}"); None @@ -380,120 +476,3 @@ defcom! { |self, app: Tek| } } - -impose!([app: Tek] { - - TekCommand => { - ("stop" [] - Some(Self::StopAll)) - ("undo" [d: usize] - Some(Self::History(-(d.unwrap_or(0)as isize)))) - ("redo" [d: usize] - Some(Self::History(d.unwrap_or(0) as isize))) - ("zoom" [z: usize] - Some(Self::Zoom(z))) - ("edit" [] - Some(Self::Edit(None))) - ("edit" [c: bool] - Some(Self::Edit(c))) - ("color" [] - Some(Self::Color(ItemPalette::random()))) - ("color" [c: Color] - Some(Self::Color(c.map(ItemPalette::from).expect("no color")))) - ("enqueue" [c: Arc>] - Some(Self::Enqueue(c))) - ("launch" [] - Some(Self::Launch)) - ("clip" [,..a] - ClipCommand::try_from_expr(app, a).map(Self::Clip)) - ("clock" [,..a] - ClockCommand::try_from_expr(app.clock(), a).map(Self::Clock)) - ("editor" [,..a] - MidiEditCommand::try_from_expr(app.editor.as_ref().expect("no editor"), a).map(Self::Editor)) - ("pool" [,..a] - PoolCommand::try_from_expr(app.pool.as_ref().expect("no pool"), a).map(Self::Pool)) - //("sampler" [,..a] - // Self::Sampler( //SamplerCommand::try_from_expr(app.sampler().as_ref().expect("no sampler"), a).expect("invalid command"))) - ("scene" [,..a] - SceneCommand::try_from_expr(app, a).map(Self::Scene)) - ("track" [,..a] - TrackCommand::try_from_expr(app, a).map(Self::Track)) - ("input" [,..a] - InputCommand::try_from_expr(app, a).map(Self::Input)) - ("output" [,..a] - OutputCommand::try_from_expr(app, a).map(Self::Output)) - ("select" [t: Selection] - Some(t.map(Self::Select).expect("no selection"))) - ("select" [t: usize, s: usize] - Some(match (t.expect("no track"), s.expect("no scene")) { - (0, 0) => Self::Select(Selection::Mix), - (t, 0) => Self::Select(Selection::Track(t)), - (0, s) => Self::Select(Selection::Scene(s)), - (t, s) => Self::Select(Selection::Clip(t, s)), - })) - } - - ClipCommand => { - ("get" [a: usize, b: usize] - Some(Self::Get(a.unwrap(), b.unwrap()))) - ("put" [a: usize, b: usize, c: Option>>] - Some(Self::Put(a.unwrap(), b.unwrap(), c.unwrap()))) - ("enqueue" [a: usize, b: usize] - Some(Self::Enqueue(a.unwrap(), b.unwrap()))) - ("edit" [a: Option>>] - Some(Self::Edit(a.unwrap()))) - ("loop" [a: usize, b: usize, c: bool] - Some(Self::SetLoop(a.unwrap(), b.unwrap(), c.unwrap()))) - ("color" [a: usize, b: usize] - Some(Self::SetColor(a.unwrap(), b.unwrap(), ItemPalette::random()))) - } - - InputCommand => { - ("add" [] Some(Self::Add)) - } - - OutputCommand => { - ("add" [] Some(Self::Add)) - } - - SceneCommand => { - ("add" [] - Some(Self::Add)) - ("del" [a: usize] - Some(Self::Del(0))) - ("zoom" [a: usize] - Some(Self::SetZoom(a.unwrap()))) - ("color" [a: usize] - Some(Self::SetColor(a.unwrap(), ItemPalette::G[128]))) - ("enqueue" [a: usize] - Some(Self::Enqueue(a.unwrap()))) - ("swap" [a: usize, b: usize] - Some(Self::Swap(a.unwrap(), b.unwrap()))) - } - - TrackCommand => { - ("add" [] - Some(Self::Add)) - ("size" [a: usize] - Some(Self::SetSize(a.unwrap()))) - ("zoom" [a: usize] - Some(Self::SetZoom(a.unwrap()))) - ("color" [a: usize] - Some(Self::SetColor(a.unwrap(), ItemPalette::random()))) - ("del" [a: usize] - Some(Self::Del(a.unwrap()))) - ("stop" [a: usize] - Some(Self::Stop(a.unwrap()))) - ("swap" [a: usize, b: usize] - Some(Self::Swap(a.unwrap(), b.unwrap()))) - ("play" [] - Some(Self::TogglePlay)) - ("solo" [] - Some(Self::ToggleSolo)) - ("rec" [] - Some(Self::ToggleRecord)) - ("mon" [] - Some(Self::ToggleMonitor)) - } - -}); diff --git a/crates/app/src/model.rs b/crates/app/src/model.rs index 83cc71cb..92f6d88a 100644 --- a/crates/app/src/model.rs +++ b/crates/app/src/model.rs @@ -1,6 +1,7 @@ use crate::*; -#[derive(Default, Debug)] pub struct Tek { +#[derive(Default, Debug)] +pub struct Tek { /// Must not be dropped for the duration of the process pub jack: Jack, /// Source of time @@ -50,50 +51,20 @@ use crate::*; // Cache of formatted strings pub view_cache: Arc>, // Input handler function - pub handler: OptionResult, Box<(dyn std::error::Error + 'static)>>> + pub handler: OptionResult, Box<(dyn std::error::Error + 'static)>>>, + // Modal overlay + pub modal: Option } impl Tek { - pub(crate) fn clip (&self) -> Option>> { - self.scene()?.clips.get(self.selected().track()?)?.clone() - } - - pub(crate) fn toggle_loop (&mut self) { - if let Some(clip) = self.clip() { - clip.write().unwrap().toggle_loop() - } - } - - pub(crate) fn activate (&mut self) -> Usually<()> { - let selected = self.selected().clone(); - match selected { - Selection::Scene(s) => { - let mut clips = vec![]; - for (t, _) in self.tracks().iter().enumerate() { - clips.push(self.scenes()[s].clips[t].clone()); - } - for (t, track) in self.tracks_mut().iter_mut().enumerate() { - if track.player.play_clip.is_some() || clips[t].is_some() { - track.player.enqueue_next(clips[t].as_ref()); - } - } - if self.clock().is_stopped() { - self.clock().play_from(Some(0))?; - } - }, - Selection::Clip(t, s) => { - let clip = self.scenes()[s].clips[t].clone(); - self.tracks_mut()[t].player.enqueue_next(clip.as_ref()); - }, - _ => {} - } - Ok(()) - } - + /// Add multiple tracks pub fn tracks_add ( - &mut self, count: usize, width: Option, - midi_from: &[PortConnect], midi_to: &[PortConnect], + &mut self, + count: usize, + width: Option, + midi_from: &[PortConnect], + midi_to: &[PortConnect], ) -> Usually<()> { let jack = self.jack().clone(); let track_color_1 = ItemColor::random(); @@ -108,8 +79,11 @@ impl Tek { Ok(()) } + /// Add a track pub fn track_add ( - &mut self, name: Option<&str>, color: Option, + &mut self, + name: Option<&str>, + color: Option, midi_froms: &[PortConnect], midi_tos: &[PortConnect], ) -> Usually<(usize, &mut Track)> { @@ -139,6 +113,7 @@ impl Tek { Ok((index, &mut self.tracks_mut()[index])) } + /// Delete a track pub fn track_del (&mut self, index: usize) { self.tracks_mut().remove(index); for scene in self.scenes_mut().iter_mut() { @@ -146,6 +121,7 @@ impl Tek { } } + /// Add multiple scenes pub fn scenes_add (&mut self, n: usize) -> Usually<()> { let scene_color_1 = ItemColor::random(); let scene_color_2 = ItemColor::random(); @@ -157,6 +133,7 @@ impl Tek { Ok(()) } + /// Add a scene pub fn scene_add (&mut self, name: Option<&str>, color: Option) -> Usually<(usize, &mut Scene)> { @@ -170,6 +147,7 @@ impl Tek { Ok((index, &mut self.scenes_mut()[index])) } + /// Generate the default name for a new scene pub fn scene_default_name (&self) -> Arc { format!("Sc{:3>}", self.scenes().len() + 1).into() } @@ -216,6 +194,45 @@ impl Tek { } } + /// Get the active clip + pub(crate) fn clip (&self) -> Option>> { + self.scene()?.clips.get(self.selected().track()?)?.clone() + } + + /// Toggle looping for the active clip + pub(crate) fn toggle_loop (&mut self) { + if let Some(clip) = self.clip() { + clip.write().unwrap().toggle_loop() + } + } + + /// Launch a clip or scene + pub(crate) fn activate (&mut self) -> Usually<()> { + let selected = self.selected().clone(); + match selected { + Selection::Scene(s) => { + let mut clips = vec![]; + for (t, _) in self.tracks().iter().enumerate() { + clips.push(self.scenes()[s].clips[t].clone()); + } + for (t, track) in self.tracks_mut().iter_mut().enumerate() { + if track.player.play_clip.is_some() || clips[t].is_some() { + track.player.enqueue_next(clips[t].as_ref()); + } + } + if self.clock().is_stopped() { + self.clock().play_from(Some(0))?; + } + }, + Selection::Clip(t, s) => { + let clip = self.scenes()[s].clips[t].clone(); + self.tracks_mut()[t].player.enqueue_next(clip.as_ref()); + }, + _ => {} + } + Ok(()) + } + } has_size!(|self: Tek|&self.size); @@ -242,8 +259,16 @@ pub trait HasSelection { fn selected_mut (&mut self) -> &mut Selection; } +/// Various possible modal overlays +#[derive(PartialEq, Clone, Copy, Debug)] +pub enum Modal { + Help, + Menu, +} + /// Represents the current user selection in the arranger -#[derive(PartialEq, Clone, Copy, Debug, Default)] pub enum Selection { +#[derive(PartialEq, Clone, Copy, Debug, Default)] +pub enum Selection { /// The whole mix is selected #[default] Mix, /// A track is selected. @@ -272,10 +297,50 @@ impl Selection { use Selection::*; match self { Clip(t, _) => Some(*t), Track(t) => Some(*t), _ => None } } + pub fn track_next (&self, len: usize) -> Self { + match self { + Selection::Mix => Selection::Track(0), + Selection::Track(t) if t + 1 < len => Selection::Track(t + 1), + Selection::Track(t) => Selection::Mix, + Selection::Scene(s) => Selection::Clip(0, *s), + Selection::Clip(t, s) if t + 1 < len => Selection::Clip(t + 1, *s), + Selection::Clip(t, s) => Selection::Scene(*s), + } + } + pub fn track_prev (&self) -> Self { + match self { + Selection::Mix => Selection::Mix, + Selection::Scene(s) => Selection::Scene(*s), + Selection::Track(0) => Selection::Mix, + Selection::Track(t) => Selection::Track(t - 1), + Selection::Clip(0, s) => Selection::Scene(*s), + Selection::Clip(t, s) => Selection::Clip(t - 1, *s), + } + } pub fn scene (&self) -> Option { use Selection::*; match self { Clip(_, s) => Some(*s), Scene(s) => Some(*s), _ => None } } + pub fn scene_next (&self, len: usize) -> Self { + match self { + Selection::Mix => Selection::Scene(0), + Selection::Track(t) => Selection::Clip(*t, 0), + Selection::Scene(s) if s + 1 < len => Selection::Scene(s + 1), + Selection::Scene(s) => Selection::Mix, + Selection::Clip(t, s) if s + 1 < len => Selection::Clip(*t, s + 1), + Selection::Clip(t, s) => Selection::Track(*t), + } + } + pub fn scene_prev (&self) -> Self { + match self { + Selection::Mix => Selection::Mix, + Selection::Track(t) => Selection::Track(*t), + Selection::Scene(0) => Selection::Mix, + Selection::Scene(s) => Selection::Scene(s - 1), + Selection::Clip(t, 0) => Selection::Track(*t), + Selection::Clip(t, s) => Selection::Clip(*t, s - 1), + } + } pub fn describe (&self, tracks: &[Track], scenes: &[Scene]) -> Arc { format!("{}", match self { Self::Mix => "Everything".to_string(), diff --git a/crates/app/src/view.rs b/crates/app/src/view.rs index 029536f6..0863db69 100644 --- a/crates/app/src/view.rs +++ b/crates/app/src/view.rs @@ -2,9 +2,17 @@ use crate::*; pub(crate) use std::fmt::Write; pub(crate) use ::tengri::tui::ratatui::prelude::Position; -view!(TuiOut: |self: Tek| self.size.of(View(self, self.view)); { +view!(TuiOut: |self: Tek| { + self.size.of(View(self, self.view)) +}; { ":nil" => Box::new("nil"), + ":modal" => + When::new(self.modal.is_some(), Bsp::b( + Fill::xy(Tui::fg_bg(Color::Rgb(64,64,64), Color::Rgb(32,32,32), "")), + Fixed::xy(20, 10, Tui::fg_bg(Color::Rgb(255,255,255), Color::Rgb(16,16,16), + Outer(true, Style::default().fg(Tui::g(96))).enclose(self.modal))) + )).boxed(), ":transport" => self.view_transport().boxed(), ":arranger" => @@ -859,3 +867,23 @@ impl ViewCache { } } } + +impl Content for Modal { + fn content (&self) -> impl Render { + match self { + Self::Menu => self.view_menu().boxed(), + Self::Help => self.view_help().boxed(), + } + } +} + +impl Modal { + fn view_menu (&self) -> impl Content { + "menu" + } + fn view_help (&self) -> impl Content { + Bsp::s(Tui::bold(true, "Help"), Bsp::s("", Map::south(1, + ||0..5, + |binding, _|Bsp::e(" key ", " command ")))) + } +} diff --git a/crates/cli/edn/arranger.edn b/crates/cli/edn/arranger.edn index 97f406ba..2b423c59 100644 --- a/crates/cli/edn/arranger.edn +++ b/crates/cli/edn/arranger.edn @@ -1,5 +1,6 @@ -(bsp/s (fixed/y 1 :transport) - (bsp/n (fixed/y 1 :status) - (fill/xy (bsp/a - (fill/xy (align/e :pool)) - :arranger)))) +(bsp/a :modal + (bsp/s (fixed/y 1 :transport) + (bsp/n (fixed/y 1 :status) + (fill/xy (bsp/a + (fill/xy (align/e :pool)) + :arranger))))) diff --git a/crates/cli/edn/groovebox.edn b/crates/cli/edn/groovebox.edn index 1f7814cc..0d3f744f 100644 --- a/crates/cli/edn/groovebox.edn +++ b/crates/cli/edn/groovebox.edn @@ -1,6 +1,7 @@ -(bsp/s (fixed/y 1 :transport) - (bsp/s :sample - (bsp/n (fixed/y 1 :status) - (bsp/w (fixed/x :w-sidebar :pool) - (bsp/e :samples-keys - (fill/y :editor)))))) +(bsp/a :modal + (bsp/s (fixed/y 1 :transport) + (bsp/s :sample + (bsp/n (fixed/y 1 :status) + (bsp/w (fixed/x :w-sidebar :pool) + (bsp/e :samples-keys + (fill/y :editor))))))) diff --git a/crates/cli/edn/sampler.edn b/crates/cli/edn/sampler.edn index 53f62325..fac8138c 100644 --- a/crates/cli/edn/sampler.edn +++ b/crates/cli/edn/sampler.edn @@ -1,3 +1,4 @@ -(bsp/s (fixed/y 1 :transport) - (bsp/n (fixed/y 1 :status) - (fill/xy :samples-grid))) +(bsp/a :modal + (bsp/s (fixed/y 1 :transport) + (bsp/n (fixed/y 1 :status) + (fill/xy :samples-grid)))) diff --git a/crates/cli/edn/sequencer.edn b/crates/cli/edn/sequencer.edn index 8ef1dbe0..8a602581 100644 --- a/crates/cli/edn/sequencer.edn +++ b/crates/cli/edn/sequencer.edn @@ -1,5 +1,6 @@ -(bsp/s (fixed/y 1 :transport) - (bsp/n (fixed/y 1 :status) - (fill/xy (bsp/a - (fill/xy (align/e :pool)) - :editor)))) +(bsp/a :modal + (bsp/s (fixed/y 1 :transport) + (bsp/n (fixed/y 1 :status) + (fill/xy (bsp/a + (fill/xy (align/e :pool)) + :editor))))) diff --git a/crates/cli/tek.rs b/crates/cli/tek.rs index 1c514893..1d8ca705 100644 --- a/crates/cli/tek.rs +++ b/crates/cli/tek.rs @@ -10,8 +10,10 @@ pub fn main () -> Usually<()> { #[derive(Debug, Parser)] #[command(version, about = Some(HEADER), long_about = Some(HEADER))] pub struct Cli { - /// Which app to initialize - #[command(subcommand)] mode: Mode, + /// Pre-defined configuration modes. + /// + /// TODO: Replace these with scripted configurations. + #[command(subcommand)] mode: LaunchMode, /// Name of JACK client #[arg(short='n', long)] name: Option, /// Whether to attempt to become transport master @@ -42,7 +44,7 @@ pub struct Cli { /// Application modes #[derive(Debug, Clone, Subcommand)] -pub enum Mode { +pub enum LaunchMode { /// ⏯️ A standalone transport clock. Clock, /// 🎼 A MIDI sequencer. @@ -82,7 +84,7 @@ impl Cli { let audio_froms = &[left_froms.as_slice(), right_froms.as_slice()]; let audio_tos = &[left_tos.as_slice(), right_tos.as_slice()]; let clip = match mode { - Mode::Sequencer | Mode::Groovebox => Some(Arc::new(RwLock::new(MidiClip::new( + LaunchMode::Sequencer | LaunchMode::Groovebox => Some(Arc::new(RwLock::new(MidiClip::new( "Clip", true, 384usize, None, Some(ItemColor::random().into())), ))), _ => None, @@ -104,44 +106,44 @@ impl Cli { color: ItemPalette::random(), clock: Clock::new(jack, self.bpm)?, view: SourceIter(match mode { - Mode::Clock => include_str!("./edn/transport.edn"), - Mode::Sequencer => include_str!("./edn/sequencer.edn"), - Mode::Groovebox => include_str!("./edn/groovebox.edn"), - Mode::Arranger { .. } => include_str!("./edn/arranger.edn"), - Mode::Sampler => include_str!("./edn/sampler.edn"), + LaunchMode::Clock => include_str!("./edn/transport.edn"), + LaunchMode::Sequencer => include_str!("./edn/sequencer.edn"), + LaunchMode::Groovebox => include_str!("./edn/groovebox.edn"), + LaunchMode::Arranger { .. } => include_str!("./edn/arranger.edn"), + LaunchMode::Sampler => include_str!("./edn/sampler.edn"), _ => todo!("{mode:?}"), }), pool: match mode { - Mode::Sequencer | Mode::Groovebox => clip.as_ref().map(Into::into), - Mode::Arranger { .. } => Some(Default::default()), + LaunchMode::Sequencer | LaunchMode::Groovebox => clip.as_ref().map(Into::into), + LaunchMode::Arranger { .. } => Some(Default::default()), _ => None, }, editor: match mode { - Mode::Sequencer | Mode::Groovebox => clip.as_ref().map(Into::into), - Mode::Arranger { .. } => Some(Default::default()), + LaunchMode::Sequencer | LaunchMode::Groovebox => clip.as_ref().map(Into::into), + LaunchMode::Arranger { .. } => Some(Default::default()), _ => None }, midi_ins, midi_outs, midi_buf: match mode { - Mode::Clock | Mode::Sampler => vec![], - Mode::Sequencer | Mode::Groovebox | Mode::Arranger {..} => vec![vec![];65536], + LaunchMode::Clock | LaunchMode::Sampler => vec![], + LaunchMode::Sequencer | LaunchMode::Groovebox | LaunchMode::Arranger {..} => vec![vec![];65536], _ => todo!("{mode:?}"), }, handler: Some(match mode { - Mode::Sequencer => handle_sequencer, - Mode::Groovebox => handle_groovebox, - Mode::Sampler => handle_sampler, - _ => handle_arranger, + LaunchMode::Sequencer => handle_sequencer, + LaunchMode::Groovebox => handle_groovebox, + LaunchMode::Sampler => handle_sampler, + _ => handle_arranger, }), tracks: match mode { - Mode::Sequencer => vec![ + LaunchMode::Sequencer => vec![ Track::new_sequencer() ], - Mode::Groovebox => vec![ + LaunchMode::Groovebox => vec![ Track::new_groovebox(jack, midi_froms.as_slice(), audio_froms, audio_tos)? ], - Mode::Sampler => vec![ + LaunchMode::Sampler => vec![ Track::new_sampler(jack, midi_froms.as_slice(), audio_froms, audio_tos)? ], _ => vec![] @@ -149,7 +151,7 @@ impl Cli { scenes, ..Default::default() }; - if let &Mode::Arranger { scenes, tracks, track_width, .. } = mode { + if let &LaunchMode::Arranger { scenes, tracks, track_width, .. } = mode { app.arranger = Default::default(); app.selected = Selection::Clip(1, 1); app.scenes_add(scenes)?;