sweeeeping sweep

This commit is contained in:
🪞👃🪞 2024-12-31 04:12:09 +01:00
parent c9b09b7dea
commit e677d1d7d4
38 changed files with 766 additions and 691 deletions

View file

@ -7,7 +7,7 @@ pub enum ArrangerMode {
/// Tracks are rows
H,
}
render!(<Tui>|self: ArrangerMode|"");
impl<E: Engine> Content<E> for ArrangerMode {}
/// Arranger display mode can be cycled
impl ArrangerMode {
/// Cycle arranger display mode

View file

@ -7,39 +7,42 @@ pub struct ArrangerVClips<'a> {
tracks: &'a Vec<ArrangerTrack>,
rows: Vec<(usize, usize)>,
}
from!(<'a>|args:(&'a ArrangerTui, usize)|ArrangerVClips<'a> = Self {
size: &args.0.size,
scenes: &args.0.scenes,
tracks: &args.0.tracks,
rows: ArrangerScene::ppqs(&args.0.scenes, args.1),
});
render!(<Tui>|self: ArrangerVClips<'a>|Fill::xy(
col!((scene, pulses) in self.scenes.iter().zip(self.rows.iter().map(|row|row.0)) => {
Self::format_scene(self.tracks, scene, pulses)
})
));
impl<'a> ArrangerVClips<'a> {
pub fn new (state: &'a ArrangerTui, zoom: usize) -> Self {
Self {
size: &state.size,
tracks: &state.tracks,
scenes: &state.scenes,
rows: ArrangerScene::ppqs(&state.scenes, zoom),
}
}
}
impl<'a, E: Engine> Content<E> for ArrangerVClips<'a> {
fn content (&self) -> Option<impl Content<E>> {
let iter = self.scenes.iter().zip(self.rows.iter().map(|row|row.0));
let col = col_iter!(iter => |(scene, pulses)|Self::format_scene(self.tracks, scene, pulses));
Some(Fill::xy(col))
}
}
impl<'a> ArrangerVClips<'a> {
fn format_scene (
tracks: &'a [ArrangerTrack], scene: &'a ArrangerScene, pulses: usize
) -> impl Render<Tui> + use<'a> {
) -> impl Content<Tui> + use<'a> {
let height = 1.max((pulses / PPQ) as u16);
let playing = scene.is_playing(tracks);
Fixed::y(height, row!([
Fixed::y(height, row!(
Tui::bg(scene.color.base.rgb,
if playing { "" } else { " " }),
Tui::fg_bg(scene.color.lightest.rgb, scene.color.base.rgb,
Expand::x(1, Tui::bold(true, scene.name.read().unwrap().as_str()))),
row!((index, track, x1, x2) in ArrangerTrack::with_widths(tracks) => {
row_iter!((index, track, x1, x2) in ArrangerTrack::with_widths(tracks) => {
Self::format_clip(scene, index, track, (x2 - x1) as u16, height)
})])
)
}
})))}
fn format_clip (
scene: &'a ArrangerScene, index: usize, track: &'a ArrangerTrack, w: u16, h: u16
) -> impl Render<Tui> + use<'a> {
) -> impl Content<Tui> + use<'a> {
Fixed::xy(w, h, Layers::new(move |add|{
if let Some(Some(phrase)) = scene.clips.get(index) {
let mut bg = TuiTheme::border_bg();

View file

@ -24,11 +24,9 @@ from!(|args:(&ArrangerTui, usize)|ArrangerVCursor = Self {
sub_modifier: Modifier::DIM
}),
});
render!(<Tui>(self: ArrangerVCursor)
|layout|Ok(Some([0, 0])),
|render|{
let area = render.area();
impl Content<Tui> for ArrangerVCursor {
fn render (&self, to: &mut TuiOutput) {
let area = to.area();
let focused = true;
let selected = self.selected;
let get_track_area = |t: usize| [
@ -67,17 +65,18 @@ render!(<Tui>(self: ArrangerVCursor)
};
let bg = self.color.lighter.rgb;//Color::Rgb(0, 255, 0);
if let Some([x, y, width, height]) = track_area {
render.fill_fg([x, y, 1, height], bg);
render.fill_fg([x + width, y, 1, height], bg);
to.fill_fg([x, y, 1, height], bg);
to.fill_fg([x + width, y, 1, height], bg);
}
if let Some([_, y, _, height]) = scene_area {
render.fill_ul([area.x(), y - 1, area.w(), 1], bg);
render.fill_ul([area.x(), y + height - 1, area.w(), 1], bg);
to.fill_ul([area.x(), y - 1, area.w(), 1], bg);
to.fill_ul([area.x(), y + height - 1, area.w(), 1], bg);
}
Ok(if focused {
render.render_in(if let Some(clip_area) = clip_area { clip_area }
to.render_in(if let Some(clip_area) = clip_area { clip_area }
else if let Some(track_area) = track_area { track_area.clip_h(HEADER_H) }
else if let Some(scene_area) = scene_area { scene_area.clip_w(self.scenes_w) }
else { area.clip_w(self.scenes_w).clip_h(HEADER_H) }, &self.reticle)?
})
});
}
}

View file

@ -15,44 +15,48 @@ from!(<'a>|state: &'a ArrangerTui|ArrangerVHead<'a> = Self { // A
scenes_w: SCENES_W_OFFSET + ArrangerScene::longest_name(&state.scenes) as u16,
});
render!(<Tui>|self: ArrangerVHead<'a>|Push::x(self.scenes_w, row!(
(_, track, x1, x2) in ArrangerTrack::with_widths(self.tracks) => {
let (w, h) = (ArrangerTrack::MIN_WIDTH.max(x2 - x1), HEADER_H);
let color = track.color();
fn row <T: Render<Tui>> (color: ItemPalette, field: &T) -> impl Render<Tui> + use<'_, T> {
row!([
Tui::fg(color.light.rgb, ""),
Tui::fg(color.lightest.rgb, field)
])
impl Content<Tui> for ArrangerVCursor {
fn content (&self) -> Option<impl Content<Tui>> {
fn row <T: Content<Tui>> (color: ItemPalette, field: &T) -> impl Content<Tui> + use<'_, T> {
row!([Tui::fg(color.light.rgb, ""), Tui::fg(color.lightest.rgb, field)])
}
Tui::bg(color.base.rgb, Min::xy(w as u16, h, Fixed::xy(w as u16, 5, col!([
row(color, &Self::format_name(track, w)),
row(color, &Self::format_input(track)?),
row(color, &Self::format_output(track)?),
row(color, &Self::format_elapsed(track, self.timebase)),
row(color, &Self::format_until_next(track, self.current)),
]))))
Some(Push::x(self.scenes_w, row_iter!(
(_0, track, x1, x2) in ArrangerTrack::with_widths(self.tracks) => {
let (w, h) = (ArrangerTrack::MIN_WIDTH.max(x2 - x1), HEADER_H);
let color = track.color();
Tui::bg(color.base.rgb, Min::xy(w as u16, h, Fixed::xy(w as u16, 5, col!([
row(color, &Self::format_name(track, w)),
row(color, &Self::format_input(track)?),
row(color, &Self::format_output(track)?),
row(color, &Self::format_elapsed(track, self.timebase)),
row(color, &Self::format_until_next(track, self.current)),
]))))
}
)))
}
)));
}
impl ArrangerVHead<'_> {
/// name and width of track
fn format_name (track: &ArrangerTrack, _w: usize) -> impl Render<Tui> {
fn format_name (track: &ArrangerTrack, _w: usize) -> impl Content<Tui> {
let name = track.name().read().unwrap().clone();
Tui::bold(true, Tui::fg(track.color.lightest.rgb, name))
}
/// input port
fn format_input (track: &ArrangerTrack) -> Usually<impl Render<Tui>> {
fn format_input (track: &ArrangerTrack) -> Usually<impl Content<Tui>> {
Ok(format!(">{}", track.player.midi_ins().first().map(|port|port.short_name())
.transpose()?.unwrap_or("?".into())))
}
/// output port
fn format_output (track: &ArrangerTrack) -> Usually<impl Render<Tui>> {
fn format_output (track: &ArrangerTrack) -> Usually<impl Content<Tui>> {
Ok(format!("<{}", track.player.midi_outs().first().map(|port|port.short_name())
.transpose()?.unwrap_or("?".into())))
}
/// beats elapsed
fn format_elapsed (track: &ArrangerTrack, timebase: &Arc<Timebase>) -> impl Render<Tui> {
fn format_elapsed (track: &ArrangerTrack, timebase: &Arc<Timebase>) -> impl Content<Tui> {
let mut result = String::new();
if let Some((_, Some(phrase))) = track.player.play_phrase().as_ref() {
let length = phrase.read().unwrap().length;
@ -66,7 +70,7 @@ impl ArrangerVHead<'_> {
}
/// beats until switchover
fn format_until_next (track: &ArrangerTrack, current: &Arc<Moment>)
-> Option<impl Render<Tui>>
-> Option<impl Content<Tui>>
{
let timebase = &current.timebase;
let mut result = String::new();

View file

@ -11,7 +11,7 @@ from!(<'a>|args: &'a ArrangerTui|ArrangerVIns<'a> = Self {
tracks: &args.tracks,
});
render!(<Tui>|self: ArrangerVIns<'a>|"");
render!(Tui: (self: ArrangerVIns<'a>) => "");
pub struct ArrangerVOuts<'a> {
size: &'a Measure<Tui>,
@ -23,4 +23,4 @@ from!(<'a>|args: &'a ArrangerTui|ArrangerVOuts<'a> = Self {
tracks: &args.tracks,
});
render!(<Tui>|self: ArrangerVOuts<'a>|"");
render!(Tui: (self: ArrangerVOuts<'a>) => "");

View file

@ -11,17 +11,15 @@ from!(|state:&ArrangerTui|ArrangerVColSep = Self {
cols: ArrangerTrack::widths(&state.tracks),
scenes_w: SCENES_W_OFFSET + ArrangerScene::longest_name(&state.scenes) as u16,
});
render!(<Tui>(self: ArrangerVColSep)
|layout|Ok(Some([0, 0])),
|render|{
let style = Some(Style::default().fg(self.fg));
Ok(for x in self.cols.iter().map(|col|col.1) {
let x = self.scenes_w + render.area().x() + x as u16;
for y in render.area().y()..render.area().y2() {
render.blit(&"", x, y, style);
}
})
});
render!(Tui: |self: ArrangerVColSep, to| {
let style = Some(Style::default().fg(self.fg));
Ok(for x in self.cols.iter().map(|col|col.1) {
let x = self.scenes_w + to.area().x() + x as u16;
for y in to.area().y()..to.area().y2() {
to.blit(&"", x, y, style);
}
})
});
pub struct ArrangerVRowSep {
fg: Color,
@ -31,16 +29,14 @@ from!(|args:(&ArrangerTui, usize)|ArrangerVRowSep = Self {
fg: TuiTheme::separator_fg(false),
rows: ArrangerScene::ppqs(&args.0.scenes, args.1),
});
render!(<Tui>(self: ArrangerVRowSep)
|layout|Ok(Some([0, 0])),
|render|Ok(for y in self.rows.iter().map(|row|row.1) {
let y = render.area().y() + (y / PPQ) as u16 + 1;
if y >= render.buffer.area.height { break }
for x in render.area().x()..render.area().x2().saturating_sub(2) {
if x < render.buffer.area.x && y < render.buffer.area.y {
let cell = render.buffer.get_mut(x, y);
cell.modifier = Modifier::UNDERLINED;
cell.underline_color = self.fg;
}
render!(Tui: |self: ArrangerVRowSep, to|for y in self.rows.iter().map(|row|row.1) {
let y = to.area().y() + (y / PPQ) as u16 + 1;
if y >= to.buffer.area.height { break }
for x in to.area().x()..to.area().x2().saturating_sub(2) {
if x < to.buffer.area.x && y < to.buffer.area.y {
let cell = to.buffer.get_mut(x, y);
cell.modifier = Modifier::UNDERLINED;
cell.underline_color = self.fg;
}
}));
}
});