From 29b2789be69ca91ee0a7493acee8068d1583a464 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 17 May 2025 17:59:43 +0300 Subject: [PATCH] starting to look very much like something --- config/keys_arranger.edn | 4 +- crates/app/src/model.rs | 3 + crates/device/src/arranger/arranger_model.rs | 2 + crates/device/src/arranger/arranger_scenes.rs | 17 --- crates/device/src/arranger/arranger_view.rs | 115 +++++++++++++----- crates/device/src/sequencer/seq_model.rs | 2 +- deps/tengri | 2 +- 7 files changed, 94 insertions(+), 51 deletions(-) diff --git a/config/keys_arranger.edn b/config/keys_arranger.edn index 1953e0c4..ee691491 100644 --- a/config/keys_arranger.edn +++ b/config/keys_arranger.edn @@ -2,8 +2,8 @@ (@q launch) (@t select :select-track-header) (@s select :select-scene-header) -(@tab edit :clip-selected) -(@enter edit :clip-selected) +(@tab edit :clip-selected) +(@enter edit :clip-selected) (@shift-I project input-add) (@shift-O project output-add) (@shift-S project scene-add) diff --git a/crates/app/src/model.rs b/crates/app/src/model.rs index 58c8eeab..632633f6 100644 --- a/crates/app/src/model.rs +++ b/crates/app/src/model.rs @@ -49,6 +49,9 @@ impl HasSceneScroll for App { fn scene_scroll (&self) -> usize { self.project.scene_scroll() } } has_clips!(|self: App|self.pool.clips); +impl HasClipsSize for App { + fn clips_size (&self) -> &Measure { &self.project.inner_size } +} //has_editor!(|self: App|{ //editor = self.editor; //editor_w = { diff --git a/crates/device/src/arranger/arranger_model.rs b/crates/device/src/arranger/arranger_model.rs index 5c3bb4d1..87c8ce04 100644 --- a/crates/device/src/arranger/arranger_model.rs +++ b/crates/device/src/arranger/arranger_model.rs @@ -37,6 +37,8 @@ pub struct Arrangement { pub arranger: Arc>, /// Display size pub size: Measure, + /// Display size of clips area + pub inner_size: Measure, } has!(Jack: |self: Arrangement|self.jack); diff --git a/crates/device/src/arranger/arranger_scenes.rs b/crates/device/src/arranger/arranger_scenes.rs index 0aca0946..0376e7eb 100644 --- a/crates/device/src/arranger/arranger_scenes.rs +++ b/crates/device/src/arranger/arranger_scenes.rs @@ -9,23 +9,6 @@ pub trait HasScenes: Has> + Send + Sync { fn scenes_mut (&mut self) -> &mut Vec { Has::>::get_mut(self) } - fn scenes_with_sizes ( - &self, - editing: bool, - height: usize, - larger: usize, - selected_track: Option, - selected_scene: Option, - ) -> impl ScenesSizes<'_> { - let mut y = 0; - self.scenes().iter().enumerate().map(move|(s, scene)|{ - let active = editing && selected_track.is_some() && selected_scene == Some(s); - let height = if active { larger } else { height }; - let data = (s, scene, y, y + height); - y += height; - data - }) - } /// Generate the default name for a new scene fn scene_default_name (&self) -> Arc { format!("s{:3>}", self.scenes().len() + 1).into() diff --git a/crates/device/src/arranger/arranger_view.rs b/crates/device/src/arranger/arranger_view.rs index ea42c575..1a234398 100644 --- a/crates/device/src/arranger/arranger_view.rs +++ b/crates/device/src/arranger/arranger_view.rs @@ -1,12 +1,25 @@ use crate::*; -impl TracksView for T -where T: ScenesView + HasMidiIns + HasMidiOuts + HasSize + HasTrackScroll + HasSelection + HasMidiIns + HasEditor {} +pub trait HasClipsSize { + fn clips_size (&self) -> &Measure; +} +impl HasClipsSize for Arrangement { + fn clips_size (&self) -> &Measure { &self.inner_size } +} + +impl TracksView for Arrangement {} impl ClipsView for T {} pub trait TracksView: - ScenesView + HasMidiIns + HasMidiOuts + HasSize + HasTrackScroll + HasSelection + HasMidiIns + HasEditor + ScenesView + + HasMidiIns + + HasMidiOuts + + HasSize + + HasTrackScroll + + HasSelection + + HasEditor + + HasClipsSize { fn tracks_width_available (&self) -> u16 { (self.width() as u16).saturating_sub(40) @@ -16,11 +29,15 @@ pub trait TracksView: let editor_width = self.editor().map(|e|e.width()); let active_track = self.selection().track(); let mut x = 0; - self.tracks().iter().enumerate().map(move |(index, track)|{ - let width = active_track.and_then(|_|editor_width).unwrap_or(track.width.max(8)); - let data = (index, track, x, x + width); - x += width + Self::TRACK_SPACING; - data + self.tracks().iter().enumerate().map_while(move |(index, track)|{ + if x < self.clips_size().w() { + let width = active_track.and_then(|_|editor_width).unwrap_or(track.width.max(8)); + let data = (index, track, x, x + width); + x += width + Self::TRACK_SPACING; + Some(data) + } else { + None + } }) } fn tracks_with_sizes_scrolled <'t> (&'t self) -> impl TracksSizes<'t> { @@ -53,7 +70,7 @@ pub trait TracksView: fn view_track_names (&self, theme: ItemTheme) -> impl Content { self.view_track_row_section( theme, - button_2("t", "rack", false), + button_2("t", "rack", false), button_2("T", "+", false), Tui::bg(theme.darker.rgb, Fixed::y(1, Fill::x( Stack::east(move|add: &mut dyn FnMut(&dyn Render)|{ @@ -130,7 +147,11 @@ pub trait TracksView: add(&Fixed::xy(self.track_width(index, track), h + 1, Align::nw(Bsp::s( Tui::bg(track.color.base.rgb, - Fill::x(Align::w(format!("·mon ·rec ·dub")))), + Fill::x(Align::w(row!( + Either(track.sequencer.monitoring, Tui::fg(Green, "●mon "), "·mon "), + Either(track.sequencer.recording, Tui::fg(Red, "●rec "), "·rec "), + Either(track.sequencer.overdub, Tui::fg(Yellow, "●dub "), "·dub "), + )))), Map::south(1, ||track.sequencer.midi_ins.iter(), |port, index|Tui::fg_bg(Rgb(255, 255, 255), track.color.dark.rgb, Fill::x(Align::w(format!("·i{index:02} {}", port.name()))))))))); @@ -147,7 +168,14 @@ pub trait TracksView: } } -pub trait ScenesView: HasEditor + HasSelection + HasSceneScroll + Send + Sync { +pub trait ScenesView: + HasEditor + + HasSelection + + HasSceneScroll + + HasClipsSize + + Send + + Sync +{ /// Default scene height. const H_SCENE: usize = 2; /// Default editor height. @@ -155,9 +183,28 @@ pub trait ScenesView: HasEditor + HasSelection + HasSceneScroll + Send + Sync { fn h_scenes (&self) -> u16; fn w_side (&self) -> u16; fn w_mid (&self) -> u16; + fn scenes_with_sizes (&self) -> impl ScenesSizes<'_> { + let editing = self.editor().is_some(); + let height = Self::H_SCENE; + let larger = self.editor().map(|e|e.height()).unwrap_or(Self::H_SCENE); + let selected_track = self.selection().track(); + let selected_scene = self.selection().scene(); + let mut y = 0; + self.scenes().iter().enumerate().skip(self.scene_scroll()).map_while(move|(s, scene)|{ + if y < self.clips_size().h() { + let active = editing && selected_track.is_some() && selected_scene == Some(s); + let height = if active { larger } else { height }; + let data = (s, scene, y, y + height); + y += height; + Some(data) + } else { + None + } + }) + } fn view_scenes_names (&self) -> impl Content { Stack::south(move|add: &mut dyn FnMut(&dyn Render)|{ - for (index, scene) in self.scenes().iter().enumerate().skip(self.scene_scroll()) { + for (index, scene, ..) in self.scenes_with_sizes() { add(&self.view_scene_name(index, scene)); } }) @@ -166,7 +213,7 @@ pub trait ScenesView: HasEditor + HasSelection + HasSceneScroll + Send + Sync { let h = if self.selection().scene() == Some(index) && let Some(editor) = self.editor() { (editor.height() as u16).max(12) } else { - Self::H_SCENE as u16 + Self::H_SCENE as u16 }; let bg = if self.selection().scene() == Some(index) { scene.color.light.rgb @@ -185,30 +232,38 @@ pub trait ScenesView: HasEditor + HasSelection + HasSceneScroll + Send + Sync { } } -pub trait ClipsView: TracksView + ScenesView + Send + Sync { +pub trait ClipsView: + TracksView + + ScenesView + + HasClipsSize + + Send + + Sync +{ fn view_scenes_clips <'a> (&'a self) -> impl Content + 'a { - Fill::xy(Stack::::east(move|column: &mut dyn FnMut(&dyn Render)|{ - for (track_index, track, _, _) in self.tracks_with_sizes() { - //column(&Fixed::x(5, Fill::xy(Tui::bg(Green, "kyp")))); - column(&Fixed::x( - if self.selection().track() == Some(track_index) - && let Some(editor) = self.editor() - { - editor.width().max(24).max(track.width) - } else { - track.width - } as u16, - Fill::y(self.view_track_clips(track_index, track)) - )) - } - })) + self.clips_size().of(Fill::xy(Bsp::a( + Fill::xy(Align::se(Tui::fg(Green, format!("{}x{}", self.clips_size().w(), self.clips_size().h())))), + Stack::::east(move|column: &mut dyn FnMut(&dyn Render)|{ + for (track_index, track, _, _) in self.tracks_with_sizes() { + //column(&Fixed::x(5, Fill::xy(Tui::bg(Green, "kyp")))); + column(&Fixed::x( + if self.selection().track() == Some(track_index) + && let Some(editor) = self.editor() + { + editor.width().max(24).max(track.width) + } else { + track.width + } as u16, + Fill::y(self.view_track_clips(track_index, track)) + )) + } + })))) } fn view_track_clips <'a> (&'a self, track_index: usize, track: &'a Track) -> impl Content + 'a { Stack::south(move|cell: &mut dyn FnMut(&dyn Render)|{ - for (scene_index, scene) in self.scenes().iter().enumerate().skip(self.scene_scroll()) { + for (scene_index, scene, ..) in self.scenes_with_sizes() { let (name, theme): (Arc, ItemTheme) = if let Some(Some(clip)) = &scene.clips.get(track_index) { let clip = clip.read().unwrap(); (clip.name.clone(), clip.color) diff --git a/crates/device/src/sequencer/seq_model.rs b/crates/device/src/sequencer/seq_model.rs index 5524dc04..22bda520 100644 --- a/crates/device/src/sequencer/seq_model.rs +++ b/crates/device/src/sequencer/seq_model.rs @@ -51,7 +51,7 @@ impl Default for Sequencer { play_clip: None, next_clip: None, recording: false, - monitoring: false, + monitoring: true, overdub: false, notes_in: RwLock::new([false;128]).into(), diff --git a/deps/tengri b/deps/tengri index a55e84c2..c9f01648 160000 --- a/deps/tengri +++ b/deps/tengri @@ -1 +1 @@ -Subproject commit a55e84c29f51606e0996f7f88b7664ca0d37365b +Subproject commit c9f01648712a0c3c1a8290fc09c65746decbbbcb