From 83eb9dd2fa1323d8871801e27ea7eee3a4923190 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Tue, 31 Dec 2024 04:37:45 +0100 Subject: [PATCH] update layout macro invocations --- layout/src/collection.rs | 35 +++++++++++------- src/arranger.rs | 8 ++-- src/arranger/arranger_v.rs | 13 ++++--- src/arranger/arranger_v/v_clips.rs | 8 ++-- src/arranger/arranger_v/v_head.rs | 40 ++++++++++---------- src/border.rs | 5 +-- src/groovebox.rs | 44 +++++++++------------- src/meter.rs | 4 +- src/mixer.rs | 9 ++--- src/piano_h.rs | 6 +-- src/plugin.rs | 13 ++----- src/pool.rs | 4 +- src/pool/phrase_selector.rs | 8 ++-- src/sampler/sample_import.rs | 4 -- src/sampler/sampler_tui.rs | 4 +- src/sequencer.rs | 14 +++---- src/status.rs | 59 ++++++++++++++---------------- src/style.rs | 8 ++-- src/transport.rs | 36 +++++++++--------- 19 files changed, 153 insertions(+), 169 deletions(-) diff --git a/layout/src/collection.rs b/layout/src/collection.rs index 317e7c46..9e90fd3e 100644 --- a/layout/src/collection.rs +++ b/layout/src/collection.rs @@ -5,6 +5,8 @@ mod stack; pub use self::stack::*; use crate::*; +use std::sync::RwLock; + /// Conditional rendering, in unary and binary forms. pub struct Cond; @@ -17,8 +19,14 @@ impl Cond { pub fn either , B: Content> (cond: bool, a: A, b: B) -> Either { Either(cond, a, b, Default::default()) } + + pub fn opt R, R: Content> (option: Option, cb: F) -> Opt { + Opt(option, cb, Default::default()) + } } +pub struct OptR, R: Content>(Option, F, PhantomData); + /// Contents `self.1` when `self.0` is true. pub struct When(bool, A, PhantomData); @@ -62,7 +70,6 @@ pub trait Collector: Send + Sync + Fn(&mut dyn FnMut(&dyn Content) impl Collector for F where E: Engine, F: Send + Sync + Fn(&mut dyn FnMut(&dyn Content)) {} -/* /// Rendering of iterable collections, one-to-one and many-to one. pub struct Coll; @@ -73,24 +80,25 @@ impl Coll { R: Content, F: Fn(T, usize)->R + Send + Sync { - Map(Default::default(), iterator, callback) - } - pub fn reduce (iterator: I, callback: F) -> Reduce where - E: Engine, - I: Iterator + Send + Sync, - R: Content, - F: Fn(R, T, usize) -> R + Send + Sync - { - Reduce(Default::default(), iterator, callback) + Map(Default::default(), RwLock::new(iterator), callback) } + //pub fn reduce (iterator: I, callback: F) -> Reduce where + //E: Engine, + //I: Iterator + Send + Sync, + //R: Content, + //F: Fn(R, T, usize) -> R + Send + Sync + //{ + //Reduce(Default::default(), iterator, callback) + //} } -pub struct Map<'a, E, T, I, R, F>(PhantomData, &'a mut I, F) where +pub struct Map(PhantomData, RwLock, F) where E: Engine, I: Iterator + Send + Sync, R: Content, F: Fn(T, usize)->R + Send + Sync; -impl<'a, E, T, I, R, F> Content for Map<'a, E, T, I, R, F> where + +impl Content for Map where E: Engine, I: Iterator + Send + Sync, R: Content, @@ -98,13 +106,14 @@ impl<'a, E, T, I, R, F> Content for Map<'a, E, T, I, R, F> where { fn render (&self, to: &mut E::Output) { let mut index = 0; - for item in self.1 { + for item in &mut*self.1.write().unwrap() { (self.2)(item, index).render(to); index += 1; } } } +/* pub struct Reduce(PhantomData<(E, R)>, I, F) where E: Engine, I: Iterator + Send + Sync, diff --git a/src/arranger.rs b/src/arranger.rs index 5c3c5454..8b0af52d 100644 --- a/src/arranger.rs +++ b/src/arranger.rs @@ -102,23 +102,23 @@ impl ArrangerTui { render!(Tui: (self: ArrangerTui) => { let play = PlayPause(self.clock.is_rolling()); let transport = TransportView::new(self, Some(ItemPalette::from(TuiTheme::g(96))), true); - let with_transport = |x|col!([row!(![&play, &transport]), &x]); + let with_transport = |x|col!(row!(&play, &transport), &x); let pool_size = if self.phrases.visible { self.splits[1] } else { 0 }; let with_pool = |x|Split::w(false, pool_size, PoolView(&self.phrases), x); let status = ArrangerStatus::from(self); let with_editbar = |x|Split::n(false, 1, MidiEditStatus(&self.editor), x); let with_status = |x|Split::n(false, 2, status, x); - let with_size = |x|lay!([&self.size, x]); + let with_size = |x|lay!(&self.size, x); let arranger = ||lay!(|add|{ let color = self.color; add(&Fill::xy(Tui::bg(color.darkest.rgb, "")))?; add(&Fill::xy(Outer(Style::default().fg(color.dark.rgb).bg(color.darkest.rgb))))?; add(&Self::render_mode(self)) }); - with_size(with_status(with_editbar(with_pool(with_transport(col!([ + with_size(with_status(with_editbar(with_pool(with_transport(col!( Fill::x(Fixed::y(20, arranger())), Fill::xy(&self.editor), - ])))))) + )))))) }); audio!(|self: ArrangerTui, client, scope|{ // Start profiling cycle diff --git a/src/arranger/arranger_v.rs b/src/arranger/arranger_v.rs index ff2a774e..810b009d 100644 --- a/src/arranger/arranger_v.rs +++ b/src/arranger/arranger_v.rs @@ -4,20 +4,21 @@ mod v_cursor; pub(crate) use self::v_cursor::*; mod v_head; pub(crate) use self::v_head::*; mod v_io; pub(crate) use self::v_io::*; mod v_sep; pub(crate) use self::v_sep::*; +// egyptian snakes den const HEADER_H: u16 = 5; const SCENES_W_OFFSET: u16 = 3; impl ArrangerTui { - pub fn render_mode_v (state: &ArrangerTui, factor: usize) -> impl Render + use<'_> { - lay!([ + pub fn render_mode_v (state: &ArrangerTui, factor: usize) -> impl Content + use<'_> { + lay!( ArrangerVColSep::from(state), ArrangerVRowSep::from((state, factor)), - col!([ + col!( ArrangerVHead::from(state), ArrangerVIns::from(state), - ArrangerVClips::from((state, factor)), + ArrangerVClips::new(state, factor), ArrangerVOuts::from(state), - ]), + ), ArrangerVCursor::from((state, factor)), - ]) + ) } } diff --git a/src/arranger/arranger_v/v_clips.rs b/src/arranger/arranger_v/v_clips.rs index 1f72f13c..686a4563 100644 --- a/src/arranger/arranger_v/v_clips.rs +++ b/src/arranger/arranger_v/v_clips.rs @@ -20,7 +20,8 @@ impl<'a> ArrangerVClips<'a> { impl<'a, E: Engine> Content for ArrangerVClips<'a> { fn content (&self) -> Option> { 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)); + let col = Coll::map(self.scenes.iter().zip(self.rows.iter().map(|row|row.0)), |(scene, pulses), i| + Self::format_scene(self.tracks, scene, pulses)); Some(Fill::xy(col)) } } @@ -36,9 +37,8 @@ impl<'a> ArrangerVClips<'a> { 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_iter!((index, track, x1, x2) in ArrangerTrack::with_widths(tracks) => { - Self::format_clip(scene, index, track, (x2 - x1) as u16, height) - })))} + Coll::map(ArrangerTrack::with_widths(tracks), |(index, track, x1, x2), _| + Push::x(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 diff --git a/src/arranger/arranger_v/v_head.rs b/src/arranger/arranger_v/v_head.rs index 38344ad3..1b773b40 100644 --- a/src/arranger/arranger_v/v_head.rs +++ b/src/arranger/arranger_v/v_head.rs @@ -15,29 +15,27 @@ from!(<'a>|state: &'a ArrangerTui|ArrangerVHead<'a> = Self { // A scenes_w: SCENES_W_OFFSET + ArrangerScene::longest_name(&state.scenes) as u16, }); -impl Content for ArrangerVCursor { - fn content (&self) -> Option> { - - fn row > (color: ItemPalette, field: &T) -> impl Content + use<'_, T> { - row!([Tui::fg(color.light.rgb, "▎"), Tui::fg(color.lightest.rgb, field)]) - } - - 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)), - ])))) - } - ))) +render!(Tui: (self: ArrangerVHead<'a>) => { + fn row > (color: ItemPalette, field: &T) -> impl Content + use<'_, T> { + row!(Tui::fg(color.light.rgb, "▎"), Tui::fg(color.lightest.rgb, field)) } -} + + Some(Push::x(self.scenes_w, + Coll::map(ArrangerTrack::with_widths(self.tracks), |(_, track, x1, x2), i| { + 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 diff --git a/src/border.rs b/src/border.rs index 9433d243..ddcf16e2 100644 --- a/src/border.rs +++ b/src/border.rs @@ -3,7 +3,7 @@ use crate::*; pub struct Bordered>(pub S, pub W); render!(Tui: (self: Bordered>) => { - Fill::xy(lay!([Border(self.0), Padding::xy(1, 1, &self.1)])) + Fill::xy(lay!(Border(self.0), Padding::xy(1, 1, &self.1))) }); pub struct Border(pub S); @@ -130,8 +130,7 @@ macro_rules! border { #[derive(Copy, Clone)] pub struct $T(pub Style); impl Content for $T { - fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> { Ok(Some([0,0])) } - fn render (&self, to: &mut TuiOutput) -> Usually<()> { self.draw(to) } + fn render (&self, to: &mut TuiOutput) { self.draw(to) } } )+} } diff --git a/src/groovebox.rs b/src/groovebox.rs index 55b8d320..bb8806f4 100644 --- a/src/groovebox.rs +++ b/src/groovebox.rs @@ -136,29 +136,29 @@ render!(Tui: (self: Groovebox) => { GrooveboxSamples(self) )), x); let status = EditStatus(&self.sampler, &self.editor, note_pt, pool(sampler(&self.editor))); - Fill::xy(lay!([ + Fill::xy(lay!( &self.size, Fill::xy(Align::s(Fixed::y(2, GrooveboxStatus::from(self)))), - Shrink::y(2, col!(![ + Shrink::y(2, col!( transport, selector, status - ])) - ])) + )) + )) }); struct EditStatus<'a, T: Content>(&'a Sampler, &'a MidiEditor, usize, T); impl<'a, T: Content> Content for EditStatus<'a, T> { fn content (&self) -> Option> { - Some(Split::n(false, 9, col!([ - row!(|add|{ - if let Some(sample) = &self.0.mapped[self.2] { - add(&format!("Sample {}", sample.read().unwrap().end))?; - } - add(&MidiEditStatus(&self.1))?; - Ok(()) - }), - lay!([ + Some(Split::n(false, 9, col!( + row!( + Cond::opt( + &self.0.mapped[self.2], + |sample|format!("Sample {}", sample.read().unwrap().end) + ), + MidiEditStatus(&self.1), + ), + lay!( Outer(Style::default().fg(TuiTheme::g(128))), Fill::x(Fixed::y(8, if let Some((_, sample)) = &self.0.recording { SampleViewer(Some(sample.clone())) @@ -167,16 +167,8 @@ impl<'a, T: Content> Content for EditStatus<'a, T> { } else { SampleViewer(None) })), - ]), - ]), &self.3)) - } -} -impl<'a, T: Content> Content for EditStatus<'a, T> { - fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> { - self.content().unwrap().min_size(to) - } - fn render (&self, to: &mut TuiOutput) -> Usually<()> { - self.content().unwrap().render(to) + ), + ), &self.3)) } } @@ -185,7 +177,7 @@ render!(Tui: (self: GrooveboxSamples<'a>) => { let note_lo = self.0.editor.note_lo().load(Relaxed); let note_pt = self.0.editor.note_point(); let note_hi = self.0.editor.note_hi(); - Fill::xy(col_iter!((note_lo..=note_hi).rev() => |note| { + Fill::xy(Coll::map((note_lo..=note_hi).rev(), |note, i| { let mut bg = if note == note_pt { TuiTheme::g(64) } else { Color::Reset }; let mut fg = TuiTheme::g(160); if let Some((index, _)) = self.0.sampler.recording { @@ -196,11 +188,11 @@ render!(Tui: (self: GrooveboxSamples<'a>) => { } else if self.0.sampler.mapped[note].is_some() { fg = TuiTheme::g(224); } - Tui::bg(bg, if let Some(sample) = &self.0.sampler.mapped[note] { + Push::y(i, Tui::bg(bg, if let Some(sample) = &self.0.sampler.mapped[note] { Tui::fg(fg, format!("{note:3} ?????? ")) } else { Tui::fg(fg, format!("{note:3} (none) ")) - }) + })) })) }); diff --git a/src/meter.rs b/src/meter.rs index 536f38a9..97cb1a21 100644 --- a/src/meter.rs +++ b/src/meter.rs @@ -2,7 +2,7 @@ use crate::*; pub struct Meters<'a>(pub &'a[f32]); -render!(Tui: (self: Meters<'a>) => col!([ +render!(Tui: (self: Meters<'a>) => col!( &format!("L/{:>+9.3}", self.0[0]), &format!("R/{:>+9.3}", self.0[1]), -])); +)); diff --git a/src/mixer.rs b/src/mixer.rs index cc9bad39..fee90830 100644 --- a/src/mixer.rs +++ b/src/mixer.rs @@ -96,10 +96,7 @@ pub struct TrackView<'a> { pub entered: bool, } -impl<'a> Render for TrackView<'a> { - fn min_size (&self, area: [u16;2]) -> Perhaps<[u16;2]> { - todo!() - } +impl<'a> Content for TrackView<'a> { fn render (&self, to: &mut TuiOutput) -> Usually<()> { todo!(); //let mut area = to.area(); @@ -131,7 +128,7 @@ impl<'a> Render for TrackView<'a> { } //impl Content for Mixer { - //fn content (&self) -> impl Render { + //fn content (&self) -> impl Content { //Stack::right(|add| { //for channel in self.tracks.iter() { //add(channel)?; @@ -142,7 +139,7 @@ impl<'a> Render for TrackView<'a> { //} //impl Content for Track { - //fn content (&self) -> impl Render { + //fn content (&self) -> impl Content { //TrackView { //chain: Some(&self), //direction: tek_core::Direction::Right, diff --git a/src/piano_h.rs b/src/piano_h.rs index cd9993fa..a66c375c 100644 --- a/src/piano_h.rs +++ b/src/piano_h.rs @@ -69,7 +69,7 @@ render!(Tui: (self: PianoHorizontal) => { let notes = move||PianoHorizontalNotes(self); let cursor = move||PianoHorizontalCursor(self); let border = Fill::xy(Outer(Style::default().fg(self.color.dark.rgb).bg(self.color.darkest.rgb))); - let with_border = |x|lay!([border, Padding::xy(0, 0, &x)]); + let with_border = |x|lay!(border, Padding::xy(0, 0, &x)); with_border(lay!( Push::x(0, row!( //" ", @@ -84,13 +84,13 @@ render!(Tui: (self: PianoHorizontal) => { )), Bsp::e( Fixed::x(self.keys_width, keys()), - Fill::xy(lay!([ + Fill::xy(lay!( &self.size, Fill::xy(lay!( Fill::xy(notes()), Fill::xy(cursor()), )) - ])), + )), ), ))) )) diff --git a/src/plugin.rs b/src/plugin.rs index c6f8e493..a12ca15f 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -150,11 +150,8 @@ impl Plugin { }) } } -impl Render for Plugin { - fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> { - Ok(Some(to)) - } - fn render (&self, to: &mut TuiOutput) -> Usually<()> { +impl Content for Plugin { + fn render (&self, to: &mut TuiOutput) { let area = to.area(); let [x, y, _, height] = area; let mut width = 20u16; @@ -186,12 +183,11 @@ impl Render for Plugin { }, _ => {} }; - draw_header(self, to, x, y, width)?; - Ok(()) + draw_header(self, to, x, y, width); } } -fn draw_header (state: &Plugin, to: &mut TuiOutput, x: u16, y: u16, w: u16) -> Usually<()> { +fn draw_header (state: &Plugin, to: &mut TuiOutput, x: u16, y: u16, w: u16) { let style = Style::default().gray(); let label1 = format!(" {}", state.name); to.blit(&label1, x + 1, y, Some(style.white().bold())); @@ -199,7 +195,6 @@ fn draw_header (state: &Plugin, to: &mut TuiOutput, x: u16, y: u16, w: u16) -> U let label2 = format!("{}…", &path[..((w as usize - 10).min(path.len()))]); to.blit(&label2, x + 2 + label1.len() as u16, y, Some(style.not_dim())); } - Ok(()) //Ok(Rect { x, y, width: w, height: 1 }) } diff --git a/src/pool.rs b/src/pool.rs index 9c6b6186..40d465c3 100644 --- a/src/pool.rs +++ b/src/pool.rs @@ -223,7 +223,7 @@ render!(Tui: (self: PoolView<'a>) => { length.focus = Some(*focus); } } - add(&Tui::bg(color.base.rgb, Fill::x(col!([ + add(&Tui::bg(color.base.rgb, Fill::x(col!( Fill::x(lay!(|add|{ add(&Fill::x(Align::w(format!(" {i}"))))?; add(&Fill::x(Align::e(Pull::x(1, length.clone())))) @@ -237,7 +237,7 @@ render!(Tui: (self: PoolView<'a>) => { }; row2 }), - ]))))?; + ))))?; if i == self.0.phrase_index() { add(&CORNERS)?; } diff --git a/src/pool/phrase_selector.rs b/src/pool/phrase_selector.rs index 3620186e..1e18c9b2 100644 --- a/src/pool/phrase_selector.rs +++ b/src/pool/phrase_selector.rs @@ -8,13 +8,13 @@ pub struct PhraseSelector { } // TODO: Display phrases always in order of appearance -render!(Tui: (self: PhraseSelector) => Fixed::xy(24, 1, row!([ +render!(Tui: (self: PhraseSelector) => Fixed::xy(24, 1, row!( Tui::fg(self.color.lightest.rgb, Tui::bold(true, &self.title)), - Tui::fg_bg(self.color.lighter.rgb, self.color.base.rgb, row!([ + Tui::fg_bg(self.color.lighter.rgb, self.color.base.rgb, row!( format!("{:8}", &self.name[0..8.min(self.name.len())]), Tui::bg(self.color.dark.rgb, &self.time), - ])), -]))); + )), +))); impl PhraseSelector { diff --git a/src/sampler/sample_import.rs b/src/sampler/sample_import.rs index 167daf80..930f0c65 100644 --- a/src/sampler/sample_import.rs +++ b/src/sampler/sample_import.rs @@ -171,10 +171,6 @@ fn draw_sample ( } impl Content for AddSampleModal { - fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> { - todo!() - //Align::Center(()).layout(to) - } fn render (&self, to: &mut TuiOutput) -> Usually<()> { todo!() //let area = to.area(); diff --git a/src/sampler/sampler_tui.rs b/src/sampler/sampler_tui.rs index ff2d5ed8..187637ff 100644 --- a/src/sampler/sampler_tui.rs +++ b/src/sampler/sampler_tui.rs @@ -50,8 +50,8 @@ render!(Tui: (self: SamplerTui) => { let fg = self.color.base.rgb; let bg = self.color.darkest.rgb; let border = Fill::xy(Outer(Style::default().fg(fg).bg(bg))); - let with_border = |x|lay!([border, Fill::xy(&x)]); - let with_size = |x|lay!([self.size, x]); + let with_border = |x|lay!(border, Fill::xy(&x)); + let with_size = |x|lay!(self.size, x); Tui::bg(bg, Fill::xy(with_border(Bsp::s( Tui::fg(self.color.light.rgb, Tui::bold(true, &"Sampler")), with_size(Shrink::y(1, Bsp::e( diff --git a/src/sequencer.rs b/src/sequencer.rs index a2cfa2a6..e912b0fd 100644 --- a/src/sequencer.rs +++ b/src/sequencer.rs @@ -49,28 +49,28 @@ render!(Tui: (self: SequencerTui) => { let status = SequencerStatus::from(self); let with_status = |x|Split::n(false, if self.status { 2 } else { 0 }, status, x); let with_editbar = |x|Split::n(false, 1, MidiEditStatus(&self.editor), x); - let with_size = |x|lay!([self.size, x]); + let with_size = |x|lay!(self.size, x); let editor = with_editbar(with_pool(Fill::xy(&self.editor))); let color = self.player.play_phrase().as_ref().map(|(_,p)| p.as_ref().map(|p|p.read().unwrap().color) ).flatten().clone(); - let toolbar = Cond::when(self.transport, row!([ + let toolbar = Cond::when(self.transport, row!( PlayPause(self.clock.is_rolling()), TransportView::new(self, color, true), - ])); + )); - let play_queue = Cond::when(self.selectors, row!([ + let play_queue = Cond::when(self.selectors, row!( PhraseSelector::play_phrase(&self.player), PhraseSelector::next_phrase(&self.player), - ])); + )); - Min::y(15, with_size(with_status(col!([ + Min::y(15, with_size(with_status(col!( toolbar, play_queue, editor, - ])))) + )))) }); audio!(|self:SequencerTui, client, scope|{ // Start profiling cycle diff --git a/src/status.rs b/src/status.rs index 10af8984..7a461789 100644 --- a/src/status.rs +++ b/src/status.rs @@ -2,22 +2,19 @@ use crate::*; pub struct MidiEditStatus<'a>(pub &'a MidiEditor); render!(Tui: (self:MidiEditStatus<'a>) => { - let (color, name, length, looped) = if let Some(phrase) = self.0.phrase().as_ref().map(|p|p.read().unwrap()) { (phrase.color, phrase.name.clone(), phrase.length, phrase.looped) } else { (ItemPalette::from(TuiTheme::g(64)), String::new(), 0, false) }; - - let field = move|x, y|row!([ + let field = move|x, y|row!( Tui::fg_bg(color.lighter.rgb, color.darker.rgb, Tui::bold(true, x)), Tui::fg_bg(color.light.rgb, color.darker.rgb, Tui::bold(true, "│")), Tui::fg_bg(color.lightest.rgb, color.dark.rgb, &y), - ]); - + ); let bg = color.darkest.rgb; let fg = color.lightest.rgb; - Tui::bg(bg, Fill::x(Tui::fg(fg, row!([ + Tui::bg(bg, Fill::x(Tui::fg(fg, row!( field(" Time", format!("{}/{}-{} ({}*{}) {}", self.0.time_point(), self.0.time_start().get(), self.0.time_end(), self.0.time_axis().get(), self.0.time_zoom().get(), @@ -27,7 +24,7 @@ render!(Tui: (self:MidiEditStatus<'a>) => { self.0.note_point(), to_note_name(self.0.note_point()), self.0.note_len(), to_note_name(self.0.note_lo().get()), to_note_name(self.0.note_hi()), self.0.note_axis().get())) - ])))) + )))) }); /// Status bar for sequencer app @@ -50,21 +47,21 @@ from!(|state:&SequencerTui|SequencerStatus = { size: format!("{}x{}│", width, state.size.h()), } }); -render!(Tui: (self: SequencerStatus) => Fixed::y(2, lay!([ +render!(Tui: (self: SequencerStatus) => Fixed::y(2, lay!( Self::help(), Fill::xy(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))), -]))); +))); impl SequencerStatus { fn help () -> impl Content { - let single = |binding, command|row!([" ", col!([ + let single = |binding, command|row!(" ", col!( Tui::fg(TuiTheme::yellow(), binding), command - ])]); - let double = |(b1, c1), (b2, c2)|col!([ - row!([" ", Tui::fg(TuiTheme::yellow(), b1), " ", c1,]), - row!([" ", Tui::fg(TuiTheme::yellow(), b2), " ", c2,]), - ]); - Tui::fg_bg(TuiTheme::g(255), TuiTheme::g(50), row!([ + )); + let double = |(b1, c1), (b2, c2)|col!( + row!(" ", Tui::fg(TuiTheme::yellow(), b1), " ", c1,), + row!(" ", Tui::fg(TuiTheme::yellow(), b2), " ", c2,), + ); + Tui::fg_bg(TuiTheme::g(255), TuiTheme::g(50), row!( single("SPACE", "play/pause"), double(("▲▼▶◀", "cursor"), ("Ctrl", "scroll"), ), double(("a", "append"), ("s", "set note"),), @@ -72,10 +69,10 @@ impl SequencerStatus { double(("[]", "phrase"), ("{}", "order"), ), double(("q", "enqueue"), ("e", "edit"), ), double(("c", "color"), ("", ""),), - ])) + )) } fn stats (&self) -> impl Content + use<'_> { - row!([&self.cpu, &self.size]) + row!(&self.cpu, &self.size) } } @@ -99,10 +96,10 @@ from!(|state: &Groovebox|GrooveboxStatus = { size: format!("{}x{}│", width, state.size.h()), } }); -render!(Tui: (self: GrooveboxStatus) => Fixed::y(2, lay!([ +render!(Tui: (self: GrooveboxStatus) => Fixed::y(2, lay!( Self::help(), Fill::xy(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))), -]))); +))); impl GrooveboxStatus { fn help () -> impl Content { let single = |binding, command|row!(" ", col!( @@ -148,21 +145,21 @@ from!(|state:&ArrangerTui|ArrangerStatus = { size: format!("{}x{}│", width, state.size.h()), } }); -render!(Tui: (self: ArrangerStatus) => Fixed::y(2, lay!([ +render!(Tui: (self: ArrangerStatus) => Fixed::y(2, lay!( Self::help(), Fill::xy(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))), -]))); +))); impl ArrangerStatus { fn help () -> impl Content { - let single = |binding, command|row!([" ", col!([ + let single = |binding, command|row!(" ", col!( Tui::fg(TuiTheme::yellow(), binding), command - ])]); - let double = |(b1, c1), (b2, c2)|col!([ - row!([" ", Tui::fg(TuiTheme::yellow(), b1), " ", c1,]), - row!([" ", Tui::fg(TuiTheme::yellow(), b2), " ", c2,]), - ]); - Tui::fg_bg(TuiTheme::g(255), TuiTheme::g(50), row!([ + )); + let double = |(b1, c1), (b2, c2)|col!( + row!(" ", Tui::fg(TuiTheme::yellow(), b1), " ", c1,), + row!(" ", Tui::fg(TuiTheme::yellow(), b2), " ", c2,), + ); + Tui::fg_bg(TuiTheme::g(255), TuiTheme::g(50), row!( single("SPACE", "play/pause"), single(" Ctrl", " scroll"), single(" ▲▼▶◀", " cell"), @@ -172,9 +169,9 @@ impl ArrangerStatus { double(("a", "append"), ("s", "set"),), double((",.", "length"), ("<>", "triplet"),), double(("[]", "phrase"), ("{}", "order"),), - ])) + )) } fn stats (&self) -> impl Content + use<'_> { - row!([&self.cpu, &self.size]) + row!(&self.cpu, &self.size) } } diff --git a/src/style.rs b/src/style.rs index ac5cf80d..941f7feb 100644 --- a/src/style.rs +++ b/src/style.rs @@ -26,7 +26,7 @@ impl> Content for Bold { fn content (&self) -> Option> { Some(&self.1) } - fn render (&self, to: &mut TuiOutput) -> Usually<()> { + fn render (&self, to: &mut TuiOutput) { to.fill_bold(to.area(), self.0); self.1.render(to) } @@ -38,7 +38,7 @@ impl> Content for Foreground { fn content (&self) -> Option> { Some(&self.1) } - fn render (&self, to: &mut TuiOutput) -> Usually<()> { + fn render (&self, to: &mut TuiOutput) { to.fill_fg(to.area(), self.0); self.1.render(to) } @@ -50,7 +50,7 @@ impl> Content for Background { fn content (&self) -> Option> { Some(&self.1) } - fn render (&self, to: &mut TuiOutput) -> Usually<()> { + fn render (&self, to: &mut TuiOutput) { to.fill_bg(to.area(), self.0); self.1.render(to) } @@ -62,7 +62,7 @@ impl Content for Styled<&str> { fn content (&self) -> Option> { Some(&self.1) } - fn render (&self, to: &mut TuiOutput) -> Usually<()> { + fn render (&self, to: &mut TuiOutput) { // FIXME let [x, y, ..] = to.area(); //let [w, h] = self.min_size(to.area().wh())?.unwrap(); diff --git a/src/transport.rs b/src/transport.rs index 6ef99005..6e612a0b 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -23,10 +23,10 @@ from_jack!(|jack|TransportTui Self { has_clock!(|self: TransportTui|&self.clock); audio!(|self: TransportTui, client, scope|ClockAudio(self).process(client, scope)); handle!(|self: TransportTui, from|TransportCommand::execute_with_state(self, from)); -render!(Tui: (self: TransportTui) => Fixed::y(3, row!([ +render!(Tui: (self: TransportTui) => Fixed::y(3, row!( " ", Fixed::x(5, PlayPause(false)), " ", Shrink::x(1, TransportView::new(self, Some(self.color), true)), -]))); +))); impl std::fmt::Debug for TransportTui { fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { f.debug_struct("TransportTui") @@ -89,42 +89,42 @@ impl TransportView { } render!(Tui: (self: TransportView) => { let color = self.color; - Fixed::y(3, Tui::bg(color.base.rgb, Fill::x(row!([ - col!([ + Fixed::y(3, Tui::bg(color.base.rgb, Fill::x(row!( + col!( TransportField(" Beat", self.beat.as_str(), &color), TransportField(" Time", format!("{:.1}s", self.current_second).as_str(), &color), TransportField(" BPM", self.bpm.as_str(), &color), - ]), - col!([ + ), + col!( TransportField(" Rate", format!("{}", self.sr).as_str(), &color), TransportField(" Chunk", format!("{}", self.chunk).as_str(), &color), TransportField(" Lag", format!("{:.3}ms", self.latency).as_str(), &color), - ]), - col!([ + ), + col!( //Field(" CPU%", format!("{:.1}ms", self.perf).as_str(), &color), - ]), - ])))) + ), + )))) }); struct TransportField<'a>(&'a str, &'a str, &'a ItemPalette); -render!(Tui: (self: TransportField<'a>) => row!([ +render!(Tui: (self: TransportField<'a>) => row!( Tui::fg_bg(self.2.lightest.rgb, self.2.base.rgb, Tui::bold(true, self.0)), Tui::fg_bg(self.2.base.rgb, self.2.darkest.rgb, "▌"), Tui::fg_bg(self.2.lightest.rgb, self.2.darkest.rgb, format!("{:>10}", self.1)), Tui::fg_bg(self.2.darkest.rgb, self.2.base.rgb, "▌"), -])); +)); pub struct PlayPause(pub bool); render!(Tui: (self: PlayPause) => Tui::bg( if self.0{Color::Rgb(0,128,0)}else{Color::Rgb(128,64,0)}, Fixed::x(5, col!(|add|if self.0 { - add(&Tui::fg(Color::Rgb(0, 255, 0), col!([ + add(&Tui::fg(Color::Rgb(0, 255, 0), col!( " 🭍🭑🬽 ", " 🭞🭜🭘 ", - ]))) + ))) } else { - add(&Tui::fg(Color::Rgb(255, 128, 0), col!([ + add(&Tui::fg(Color::Rgb(255, 128, 0), col!( " ▗▄▖ ", " ▝▀▘ ", - ]))) + ))) })) )); impl HasFocus for TransportTui { @@ -152,7 +152,7 @@ impl FocusWrap for TransportFocus { let focused = focus == self; let corners = focused.then_some(CORNERS); //let highlight = focused.then_some(Tui::bg(Color::Rgb(60, 70, 50))); - lay!([corners, /*highlight,*/ *content]) + lay!(corners, /*highlight,*/ *content) } } impl FocusWrap for Option { @@ -162,7 +162,7 @@ impl FocusWrap for Option { let focused = Some(focus) == self; let corners = focused.then_some(CORNERS); //let highlight = focused.then_some(Background(Color::Rgb(60, 70, 50))); - lay!([corners, /*highlight,*/ *content]) + lay!(corners, /*highlight,*/ *content) } } pub trait TransportControl: HasClock + {