diff --git a/crates/app/src/view.rs b/crates/app/src/view.rs index b2b8b9e9..c3b8a907 100644 --- a/crates/app/src/view.rs +++ b/crates/app/src/view.rs @@ -23,8 +23,8 @@ impl Tek { pub fn view_modal (&self) -> impl Content + use<'_> { When::new(self.modal.is_some(), Bsp::b( - Fill::xy(Tui::fg_bg(Rgb(64,64,64), Rgb(32,32,32), "")), - Fixed::xy(30, 15, Tui::fg_bg(Rgb(255,255,255), Rgb(16,16,16), Bsp::b( + Fill::xy(Tui::fg_bg(Color::Rgb(64,64,64), Color::Rgb(32,32,32), "")), + Fixed::xy(30, 15, Tui::fg_bg(Color::Rgb(255,255,255), Color::Rgb(16,16,16), Bsp::b( Repeat(" "), Outer(true, Style::default().fg(Tui::g(96))) .enclose(self.modal.map(|modal|match modal { @@ -37,7 +37,7 @@ impl Tek { fn view_modal_menu (&self) -> impl Content { let options = ||["Projects", "Settings", "Help", "Quit"].iter(); - let option = |a,i|Tui::fg(Rgb(255,255,255), format!("{}", a)); + let option = |a,i|Tui::fg(Color::Rgb(255,255,255), format!("{}", a)); Bsp::s(Tui::bold(true, "tek!"), Bsp::s("", Map::south(1, options, option))) } @@ -51,14 +51,14 @@ impl Tek { None }); let binding = |mut binding: TokenIter, _|Bsp::e( - Fixed::x(15, Align::w(Tui::bold(true, Tui::fg(Rgb(255,192,0), if let Some(Token { + Fixed::x(15, Align::w(Tui::bold(true, Tui::fg(Color::Rgb(255,192,0), if let Some(Token { value: Value::Sym(key), .. }) = binding.next() { Some(key.to_string()) } else { None })))), - Bsp::e(" ", Tui::fg(Rgb(255,255,255), if let Some(Token { + Bsp::e(" ", Tui::fg(Color::Rgb(255,255,255), if let Some(Token { value: Value::Key(command), .. }) = binding.next() { Some(command.to_string()) @@ -134,35 +134,24 @@ impl Tek { /// Height available to display track headers. pub(crate) fn h_tracks_area (&self) -> u16 { - 5 // FIXME + 5 //self.h().saturating_sub(self.h_inputs() + self.h_outputs()) } /// Height available to display tracks. pub(crate) fn h_scenes_area (&self) -> u16 { //15 - self.h().saturating_sub( - self.h_inputs() + - self.h_outputs() + - self.h_devices() + - 13 // FIXME - ) + self.h().saturating_sub(self.h_inputs() + self.h_outputs() + 11) } /// Height taken by all inputs. pub(crate) fn h_inputs (&self) -> u16 { - self.inputs_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0) + 1 + self.inputs_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0) } /// Height taken by all outputs. pub(crate) fn h_outputs (&self) -> u16 { - self.outputs_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0) - } - - /// Height taken by visible device slots. - pub(crate) fn h_devices (&self) -> u16 { - 2 - //1 + self.devices_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0) + 1 + self.outputs_with_sizes().last().map(|(_, _, _, _, y)|y as u16).unwrap_or(0) } /// Height taken by all scenes. @@ -266,14 +255,13 @@ pub(crate) struct ArrangerView<'a> { impl<'a> Content for ArrangerView<'a> { fn content (&self) -> impl Render { - let ins = |x|Bsp::n(self.inputs(), x); - let tracks = |x|Bsp::s(self.tracks(), x); - let devices = |x|Bsp::s(self.devices(), x); - let outs = |x|Bsp::s(self.outputs(), x); - let bg = |x|Tui::bg(Reset, x); + let ins = |x|Bsp::s(self.inputs(), x); + let tracks = |x|Bsp::s(self.tracks(), x); + let outs = |x|Bsp::n(self.outputs(), x); + let bg = |x|Tui::bg(Color::Reset, x); //let track_scroll = |x|Bsp::s(&self.track_scroll, x); //let scene_scroll = |x|Bsp::e(&self.scene_scroll, x); - outs(tracks(devices(ins(bg(self.scenes()))))) + ins(tracks(outs(bg(self.scenes())))) } } @@ -287,10 +275,10 @@ impl<'a> ArrangerView<'a> { width_mid: app.w_tracks_area(), width_side: app.w_sidebar(), - inputs_height: app.h_inputs(), + inputs_height: app.h_inputs().saturating_sub(1), inputs_count: app.midi_ins.len(), - outputs_height: app.h_outputs(), + outputs_height: app.h_outputs().saturating_sub(1), outputs_count: app.midi_outs.len(), scenes_height: app.h_scenes_area(), @@ -318,57 +306,12 @@ impl<'a> ArrangerView<'a> { /// Render input matrix. pub(crate) fn inputs (&'a self) -> impl Content + 'a { - Tui::bg(Reset, Bsp::s( - self.input_intos(), + Tui::bg(Color::Reset, Bsp::s( Bsp::s(self.input_routes(), self.input_ports()), + self.input_intos() )) } - /// Render output matrix. - pub(crate) fn outputs (&'a self) -> impl Content + 'a { - Tui::bg(Reset, Align::n(Bsp::s( - Bsp::s(self.output_ports(), self.output_conns()), - Bsp::s(self.output_nexts(), self.output_froms()), - ))) - } - - /// Render device switches. - pub(crate) fn devices (&'a self) -> impl Content + 'a { - let Self { width_side, width_mid, track_count, track_selected, is_editing, .. } = self; - Tryptich::top(1) - .left(*width_side, button_3("x", "devices", format!("{}", 0), *is_editing)) - .right(*width_side, button_2("X", "add device", *is_editing)) - .middle(*width_mid, per_track_top(*width_mid, ||self.tracks_with_sizes_scrolled(), - move|index, track|{ - wrap(if *track_selected == Some(index) { - track.color.light - } else { - track.color.base - }.rgb, Tui::g(224), Tui::bold(true, Fill::x(Bsp::e( - Tui::fg_bg(Reset, Reset, "[ "), - Tui::fg_bg(Reset, Reset, " ]"), - )))) - })) - } - - /// Render track headers - pub(crate) fn tracks (&'a self) -> impl Content + 'a { - let Self { width_side, width_mid, track_count, track_selected, is_editing, .. } = self; - Tryptich::center(3) - .left(*width_side, button_3("t", "track", format!("{}", *track_count), *is_editing)) - .right(*width_side, button_2("T", "add track", *is_editing)) - .middle(*width_mid, per_track(*width_mid, ||self.tracks_with_sizes_scrolled(), - |index, track|wrap( - if *track_selected == Some(index) { - track.color.light - } else { - track.color.base - }.rgb, - track.color.lightest.rgb, - Tui::bold(true, Fill::xy(Align::nw(&track.name))) - ))) - } - fn input_routes (&'a self) -> impl Content + 'a { Tryptich::top(self.inputs_height) .left(self.width_side, @@ -421,6 +364,14 @@ impl<'a> ArrangerView<'a> { |_, _|Tui::bg(Reset, Align::c(Bsp::s(OctaveVertical::default(), " ------ "))))) } + /// Render output matrix. + pub(crate) fn outputs (&'a self) -> impl Content + 'a { + Tui::bg(Color::Reset, Align::n(Bsp::s( + Bsp::s(self.output_nexts(), self.output_froms()), + Bsp::s(self.output_ports(), self.output_conns()), + ))) + } + fn output_nexts (&'a self) -> impl Content + 'a { Tryptich::top(2) .left(self.width_side, Align::ne("From clip:")) @@ -458,35 +409,58 @@ impl<'a> ArrangerView<'a> { .right(self.width_side, button_2("O", "add midi out", self.is_editing)) .middle(self.width_mid, - per_track_top(self.width_mid, ||self.tracks_with_sizes_scrolled(), move|i, t|{ - let mute = false; - let solo = false; - let mute = if mute { White } else { t.color.darkest.rgb }; - let solo = if solo { White } else { t.color.darkest.rgb }; - let bg_1 = if self.track_selected == Some(i) { - t.color.light.rgb - } else { - t.color.base.rgb - }; - let bg_2 = if i > 0 { t.color.base.rgb } else { Reset }; - let mute = Tui::fg_bg(mute, bg_1, "Play "); - let solo = Tui::fg_bg(solo, bg_1, "Solo "); - wrap(bg_1, Tui::g(224), Tui::bold(true, Fill::x(Bsp::e(mute, solo)))) - })) + per_track_top( + self.width_mid, + ||self.tracks_with_sizes_scrolled(), + move|i, t|{ + let mute = false; + let solo = false; + let mute = if mute { White } else { t.color.darkest.rgb }; + let solo = if solo { White } else { t.color.darkest.rgb }; + let bg_1 = if self.track_selected == Some(i) { + t.color.light.rgb + } else { + t.color.base.rgb + }; + let bg_2 = if i > 0 { t.color.base.rgb } else { Reset }; + let mute = Tui::fg_bg(mute, bg_1, "Play "); + let solo = Tui::fg_bg(solo, bg_1, "Solo "); + wrap(bg_1, Tui::g(224), Tui::bold(true, Fill::x(Bsp::e(mute, solo)))) + })) } fn output_conns (&'a self) -> impl Content + 'a { Tryptich::top(self.outputs_height) .left(self.width_side, io_ports(Tui::g(224), Tui::g(32), ||self.app.outputs_with_sizes())) - .middle(self.width_mid, - per_track_top(self.width_mid, ||self.tracks_with_sizes_scrolled(), |_, t|io_conns( + .middle(self.width_mid, per_track_top( + self.width_mid, + ||self.tracks_with_sizes_scrolled(), + |_, t|io_conns( t.color.dark.rgb, t.color.darker.rgb, ||self.app.outputs_with_sizes() ))) } + /// Render track headers + pub(crate) fn tracks (&'a self) -> impl Content + 'a { + let Self { width_side, width_mid, track_count, track_selected, is_editing, .. } = self; + Tryptich::center(3) + .left(*width_side, button_3("t", "track", format!("{}", *track_count), *is_editing)) + .right(*width_side, button_2("T", "add track", *is_editing)) + .middle(*width_mid, per_track(*width_mid, ||self.tracks_with_sizes_scrolled(), + |index, track|wrap( + if *track_selected == Some(index) { + track.color.light + } else { + track.color.base + }.rgb, + track.color.lightest.rgb, + Tui::bold(true, Fill::x(Align::nw(&track.name))) + ))) + } + /// Render scenes with clips pub(crate) fn scenes (&'a self) -> impl Content + 'a { @@ -715,14 +689,17 @@ pub(crate) fn view_meters (values: &[f32;2]) -> impl Content + use<'_> { } pub(crate) fn wrap (bg: Color, fg: Color, content: impl Content) -> impl Content { - let left = Tui::fg_bg(bg, Reset, Fixed::x(1, RepeatV("▐"))); - let right = Tui::fg_bg(bg, Reset, Fixed::x(1, RepeatV("▌"))); + let left = Tui::fg_bg(bg, Reset, "▐"); + let right = Tui::fg_bg(bg, Reset, "▌"); Bsp::e(left, Bsp::w(right, Tui::fg_bg(fg, bg, content))) } -pub(crate) fn button_2 <'a> ( - key: impl Content + 'a, label: impl Content + 'a, editing: bool, -) -> impl Content + 'a { +pub(crate) fn button_2 <'a, K, L> ( + key: K, label: L, editing: bool, +) -> impl Content + 'a where + K: Content + 'a, + L: Content + 'a, +{ let key = Tui::fg_bg(Tui::g(0), Tui::orange(), Bsp::e( Tui::fg_bg(Tui::orange(), Reset, "▐"), Bsp::e(key, Tui::fg(Tui::g(96), "▐")) @@ -950,7 +927,7 @@ content!(TuiOut: |self: PoolView<'a>| { let border = |x|x;//Outer(Style::default().fg(color.dark.rgb).bg(color.darkest.rgb)).enclose(x); let iter = | |model.clips().clone().into_iter(); let height = clips.read().unwrap().len() as u16; - Tui::bg(Reset, Fixed::y(height, on_bg(border(Map::new(iter, move|clip: Arc>, i|{ + Tui::bg(Color::Reset, Fixed::y(height, on_bg(border(Map::new(iter, move|clip: Arc>, i|{ let item_height = 1; let item_offset = i as u16 * item_height; let selected = i == model.clip_index(); @@ -969,15 +946,18 @@ content!(TuiOut: |self: PoolView<'a>| { }); content!(TuiOut: |self: ClipLength| { - use ClipLengthFocus::*; let bars = ||self.bars_string(); let beats = ||self.beats_string(); let ticks = ||self.ticks_string(); match self.focus { - None => row!(" ", bars(), ".", beats(), ".", ticks()), - Some(Bar) => row!("[", bars(), "]", beats(), ".", ticks()), - Some(Beat) => row!(" ", bars(), "[", beats(), "]", ticks()), - Some(Tick) => row!(" ", bars(), ".", beats(), "[", ticks()), + None => + row!(" ", bars(), ".", beats(), ".", ticks()), + Some(ClipLengthFocus::Bar) => + row!("[", bars(), "]", beats(), ".", ticks()), + Some(ClipLengthFocus::Beat) => + row!(" ", bars(), "[", beats(), "]", ticks()), + Some(ClipLengthFocus::Tick) => + row!(" ", bars(), ".", beats(), "[", ticks()), } }); @@ -1019,9 +999,7 @@ impl PianoHorizontal { } } -pub(crate) fn note_y_iter (note_lo: usize, note_hi: usize, y0: u16) - -> impl Iterator -{ +pub(crate) fn note_y_iter (note_lo: usize, note_hi: usize, y0: u16) -> impl Iterator { (note_lo..=note_hi).rev().enumerate().map(move|(y, n)|(y, y0 + y as u16, n)) } @@ -1292,8 +1270,18 @@ impl std::fmt::Debug for PianoHorizontal { fn to_key (note: usize) -> &'static str { match note % 12 { - 11 | 9 | 7 | 5 | 4 | 2 | 0 => "████▌", - 10 | 8 | 6 | 3 | 1 => " ", + 11 => "████▌", + 10 => " ", + 9 => "████▌", + 8 => " ", + 7 => "████▌", + 6 => " ", + 5 => "████▌", + 4 => "████▌", + 3 => " ", + 2 => "████▌", + 1 => " ", + 0 => "████▌", _ => unreachable!(), } }