arranger: cursor highlight

This commit is contained in:
🪞👃🪞 2025-05-17 11:48:54 +03:00
parent a9288cb0c2
commit b663c53b0a
2 changed files with 125 additions and 80 deletions

View file

@ -26,4 +26,6 @@
(fill/xy (align/n (bsp/s :view-arranger-track-names (fill/xy (align/n (bsp/s :view-arranger-track-names
(bsp/s :view-arranger-track-outputs (bsp/s :view-arranger-track-outputs
(bsp/s :view-arranger-track-devices :view-arranger-track-inputs))))))) (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)))))

View file

@ -214,7 +214,10 @@ pub trait TracksView: HasSize<TuiOut> + HasTrackScroll + HasSelection + HasMidiI
} }
})))))); }))))));
Bsp::w( 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 content
) )
} }
@ -239,7 +242,10 @@ pub trait TracksView: HasSize<TuiOut> + HasTrackScroll + HasSelection + HasMidiI
} }
})))))); }))))));
Bsp::w( 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 content
) )
} }
@ -265,7 +271,10 @@ pub trait TracksView: HasSize<TuiOut> + HasTrackScroll + HasSelection + HasMidiI
})))); }))));
Bsp::w( 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)))), Fixed::y(h, Fill::x(Align::w(Fixed::y(h + 1, content)))),
) )
} }
@ -275,7 +284,10 @@ pub trait TracksView: HasSize<TuiOut> + HasTrackScroll + HasSelection + HasMidiI
h = h.max(track.devices.len() as u16); h = h.max(track.devices.len() as u16);
} }
Bsp::w( 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( Fixed::y(h, Tui::bg(theme.darker.rgb, Align::w(Fill::x(Stack::east(
move|add: &mut dyn FnMut(&dyn Render<TuiOut>)|{ move|add: &mut dyn FnMut(&dyn Render<TuiOut>)|{
for (index, track, x1, x2) in self 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_side (&self) -> u16;
fn width_mid (&self) -> u16; fn width_mid (&self) -> u16;
fn view_scenes_names (&self) -> impl Content<TuiOut> { fn view_scenes_names (&self) -> impl Content<TuiOut> {
let h = self.scenes_with_prev_color().last().map(|(_,_,_,h,_)|h as u16).unwrap_or(0); Stack::south(move|add: &mut dyn FnMut(&dyn Render<TuiOut>)|{
Fixed::y(h, Map::new(move||self.scenes_with_prev_color(), for (index, scene) in self.scenes().iter().enumerate().skip(self.scene_scroll()) {
move|(s, scene, y1, y2, previous): SceneWith<'_, Option<ItemTheme>>, _|{ add(&Self::view_scene_name(index, scene));
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]
})))
}))
} }
fn scenes_names_2 (&self, theme: ItemTheme) -> impl Content<TuiOut> { fn view_scene_name (index: usize, scene: &Scene) -> impl Content<TuiOut> {
let h = self.scenes().len() as u16 * 2; Fixed::xy(20, 2, Tui::bg(scene.color.dark.rgb, Align::nw(Bsp::e(
let bg = theme.darker.rgb; format!(" {index:2} "),
Fixed::y(h, Tui::bg(bg, Align::w(Fill::x(Map::new( Tui::fg(Rgb(255, 255, 255),
||self.scenes().iter().skip(self.scene_scroll()), Tui::bold(true, format!("{}", scene.name)))))))
move|scene: &Scene, index| //let height = (1 + y2 - y1) as u16;
Push::y(index as u16 * 2u16, Fixed::xy(20, 2, //let name = Some(scene.name.clone());
Tui::bg(scene.color.dark.rgb, Align::nw(Bsp::e( //let content = Fill::x(Align::w(Tui::bold(true, Bsp::e(" ⯈ ", name))));
format!(" {index:2} "), //let selected = self.scene_selected() == Some(s);
Tui::fg(Rgb(255, 255, 255), //let neighbor = s > 0 && self.scene_selected() == Some(s - 1);
Tui::bold(true, format!("{}", scene.name))))))))))))) //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<Item=SceneWith<Option<ItemTheme>>> + Send + Sync { fn scenes_with_prev_color (&self) -> impl Iterator<Item=SceneWith<Option<ItemTheme>>> + Send + Sync {
self.scenes_iter().map(|(s, scene, y1, y2)|(s, scene, y1, y2, 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<MidiEditor>) fn view_scenes_clips <'a> (&'a self, editor: &'a Option<MidiEditor>)
-> impl Content<TuiOut> + 'a -> impl Content<TuiOut> + 'a
{ {
let is_editing = false; //FIXME Fill::xy(Stack::<TuiOut, _>::east(move|column: &mut dyn FnMut(&dyn Render<TuiOut>)|{
let h = self.scenes_with_prev_color().last().map(|(_,_,_,h,_)|h as u16).unwrap_or(0); for (track_index, track, _, _) in self
Fixed::y(h, Self::per_track(||self.tracks_with_sizes_scrolled(), .tracks_with_sizes(&self.selection(), None)
move|track_index, track|Map::new(move||self.scenes_with_clip(track_index), .skip(self.track_scroll())
move|(s, scene, y1, y2, previous): SceneWith<'_, Option<ItemTheme>>, _|{ {
let (name, theme) = if let Some(clip) = &scene.clips[track_index] { //column(&Fixed::x(5, Fill::xy(Tui::bg(Green, "kyp"))));
let clip = clip.read().unwrap(); column(&Fixed::x(
(Some(clip.name.clone()), clip.color) track.width as u16,
} else { Fill::y(self.view_track_clips(track_index, track))
(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
)))
})))
} }
fn view_track_clips <'a> (&'a self, track_index: usize, track: &Track) -> impl Content<TuiOut> {
Stack::south(move|cell: &mut dyn FnMut(&dyn Render<TuiOut>)|{
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> ( fn scenes_clips_2 <'a> (
&'a self, &'a self,
theme: ItemTheme theme: ItemTheme