From b663c53b0aa2cc589a5e75bc88227227f2a81fbc Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 17 May 2025 11:48:54 +0300 Subject: [PATCH] arranger: cursor highlight --- config/config_arranger.edn | 4 +- crates/device/src/arranger/arranger_view.rs | 201 ++++++++++++-------- 2 files changed, 125 insertions(+), 80 deletions(-) diff --git a/config/config_arranger.edn b/config/config_arranger.edn index 1eb5e376..1c97d326 100644 --- a/config/config_arranger.edn +++ b/config/config_arranger.edn @@ -26,4 +26,6 @@ (fill/xy (align/n (bsp/s :view-arranger-track-names (bsp/s :view-arranger-track-outputs (bsp/s :view-arranger-track-devices :view-arranger-track-inputs))))))) - (fill/xy (align/w :view-arranger))))) + (fill/xy (bsp/e + (fixed/x 20 (align/nw :view-arranger-scenes-names)) + :view-arranger-scenes-clips))))) diff --git a/crates/device/src/arranger/arranger_view.rs b/crates/device/src/arranger/arranger_view.rs index feaaa29e..1f4d7468 100644 --- a/crates/device/src/arranger/arranger_view.rs +++ b/crates/device/src/arranger/arranger_view.rs @@ -214,7 +214,10 @@ pub trait TracksView: HasSize + HasTrackScroll + HasSelection + HasMidiI } })))))); Bsp::w( - self.view_track_header(theme, row!(Tui::bold(true, "[t]rack "), "[T] +")), + self.view_track_header(theme, row!( + Tui::bold(true, button_2("t", "rack ", false)), + button_2("T", "+", false) + )), content ) } @@ -239,7 +242,10 @@ pub trait TracksView: HasSize + HasTrackScroll + HasSelection + HasMidiI } })))))); Bsp::w( - self.view_track_header(theme, row!(Tui::bold(true, "[o]utput"), "[O] +")), + self.view_track_header(theme, row!( + Tui::bold(true, button_2("o", "utput", false)), + button_2("O", "+", false) + )), content ) } @@ -265,7 +271,10 @@ pub trait TracksView: HasSize + HasTrackScroll + HasSelection + HasMidiI })))); Bsp::w( - self.view_track_header(theme, row!(Tui::bold(true, "[i]nputs"), "[I] +")), + self.view_track_header(theme, row!( + Tui::bold(true, button_2("i", "nputs", false)), + button_2("I", "+", false) + )), Fixed::y(h, Fill::x(Align::w(Fixed::y(h + 1, content)))), ) } @@ -275,7 +284,10 @@ pub trait TracksView: HasSize + HasTrackScroll + HasSelection + HasMidiI h = h.max(track.devices.len() as u16); } Bsp::w( - self.view_track_header(theme, row!(Tui::bold(true, "[d]evice "), "[D]+")), + self.view_track_header(theme, row!( + Tui::bold(true, button_2("d", "evice", false)), + button_2("D", "+", false) + )), Fixed::y(h, Tui::bg(theme.darker.rgb, Align::w(Fill::x(Stack::east( move|add: &mut dyn FnMut(&dyn Render)|{ for (index, track, x1, x2) in self @@ -307,44 +319,40 @@ pub trait ScenesView: HasSelection + HasSceneScroll + Send + Sync { fn width_side (&self) -> u16; fn width_mid (&self) -> u16; fn view_scenes_names (&self) -> impl Content { - let h = self.scenes_with_prev_color().last().map(|(_,_,_,h,_)|h as u16).unwrap_or(0); - Fixed::y(h, Map::new(move||self.scenes_with_prev_color(), - move|(s, scene, y1, y2, previous): SceneWith<'_, Option>, _|{ - let height = (1 + y2 - y1) as u16; - let name = Some(scene.name.clone()); - let content = Fill::x(Align::w(Tui::bold(true, Bsp::e(" ⯈ ", name)))); - let selected = self.scene_selected() == Some(s); - let neighbor = s > 0 && self.scene_selected() == Some(s - 1); - let is_last = self.scenes().len().saturating_sub(1) == s; - let theme = scene.color; - let fg = theme.lightest.rgb; - let bg = if selected { theme.light } else { theme.base }.rgb; - let hi = if let Some(previous) = previous { - if neighbor { previous.light.rgb } else { previous.base.rgb } - } else { - Reset - }; - let lo = if is_last { Reset } else if selected { - theme.light.rgb - } else { - theme.base.rgb - }; - Fill::x(map_south(y1 as u16, height, Fixed::y(height, Phat { - width: 0, height: 0, content, colors: [fg, bg, hi, lo] - }))) - })) + Stack::south(move|add: &mut dyn FnMut(&dyn Render)|{ + for (index, scene) in self.scenes().iter().enumerate().skip(self.scene_scroll()) { + add(&Self::view_scene_name(index, scene)); + } + }) } - fn scenes_names_2 (&self, theme: ItemTheme) -> impl Content { - let h = self.scenes().len() as u16 * 2; - let bg = theme.darker.rgb; - Fixed::y(h, Tui::bg(bg, Align::w(Fill::x(Map::new( - ||self.scenes().iter().skip(self.scene_scroll()), - move|scene: &Scene, index| - Push::y(index as u16 * 2u16, Fixed::xy(20, 2, - Tui::bg(scene.color.dark.rgb, Align::nw(Bsp::e( - format!(" {index:2} "), - Tui::fg(Rgb(255, 255, 255), - Tui::bold(true, format!("{}", scene.name))))))))))))) + fn view_scene_name (index: usize, scene: &Scene) -> impl Content { + Fixed::xy(20, 2, Tui::bg(scene.color.dark.rgb, Align::nw(Bsp::e( + format!(" {index:2} "), + Tui::fg(Rgb(255, 255, 255), + Tui::bold(true, format!("{}", scene.name))))))) + //let height = (1 + y2 - y1) as u16; + //let name = Some(scene.name.clone()); + //let content = Fill::x(Align::w(Tui::bold(true, Bsp::e(" ⯈ ", name)))); + //let selected = self.scene_selected() == Some(s); + //let neighbor = s > 0 && self.scene_selected() == Some(s - 1); + //let is_last = self.scenes().len().saturating_sub(1) == s; + //let theme = scene.color; + //let fg = theme.lightest.rgb; + //let bg = if selected { theme.light } else { theme.base }.rgb; + //let hi = if let Some(previous) = previous { + //if neighbor { previous.light.rgb } else { previous.base.rgb } + //} else { + //Reset + //}; + //let lo = if is_last { Reset } else if selected { + //theme.light.rgb + //} else { + //theme.base.rgb + //}; + //add(&Fill::x(map_south(y1 as u16, height, Fixed::y(height, Phat { + //width: 0, height: 0, content, colors: [fg, bg, hi, lo] + //})))) + //} } fn scenes_with_prev_color (&self) -> impl Iterator>> + Send + Sync { self.scenes_iter().map(|(s, scene, y1, y2)|(s, scene, y1, y2, @@ -392,45 +400,80 @@ pub trait ClipsView: TracksView + ScenesView + Send + Sync { fn view_scenes_clips <'a> (&'a self, editor: &'a Option) -> impl Content + 'a { - let is_editing = false; //FIXME - let h = self.scenes_with_prev_color().last().map(|(_,_,_,h,_)|h as u16).unwrap_or(0); - Fixed::y(h, Self::per_track(||self.tracks_with_sizes_scrolled(), - move|track_index, track|Map::new(move||self.scenes_with_clip(track_index), - move|(s, scene, y1, y2, previous): SceneWith<'_, Option>, _|{ - let (name, theme) = if let Some(clip) = &scene.clips[track_index] { - let clip = clip.read().unwrap(); - (Some(clip.name.clone()), clip.color) - } else { - (None, ItemTheme::G[32]) - }; - let content = Fill::x(Align::w(Tui::bold(true, Bsp::e(" ⏹ ", name)))); - let same_track = self.track_selected() == Some(track_index); - let selected = same_track && self.scene_selected() == Some(s); - let neighbor = same_track && s > 0 && self.scene_selected() == Some(s - 1); - let is_last = self.scenes().len().saturating_sub(1) == s; - let fg = theme.lightest.rgb; - let bg = if selected { theme.light } else { theme.base }.rgb; - let hi = if let Some(previous) = previous { - if neighbor { previous.light.rgb } else { previous.base.rgb } - } else { - Reset - }; - let lo = if is_last { - Reset - } else if selected { - theme.light.rgb - } else { - theme.base.rgb - }; - let height = (1 + y2 - y1) as u16; - map_south(y1 as u16, height, Bsp::b(Fixed::y(height, Phat { - width: 0, height: 0, content, colors: [fg, bg, hi, lo] - }), When( - is_editing && same_track && self.scene_selected() == Some(s), - editor - ))) - }))) + Fill::xy(Stack::::east(move|column: &mut dyn FnMut(&dyn Render)|{ + for (track_index, track, _, _) in self + .tracks_with_sizes(&self.selection(), None) + .skip(self.track_scroll()) + { + //column(&Fixed::x(5, Fill::xy(Tui::bg(Green, "kyp")))); + column(&Fixed::x( + track.width as u16, + Fill::y(self.view_track_clips(track_index, track)) + )) + } + })) } + + fn view_track_clips <'a> (&'a self, track_index: usize, track: &Track) -> impl Content { + Stack::south(move|cell: &mut dyn FnMut(&dyn Render)|{ + for (scene_index, scene) in self.scenes().iter().enumerate().skip(self.scene_scroll()) { + let (name, theme) = if let Some(Some(clip)) = &scene.clips.get(track_index) { + let clip = clip.read().unwrap(); + (Some(clip.name.clone()), clip.color) + } else { + (None, ItemTheme::G[32]) + }; + let fg = theme.lightest.rgb; + let bg = if self.selection().track() == Some(track_index) + && self.selection().scene() == Some(scene_index) + { + theme.light.rgb + } else if self.selection().track() == Some(track_index) + || self.selection().scene() == Some(scene_index) + { + theme.base.rgb + } else { + theme.dark.rgb + }; + cell(&Fixed::xy(track.width as u16, 2, Tui::fg_bg(fg, bg, Align::nw(name.unwrap_or(" ---- ".into()))))); + //let (name, theme) = if let Some(clip) = &scene.clips.get(track_index).flatten() { + //let clip = clip.read().unwrap(); + //(Some(clip.name.clone()), clip.color) + //} else { + //(None, ItemTheme::G[32]) + //}; + //let content = Fill::x(Align::w(Tui::bold(true, Bsp::e(" ⏹ ", name)))); + //let same_track = self.track_selected() == Some(track_index); + //let selected = same_track && self.scene_selected() == Some(s); + //let neighbor = same_track && s > 0 && self.scene_selected() == Some(s - 1); + //let is_last = self.scenes().len().saturating_sub(1) == s; + //let fg = theme.lightest.rgb; + //let bg = if selected { theme.light } else { theme.base }.rgb; + //let hi = if let Some(previous) = previous { + //if neighbor { previous.light.rgb } else { previous.base.rgb } + //} else { + //Reset + //}; + //let lo = if is_last { + //Reset + //} else if selected { + //theme.light.rgb + //} else { + //theme.base.rgb + //}; + //let height = (1 + y2 - y1) as u16; + //let is_editing = false; //FIXME + //let editor = (); //FIXME + //cell(&Fixed::xy(track.width as u16, 2, Bsp::b(Fixed::y(height, Phat { + //width: 0, height: 0, content, colors: [fg, bg, hi, lo] + //}), When( + //is_editing && same_track && self.scene_selected() == Some(s), + //editor + //)))) + } + }) + } + fn scenes_clips_2 <'a> ( &'a self, theme: ItemTheme