diff --git a/crates/tek_api/src/arrange.rs b/crates/tek_api/src/arrange.rs index 98eca32c..5cfb1a93 100644 --- a/crates/tek_api/src/arrange.rs +++ b/crates/tek_api/src/arrange.rs @@ -1,7 +1,7 @@ use crate::*; #[derive(Debug)] -pub struct Arrangement { +pub struct ArrangerModel { /// JACK client handle (needs to not be dropped for standalone mode to work). pub jack: Arc>, /// Global timebase @@ -9,15 +9,15 @@ pub struct Arrangement { /// Name of arranger pub name: Arc>, /// Collection of phrases. - pub phrases: Arc>>, + pub phrases: Arc>, /// Collection of tracks. - pub tracks: Vec, + pub tracks: Vec, /// Collection of scenes. - pub scenes: Vec, + pub scenes: Vec, } #[derive(Debug)] -pub struct ArrangementTrack { +pub struct ArrangerTrack { /// Name of track pub name: Arc>, /// Preferred width of track column @@ -29,7 +29,7 @@ pub struct ArrangementTrack { } #[derive(Default, Debug, Clone)] -pub struct ArrangementScene { +pub struct ArrangerScene { /// Name of scene pub name: Arc>, /// Clips in scene, one per track @@ -38,7 +38,7 @@ pub struct ArrangementScene { pub color: ItemColor, } -impl Arrangement { +impl ArrangerModel { pub fn is_stopped (&self) -> bool { *self.clock.playing.read().unwrap() == Some(TransportState::Stopped) } @@ -50,9 +50,9 @@ impl Arrangement { } pub fn track_add ( &mut self, name: Option<&str>, color: Option - ) -> Usually<&mut ArrangementTrack> { + ) -> Usually<&mut ArrangerTrack> { let name = name.map_or_else(||self.track_default_name(), |x|x.to_string()); - self.tracks.push(ArrangementTrack { + self.tracks.push(ArrangerTrack { width: name.len() + 2, color: color.unwrap_or_else(||ItemColor::random()), player: MIDIPlayer::new(&self.jack, &self.clock, name.as_str())?, @@ -63,9 +63,9 @@ impl Arrangement { } pub fn scene_add ( &mut self, name: Option<&str>, color: Option - ) -> Usually<&mut ArrangementScene> { + ) -> Usually<&mut ArrangerScene> { let name = name.map_or_else(||self.scene_default_name(), |x|x.to_string()); - self.scenes.push(ArrangementScene { + self.scenes.push(ArrangerScene { name: Arc::new(name.into()), clips: vec![None;self.tracks.len()], color: color.unwrap_or_else(||ItemColor::random()), @@ -84,7 +84,7 @@ impl Arrangement { } } -impl ArrangementScene { +impl ArrangerScene { pub fn ppqs (scenes: &[Self], factor: usize) -> Vec<(usize, usize)> { let mut total = 0; if factor == 0 { @@ -113,7 +113,7 @@ impl ArrangementScene { /// Returns true if all phrases in the scene are /// currently playing on the given collection of tracks. - pub fn is_playing (&self, tracks: &[ArrangementTrack]) -> bool { + pub fn is_playing (&self, tracks: &[ArrangerTrack]) -> bool { self.clips.iter().any(|clip|clip.is_some()) && self.clips.iter().enumerate() .all(|(track_index, clip)|match clip { Some(clip) => tracks @@ -153,7 +153,7 @@ impl ArrangementScene { //}, //_ => panic!("unexpected in scene '{name:?}': {edn:?}") //}); - //Ok(ArrangementScene { + //Ok(ArrangerScene { //name: Arc::new(name.unwrap_or("").to_string().into()), //color: ItemColor::random(), //clips, @@ -161,7 +161,7 @@ impl ArrangementScene { //} } -impl ArrangementTrack { +impl ArrangerTrack { pub fn longest_name (tracks: &[Self]) -> usize { tracks.iter().map(|s|s.name.read().unwrap().len()).fold(0, usize::max) } diff --git a/crates/tek_api/src/arrange_cmd.rs b/crates/tek_api/src/arrange_cmd.rs index 74b5d67d..aacf0fd1 100644 --- a/crates/tek_api/src/arrange_cmd.rs +++ b/crates/tek_api/src/arrange_cmd.rs @@ -1,18 +1,18 @@ use crate::*; #[derive(Clone)] -pub enum ArrangementCommand { +pub enum ArrangerCommand { Clear, Export, Import, StopAll, - Scene(ArrangementSceneCommand), - Track(ArrangementTrackCommand), - Clip(ArrangementClipCommand), + Scene(ArrangerSceneCommand), + Track(ArrangerTrackCommand), + Clip(ArrangerClipCommand), } #[derive(Clone)] -pub enum ArrangementSceneCommand { +pub enum ArrangerSceneCommand { Add, Delete(usize), RandomColor, @@ -23,7 +23,7 @@ pub enum ArrangementSceneCommand { } #[derive(Clone)] -pub enum ArrangementTrackCommand { +pub enum ArrangerTrackCommand { Add, Delete(usize), RandomColor, @@ -34,7 +34,7 @@ pub enum ArrangementTrackCommand { } #[derive(Clone)] -pub enum ArrangementClipCommand { +pub enum ArrangerClipCommand { Play, Get(usize, usize), Set(usize, usize, Option>>), @@ -43,8 +43,8 @@ pub enum ArrangementClipCommand { RandomColor, } -impl Command for ArrangementCommand { - fn execute (self, state: &mut Arrangement) -> Perhaps { +impl Command for ArrangerCommand { + fn execute (self, state: &mut ArrangerModel) -> Perhaps { match self { Self::Scene(command) => { return Ok(command.execute(state)?.map(Self::Scene)) }, Self::Track(command) => { return Ok(command.execute(state)?.map(Self::Track)) }, @@ -55,8 +55,8 @@ impl Command for ArrangementCommand { } } -impl Command for ArrangementSceneCommand { - fn execute (self, state: &mut Arrangement) -> Perhaps { +impl Command for ArrangerSceneCommand { + fn execute (self, state: &mut ArrangerModel) -> Perhaps { match self { Self::Delete(index) => { state.scene_del(index); }, _ => todo!() @@ -65,8 +65,8 @@ impl Command for ArrangementSceneCommand { } } -impl Command for ArrangementTrackCommand { - fn execute (self, state: &mut Arrangement) -> Perhaps { +impl Command for ArrangerTrackCommand { + fn execute (self, state: &mut ArrangerModel) -> Perhaps { match self { Self::Delete(index) => { state.track_del(index); }, _ => todo!() @@ -75,8 +75,8 @@ impl Command for ArrangementTrackCommand { } } -impl Command for ArrangementClipCommand { - fn execute (self, state: &mut Arrangement) -> Perhaps { +impl Command for ArrangerClipCommand { + fn execute (self, state: &mut ArrangerModel) -> Perhaps { match self { _ => todo!() } @@ -84,7 +84,7 @@ impl Command for ArrangementClipCommand { } } -//impl Command for ArrangementSceneCommand { +//impl Command for ArrangerSceneCommand { //} //Edit(phrase) => { state.state.phrase = phrase.clone() }, //ToggleViewMode => { state.state.mode.to_next(); }, @@ -101,27 +101,27 @@ impl Command for ArrangementClipCommand { //AddTrack => { state.state.track_add(None, None)?; }, //ToggleLoop => { state.state.toggle_loop() }, //pub fn zoom_in (&mut self) { - //if let ArrangementEditorMode::Vertical(factor) = self.mode { - //self.mode = ArrangementEditorMode::Vertical(factor + 1) + //if let ArrangerEditorMode::Vertical(factor) = self.mode { + //self.mode = ArrangerEditorMode::Vertical(factor + 1) //} //} //pub fn zoom_out (&mut self) { - //if let ArrangementEditorMode::Vertical(factor) = self.mode { - //self.mode = ArrangementEditorMode::Vertical(factor.saturating_sub(1)) + //if let ArrangerEditorMode::Vertical(factor) = self.mode { + //self.mode = ArrangerEditorMode::Vertical(factor.saturating_sub(1)) //} //} //pub fn move_back (&mut self) { //match self.selected { - //ArrangementEditorFocus::Scene(s) => { + //ArrangerEditorFocus::Scene(s) => { //if s > 0 { //self.scenes.swap(s, s - 1); - //self.selected = ArrangementEditorFocus::Scene(s - 1); + //self.selected = ArrangerEditorFocus::Scene(s - 1); //} //}, - //ArrangementEditorFocus::Track(t) => { + //ArrangerEditorFocus::Track(t) => { //if t > 0 { //self.tracks.swap(t, t - 1); - //self.selected = ArrangementEditorFocus::Track(t - 1); + //self.selected = ArrangerEditorFocus::Track(t - 1); //// FIXME: also swap clip order in scenes //} //}, @@ -130,16 +130,16 @@ impl Command for ArrangementClipCommand { //} //pub fn move_forward (&mut self) { //match self.selected { - //ArrangementEditorFocus::Scene(s) => { + //ArrangerEditorFocus::Scene(s) => { //if s < self.scenes.len().saturating_sub(1) { //self.scenes.swap(s, s + 1); - //self.selected = ArrangementEditorFocus::Scene(s + 1); + //self.selected = ArrangerEditorFocus::Scene(s + 1); //} //}, - //ArrangementEditorFocus::Track(t) => { + //ArrangerEditorFocus::Track(t) => { //if t < self.tracks.len().saturating_sub(1) { //self.tracks.swap(t, t + 1); - //self.selected = ArrangementEditorFocus::Track(t + 1); + //self.selected = ArrangerEditorFocus::Track(t + 1); //// FIXME: also swap clip order in scenes //} //}, diff --git a/crates/tek_api/src/pool.rs b/crates/tek_api/src/pool.rs index a631f44d..211aef62 100644 --- a/crates/tek_api/src/pool.rs +++ b/crates/tek_api/src/pool.rs @@ -1,6 +1,7 @@ use crate::*; /// Contains all phrases in a project +#[derive(Debug)] pub struct PhrasePool { /// Phrases in the pool pub phrases: Vec>>, diff --git a/crates/tek_cli/src/cli_arranger.rs b/crates/tek_cli/src/cli_arranger.rs index 13d0b135..29195126 100644 --- a/crates/tek_cli/src/cli_arranger.rs +++ b/crates/tek_cli/src/cli_arranger.rs @@ -22,10 +22,7 @@ impl ArrangerCli { /// Run the arranger TUI from CLI arguments. fn run (&self) -> Usually<()> { Tui::run(JackClient::new("tek_arranger")?.activate_with(|jack|{ - let transport = TransportView::new(jack, None); - let phrases = Arc::new(RwLock::new(PhrasePool::new())); - let mut arrangement = Arrangement::new(&jack, &transport.clock, "", &phrases); - let transport = Arc::new(RwLock::new(transport)); + let mut app = TransportApp::try_from(jack)?; if let Some(name) = self.name.as_ref() { *arrangement.name.write().unwrap() = name.clone(); } @@ -45,13 +42,8 @@ impl ArrangerCli { Some(scene_color_1.mix(scene_color_2, i as f32 / self.scenes as f32)) )?; } - Ok(ArrangerView::new( - jack, - self.transport.then_some(transport), - arrangement, - phrases, - )) - })?)?; + Ok(app) + })?)? Ok(()) } } diff --git a/crates/tek_cli/src/cli_sequencer.rs b/crates/tek_cli/src/cli_sequencer.rs index 4b7f3f39..0c190a0f 100644 --- a/crates/tek_cli/src/cli_sequencer.rs +++ b/crates/tek_cli/src/cli_sequencer.rs @@ -20,7 +20,7 @@ pub struct SequencerCli { impl SequencerCli { fn run (&self) -> Usually<()> { Tui::run(JackClient::new("tek_sequencer")?.activate_with(|jack|{ - let transport = TransportView::new(jack, None); + let mut app = SequencerApp::try_from(jack)?; if let Some(_) = self.name.as_ref() { // TODO: sequencer.name = Arc::new(RwLock::new(name.clone())); } @@ -32,16 +32,7 @@ impl SequencerCli { //phrase.write().unwrap().length = length; //} } - Ok(SequencerView { - jack: jack.clone(), - focus_cursor: (1, 1), - entered: false, - phrases: Arc::new(RwLock::new(PhrasePool::new())), - editor: PhraseEditor::new(), - clock: transport.clock.clone(), - player: PhrasePlayer::new(jack, &transport.clock, "tek_sequencer")?, - transport: self.transport.then_some(Arc::new(RwLock::new(transport))), - }) + Ok(app) })?)?; Ok(()) } diff --git a/crates/tek_cli/src/cli_transport.rs b/crates/tek_cli/src/cli_transport.rs index 88aadec9..de29abeb 100644 --- a/crates/tek_cli/src/cli_transport.rs +++ b/crates/tek_cli/src/cli_transport.rs @@ -2,6 +2,6 @@ use tek_core::clap::{self, Parser}; /// Application entrypoint. pub fn main () -> Usually<()> { - Tui::run(JackClient::new("tek_transport")?.activate_with(TransportApp::run)?)? + Tui::run(JackClient::new("tek_transport")?.activate_with(TransportApp::try_from)?)? Ok(()) } diff --git a/crates/tek_snd/src/snd_arrange.rs b/crates/tek_snd/src/snd_arrange.rs index 5ffd4abf..13b7cf27 100644 --- a/crates/tek_snd/src/snd_arrange.rs +++ b/crates/tek_snd/src/snd_arrange.rs @@ -1,6 +1,6 @@ use crate::*; -pub struct ArrangerAudio(pub Arc>); +pub struct ArrangerAudio(pub Arc>); impl Audio for ArrangerAudio { #[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control { @@ -8,7 +8,7 @@ impl Audio for ArrangerAudio { } } -pub struct ArrangerRefAudio<'a>(pub &'a mut Arrangement); +pub struct ArrangerRefAudio<'a>(pub &'a mut ArrangerModel); impl<'a> Audio for ArrangerRefAudio<'a> { #[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control { diff --git a/crates/tek_tui/src/tui_arranger.rs b/crates/tek_tui/src/tui_arranger.rs index 4be87038..5487edc9 100644 --- a/crates/tek_tui/src/tui_arranger.rs +++ b/crates/tek_tui/src/tui_arranger.rs @@ -9,8 +9,9 @@ pub type ArrangerApp = AppContainer< ArrangerStatusBar >; -impl ArrangerApp { - pub fn run <'a> (jack: &Arc>) -> Usually { +impl TryFrom<&Arc>> for ArrangerApp { + type Error = Box; + fn try_from (jack: &Arc>) -> Usually { let clock = Arc::new(Clock::from(Instant::default())); let transport = Arc::new(RwLock::new(tek_api::Transport { @@ -20,30 +21,22 @@ impl ArrangerApp { clock: clock.clone() })); - let phrases = Arc::new(RwLock::new(PhrasePool { - phrases: vec![] - })); + let phrases = Arc::new(RwLock::new(PhrasePool { phrases: vec![] })); - let player = Arc::new(RwLock::new(MIDIPlayer::new(jack, &clock, "preview")?)); - - let arrangement = Arc::new(RwLock::new(Arrangement { - jack: jack.clone(), - clock: clock.clone(), - name: Arc::new(RwLock::new(String::new())), - phrases: phrases.read().unwrap().phrases.clone(), // FIXME - tracks: vec![], - scenes: vec![], - })); - - let sequencer = Arc::new(RwLock::new(SequencerModel { - transport: transport.clone(), - phrases: phrases.clone(), - player: player.clone(), - })); - - let model = Arc::new(RwLock::new(ArrangerModel { - arrangement: arrangement.clone(), - sequencer: sequencer.clone(), + let model = Arc::new(RwLock::new(Arranger { + arrangement: Arc::new(RwLock::new(ArrangerModel { + jack: jack.clone(), + clock: clock.clone(), + name: Arc::new(RwLock::new(String::new())), + phrases: phrases.clone(), // FIXME + tracks: vec![], + scenes: vec![], + })), + sequencer: Arc::new(RwLock::new(SequencerModel { + transport: transport.clone(), + phrases: phrases.clone(), + player: Arc::new(RwLock::new(MIDIPlayer::new(jack, &clock, "preview")?)), + })), transport: transport.clone(), phrases: phrases.clone(), })); @@ -51,28 +44,28 @@ impl ArrangerApp { Ok(Self::new( &model, ArrangerView::from(&model), - ArrangerAudio(arrangement.clone()), + ArrangerAudio(model.clone()), None, None )) } } -pub struct ArrangerModel { - pub arrangement: Arc>, +pub struct Arranger { + pub arrangement: Arc>, pub sequencer: Arc>, pub transport: Arc>, pub phrases: Arc>, } -impl From<&Arc>> for ArrangerView { - fn from (model: &Arc>) -> Self { +impl From<&Arc>> for ArrangerView { + fn from (model: &Arc>) -> Self { let mut view = Self { model: model.clone(), sequencer: SequencerView::from(&model.read().unwrap().sequencer), split: 20, - selected: ArrangementEditorFocus::Clip(0, 0), - mode: ArrangementEditorMode::Vertical(2), + selected: ArrangerFocus::Clip(0, 0), + mode: ArrangerMode::Vertical(2), color: Color::Rgb(28, 35, 25).into(), size: Measure::new(), focused: false, @@ -85,15 +78,15 @@ impl From<&Arc>> for ArrangerView { /// Root level object for standalone `tek_arranger` pub struct ArrangerView { - pub model: Arc>, + pub model: Arc>, /// Sequencer component pub sequencer: SequencerView, /// Height of arrangement pub split: u16, /// Currently selected element. - pub selected: ArrangementEditorFocus, + pub selected: ArrangerFocus, /// Display mode of arranger - pub mode: ArrangementEditorMode, + pub mode: ArrangerMode, /// Background color of arrangement pub color: ItemColor, /// Whether the arranger is currently focused @@ -106,7 +99,7 @@ pub struct ArrangerView { /// Display mode of arranger #[derive(Clone, PartialEq)] -pub enum ArrangementEditorMode { +pub enum ArrangerMode { /// Tracks are rows Horizontal, /// Tracks are columns @@ -114,7 +107,7 @@ pub enum ArrangementEditorMode { } /// Arranger display mode can be cycled -impl ArrangementEditorMode { +impl ArrangerMode { /// Cycle arranger display mode pub fn to_next (&mut self) { *self = match self { @@ -130,7 +123,7 @@ impl ArrangementEditorMode { impl Audio for ArrangerView { #[inline] fn process (&mut self, _: &Client, _: &ProcessScope) -> Control { // FIXME: one of these per playing track - if let ArrangementEditorFocus::Clip(t, s) = self.selected { + if let ArrangerFocus::Clip(t, s) = self.selected { let phrase = self.model.scenes.get(s).map(|scene|scene.clips.get(t)); if let Some(Some(Some(phrase))) = phrase { if let Some(track) = self.model.tracks.get(t) { @@ -164,9 +157,9 @@ impl Content for ArrangerView { lay!( Layers::new(move |add|{ match self.mode { - ArrangementEditorMode::Horizontal => + ArrangerMode::Horizontal => add(&arranger_content_horizontal(self))?, - ArrangementEditorMode::Vertical(factor) => + ArrangerMode::Vertical(factor) => add(&arranger_content_vertical(self, factor))? }; add(&self.size) @@ -176,7 +169,7 @@ impl Content for ArrangerView { .bg(TuiTheme::border_bg()) .fg(TuiTheme::border_fg(self.focused)))), widget(&self.size), - widget(&format!("[{}] Arrangement", if self.entered { + widget(&format!("[{}] Arranger", if self.entered { "■" } else { " " @@ -206,7 +199,7 @@ impl ArrangerView { pub fn activate (&mut self) { let arrangement = self.model.read().unwrap().arrangement.read().unwrap(); match self.selected { - ArrangementEditorFocus::Scene(s) => { + ArrangerFocus::Scene(s) => { for (t, track) in self.model.tracks.iter_mut().enumerate() { let player = &mut track.player; let clip = self.model.scenes[s].clips[t].as_ref(); @@ -220,7 +213,7 @@ impl ArrangerView { //self.transport.toggle_play() //} }, - ArrangementEditorFocus::Clip(t, s) => { + ArrangerFocus::Clip(t, s) => { let clip = self.model.scenes[s].clips[t].as_ref(); self.model.tracks[t].player.enqueue_next(clip); }, @@ -238,8 +231,8 @@ impl ArrangerView { let arrangement = self.model.read().unwrap().arrangement.read().unwrap(); let selected = self.selected; (self.model.scenes.len() == 0 && (selected.is_mix() || selected.is_track())) || match selected { - ArrangementEditorFocus::Scene(s) => s == self.model.scenes.len() - 1, - ArrangementEditorFocus::Clip(_, s) => s == self.model.scenes.len() - 1, + ArrangerFocus::Scene(s) => s == self.model.scenes.len() - 1, + ArrangerFocus::Clip(_, s) => s == self.model.scenes.len() - 1, _ => false } } @@ -253,26 +246,26 @@ impl ArrangerView { pub fn randomize_color (&mut self) { let arrangement = self.model.read().unwrap().arrangement.read().unwrap(); match self.selected { - ArrangementEditorFocus::Mix => { + ArrangerFocus::Mix => { self.color = ItemColor::random_dark() }, - ArrangementEditorFocus::Track(t) => { + ArrangerFocus::Track(t) => { self.model.tracks[t].color = ItemColor::random() }, - ArrangementEditorFocus::Scene(s) => { + ArrangerFocus::Scene(s) => { self.model.scenes[s].color = ItemColor::random() }, - ArrangementEditorFocus::Clip(t, s) => { + ArrangerFocus::Clip(t, s) => { if let Some(phrase) = &self.model.scenes[s].clips[t] { phrase.write().unwrap().color = ItemColorTriplet::random(); } } } } - pub fn selected_scene (&self) -> Option<&ArrangementScene> { + pub fn selected_scene (&self) -> Option<&ArrangerScene> { self.selected.scene().map(|s|self.model.scenes.get(s)).flatten() } - pub fn selected_scene_mut (&mut self) -> Option<&mut ArrangementScene> { + pub fn selected_scene_mut (&mut self) -> Option<&mut ArrangerScene> { self.selected.scene().map(|s|self.model.scenes.get_mut(s)).flatten() } pub fn selected_phrase (&self) -> Option>> { diff --git a/crates/tek_tui/src/tui_arranger_bar.rs b/crates/tek_tui/src/tui_arranger_bar.rs index e3d0602d..721d58c2 100644 --- a/crates/tek_tui/src/tui_arranger_bar.rs +++ b/crates/tek_tui/src/tui_arranger_bar.rs @@ -3,10 +3,10 @@ use crate::*; /// Status bar for arranger ap pub enum ArrangerStatusBar { Transport, - ArrangementMix, - ArrangementTrack, - ArrangementScene, - ArrangementClip, + ArrangerMix, + ArrangerTrack, + ArrangerScene, + ArrangerClip, PhrasePool, PhraseView, PhraseEdit, @@ -21,15 +21,15 @@ impl StatusBar for ArrangerStatusBar { impl ArrangerStatusBar { fn update (&mut self, state: &ArrangerView) { *self = match state.focused() { - ArrangerViewFocus::Transport => ArrangerStatusBar::Transport, - ArrangerViewFocus::Arrangement => match state.arrangement.selected { - ArrangementEditorFocus::Mix => ArrangerStatusBar::ArrangementMix, - ArrangementEditorFocus::Track(_) => ArrangerStatusBar::ArrangementTrack, - ArrangementEditorFocus::Scene(_) => ArrangerStatusBar::ArrangementScene, - ArrangementEditorFocus::Clip(_, _) => ArrangerStatusBar::ArrangementClip, + ArrangerViewFocus::Transport => ArrangerStatusBar::Transport, + ArrangerViewFocus::Arranger => match state.selected { + ArrangerFocus::Mix => ArrangerStatusBar::ArrangerMix, + ArrangerFocus::Track(_) => ArrangerStatusBar::ArrangerTrack, + ArrangerFocus::Scene(_) => ArrangerStatusBar::ArrangerScene, + ArrangerFocus::Clip(_, _) => ArrangerStatusBar::ArrangerClip, }, - ArrangerViewFocus::PhrasePool => ArrangerStatusBar::PhrasePool, - ArrangerViewFocus::PhraseEditor => match state.sequencer.editor.entered { + ArrangerViewFocus::PhrasePool => ArrangerStatusBar::PhrasePool, + ArrangerViewFocus::PhraseEditor => match state.sequencer.editor.entered { true => ArrangerStatusBar::PhraseEdit, false => ArrangerStatusBar::PhraseView, }, @@ -42,10 +42,10 @@ impl Content for ArrangerStatusBar { fn content (&self) -> impl Widget { let label = match self { Self::Transport => "TRANSPORT", - Self::ArrangementMix => "PROJECT", - Self::ArrangementTrack => "TRACK", - Self::ArrangementScene => "SCENE", - Self::ArrangementClip => "CLIP", + Self::ArrangerMix => "PROJECT", + Self::ArrangerTrack => "TRACK", + Self::ArrangerScene => "SCENE", + Self::ArrangerClip => "CLIP", Self::PhrasePool => "SEQ LIST", Self::PhraseView => "VIEW SEQ", Self::PhraseEdit => "EDIT SEQ", @@ -55,14 +55,14 @@ impl Content for ArrangerStatusBar { let mode_fg = TuiTheme::mode_fg(); let mode = TuiStyle::bold(format!(" {label} "), true).bg(mode_bg).fg(mode_fg); let commands = match self { - Self::ArrangementMix => Self::command(&[ + Self::ArrangerMix => Self::command(&[ ["", "c", "olor"], ["", "<>", "resize"], ["", "+-", "zoom"], ["", "n", "ame/number"], ["", "Enter", " stop all"], ]), - Self::ArrangementClip => Self::command(&[ + Self::ArrangerClip => Self::command(&[ ["", "g", "et"], ["", "s", "et"], ["", "a", "dd"], @@ -74,7 +74,7 @@ impl Content for ArrangerStatusBar { ["", ",.", "select"], ["", "Enter", " launch"], ]), - Self::ArrangementTrack => Self::command(&[ + Self::ArrangerTrack => Self::command(&[ ["re", "n", "ame"], ["", ",.", "resize"], ["", "<>", "move"], @@ -85,7 +85,7 @@ impl Content for ArrangerStatusBar { ["", "Del", "ete"], ["", "Enter", " stop"], ]), - Self::ArrangementScene => Self::command(&[ + Self::ArrangerScene => Self::command(&[ ["re", "n", "ame"], ["", "Del", "ete"], ["", "Enter", " launch"], @@ -121,20 +121,20 @@ impl Content for ArrangerStatusBar { } //pub fn arranger_menu_bar () -> MenuBar { - //use ArrangementEditorCommand as Cmd; - //use ArrangementCommand as Edit; - //use ArrangementEditorFocus as Focus; - //use ArrangementTrackCommand as Track; - //use ArrangementClipCommand as Clip; - //use ArrangementSceneCommand as Scene; + //use ArrangerCommand as Cmd; + //use ArrangerCommand as Edit; + //use ArrangerFocus as Focus; + //use ArrangerTrackCommand as Track; + //use ArrangerClipCommand as Clip; + //use ArrangerSceneCommand as Scene; //use TransportCommand as Transport; //MenuBar::new() //.add({ - //use ArrangementCommand::*; + //use ArrangerCommand::*; //Menu::new("File") - //.cmd("n", "New project", ArrangerViewCommand::Arrangement(New)) - //.cmd("l", "Load project", ArrangerViewCommand::Arrangement(Load)) - //.cmd("s", "Save project", ArrangerViewCommand::Arrangement(Save)) + //.cmd("n", "New project", ArrangerViewCommand::Arranger(New)) + //.cmd("l", "Load project", ArrangerViewCommand::Arranger(Load)) + //.cmd("s", "Save project", ArrangerViewCommand::Arranger(Save)) //}) //.add({ //Menu::new("Transport") @@ -144,24 +144,24 @@ impl Content for ArrangerStatusBar { //.cmd("S", "Stop and rewind", TransportCommand::Transport(Stop(Some(0)))) //}) //.add({ - //use ArrangementCommand::*; + //use ArrangerCommand::*; //Menu::new("Track") - //.cmd("a", "Append new", ArrangerViewCommand::Arrangement(AddTrack)) - //.cmd("i", "Insert new", ArrangerViewCommand::Arrangement(AddTrack)) - //.cmd("n", "Rename", ArrangerViewCommand::Arrangement(AddTrack)) - //.cmd("d", "Delete", ArrangerViewCommand::Arrangement(AddTrack)) - //.cmd(">", "Move up", ArrangerViewCommand::Arrangement(AddTrack)) - //.cmd("<", "Move down", ArrangerViewCommand::Arrangement(AddTrack)) + //.cmd("a", "Append new", ArrangerViewCommand::Arranger(AddTrack)) + //.cmd("i", "Insert new", ArrangerViewCommand::Arranger(AddTrack)) + //.cmd("n", "Rename", ArrangerViewCommand::Arranger(AddTrack)) + //.cmd("d", "Delete", ArrangerViewCommand::Arranger(AddTrack)) + //.cmd(">", "Move up", ArrangerViewCommand::Arranger(AddTrack)) + //.cmd("<", "Move down", ArrangerViewCommand::Arranger(AddTrack)) //}) //.add({ - //use ArrangementCommand::*; + //use ArrangerCommand::*; //Menu::new("Scene") - //.cmd("a", "Append new", ArrangerViewCommand::Arrangement(AddScene)) - //.cmd("i", "Insert new", ArrangerViewCommand::Arrangement(AddTrack)) - //.cmd("n", "Rename", ArrangerViewCommand::Arrangement(AddTrack)) - //.cmd("d", "Delete", ArrangerViewCommand::Arrangement(AddTrack)) - //.cmd(">", "Move up", ArrangerViewCommand::Arrangement(AddTrack)) - //.cmd("<", "Move down", ArrangerViewCommand::Arrangement(AddTrack)) + //.cmd("a", "Append new", ArrangerViewCommand::Arranger(AddScene)) + //.cmd("i", "Insert new", ArrangerViewCommand::Arranger(AddTrack)) + //.cmd("n", "Rename", ArrangerViewCommand::Arranger(AddTrack)) + //.cmd("d", "Delete", ArrangerViewCommand::Arranger(AddTrack)) + //.cmd(">", "Move up", ArrangerViewCommand::Arranger(AddTrack)) + //.cmd("<", "Move down", ArrangerViewCommand::Arranger(AddTrack)) //}) //.add({ //use PhraseRenameCommand as Rename; diff --git a/crates/tek_tui/src/tui_arranger_cmd.rs b/crates/tek_tui/src/tui_arranger_cmd.rs index e9049394..df945438 100644 --- a/crates/tek_tui/src/tui_arranger_cmd.rs +++ b/crates/tek_tui/src/tui_arranger_cmd.rs @@ -3,20 +3,15 @@ use crate::*; #[derive(Clone)] pub enum ArrangerViewCommand { Focus(FocusCommand), - Arrangement(ArrangementEditorCommand), + Edit(ArrangerCommand), + Select(ArrangerFocus), + Zoom(usize), Transport(TransportViewCommand), Phrases(PhrasePoolViewCommand), Editor(PhraseEditorCommand), EditPhrase(Option>>), } -#[derive(Clone)] -pub enum ArrangementEditorCommand { - Edit(ArrangementCommand), - Select(ArrangementEditorFocus), - Zoom(usize), -} - /// Handle top-level events in standalone arranger. impl Handle for ArrangerView { fn handle (&mut self, i: &TuiInput) -> Perhaps { @@ -57,13 +52,120 @@ impl InputToCommand> for ArrangerViewCommand { PhrasePoolViewCommand::input_to_command(&view.sequencer.phrases, input)? ) }, - ArrangerViewFocus::Arrangement => match input.event() { - key!(KeyCode::Char('e')) => EditPhrase( - view.selected_phrase() - ), - _ => Arrangement( - ArrangementEditorCommand::input_to_command(&view, &input)? - ) + ArrangerViewFocus::Arranger => { + use ArrangerFocus as Focus; + use ArrangerCommand as Model; + use ArrangerTrackCommand as Track; + use ArrangerClipCommand as Clip; + use ArrangerSceneCommand as Scene; + match input.event() { + key!(KeyCode::Char('e')) => EditPhrase( + view.selected_phrase() + ), + _ => match input.event() { + // FIXME: boundary conditions + + key!(KeyCode::Up) => match view.selected { + ArrangerFocus::Mix => return None, + ArrangerFocus::Track(t) => return None, + ArrangerFocus::Scene(s) => Select(Focus::Scene(s - 1)), + ArrangerFocus::Clip(t, s) => Select(Focus::Clip(t, s - 1)), + }, + + key!(KeyCode::Down) => match view.selected { + ArrangerFocus::Mix => Select(Focus::Scene(0)), + ArrangerFocus::Track(t) => Select(Focus::Clip(t, 0)), + ArrangerFocus::Scene(s) => Select(Focus::Scene(s + 1)), + ArrangerFocus::Clip(t, s) => Select(Focus::Clip(t, s + 1)), + }, + + key!(KeyCode::Left) => match view.selected { + ArrangerFocus::Mix => return None, + ArrangerFocus::Track(t) => Select(Focus::Track(t - 1)), + ArrangerFocus::Scene(s) => return None, + ArrangerFocus::Clip(t, s) => Select(Focus::Clip(t - 1, s)), + }, + + key!(KeyCode::Right) => match view.selected { + ArrangerFocus::Mix => return None, + ArrangerFocus::Track(t) => Select(Focus::Track(t + 1)), + ArrangerFocus::Scene(s) => Select(Focus::Clip(0, s)), + ArrangerFocus::Clip(t, s) => Select(Focus::Clip(t, s - 1)), + }, + + key!(KeyCode::Char('+')) => Zoom(0), + + key!(KeyCode::Char('=')) => Zoom(0), + + key!(KeyCode::Char('_')) => Zoom(0), + + key!(KeyCode::Char('-')) => Zoom(0), + + key!(KeyCode::Char('`')) => { todo!("toggle view mode") }, + + key!(KeyCode::Char(',')) => match view.selected { + ArrangerFocus::Mix => Zoom(0), + ArrangerFocus::Track(t) => Edit(Model::Track(Track::Swap(t, t - 1))), + ArrangerFocus::Scene(s) => Edit(Model::Scene(Scene::Swap(s, s - 1))), + ArrangerFocus::Clip(t, s) => Edit(Model::Clip(Clip::Set(t, s, None))), + }, + + key!(KeyCode::Char('.')) => match view.selected { + ArrangerFocus::Mix => Zoom(0), + ArrangerFocus::Track(t) => Edit(Model::Track(Track::Swap(t, t + 1))), + ArrangerFocus::Scene(s) => Edit(Model::Scene(Scene::Swap(s, s + 1))), + ArrangerFocus::Clip(t, s) => Edit(Model::Clip(Clip::Set(t, s, None))), + }, + + key!(KeyCode::Char('<')) => match view.selected { + ArrangerFocus::Mix => Zoom(0), + ArrangerFocus::Track(t) => Edit(Model::Track(Track::Swap(t, t - 1))), + ArrangerFocus::Scene(s) => Edit(Model::Scene(Scene::Swap(s, s - 1))), + ArrangerFocus::Clip(t, s) => Edit(Model::Clip(Clip::Set(t, s, None))), + }, + + key!(KeyCode::Char('>')) => match view.selected { + ArrangerFocus::Mix => Zoom(0), + ArrangerFocus::Track(t) => Edit(Model::Track(Track::Swap(t, t + 1))), + ArrangerFocus::Scene(s) => Edit(Model::Scene(Scene::Swap(s, s + 1))), + ArrangerFocus::Clip(t, s) => Edit(Model::Clip(Clip::Set(t, s, None))), + }, + + key!(KeyCode::Enter) => match view.selected { + ArrangerFocus::Mix => return None, + ArrangerFocus::Track(t) => return None, + ArrangerFocus::Scene(s) => Edit(Model::Scene(Scene::Play(s))), + ArrangerFocus::Clip(t, s) => return None, + }, + + key!(KeyCode::Delete) => match view.selected { + ArrangerFocus::Mix => Edit(Model::Clear), + ArrangerFocus::Track(t) => Edit(Model::Track(Track::Delete(t))), + ArrangerFocus::Scene(s) => Edit(Model::Scene(Scene::Delete(s))), + ArrangerFocus::Clip(t, s) => Edit(Model::Clip(Clip::Set(t, s, None))), + }, + + key!(KeyCode::Char('c')) => Edit(Model::Clip(Clip::RandomColor)), + + key!(KeyCode::Char('s')) => match view.selected { + ArrangerFocus::Clip(t, s) => Edit(Model::Clip(Clip::Set(t, s, None))), + _ => return None, + }, + + key!(KeyCode::Char('g')) => match view.selected { + ArrangerFocus::Clip(t, s) => Edit(Model::Clip(Clip::Get(t, s))), + _ => return None, + }, + + key!(Ctrl-KeyCode::Char('a')) => Edit(Model::Scene(Scene::Add)), + + key!(Ctrl-KeyCode::Char('t')) => Edit(Model::Track(Track::Add)), + + key!(KeyCode::Char('l')) => Edit(Model::Clip(Clip::SetLoop(false))), + + _ => return None + } + } } } }) @@ -81,8 +183,15 @@ impl Command> for ArrangerViewCommand { delegate(cmd, Self::Editor, &mut view.sequencer.editor), Self::Transport(cmd) => delegate(cmd, Self::Transport, &mut view.sequencer.transport), - Self::Arrangement(cmd) => - delegate(cmd, Self::Arrangement, &mut view), + Self::Zoom(zoom) => { + todo!(); + }, + Self::Select(selected) => { + view.selected = selected; + }, + Self::Edit(command) => { + return Ok(command.execute(&mut view.model)?.map(Self::Edit)) + }, Self::EditPhrase(phrase) => { view.sequencer.editor.phrase = phrase.clone(); view.focus(ArrangerViewFocus::PhraseEditor); @@ -96,139 +205,8 @@ impl Command> for ArrangerViewCommand { } } -impl InputToCommand> for ArrangementEditorCommand { - fn input_to_command (state: &ArrangerView, input: &TuiInput) -> Option { - use ArrangementEditorCommand as Cmd; - use ArrangementCommand as Edit; - use ArrangementEditorFocus as Focus; - use ArrangementTrackCommand as Track; - use ArrangementClipCommand as Clip; - use ArrangementSceneCommand as Scene; - Some(match input.event() { - // FIXME: boundary conditions - - key!(KeyCode::Up) => match state.selected { - ArrangementEditorFocus::Mix => return None, - ArrangementEditorFocus::Track(t) => return None, - ArrangementEditorFocus::Scene(s) => Cmd::Select(Focus::Scene(s - 1)), - ArrangementEditorFocus::Clip(t, s) => Cmd::Select(Focus::Clip(t, s - 1)), - }, - - key!(KeyCode::Down) => match state.selected { - ArrangementEditorFocus::Mix => Cmd::Select(Focus::Scene(0)), - ArrangementEditorFocus::Track(t) => Cmd::Select(Focus::Clip(t, 0)), - ArrangementEditorFocus::Scene(s) => Cmd::Select(Focus::Scene(s + 1)), - ArrangementEditorFocus::Clip(t, s) => Cmd::Select(Focus::Clip(t, s + 1)), - }, - - key!(KeyCode::Left) => match state.selected { - ArrangementEditorFocus::Mix => return None, - ArrangementEditorFocus::Track(t) => Cmd::Select(Focus::Track(t - 1)), - ArrangementEditorFocus::Scene(s) => return None, - ArrangementEditorFocus::Clip(t, s) => Cmd::Select(Focus::Clip(t - 1, s)), - }, - - key!(KeyCode::Right) => match state.selected { - ArrangementEditorFocus::Mix => return None, - ArrangementEditorFocus::Track(t) => Cmd::Select(Focus::Track(t + 1)), - ArrangementEditorFocus::Scene(s) => Cmd::Select(Focus::Clip(0, s)), - ArrangementEditorFocus::Clip(t, s) => Cmd::Select(Focus::Clip(t, s - 1)), - }, - - key!(KeyCode::Char('+')) => Cmd::Zoom(0), - - key!(KeyCode::Char('=')) => Cmd::Zoom(0), - - key!(KeyCode::Char('_')) => Cmd::Zoom(0), - - key!(KeyCode::Char('-')) => Cmd::Zoom(0), - - key!(KeyCode::Char('`')) => { todo!("toggle view mode") }, - - key!(KeyCode::Char(',')) => match state.selected { - ArrangementEditorFocus::Mix => Cmd::Zoom(0), - ArrangementEditorFocus::Track(t) => Cmd::Edit(Edit::Track(Track::Swap(0, 0))), - ArrangementEditorFocus::Scene(s) => Cmd::Edit(Edit::Scene(Scene::Swap(0, 0))), - ArrangementEditorFocus::Clip(t, s) => Cmd::Edit(Edit::Clip(Clip::Set(t, s, None))), - }, - - key!(KeyCode::Char('.')) => match state.selected { - ArrangementEditorFocus::Mix => Cmd::Zoom(0), - ArrangementEditorFocus::Track(t) => Cmd::Edit(Edit::Track(Track::Swap(0, 0))), - ArrangementEditorFocus::Scene(s) => Cmd::Edit(Edit::Scene(Scene::Swap(0, 0))), - ArrangementEditorFocus::Clip(t, s) => Cmd::Edit(Edit::Clip(Clip::Set(t, s, None))), - }, - - key!(KeyCode::Char('<')) => match state.selected { - ArrangementEditorFocus::Mix => Cmd::Zoom(0), - ArrangementEditorFocus::Track(t) => Cmd::Edit(Edit::Track(Track::Swap(0, 0))), - ArrangementEditorFocus::Scene(s) => Cmd::Edit(Edit::Scene(Scene::Swap(0, 0))), - ArrangementEditorFocus::Clip(t, s) => Cmd::Edit(Edit::Clip(Clip::Set(t, s, None))), - }, - - key!(KeyCode::Char('>')) => match state.selected { - ArrangementEditorFocus::Mix => Cmd::Zoom(0), - ArrangementEditorFocus::Track(t) => Cmd::Edit(Edit::Track(Track::Swap(0, 0))), - ArrangementEditorFocus::Scene(s) => Cmd::Edit(Edit::Scene(Scene::Swap(0, 0))), - ArrangementEditorFocus::Clip(t, s) => Cmd::Edit(Edit::Clip(Clip::Set(t, s, None))), - }, - - key!(KeyCode::Enter) => match state.selected { - ArrangementEditorFocus::Mix => return None, - ArrangementEditorFocus::Track(t) => return None, - ArrangementEditorFocus::Scene(s) => Cmd::Edit(Edit::Scene(Scene::Play(s))), - ArrangementEditorFocus::Clip(t, s) => return None, - }, - - key!(KeyCode::Delete) => match state.selected { - ArrangementEditorFocus::Mix => Cmd::Edit(Edit::Clear), - ArrangementEditorFocus::Track(t) => Cmd::Edit(Edit::Track(Track::Delete(t))), - ArrangementEditorFocus::Scene(s) => Cmd::Edit(Edit::Scene(Scene::Delete(s))), - ArrangementEditorFocus::Clip(t, s) => Cmd::Edit(Edit::Clip(Clip::Set(t, s, None))), - }, - - key!(KeyCode::Char('c')) => Cmd::Edit(Edit::Clip(Clip::RandomColor)), - - key!(KeyCode::Char('s')) => match state.selected { - ArrangementEditorFocus::Clip(t, s) => Cmd::Edit(Edit::Clip(Clip::Set(t, s, None))), - _ => return None, - }, - - key!(KeyCode::Char('g')) => match state.selected { - ArrangementEditorFocus::Clip(t, s) => Cmd::Edit(Edit::Clip(Clip::Get(t, s))), - _ => return None, - }, - - key!(Ctrl-KeyCode::Char('a')) => Cmd::Edit(Edit::Scene(Scene::Add)), - - key!(Ctrl-KeyCode::Char('t')) => Cmd::Edit(Edit::Track(Track::Add)), - - key!(KeyCode::Char('l')) => Cmd::Edit(Edit::Clip(Clip::SetLoop(false))), - - _ => return None - }) - } -} - -impl Command> for ArrangementEditorCommand { - fn execute (self, view: &mut ArrangerView) -> Perhaps { - match self { - Self::Zoom(zoom) => { - todo!(); - }, - Self::Select(selected) => { - view.selected = selected; - }, - Self::Edit(command) => { - return Ok(command.execute(&mut view.model)?.map(Self::Edit)) - }, - } - Ok(None) - } -} - //pub fn phrase_next (&mut self) { - //if let ArrangementEditorFocus::Clip(track, scene) = self.selected { + //if let ArrangerFocus::Clip(track, scene) = self.selected { //if let Some(ref mut phrase) = self.model.scenes[scene].clips[track] { //let phrases = self.model.phrases.read().unwrap(); //let index = phrases.index_of(&*phrase.read().unwrap()); @@ -241,7 +219,7 @@ impl Command> for ArrangementEditorCommand { //} //} //pub fn phrase_prev (&mut self) { - //if let ArrangementEditorFocus::Clip(track, scene) = self.selected { + //if let ArrangerFocus::Clip(track, scene) = self.selected { //if let Some(ref mut phrase) = self.model.scenes[scene].clips[track] { //let phrases = self.model.phrases.read().unwrap(); //let index = phrases.index_of(&*phrase.read().unwrap()); @@ -255,7 +233,7 @@ impl Command> for ArrangementEditorCommand { //} //pub fn phrase_get (&mut self) { - //if let ArrangementEditorFocus::Clip(track, scene) = self.selected { + //if let ArrangerFocus::Clip(track, scene) = self.selected { //if let Some(phrase) = &self.model.scenes[scene].clips[track] { //let mut phrases = self.model.phrases.write().unwrap(); //if let Some(index) = &*phrases.index_of(&*phrase.read().unwrap()) { @@ -277,7 +255,7 @@ impl Command> for ArrangementEditorCommand { //} //pub fn next_color (&self) -> ItemColor { - //if let ArrangementEditorFocus::Clip(track, scene) = self.arrangement.selected { + //if let ArrangerFocus::Clip(track, scene) = self.arrangement.selected { //let track_color = self.arrangement.model.tracks[track].color; //let scene_color = self.arrangement.model.scenes[scene].color; //track_color.mix(scene_color, 0.5).mix(ItemColor::random(), 0.25) @@ -295,14 +273,14 @@ impl Command> for ArrangementEditorCommand { //.map(|scene|scene.clips[track_index] = None)); //} //pub fn phrase_put (&mut self) { - //if let ArrangementEditorFocus::Clip(track, scene) = self.selected { + //if let ArrangerFocus::Clip(track, scene) = self.selected { //self.model.scenes[scene].clips[track] = self.selected_phrase().clone(); //} //} - //pub fn selected_scene (&self) -> Option<&ArrangementScene> { + //pub fn selected_scene (&self) -> Option<&ArrangerScene> { //self.selected.scene().map(|s|self.model.scenes.get(s)).flatten() //} - //pub fn selected_scene_mut (&mut self) -> Option<&mut ArrangementScene> { + //pub fn selected_scene_mut (&mut self) -> Option<&mut ArrangerScene> { //self.selected.scene().map(|s|self.model.scenes.get_mut(s)).flatten() //} //pub fn selected_phrase (&self) -> Option>> { diff --git a/crates/tek_tui/src/tui_arranger_foc.rs b/crates/tek_tui/src/tui_arranger_foc.rs index 488a39e1..3d34a4ce 100644 --- a/crates/tek_tui/src/tui_arranger_foc.rs +++ b/crates/tek_tui/src/tui_arranger_foc.rs @@ -6,7 +6,7 @@ pub enum ArrangerViewFocus { /// The transport (toolbar) is focused Transport, /// The arrangement (grid) is focused - Arrangement, + Arranger, /// The phrase list (pool) is focused PhrasePool, /// The phrase editor (sequencer) is focused @@ -26,7 +26,7 @@ impl FocusGrid for ArrangerView { let focused = self.focused(); if !self.entered { self.entered = - focused == ArrangerViewFocus::Arrangement; + focused == ArrangerViewFocus::Arranger; self.sequencer.editor.entered = focused == ArrangerViewFocus::PhraseEditor; self.sequencer.phrases.entered = @@ -51,14 +51,14 @@ impl FocusGrid for ArrangerView { use ArrangerViewFocus::*; &[ &[Transport, Transport], - &[Arrangement, Arrangement], + &[Arranger, Arranger], &[PhrasePool, PhraseEditor], ] } fn update_focus (&mut self) { let focused = self.focused(); self.focused = - focused == ArrangerViewFocus::Arrangement; + focused == ArrangerViewFocus::Arranger; self.sequencer.transport.focused = focused == ArrangerViewFocus::Transport; self.sequencer.phrases.focused = @@ -70,7 +70,7 @@ impl FocusGrid for ArrangerView { #[derive(PartialEq, Clone, Copy)] /// Represents the current user selection in the arranger -pub enum ArrangementEditorFocus { +pub enum ArrangerFocus { /// The whole mix is selected Mix, /// A track is selected. @@ -82,11 +82,11 @@ pub enum ArrangementEditorFocus { } /// Focus identification methods -impl ArrangementEditorFocus { +impl ArrangerFocus { pub fn description ( &self, - tracks: &Vec, - scenes: &Vec, + tracks: &Vec, + scenes: &Vec, ) -> String { format!("Selected: {}", match self { Self::Mix => format!("Everything"), @@ -120,7 +120,7 @@ impl ArrangementEditorFocus { match self { Self::Clip(_, _) => true, _ => false } } pub fn track (&self) -> Option { - use ArrangementEditorFocus::*; + use ArrangerFocus::*; match self { Clip(t, _) => Some(*t), Track(t) => Some(*t), @@ -128,7 +128,7 @@ impl ArrangementEditorFocus { } } pub fn scene (&self) -> Option { - use ArrangementEditorFocus::*; + use ArrangerFocus::*; match self { Clip(_, s) => Some(*s), Scene(s) => Some(*s), @@ -137,7 +137,7 @@ impl ArrangementEditorFocus { } } //pub fn track_next (&mut self, last_track: usize) { - //use ArrangementEditorFocus::*; + //use ArrangerFocus::*; //*self = match self { //Mix => Track(0), //Track(t) => Track(last_track.min(*t + 1)), @@ -146,7 +146,7 @@ impl ArrangementEditorFocus { //} //} //pub fn track_prev (&mut self) { - //use ArrangementEditorFocus::*; + //use ArrangerFocus::*; //*self = match self { //Mix => Mix, //Scene(s) => Scene(*s), @@ -155,7 +155,7 @@ impl ArrangementEditorFocus { //} //} //pub fn scene_next (&mut self, last_scene: usize) { - //use ArrangementEditorFocus::*; + //use ArrangerFocus::*; //*self = match self { //Mix => Scene(0), //Track(t) => Clip(*t, 0), @@ -164,7 +164,7 @@ impl ArrangementEditorFocus { //} //} //pub fn scene_prev (&mut self) { - //use ArrangementEditorFocus::*; + //use ArrangerFocus::*; //*self = match self { //Mix => Mix, //Track(t) => Track(*t), diff --git a/crates/tek_tui/src/tui_arranger_hor.rs b/crates/tek_tui/src/tui_arranger_hor.rs index 05582c9a..84bc65d1 100644 --- a/crates/tek_tui/src/tui_arranger_hor.rs +++ b/crates/tek_tui/src/tui_arranger_hor.rs @@ -158,13 +158,13 @@ pub fn arranger_content_horizontal ( }), // scenes CustomWidget::new(|_|{todo!()}, |to: &mut TuiOutput|{ - let selected = &view.selected; - let scenes = &view.model.scenes; - let area = to.area(); + let [x, y, _, height] = to.area(); let mut x2 = 0; - let [x, y, _, height] = area; - Ok(for (scene_index, scene) in scenes.iter().enumerate() { - let active_scene = selected.scene() == Some(scene_index); + Ok(for (scene_index, scene) in view.model.read().unwrap() + .arrangement.read().unwrap(). + scenes.iter().enumerate() + { + let active_scene = view.selected.scene() == Some(scene_index); let sep = Some(if active_scene { Style::default().yellow().not_dim() } else { @@ -177,7 +177,7 @@ pub fn arranger_content_horizontal ( let mut x3 = name.len() as u16; to.blit(&*name, x + x2, y, sep); for (i, clip) in scene.clips.iter().enumerate() { - let active_track = selected.track() == Some(i); + let active_track = view.selected.track() == Some(i); if let Some(clip) = clip { let y2 = y + 2 + i as u16 * 2; let label = format!("{}", clip.read().unwrap().name); diff --git a/crates/tek_tui/src/tui_arranger_ver.rs b/crates/tek_tui/src/tui_arranger_ver.rs index 7dc02b6c..b273c73d 100644 --- a/crates/tek_tui/src/tui_arranger_ver.rs +++ b/crates/tek_tui/src/tui_arranger_ver.rs @@ -1,6 +1,6 @@ use crate::*; -fn track_widths (tracks: &[ArrangementTrack]) -> Vec<(usize, usize)> { +fn track_widths (tracks: &[ArrangerTrack]) -> Vec<(usize, usize)> { let mut widths = vec![]; let mut total = 0; for track in tracks.iter() { @@ -16,16 +16,17 @@ pub fn arranger_content_vertical ( view: &ArrangerView, factor: usize ) -> impl Widget + use<'_> { - let tracks = view.model.tracks.as_slice(); - let scenes = view.model.scenes.as_slice(); + let model = view.model.read().unwrap(); + let clock = model.transport.read().unwrap().clock; + let tracks = model.arrangement.read().unwrap().tracks.as_slice(); + let scenes = model.arrangement.read().unwrap().scenes.as_slice(); let cols = track_widths(tracks); - let rows = ArrangementScene::ppqs(scenes, factor); + let rows = ArrangerScene::ppqs(scenes, factor); let bg = view.color; let clip_bg = TuiTheme::border_bg(); let sep_fg = TuiTheme::separator_fg(false); let header_h = 3u16;//5u16; - let scenes_w = 3 + ArrangementScene::longest_name(scenes) as u16; // x of 1st track - let clock = &view.sequencer.transport.model.clock; + let scenes_w = 3 + ArrangerScene::longest_name(scenes) as u16; // x of 1st track let arrangement = Layers::new(move |add|{ let rows: &[(usize, usize)] = rows.as_ref(); let cols: &[(usize, usize)] = cols.as_ref(); @@ -98,12 +99,12 @@ pub fn arranger_content_vertical ( .push_x(scenes_w) }); // scene titles - let scene_name = |scene: &ArrangementScene, playing: bool, height|row!( + let scene_name = |scene: &ArrangerScene, playing: bool, height|row!( if playing { "▶ " } else { " " }, TuiStyle::bold(scene.name.read().unwrap().as_str(), true), ).fixed_xy(scenes_w, height); // scene clips - let scene_clip = |scene: &ArrangementScene, track: usize, w: u16, h: u16|Layers::new(move |add|{ + let scene_clip = |scene: &ArrangerScene, track: usize, w: u16, h: u16|Layers::new(move |add|{ let mut bg = clip_bg; match (tracks.get(track), scene.clips.get(track)) { (Some(track), Some(Some(phrase))) => { @@ -164,16 +165,16 @@ pub fn arranger_content_vertical ( let mut scene_area: Option<[u16;4]> = None; let mut clip_area: Option<[u16;4]> = None; let area = match selected { - ArrangementEditorFocus::Mix => area, - ArrangementEditorFocus::Track(t) => { + ArrangerFocus::Mix => area, + ArrangerFocus::Track(t) => { track_area = Some(get_track_area(t)); area }, - ArrangementEditorFocus::Scene(s) => { + ArrangerFocus::Scene(s) => { scene_area = Some(get_scene_area(s)); area }, - ArrangementEditorFocus::Clip(t, s) => { + ArrangerFocus::Clip(t, s) => { track_area = Some(get_track_area(t)); scene_area = Some(get_scene_area(s)); clip_area = Some(get_clip_area(t, s)); diff --git a/crates/tek_tui/src/tui_sequencer.rs b/crates/tek_tui/src/tui_sequencer.rs index 05da766f..6f317de8 100644 --- a/crates/tek_tui/src/tui_sequencer.rs +++ b/crates/tek_tui/src/tui_sequencer.rs @@ -9,8 +9,9 @@ pub type SequencerApp = AppContainer< SequencerStatusBar >; -impl SequencerApp { - pub fn run <'a> (jack: &Arc>) -> Usually { +impl TryFrom<&Arc>> for SequencerApp { + type Error = Box; + fn try_from (jack: &Arc>) -> Usually { let clock = Arc::new(Clock::from(Instant::default())); let transport = Arc::new(RwLock::new(tek_api::Transport { diff --git a/crates/tek_tui/src/tui_transport.rs b/crates/tek_tui/src/tui_transport.rs index 187e7bad..d3ac96df 100644 --- a/crates/tek_tui/src/tui_transport.rs +++ b/crates/tek_tui/src/tui_transport.rs @@ -10,8 +10,9 @@ pub type TransportApp = AppContainer< TransportStatusBar >; -impl TransportApp { - pub fn run <'a> (jack: &Arc>) -> Usually { +impl TryFrom<&Arc>> for TransportApp { + type Error = Box; + fn try_from (jack: &Arc>) -> Usually { let model = Arc::new(RwLock::new(Transport { metronome: false, transport: jack.read().unwrap().transport(),