From 598319af35a9af177a4dbfbea7ef8bb4b16a25be Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 20 Dec 2024 23:45:55 +0100 Subject: [PATCH] more arranger view refactors --- crates/tek/src/core.rs | 4 +- crates/tek/src/tui/arranger_mode_v.rs | 184 ++++++++++++-------------- 2 files changed, 90 insertions(+), 98 deletions(-) diff --git a/crates/tek/src/core.rs b/crates/tek/src/core.rs index 621074be..f8906185 100644 --- a/crates/tek/src/core.rs +++ b/crates/tek/src/core.rs @@ -14,8 +14,8 @@ pub use self::{ /// Prototypal case of implementor macro. /// Saves 4loc per data pats. #[macro_export] macro_rules! from { - ($(<$lt:lifetime>)?|$state:ident:$Source:ty|$Target:ty=$cb:expr) => { - impl $(<$lt>)? From<$Source> for $Target { + ($(<$($lt:lifetime),+>)?|$state:ident:$Source:ty|$Target:ty=$cb:expr) => { + impl $(<$($lt),+>)? From<$Source> for $Target { fn from ($state:$Source) -> Self { $cb } } }; diff --git a/crates/tek/src/tui/arranger_mode_v.rs b/crates/tek/src/tui/arranger_mode_v.rs index 354b4260..f8d54086 100644 --- a/crates/tek/src/tui/arranger_mode_v.rs +++ b/crates/tek/src/tui/arranger_mode_v.rs @@ -1,60 +1,68 @@ use crate::*; +const HEADER_H: u16 = 3; +fn track_widths (tracks: &[ArrangerTrack]) -> Vec<(usize, usize)> { + let mut widths = vec![]; + let mut total = 0; + for track in tracks.iter() { + let width = track.width; + widths.push((width, total)); + total += width; + } + widths.push((0, total)); + widths +} +fn tracks_with_widths (tracks: &[ArrangerTrack]) + -> impl Iterator +{ + let mut x = 0; + tracks.iter().enumerate().map(move |(index, track)|{ + let data = (index, track, x, x + track.width); + x += track.width; + data + }) +} pub struct ArrangerVHead<'a> { - focused: bool, - selected: ArrangerSelection, scenes_w: u16, - header_h: u16, timebase: &'a Arc, current: &'a Arc, - tracks: Vec<(&'a ArrangerTrack, usize, usize)>, + tracks: &'a [ArrangerTrack], } from!(<'a>|state: &'a ArrangerTui|ArrangerVHead<'a> = Self { // A - focused: true, - selected: state.selected, - scenes_w: 3 + ArrangerScene::longest_name(state.scenes()) as u16, - header_h: 3, + tracks: state.tracks(), timebase: state.clock().timebase(), current: &state.clock().playhead, - tracks: track_widths(state.tracks()) - .iter() - .enumerate() - .map(|(i, (a, b))|(&state.tracks()[i], *a, *b)) - .collect(), + scenes_w: 3 + ArrangerScene::longest_name(state.scenes()) as u16, }); -render!(|self: ArrangerVHead<'a>|row!( - (track, w, _) in self.tracks.iter() => { - let name = Self::format_name(track, *w); - let input = Self::format_input(track)?; - let elapsed = Self::format_elapsed(track, &self.timebase); - let until_next = Self::format_until_next(track, &self.timebase, &self.current); - let output = Self::format_output(track)?; - Tui::push_x(self.scenes_w, - Tui::bg(track.color().base.rgb, - Tui::min_xy(*w as u16, self.header_h, row!([ - col!(!["▎", "▎", "▎", "▎", "▎", "▎",]), - col!(![name, input, output, elapsed, until_next, output])])))) +render!(|self: ArrangerVHead<'a>|Tui::push_x(self.scenes_w, row!( + (_, track, x1, x2) in tracks_with_widths(self.tracks) => { + let (w, h) = (x2 - x1, HEADER_H); + let color = track.color(); + Tui::bg(color.base.rgb, Tui::min_xy(w as u16, h, Fixed::wh(w as u16, 5, col!([ + row!(![Tui::fg(color.light.rgb, "▎"), Self::format_name(track, w)]), + row!(![Tui::fg(color.light.rgb, "▎"), Self::format_input(track)?]), + row!(![Tui::fg(color.light.rgb, "▎"), Self::format_output(track)?]), + row!(![Tui::fg(color.light.rgb, "▎"), Self::format_elapsed(track, &self.timebase)]), + row!(![Tui::fg(color.light.rgb, "▎"), Self::format_until_next(track, &self.current)]), + ])))) } -)); +))); impl<'a> ArrangerVHead<'a> { /// name and width of track fn format_name (track: &ArrangerTrack, w: usize) -> impl Render { let name = track.name().read().unwrap(); let max_w = w.saturating_sub(1).min(name.len()).max(2); - Tui::bold(true, Tui::fg(track.color.lightest.rgb, format!("▎{}", &name[0..max_w]))); + let name = String::from(&name[0..max_w]); + Tui::bold(true, Tui::fg(track.color.lightest.rgb, name)); } /// input port fn format_input (track: &ArrangerTrack) -> Usually> { - Ok(format!(">{}", track.player.midi_ins().get(0) - .map(|port|port.short_name()) - .transpose()? - .unwrap_or("(none)".into()))) + Ok(format!(">{}", track.player.midi_ins().get(0).map(|port|port.short_name()) + .transpose()?.unwrap_or("?".into()))) } /// output port fn format_output (track: &ArrangerTrack) -> Usually> { - Ok(format!("<{}", track.player.midi_outs().get(0) - .map(|port|port.short_name()) - .transpose()? - .unwrap_or("(none)".into()))) + Ok(format!("<{}", track.player.midi_outs().get(0).map(|port|port.short_name()) + .transpose()?.unwrap_or("?".into()))) } /// beats elapsed fn format_elapsed (track: &ArrangerTrack, timebase: &Arc) -> impl Render { @@ -70,9 +78,10 @@ impl<'a> ArrangerVHead<'a> { } } /// beats until switchover - fn format_until_next (track: &ArrangerTrack, timebase: &Arc, current: &Arc) + fn format_until_next (track: &ArrangerTrack, current: &Arc) -> Option> { + let timebase = ¤t.timebase; track.player.next_phrase().as_ref().map(|(t, _)|{ let target = t.pulse.get(); let current = current.pulse.get(); @@ -128,22 +137,18 @@ render!(|self: ArrangerVRowSep|render(move|to: &mut TuiOutput|{ pub struct ArrangerVCursor { cols: Vec<(usize, usize)>, rows: Vec<(usize, usize)>, - focused: bool, selected: ArrangerSelection, scenes_w: u16, - header_h: u16, } from!(|args:(&ArrangerTui, usize)|ArrangerVCursor = Self { cols: track_widths(args.0.tracks()), rows: ArrangerScene::ppqs(args.0.scenes(), args.1), - focused: true, selected: args.0.selected(), scenes_w: 3 + ArrangerScene::longest_name(args.0.scenes()) as u16, - header_h: 3, }); render!(|self: ArrangerVCursor|render(move|to: &mut TuiOutput|{ let area = to.area(); - let focused = self.focused; + let focused = true; let selected = self.selected; let get_track_area = |t: usize| [ self.scenes_w + area.x() + self.cols[t].1 as u16, @@ -153,13 +158,13 @@ render!(|self: ArrangerVCursor|render(move|to: &mut TuiOutput|{ ]; let get_scene_area = |s: usize| [ area.x(), - self.header_h + area.y() + (self.rows[s].1 / PPQ) as u16, + HEADER_H + area.y() + (self.rows[s].1 / PPQ) as u16, area.w(), (self.rows[s].0 / PPQ) as u16 ]; let get_clip_area = |t: usize, s: usize| [ self.scenes_w + area.x() + self.cols[t].1 as u16, - self.header_h + area.y() + (self.rows[s].1/PPQ) as u16, + HEADER_H + area.y() + (self.rows[s].1/PPQ) as u16, self.cols[t].0 as u16, (self.rows[s].0 / PPQ) as u16 ]; @@ -194,78 +199,65 @@ render!(|self: ArrangerVCursor|render(move|to: &mut TuiOutput|{ } Ok(if focused { to.render_in(if let Some(clip_area) = clip_area { clip_area } - else if let Some(track_area) = track_area { track_area.clip_h(self.header_h) } + 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(self.header_h) }, &CORNERS)? + else { area.clip_w(self.scenes_w).clip_h(HEADER_H) }, &CORNERS)? }) })); - pub struct ArrangerVBody<'a> { size: &'a Measure, scenes: &'a Vec, tracks: &'a Vec, rows: Vec<(usize, usize)>, - cols: Vec<(usize, usize)>, - header_h: u16, } - -impl<'a> From<(&'a ArrangerTui, usize)> for ArrangerVBody<'a> { - fn from ((state, factor): (&'a ArrangerTui, usize)) -> Self { - Self { - size: &state.size, - scenes: &state.scenes, - tracks: &state.tracks, - rows: ArrangerScene::ppqs(state.scenes(), factor), - cols: track_widths(state.tracks()), - header_h: 3, - } - } -} - +from!(<'a>|args:(&'a ArrangerTui, usize)|ArrangerVBody<'a> = Self { + size: &args.0.size, + scenes: &args.0.scenes, + tracks: &args.0.tracks, + rows: ArrangerScene::ppqs(args.0.scenes(), args.1), +}); render!(|self: ArrangerVBody<'a>|Fixed::h( - (self.size.h() as u16).saturating_sub(self.header_h), + (self.size.h() as u16).saturating_sub(HEADER_H), col!((scene, pulses) in self.scenes.iter().zip(self.rows.iter().map(|row|row.0)) => { let height = 1.max((pulses / PPQ) as u16); let playing = scene.is_playing(self.tracks); Fixed::h(height, row!([ - if playing { "▶ " } else { " " }, + Self::format_play(playing), Tui::bold(true, scene.name.read().unwrap().as_str()), - row!((track, w) in self.cols.iter().map(|col|col.0).enumerate() => { - Fixed::wh(w as u16, height, Layers::new(move |add|{ - let mut bg = TuiTheme::border_bg(); - match (self.tracks.get(track), scene.clips.get(track)) { - (Some(track), Some(Some(phrase))) => { - let name = &(phrase as &Arc>).read().unwrap().name; - let name = format!("{}", name); - let max_w = name.len().min((w as usize).saturating_sub(2)); - let color = phrase.read().unwrap().color; - bg = color.dark.rgb; - if let Some((_, Some(ref playing))) = track.player.play_phrase() { - if *playing.read().unwrap() == *phrase.read().unwrap() { - bg = color.light.rgb - } - }; - add(&Fixed::w(w as u16, Tui::push_x(1, &name.as_str()[0..max_w])))?; - }, - _ => {} - }; - //add(&Background(bg)) - Ok(()) - })) + row!((index, _, x1, x2) in tracks_with_widths(self.tracks) => { + Self::format_clip(&self.tracks, &scene, index, (x2 - x1) as u16, height) })]) ) }) )); - -fn track_widths (tracks: &[ArrangerTrack]) -> Vec<(usize, usize)> { - let mut widths = vec![]; - let mut total = 0; - for track in tracks.iter() { - let width = track.width; - widths.push((width, total)); - total += width; +impl<'a> ArrangerVBody<'a> { + fn format_play (playing: bool) -> &'static str { + if playing { "▶ " } else { " " } + } + fn format_clip (tracks: &'a [ArrangerTrack], scene: &'a ArrangerScene, i: usize, w: u16, h: u16) + -> impl Render + use<'a> + { + Fixed::wh(w, h, Layers::new(move |add|{ + let mut bg = TuiTheme::border_bg(); + match (tracks.get(i), scene.clips.get(i)) { + (Some(track), Some(Some(phrase))) => { + let name = &(phrase as &Arc>).read().unwrap().name; + let name = format!("{}", name); + let max_w = name.len().min((w as usize).saturating_sub(2)); + let color = phrase.read().unwrap().color; + bg = color.dark.rgb; + if let Some((_, Some(ref playing))) = track.player.play_phrase() { + if *playing.read().unwrap() == *phrase.read().unwrap() { + bg = color.light.rgb + } + }; + add(&Fixed::w(w as u16, Tui::push_x(1, &name.as_str()[0..max_w])))?; + }, + _ => {} + }; + //add(&Background(bg)) + Ok(()) + })) } - widths.push((0, total)); - widths }