diff --git a/crates/tek/src/cli/cli_arranger.rs b/crates/tek/src/cli/cli_arranger.rs index dc5f589b..98a5e026 100644 --- a/crates/tek/src/cli/cli_arranger.rs +++ b/crates/tek/src/cli/cli_arranger.rs @@ -17,7 +17,7 @@ pub struct ArrangerCli { transport: bool, /// Number of tracks - #[arg(short = 'x', long, default_value_t = 8)] + #[arg(short = 'x', long, default_value_t = 4)] tracks: usize, /// Number of scenes diff --git a/crates/tek/src/tui/app_arranger.rs b/crates/tek/src/tui/app_arranger.rs index 578143d0..60e2160f 100644 --- a/crates/tek/src/tui/app_arranger.rs +++ b/crates/tek/src/tui/app_arranger.rs @@ -44,7 +44,7 @@ from_jack!(|jack| ArrangerTui { render!(|self: ArrangerTui|{ let arranger = ||lay!(|add|{ let color = self.color; - add(&Fill::wh(Lozenge(Style::default().bg(color.light.rgb).fg(color.darker.rgb))))?; + //add(&Fill::wh(Lozenge(Style::default().bg(color.light.rgb).fg(color.darker.rgb))))?; add(&self.size)?; match self.mode { ArrangerMode::H => todo!("horizontal arranger"), @@ -64,11 +64,20 @@ render!(|self: ArrangerTui|{ ])), } }); - let with_pool = |x|Split::left(false, self.splits[1], PhraseListView(&self.phrases), x); - let play = Fixed::wh(5, 2, PlayPause(self.clock.is_rolling())); - let transport = TransportView::from((self, None, true)); + let with_pool = |x|Split::left(false, self.splits[1], PhraseListView(&self.phrases), x); + let play = Fixed::wh(5, 2, PlayPause(self.clock.is_rolling())); + let transport = TransportView::from((self, None, true)); let with_transport = |x|col!([row!(![&play, &transport]), &x]); - with_transport(with_pool(col!([Fixed::h(self.splits[0], arranger()), &self.editor]))) + let color = self.color; + let with_frame = |x|lay!([ + Fill::wh(Tui::bg(color.darkest.rgb, " ")), + Fill::wh(Lozenge(Style::default().bg(color.light.rgb).fg(color.darker.rgb))), + x + ]); + with_transport(with_pool(with_frame(row!([ + Fixed::w(30, arranger()), + Fill::wh(&self.editor) + ])))) }); audio!(|self: ArrangerTui, client, scope|{ // Start profiling cycle @@ -217,7 +226,15 @@ command!(|self:ArrangerCommand,state:ArrangerTui|{ _ => { todo!() } } }); -command!(|self:ArrangerSceneCommand,_state:ArrangerTui|None); +command!(|self:ArrangerSceneCommand,state:ArrangerTui|match self { + //Self::Delete(index) => { state.scene_del(index); }, + Self::SetColor(index, color) => { + let old = state.scenes[index].color; + state.scenes[index].color = color; + Some(Self::SetColor(index, old)) + }, + _ => None +}); command!(|self:ArrangerTrackCommand,_state:ArrangerTui|None); command!(|self:ArrangerClipCommand, _state:ArrangerTui|None); #[derive(Clone, Debug)] diff --git a/crates/tek/src/tui/arranger_scene.rs b/crates/tek/src/tui/arranger_scene.rs index db61f32a..b9039f38 100644 --- a/crates/tek/src/tui/arranger_scene.rs +++ b/crates/tek/src/tui/arranger_scene.rs @@ -1,50 +1,23 @@ use crate::*; - -pub trait HasScenes { - fn scenes (&self) -> &Vec; - fn scenes_mut (&mut self) -> &mut Vec; - fn scene_add (&mut self, name: Option<&str>, color: Option) -> Usually<&mut S>; - fn scene_del (&mut self, index: usize) { - self.scenes_mut().remove(index); - } - fn scene_default_name (&self) -> String { - format!("Scene {}", self.scenes().len() + 1) - } - fn selected_scene (&self) -> Option<&S> { - None - } - fn selected_scene_mut (&mut self) -> Option<&mut S> { - None - } +#[derive(Default, Debug, Clone)] pub struct ArrangerScene { + /// Name of scene + pub(crate) name: Arc>, + /// Clips in scene, one per track + pub(crate) clips: Vec>>>, + /// Identifying color of scene + pub(crate) color: ItemPalette, } - -#[derive(Clone, Debug)] -pub enum ArrangerSceneCommand { - Add, - Delete(usize), - RandomColor, - Play(usize), - Swap(usize, usize), - SetSize(usize), - SetZoom(usize), -} - -//impl Command for ArrangerSceneCommand { - //fn execute (self, state: &mut T) -> Perhaps { - //match self { - //Self::Delete(index) => { state.scene_del(index); }, - //_ => todo!() - //} - //Ok(None) - //} -//} - -pub trait ArrangerSceneApi: Sized { - fn name (&self) -> &Arc>; - fn clips (&self) -> &Vec>>>; - fn color (&self) -> ItemPalette; - - fn ppqs (scenes: &[Self], factor: usize) -> Vec<(usize, usize)> { +impl ArrangerScene { + pub fn name (&self) -> &Arc> { + &self.name + } + pub fn clips (&self) -> &Vec>>> { + &self.clips + } + pub fn color (&self) -> ItemPalette { + self.color + } + pub fn ppqs (scenes: &[Self], factor: usize) -> Vec<(usize, usize)> { let mut total = 0; if factor == 0 { scenes.iter().map(|scene|{ @@ -58,21 +31,18 @@ pub trait ArrangerSceneApi: Sized { }).collect() } } - - fn longest_name (scenes: &[Self]) -> usize { + pub fn longest_name (scenes: &[Self]) -> usize { scenes.iter().map(|s|s.name().read().unwrap().len()).fold(0, usize::max) } - /// Returns the pulse length of the longest phrase in the scene - fn pulses (&self) -> usize { + pub fn pulses (&self) -> usize { self.clips().iter().fold(0, |a, p|{ a.max(p.as_ref().map(|q|q.read().unwrap().length).unwrap_or(0)) }) } - /// Returns true if all phrases in the scene are /// currently playing on the given collection of tracks. - fn is_playing (&self, tracks: &[T]) -> bool { + pub fn is_playing (&self, tracks: &[T]) -> bool { self.clips().iter().any(|clip|clip.is_some()) && self.clips().iter().enumerate() .all(|(track_index, clip)|match clip { Some(clip) => tracks @@ -88,11 +58,20 @@ pub trait ArrangerSceneApi: Sized { None => true }) } - - fn clip (&self, index: usize) -> Option<&Arc>> { + pub fn clip (&self, index: usize) -> Option<&Arc>> { match self.clips().get(index) { Some(Some(clip)) => Some(clip), _ => None } } - +} +#[derive(Clone, Debug)] +pub enum ArrangerSceneCommand { + Add, + Delete(usize), + RandomColor, + Play(usize), + Swap(usize, usize), + SetSize(usize), + SetZoom(usize), + SetColor(usize, ItemPalette), } pub fn to_arranger_scene_command (input: &TuiInput, s: usize) -> Option { use KeyCode::{Char, Up, Down, Right, Enter, Delete}; @@ -108,20 +87,20 @@ pub fn to_arranger_scene_command (input: &TuiInput, s: usize) -> Option Cmd::Scene(Scene::Swap(s, s - 1)), key_pat!(Char('>')) => Cmd::Scene(Scene::Swap(s, s + 1)), key_pat!(Char('q')) => Cmd::Scene(Scene::Play(s)), + key_pat!(Char('c')) => Cmd::Scene(Scene::SetColor(s, ItemPalette::random())), key_pat!(Delete) => Cmd::Scene(Scene::Delete(s)), //key_pat!(Char('c')) => Cmd::Track(Scene::Color(s, ItemPalette::random())), _ => return None }) } - -impl HasScenes for ArrangerTui { - fn scenes (&self) -> &Vec { +impl ArrangerTui { + pub fn scenes (&self) -> &Vec { &self.scenes } - fn scenes_mut (&mut self) -> &mut Vec { + pub fn scenes_mut (&mut self) -> &mut Vec { &mut self.scenes } - fn scene_add (&mut self, name: Option<&str>, color: Option) + pub fn scene_add (&mut self, name: Option<&str>, color: Option) -> Usually<&mut ArrangerScene> { let name = name.map_or_else(||self.scene_default_name(), |x|x.to_string()); @@ -134,29 +113,13 @@ impl HasScenes for ArrangerTui { let index = self.scenes().len() - 1; Ok(&mut self.scenes_mut()[index]) } - fn selected_scene (&self) -> Option<&ArrangerScene> { + fn scene_default_name (&self) -> String { + format!("S{:3>0}", self.scenes().len() + 1) + } + pub fn selected_scene (&self) -> Option<&ArrangerScene> { self.selected.scene().map(|s|self.scenes().get(s)).flatten() } - fn selected_scene_mut (&mut self) -> Option<&mut ArrangerScene> { + pub fn selected_scene_mut (&mut self) -> Option<&mut ArrangerScene> { self.selected.scene().map(|s|self.scenes_mut().get_mut(s)).flatten() } } -#[derive(Default, Debug, Clone)] pub struct ArrangerScene { - /// Name of scene - pub(crate) name: Arc>, - /// Clips in scene, one per track - pub(crate) clips: Vec>>>, - /// Identifying color of scene - pub(crate) color: ItemPalette, -} -impl ArrangerSceneApi for ArrangerScene { - fn name (&self) -> &Arc> { - &self.name - } - fn clips (&self) -> &Vec>>> { - &self.clips - } - fn color (&self) -> ItemPalette { - self.color - } -} diff --git a/crates/tek/src/tui/arranger_track.rs b/crates/tek/src/tui/arranger_track.rs index cdb63b23..79c7fa58 100644 --- a/crates/tek/src/tui/arranger_track.rs +++ b/crates/tek/src/tui/arranger_track.rs @@ -19,7 +19,7 @@ pub trait ArrangerTracksApi: HasTracks { fn track_add (&mut self, name: Option<&str>, color: Option)-> Usually<&mut T>; fn track_del (&mut self, index: usize); fn track_default_name (&self) -> String { - format!("Track {}", self.tracks().len() + 1) + format!("T{}", self.tracks().len() + 1) } } diff --git a/crates/tek/src/tui/piano_horizontal.rs b/crates/tek/src/tui/piano_horizontal.rs index 2990ff98..e3ed1ec1 100644 --- a/crates/tek/src/tui/piano_horizontal.rs +++ b/crates/tek/src/tui/piano_horizontal.rs @@ -60,19 +60,18 @@ impl PianoHorizontal { } render!(|self: PianoHorizontal|{ - let color = self.color; let keys = move||PianoHorizontalKeys(&self); let timeline = move||PianoHorizontalTimeline(&self); let notes = move||PianoHorizontalNotes(&self); let cursor = move||PianoHorizontalCursor(&self); let keys_width = 5; - Tui::bg(color.darker.rgb, Fill::wh(Bsp::s( + Fill::wh(Bsp::s( Fixed::h(1, Bsp::e(Fixed::w(keys_width, ""), Fill::w(timeline()),)), Bsp::e( Fixed::w(keys_width, keys()), Fill::wh(lay!([&self.size, Fill::wh(lay!([Fill::wh(notes()), Fill::wh(cursor()),]))])), ), - ))) + )) }); pub struct PianoHorizontalTimeline<'a>(&'a PianoHorizontal);