From 999dc5906e424ed6694e629ffd8fe0e395b76ed4 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sun, 15 Dec 2024 00:39:23 +0100 Subject: [PATCH] remove modality; rename splits --- crates/tek/src/layout/split.rs | 8 +- crates/tek/src/tui/app_sequencer.rs | 122 ++++++++++++++++++++++++- crates/tek/src/tui/piano_horizontal.rs | 2 +- 3 files changed, 125 insertions(+), 7 deletions(-) diff --git a/crates/tek/src/layout/split.rs b/crates/tek/src/layout/split.rs index 6da13980..e4c98785 100644 --- a/crates/tek/src/layout/split.rs +++ b/crates/tek/src/layout/split.rs @@ -8,22 +8,22 @@ pub trait LayoutSplit { ) -> Split { Split::new(flip, direction, amount, a, b) } - fn split_up , B: Render> ( + fn split_n , B: Render> ( flip: bool, amount: E::Unit, a: A, b: B ) -> Split { Self::split(flip, Direction::Up, amount, a, b) } - fn split_down , B: Render> ( + fn split_s , B: Render> ( flip: bool, amount: E::Unit, a: A, b: B ) -> Split { Self::split(flip, Direction::Down, amount, a, b) } - fn split_left , B: Render> ( + fn split_w , B: Render> ( flip: bool, amount: E::Unit, a: A, b: B ) -> Split { Self::split(flip, Direction::Left, amount, a, b) } - fn split_right , B: Render> ( + fn split_e , B: Render> ( flip: bool, amount: E::Unit, a: A, b: B ) -> Split { Self::split(flip, Direction::Right, amount, a, b) diff --git a/crates/tek/src/tui/app_sequencer.rs b/crates/tek/src/tui/app_sequencer.rs index 2197f104..c4a881b1 100644 --- a/crates/tek/src/tui/app_sequencer.rs +++ b/crates/tek/src/tui/app_sequencer.rs @@ -173,12 +173,12 @@ audio!(|self:SequencerTui,client,scope|{ Control::Continue }); -render!(|self: SequencerTui|lay!([self.size, Tui::split_up(false, 3, +render!(|self: SequencerTui|lay!([self.size, Tui::split_n(false, 3, Tui::fill_xy(col!([ PhraseEditStatus(&self.editor), SequencerStatusBar::from(self) ])), - Tui::split_right(false, if self.size.w() > 60 { + Tui::split_e(false, if self.size.w() > 60 { 20 } else if self.size.w() > 40 { 15 @@ -322,3 +322,121 @@ impl Handle for SequencerTui { SequencerCommand::execute_with_state(self, i) } } + +/// Status bar for sequencer app +#[derive(Clone)] +pub struct SequencerStatusBar { + pub(crate) width: usize, + pub(crate) cpu: Option, + pub(crate) size: String, + pub(crate) res: String, + pub(crate) mode: &'static str, + pub(crate) help: &'static [(&'static str, &'static str, &'static str)] +} + +impl StatusBar for SequencerStatusBar { + type State = SequencerTui; + fn hotkey_fg () -> Color { + TuiTheme::HOTKEY_FG + } + fn update (&mut self, _: &SequencerTui) { + todo!() + } +} + +impl From<&SequencerTui> for SequencerStatusBar { + fn from (state: &SequencerTui) -> Self { + let samples = state.clock.chunk.load(Ordering::Relaxed); + let rate = state.clock.timebase.sr.get() as f64; + let buffer = samples as f64 / rate; + let width = state.size.w(); + Self { + width, + cpu: state.perf.percentage().map(|cpu|format!("│{cpu:.01}%")), + size: format!("{}x{}│", width, state.size.h()), + res: format!("│{}s│{:.1}kHz│{:.1}ms│", samples, rate / 1000., buffer * 1000.), + mode: " SEQUENCER ", + help: &[ + ("", "SPACE", " play/pause"), + ("", "✣", " cursor"), + ("", "Ctrl-✣", " scroll"), + ("", ".,", " length"), + ("", "><", " triplet"), + ("", "[]", " phrase"), + ("", "{}", " order"), + ("en", "q", "ueue"), + ("", "e", "dit"), + ("", "a", "dd note"), + ("", "A", "dd phrase"), + ("", "D", "uplicate phrase"), + ] + } + } +} + +render!(|self: SequencerStatusBar|{ + lay!(|add|if self.width > 40 { + add(&Tui::fill_x(Tui::fixed_y(1, lay!([ + Tui::fill_x(Tui::at_w(SequencerModeline::from(self))), + Tui::fill_x(Tui::at_e(SequencerStats::from(self))), + ])))) + } else { + add(&Tui::fill_x(Tui::fixed_y(2, col!(![ + Tui::fill_x(Tui::center_x(SequencerModeline::from(self))), + Tui::fill_x(Tui::center_x(SequencerStats::from(self))), + ])))) + }) +}); + +struct SequencerModeline { + mode: &'static str, + help: &'static [(&'static str, &'static str, &'static str)] +} +impl From<&SequencerStatusBar> for SequencerModeline { + fn from (state: &SequencerStatusBar) -> Self { + Self { + mode: state.mode, + help: state.help, + } + } +} +render!(|self: SequencerModeline|{ + let black = TuiTheme::g(0); + let light = TuiTheme::g(50); + let white = TuiTheme::g(255); + let orange = TuiTheme::orange(); + let yellow = TuiTheme::yellow(); + row!([ + //Tui::bg(orange, Tui::fg(black, Tui::bold(true, self.mode))), + Tui::bg(light, Tui::fg(white, row!((prefix, hotkey, suffix) in self.help.iter() => { + row!([" ", prefix, Tui::fg(yellow, *hotkey), suffix]) + }))) + ]) +}); + +struct SequencerStats<'a> { + cpu: &'a Option, + size: &'a String, + res: &'a String, +} +impl<'a> From<&'a SequencerStatusBar> for SequencerStats<'a> { + fn from (state: &'a SequencerStatusBar) -> Self { + Self { + cpu: &state.cpu, + size: &state.size, + res: &state.res, + } + } +} +render!(|self:SequencerStats<'a>|{ + let orange = TuiTheme::orange(); + let dark = TuiTheme::g(25); + let cpu = &self.cpu; + let res = &self.res; + let size = &self.size; + Tui::bg(dark, row!([ + Tui::fg(orange, cpu), + Tui::fg(orange, res), + Tui::fg(orange, size), + ])) +}); diff --git a/crates/tek/src/tui/piano_horizontal.rs b/crates/tek/src/tui/piano_horizontal.rs index 38516249..891d5c7e 100644 --- a/crates/tek/src/tui/piano_horizontal.rs +++ b/crates/tek/src/tui/piano_horizontal.rs @@ -48,7 +48,7 @@ render!(|self: PianoHorizontal|{ let time_point = self.point.time_point(); let note_point = self.point.note_point(); let note_len = self.point.note_len(); - Tui::bg(bg, Tui::split_down(false, 1, + Tui::bg(bg, Tui::split_s(false, 1, Tui::debug(Tui::fill_x(Tui::push_x(5, Tui::bg(fg.darkest.rgb, Tui::fg(fg.lightest.rgb, PianoHorizontalTimeline { time_start,