diff --git a/jack/src/jack_port.rs b/jack/src/jack_port.rs index 4d82bc7c..df267172 100644 --- a/jack/src/jack_port.rs +++ b/jack/src/jack_port.rs @@ -13,7 +13,7 @@ macro_rules! impl_port { } impl AsRef> for $Name { fn as_ref (&self) -> &Port<$Spec> { &self.port } } impl $Name { - pub fn name (&self) -> &str { self.name.as_ref() } + pub fn name (&self) -> &Arc { &self.name } pub fn port (&self) -> &Port<$Spec> { &self.port } pub fn port_mut (&mut self) -> &mut Port<$Spec> { &mut self.port } pub fn new ($jack: &Jack, name: impl AsRef, connect: &[PortConnect]) diff --git a/tek/src/lib.rs b/tek/src/lib.rs index 6e5a88b4..c5021122 100644 --- a/tek/src/lib.rs +++ b/tek/src/lib.rs @@ -5,6 +5,7 @@ #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(type_alias_impl_trait)] +#![feature(trait_alias)] mod cli; pub use self::cli::*; mod model; pub use self::model::*; mod view; pub use self::view::*; diff --git a/tek/src/view.rs b/tek/src/view.rs index e781d2bb..b4643592 100644 --- a/tek/src/view.rs +++ b/tek/src/view.rs @@ -1,9 +1,17 @@ use crate::*; use std::fmt::Write; -#[derive(Debug, Default)] struct ViewMemo { - value: T, - view: Arc> +macro_rules! def_sizes_iter { + ($Type:ident => $($Item:ty),+) => { + trait $Type<'a> = Iterator + Send + Sync + 'a; + } } +def_sizes_iter!(ScenesSizes => Scene); +def_sizes_iter!(TracksSizes => Track); +def_sizes_iter!(InputsSizes => JackMidiIn); +def_sizes_iter!(OutputsSizes => JackMidiOut); +def_sizes_iter!(PortsSizes => Arc, [PortConnect]); + +#[derive(Debug, Default)] struct ViewMemo { value: T, view: Arc> } impl ViewMemo { fn new (value: T, view: U) -> Self { Self { @@ -186,12 +194,6 @@ macro_rules! per_track { let content = Fixed::y(1, $content); let styled = Tui::fg_bg($track.color.lightest.rgb, $track.color.base.rgb, content); map_east(x1 as u16, width, Align::y(Fixed::x(width, styled))) }))).into() }} } -macro_rules! io_header { - ($self:ident, $key:expr, $label:expr, $count:expr, $content:expr) => { - (move||Fill::xy(Align::nw({ - let button = $self.button($key, format!("{:10} ({})", $label, $count)); - Bsp::s(button, $content) - })).boxed()).into() } } macro_rules! per_track_top { ($area:expr;|$self:ident,$track:ident,$index:ident|$content:expr) => {{ let tracks = ||$self.tracks_sizes($self.is_editing(), $self.editor_w()) @@ -215,14 +217,44 @@ impl Tek { fn wrap (bg: Color, fg: Color, content: impl Content) -> impl Content { Bsp::e(Tui::fg_bg(bg, Reset, "▐"), Bsp::w(Tui::fg_bg(bg, Reset, "▌"), Tui::fg_bg(fg, bg, content))) } + fn view_header <'a> ( + &'a self, key: &'a str, label: &str, count: usize, content: impl Content + Send + Sync + 'a + ) -> impl Content + 'a { + Fill::xy(Align::nw(Bsp::s( + self.button(key, format!("{:10} ({})", label, count)), + content, + ))) + } + fn view_io_header <'a, T: PortsSizes<'a>> ( + &'a self, + key: &'a str, + label: &str, + count: usize, + fg: Color, + bg: Color, + iter: impl Fn()->T + Send + Sync + 'a, + ) -> impl Content + 'a { + self.view_header(key, label, count, Map::new(iter, + move|(index, name, connections, y, y2), _|map_south(y as u16, (y2-y) as u16, Bsp::s( + Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(name)))), + Map::new(||connections.iter(), move|connect, index|map_south(index as u16, 1, + Fill::x(Align::w(Tui::bold(false, Tui::fg_bg(fg, bg, connect.info())))))))))) + } + fn button <'a> ( + &'a self, key: impl Content + 'a, label: impl Content + 'a + ) -> impl Content + 'a { + let compact = !self.is_editing(); + Tui::bold(true, Bsp::e( + Margin::x(1, Tui::fg_bg(Tui::g(0), Tui::orange(), key)), + When::new(compact, Margin::x(1, Tui::fg_bg(Tui::g(255), Tui::g(96), label))), + )) + } // TRACKS ///////////////////////////////////////////////////////////////////////////////////// fn w_tracks (&self, editing: bool, bigger: usize) -> u16 { self.tracks_sizes(editing, bigger).last().map(|(_, _, _, x)|x as u16).unwrap_or(0) } - fn tracks_sizes <'a> (&'a self, editing: bool, bigger: usize) - -> impl Iterator + Send + Sync + 'a - { + fn tracks_sizes <'a> (&'a self, editing: bool, bigger: usize) -> impl TracksSizes<'a> { let mut x = 0; let active = match self.selected() { Selection::Track(t) if editing => Some(t.saturating_sub(1)), @@ -254,28 +286,22 @@ impl Tek { } // INPUTS ///////////////////////////////////////////////////////////////////////////////////// - fn inputs_sizes (&self) -> impl Iterator + Send + Sync { + fn inputs_sizes (&self) -> impl PortsSizes<'_> { let mut y = 0; self.midi_ins.iter().enumerate().map(move|(i, input)|{ let height = 1 + input.conn().len(); - let data = (i, input, y, y + height); + let data = (i, input.name(), input.conn(), y, y + height); y += height; data }) } fn h_inputs (&self) -> u16 { - 1 + self.inputs_sizes().last().map(|(_, _, _, y)|y as u16).unwrap_or(0) + 1 + self.inputs_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0) } fn view_inputs (&self) -> impl Content + use<'_> { let fg = Tui::g(224); let bg = Tui::g(64); - let header: ThunkBox<_> = io_header!(self, " I ", " midi ins", self.midi_ins.len(), - Map::new(||self.inputs_sizes(), - move|(index, input, y, y2), _|map_south(y as u16, (y2-y) as u16, Bsp::s( - Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(input.name())))), - Map::new(||input.conn().iter(), move|connect, index|map_south(index as u16, 1, - Fill::x(Align::w(Tui::bold(false, Tui::fg_bg(fg, bg, connect.info())))))))))); - + let header = self.view_io_header(" I ", " midi ins", self.midi_ins.len(), fg, bg, ||self.inputs_sizes()); let cells: ThunkBox<_> = per_track_top!(self.size.w();|self, track, t|{ let rec = track.player.recording; let mon = track.player.monitoring; @@ -287,7 +313,7 @@ impl Tek { Tui::fg_bg(if mon { White } else { track.color.darkest.rgb }, bg, "Mon ")))))), Fill::y(Tui::bg(Green, Map::new( ||self.inputs_sizes(), - move|(index, input, y, y2), _|map_south(y as u16, (y2-y) as u16, + move|(index, name, conn, y, y2), _|map_south(y as u16, (y2-y) as u16, Self::wrap(bg, fg, Bsp::e( Tui::fg_bg(if rec { White } else { track.color.darkest.rgb }, bg, "R▞▞▞▞"), Tui::fg_bg(if mon { White } else { track.color.darkest.rgb }, bg, "M▞▞▞▞"))))))))}); @@ -300,13 +326,13 @@ impl Tek { // OUTPUTS //////////////////////////////////////////////////////////////////////////////////// fn h_outputs (&self) -> u16 { - 1 + self.outputs_sizes().last().map(|(_, _, _, y)|y as u16).unwrap_or(0) + 1 + self.outputs_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0) } - fn outputs_sizes (&self) -> impl Iterator + Send + Sync { + fn outputs_sizes (&self) -> impl PortsSizes<'_> { let mut y = 0; self.midi_outs.iter().enumerate().map(move|(i, output)|{ let height = 1 + output.conn().len(); - let data = (i, output, y, y + height); + let data = (i, output.name(), output.conn(), y, y + height); y += height; data }) @@ -314,13 +340,7 @@ impl Tek { fn view_outputs (&self) -> impl Content + use<'_> { let fg = Tui::g(224); let bg = Tui::g(64); - let header: ThunkBox<_> = io_header!(self, " O ", " midi outs", self.midi_outs.len(), - Map::new(||self.outputs_sizes(), - move|(index, output, y, y2), _|map_south(y as u16, (y2-y) as u16, Bsp::s( - Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(output.name())))), - Map::new(||output.conn().iter(), move|connect, index|map_south(index as u16, 1, - Fill::x(Align::w(Tui::bold(false, Tui::fg_bg(fg, bg, connect.info())))))))))); - + let header = self.view_io_header(" O ", " midi outs", self.midi_outs.len(), fg, bg, ||self.outputs_sizes()); let mute = false; let solo = false; let cells: ThunkBox<_> = per_track_top!(self.size.w();|self, track, t|{ @@ -332,7 +352,7 @@ impl Tek { Tui::fg_bg(if solo { White } else { track.color.darkest.rgb }, bg, "Solo "),)))), Fill::y(Map::new( ||self.outputs_sizes(), - move|(index, output, y, y2), _|map_south(y as u16, (y2-y) as u16, + move|(index, name, conn, y, y2), _|map_south(y as u16, (y2-y) as u16, Self::wrap(bg, fg, Bsp::e( Tui::fg_bg(if mute { White } else { track.color.darkest.rgb }, bg, "P▞▞▞▞"), Tui::fg_bg(if solo { White } else { track.color.darkest.rgb }, bg, "S▞▞▞▞")))))))}); @@ -346,9 +366,7 @@ impl Tek { fn h_scenes (&self, editing: bool, height: usize, larger: usize) -> u16 { self.scenes_sizes(editing, height, larger).last().map(|(_, _, _, y)|y as u16).unwrap_or(0) } - fn scenes_sizes (&self, editing: bool, height: usize, larger: usize) - -> impl Iterator + Send + Sync - { + fn scenes_sizes (&self, editing: bool, height: usize, larger: usize) -> impl ScenesSizes<'_> { let mut y = 0; let (selected_track, selected_scene) = match self.selected() { Selection::Clip(t, s) => (Some(t.saturating_sub(1)), Some(s.saturating_sub(1))), @@ -461,15 +479,6 @@ impl Tek { //let w = if self.is_editing() { w / 2 } else { w }; w as u16 } - fn button <'a> ( - &'a self, key: impl Content + 'a, label: impl Content + 'a - ) -> impl Content + 'a { - let compact = !self.is_editing(); - Tui::bold(true, Bsp::e( - Margin::x(1, Tui::fg_bg(Tui::g(0), Tui::orange(), key)), - When::new(compact, Margin::x(1, Tui::fg_bg(Tui::g(255), Tui::g(96), label))), - )) - } fn view_track_add (&self) -> impl Content + use<'_> { let data = (self.selected.track().unwrap_or(0), self.tracks().len()); self.fmtd.write().unwrap().trks.update(Some(data),