From 32c9654a0c07d8b5535ad2cea04f6ac8ba8e75d0 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Mon, 23 Dec 2024 22:03:34 +0100 Subject: [PATCH] add arranger help; don't rollover, just stup --- .scratch.rs | 122 ++++++++++++++++ crates/tek/src/tui/app_arranger.rs | 2 +- crates/tek/src/tui/arranger_clip.rs | 4 +- crates/tek/src/tui/arranger_mode_v.rs | 2 +- crates/tek/src/tui/arranger_scene.rs | 2 +- crates/tek/src/tui/arranger_track.rs | 2 +- crates/tek/src/tui/status_bar.rs | 202 ++++++++------------------ 7 files changed, 192 insertions(+), 144 deletions(-) create mode 100644 .scratch.rs diff --git a/.scratch.rs b/.scratch.rs new file mode 100644 index 00000000..f7c9cee7 --- /dev/null +++ b/.scratch.rs @@ -0,0 +1,122 @@ +//impl Bar for ArrangerStatus { + //type State = (ArrangerFocus, ArrangerSelection, bool); + //fn hotkey_fg () -> Color where Self: Sized { + //TuiTheme::HOTKEY_FG + //} + //fn update (&mut self, (focused, selected, entered): &Self::State) { + //*self = match focused { + ////ArrangerFocus::Menu => { todo!() }, + //ArrangerFocus::Transport(_) => ArrangerStatus::Transport, + //ArrangerFocus::Arranger => match selected { + //ArrangerSelection::Mix => ArrangerStatus::ArrangerMix, + //ArrangerSelection::Track(_) => ArrangerStatus::ArrangerTrack, + //ArrangerSelection::Scene(_) => ArrangerStatus::ArrangerScene, + //ArrangerSelection::Clip(_, _) => ArrangerStatus::ArrangerClip, + //}, + //ArrangerFocus::Phrases => ArrangerStatus::PhrasePool, + //ArrangerFocus::PhraseEditor => match entered { + //true => ArrangerStatus::PhraseEdit, + //false => ArrangerStatus::PhraseView, + //}, + //} + //} +//} + +//render!(|self: ArrangerStatus|{ + + //let label = match self { + //Self::Transport => "TRANSPORT", + //Self::ArrangerMix => "PROJECT", + //Self::ArrangerTrack => "TRACK", + //Self::ArrangerScene => "SCENE", + //Self::ArrangerClip => "CLIP", + //Self::PhrasePool => "SEQ LIST", + //Self::PhraseView => "VIEW SEQ", + //Self::PhraseEdit => "EDIT SEQ", + //}; + + //let status_bar_bg = TuiTheme::status_bar_bg(); + + //let mode_bg = TuiTheme::mode_bg(); + //let mode_fg = TuiTheme::mode_fg(); + //let mode = Tui::fg(mode_fg, Tui::bg(mode_bg, Tui::bold(true, format!(" {label} ")))); + + //let commands = match self { + //Self::ArrangerMix => Self::command(&[ + //["", "c", "olor"], + //["", "<>", "resize"], + //["", "+-", "zoom"], + //["", "n", "ame/number"], + //["", "Enter", " stop all"], + //]), + //Self::ArrangerClip => Self::command(&[ + //["", "g", "et"], + //["", "s", "et"], + //["", "a", "dd"], + //["", "i", "ns"], + //["", "d", "up"], + //["", "e", "dit"], + //["", "c", "olor"], + //["re", "n", "ame"], + //["", ",.", "select"], + //["", "Enter", " launch"], + //]), + //Self::ArrangerTrack => Self::command(&[ + //["re", "n", "ame"], + //["", ",.", "resize"], + //["", "<>", "move"], + //["", "i", "nput"], + //["", "o", "utput"], + //["", "m", "ute"], + //["", "s", "olo"], + //["", "Del", "ete"], + //["", "Enter", " stop"], + //]), + //Self::ArrangerScene => Self::command(&[ + //["re", "n", "ame"], + //["", "Del", "ete"], + //["", "Enter", " launch"], + //]), + //Self::PhrasePool => Self::command(&[ + //["", "a", "ppend"], + //["", "i", "nsert"], + //["", "d", "uplicate"], + //["", "Del", "ete"], + //["", "c", "olor"], + //["re", "n", "ame"], + //["leng", "t", "h"], + //["", ",.", "move"], + //["", "+-", "resize view"], + //]), + //Self::PhraseView => Self::command(&[ + //["", "enter", " edit"], + //["", "arrows/pgup/pgdn", " scroll"], + //["", "+=", "zoom"], + //]), + //Self::PhraseEdit => Self::command(&[ + //["", "esc", " exit"], + //["", "a", "ppend"], + //["", "s", "et"], + //["", "][", "length"], + //["", "+-", "zoom"], + //]), + //_ => Self::command(&[]) + //}; + + ////let commands = commands.iter().reduce(String::new(), |s, (a, b, c)| format!("{s} {a}{b}{c}")); + //Tui::bg(status_bar_bg, Fill::w(row!([mode, commands]))) + +//}); + +///// Status bar for arranger app +//#[derive(Copy, Clone, Debug)] +//pub enum ArrangerStatus { + //Transport, + //ArrangerMix, + //ArrangerTrack, + //ArrangerScene, + //ArrangerClip, + //PhrasePool, + //PhraseView, + //PhraseEdit, +//} diff --git a/crates/tek/src/tui/app_arranger.rs b/crates/tek/src/tui/app_arranger.rs index 5dfb11e7..61d86e7b 100644 --- a/crates/tek/src/tui/app_arranger.rs +++ b/crates/tek/src/tui/app_arranger.rs @@ -108,7 +108,7 @@ render!(|self: ArrangerTui|{ let with_transport = |x|col!([row!(![&play, &transport]), &x]); let pool_size = if self.show_pool { self.splits[1] } else { 0 }; let with_pool = |x|Split::left(false, pool_size, PhraseListView(&self.phrases), x); - let status = SequencerStatus::from(self); + let status = ArrangerStatus::from(self); let with_editbar = |x|Tui::split_n(false, 3, PhraseEditStatus(&self.editor), x); let with_status = |x|Tui::split_n(false, 2, status, x); let with_size = |x|lay!([&self.size, x]); diff --git a/crates/tek/src/tui/arranger_clip.rs b/crates/tek/src/tui/arranger_clip.rs index 47338b47..b4685fb4 100644 --- a/crates/tek/src/tui/arranger_clip.rs +++ b/crates/tek/src/tui/arranger_clip.rs @@ -7,9 +7,9 @@ pub fn to_arranger_clip_command (input: &TuiInput, t: usize, len_t: usize, s: us use ArrangerClipCommand as Clip; Some(match input.event() { key_pat!(Char('w')) => Cmd::Select(if s > 0 { Select::Clip(t, s - 1) } else { Select::Track(t) }), - key_pat!(Char('s')) => Cmd::Select(Select::Clip(t, (s + 1) % len_s)), + key_pat!(Char('s')) => Cmd::Select(Select::Clip(t, (s + 1).min(len_s.saturating_sub(1)))), key_pat!(Char('a')) => Cmd::Select(if t > 0 { Select::Clip(t - 1, s) } else { Select::Scene(s) }), - key_pat!(Char('d')) => Cmd::Select(Select::Clip((t + 1) % len_t, s)), + key_pat!(Char('d')) => Cmd::Select(Select::Clip((t + 1).min(len_t.saturating_sub(1)), s)), key_pat!(Char(',')) => Cmd::Clip(Clip::Set(t, s, None)), key_pat!(Char('.')) => Cmd::Clip(Clip::Set(t, s, None)), key_pat!(Char('<')) => Cmd::Clip(Clip::Set(t, s, None)), diff --git a/crates/tek/src/tui/arranger_mode_v.rs b/crates/tek/src/tui/arranger_mode_v.rs index 9616fbd4..1bc58ecf 100644 --- a/crates/tek/src/tui/arranger_mode_v.rs +++ b/crates/tek/src/tui/arranger_mode_v.rs @@ -139,7 +139,7 @@ from!(|args:(&ArrangerTui, usize)|ArrangerVCursor = Self { scenes_w: SCENES_W_OFFSET + ArrangerScene::longest_name(args.0.scenes()) as u16, color: args.0.color, reticle: Reticle(Style { - fg: Some(args.0.color.lightest.rgb), + fg: Some(args.0.color.lighter.rgb), bg: None, underline_color: None, add_modifier: Modifier::empty(), diff --git a/crates/tek/src/tui/arranger_scene.rs b/crates/tek/src/tui/arranger_scene.rs index 8ad8a9bf..f8a4f3e7 100644 --- a/crates/tek/src/tui/arranger_scene.rs +++ b/crates/tek/src/tui/arranger_scene.rs @@ -80,7 +80,7 @@ pub fn to_arranger_scene_command (input: &TuiInput, s: usize, len: usize) -> Opt use ArrangerSceneCommand as Scene; Some(match input.event() { key_pat!(Char('w')) => Cmd::Select(if s > 0 { Select::Scene(s - 1) } else { Select::Mix }), - key_pat!(Char('s')) => Cmd::Select(Select::Scene((s + 1) % len)), + key_pat!(Char('s')) => Cmd::Select(Select::Scene((s + 1).min(len.saturating_sub(1)))), key_pat!(Char('d')) => Cmd::Select(Select::Clip(0, s)), key_pat!(Char(',')) => Cmd::Scene(Scene::Swap(s, s - 1)), key_pat!(Char('.')) => Cmd::Scene(Scene::Swap(s, s + 1)), diff --git a/crates/tek/src/tui/arranger_track.rs b/crates/tek/src/tui/arranger_track.rs index 8ce4f536..bc81c239 100644 --- a/crates/tek/src/tui/arranger_track.rs +++ b/crates/tek/src/tui/arranger_track.rs @@ -139,7 +139,7 @@ pub fn to_arranger_track_command (input: &TuiInput, t: usize, len: usize) -> Opt Some(match input.event() { key_pat!(Char('s')) => Select(Selected::Clip(t, 0)), key_pat!(Char('a')) => Select(if t > 0 { Selected::Track(t - 1) } else { Selected::Mix }), - key_pat!(Char('d')) => Select(Selected::Track((t + 1) % len)), + key_pat!(Char('d')) => Select(Selected::Track((t + 1).min(len.saturating_sub(1)))), key_pat!(Char('c')) => Track(Tracks::SetColor(t, ItemPalette::random())), key_pat!(Char(',')) => Track(Tracks::Swap(t, t - 1)), key_pat!(Char('.')) => Track(Tracks::Swap(t, t + 1)), diff --git a/crates/tek/src/tui/status_bar.rs b/crates/tek/src/tui/status_bar.rs index 2a85ce5d..903252c2 100644 --- a/crates/tek/src/tui/status_bar.rs +++ b/crates/tek/src/tui/status_bar.rs @@ -44,19 +44,6 @@ from!(|state:&SequencerTui|SequencerStatus = { res: format!("│{}s│{:.1}kHz│{:.1}ms│", samples, rate / 1000., buffer * 1000.), } }); -from!(|state:&ArrangerTui|SequencerStatus = { - let samples = state.clock.chunk.load(Relaxed); - let rate = state.clock.timebase.sr.get() as f64; - let buffer = samples as f64 / rate; - let width = state.size.w(); - Self { - width, - playing: state.clock.is_rolling(), - 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.), - } -}); render!(|self: SequencerStatus|Fixed::h(2, lay!([ Self::help(), Fill::wh(Align::se({Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats())})), @@ -73,11 +60,12 @@ impl SequencerStatus { ]); Tui::fg_bg(TuiTheme::g(255), TuiTheme::g(50), row!([ single("SPACE", "play/pause"), - double((" ✣", "cursor"), ("C-✣", "scroll"), ), - double(("a", "append"), ("s", "set note"),), - double((",.", "note"), ("<>", "triplet"), ), - double(("[]", "phrase"), ("{}", "order"), ), - double(("q", "enqueue"), ("e", "edit"), ), + double(("▲▼▶◀", "cursor"), ("C-✣", "scroll"), ), + double(("a", "append"), ("s", "set note"),), + double((",.", "length"), ("<>", "triplet"), ), + double(("[]", "phrase"), ("{}", "order"), ), + double(("q", "enqueue"), ("e", "edit"), ), + double(("c", "color"), ("", ""),), ])) } fn stats <'a> (&'a self) -> impl Render + use<'a> { @@ -94,125 +82,63 @@ impl Bar for SequencerStatus { } } -//impl Bar for ArrangerStatus { - //type State = (ArrangerFocus, ArrangerSelection, bool); - //fn hotkey_fg () -> Color where Self: Sized { - //TuiTheme::HOTKEY_FG - //} - //fn update (&mut self, (focused, selected, entered): &Self::State) { - //*self = match focused { - ////ArrangerFocus::Menu => { todo!() }, - //ArrangerFocus::Transport(_) => ArrangerStatus::Transport, - //ArrangerFocus::Arranger => match selected { - //ArrangerSelection::Mix => ArrangerStatus::ArrangerMix, - //ArrangerSelection::Track(_) => ArrangerStatus::ArrangerTrack, - //ArrangerSelection::Scene(_) => ArrangerStatus::ArrangerScene, - //ArrangerSelection::Clip(_, _) => ArrangerStatus::ArrangerClip, - //}, - //ArrangerFocus::Phrases => ArrangerStatus::PhrasePool, - //ArrangerFocus::PhraseEditor => match entered { - //true => ArrangerStatus::PhraseEdit, - //false => ArrangerStatus::PhraseView, - //}, - //} - //} -//} - -//render!(|self: ArrangerStatus|{ - - //let label = match self { - //Self::Transport => "TRANSPORT", - //Self::ArrangerMix => "PROJECT", - //Self::ArrangerTrack => "TRACK", - //Self::ArrangerScene => "SCENE", - //Self::ArrangerClip => "CLIP", - //Self::PhrasePool => "SEQ LIST", - //Self::PhraseView => "VIEW SEQ", - //Self::PhraseEdit => "EDIT SEQ", - //}; - - //let status_bar_bg = TuiTheme::status_bar_bg(); - - //let mode_bg = TuiTheme::mode_bg(); - //let mode_fg = TuiTheme::mode_fg(); - //let mode = Tui::fg(mode_fg, Tui::bg(mode_bg, Tui::bold(true, format!(" {label} ")))); - - //let commands = match self { - //Self::ArrangerMix => Self::command(&[ - //["", "c", "olor"], - //["", "<>", "resize"], - //["", "+-", "zoom"], - //["", "n", "ame/number"], - //["", "Enter", " stop all"], - //]), - //Self::ArrangerClip => Self::command(&[ - //["", "g", "et"], - //["", "s", "et"], - //["", "a", "dd"], - //["", "i", "ns"], - //["", "d", "up"], - //["", "e", "dit"], - //["", "c", "olor"], - //["re", "n", "ame"], - //["", ",.", "select"], - //["", "Enter", " launch"], - //]), - //Self::ArrangerTrack => Self::command(&[ - //["re", "n", "ame"], - //["", ",.", "resize"], - //["", "<>", "move"], - //["", "i", "nput"], - //["", "o", "utput"], - //["", "m", "ute"], - //["", "s", "olo"], - //["", "Del", "ete"], - //["", "Enter", " stop"], - //]), - //Self::ArrangerScene => Self::command(&[ - //["re", "n", "ame"], - //["", "Del", "ete"], - //["", "Enter", " launch"], - //]), - //Self::PhrasePool => Self::command(&[ - //["", "a", "ppend"], - //["", "i", "nsert"], - //["", "d", "uplicate"], - //["", "Del", "ete"], - //["", "c", "olor"], - //["re", "n", "ame"], - //["leng", "t", "h"], - //["", ",.", "move"], - //["", "+-", "resize view"], - //]), - //Self::PhraseView => Self::command(&[ - //["", "enter", " edit"], - //["", "arrows/pgup/pgdn", " scroll"], - //["", "+=", "zoom"], - //]), - //Self::PhraseEdit => Self::command(&[ - //["", "esc", " exit"], - //["", "a", "ppend"], - //["", "s", "et"], - //["", "][", "length"], - //["", "+-", "zoom"], - //]), - //_ => Self::command(&[]) - //}; - - ////let commands = commands.iter().reduce(String::new(), |s, (a, b, c)| format!("{s} {a}{b}{c}")); - //Tui::bg(status_bar_bg, Fill::w(row!([mode, commands]))) - -//}); - /// Status bar for arranger app -#[derive(Copy, Clone, Debug)] -pub enum ArrangerStatus { - Transport, - ArrangerMix, - ArrangerTrack, - ArrangerScene, - ArrangerClip, - PhrasePool, - PhraseView, - PhraseEdit, +#[derive(Clone)] +pub struct ArrangerStatus { + pub(crate) width: usize, + pub(crate) cpu: Option, + pub(crate) size: String, + pub(crate) res: String, + pub(crate) playing: bool, +} +from!(|state:&ArrangerTui|ArrangerStatus = { + let samples = state.clock.chunk.load(Relaxed); + let rate = state.clock.timebase.sr.get() as f64; + let buffer = samples as f64 / rate; + let width = state.size.w(); + Self { + width, + playing: state.clock.is_rolling(), + 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.), + } +}); +render!(|self: ArrangerStatus|Fixed::h(2, lay!([ + Self::help(), + Fill::wh(Align::se({Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats())})), +]))); +impl ArrangerStatus { + fn help () -> impl Render { + 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!([ + single("SPACE", "play/pause"), + single(" Ctrl", " scroll"), + single(" wsad", " cell"), + double(("q", "enqueue"), ("e", "edit")), + single(" ▲▼▶◀", " note"), + double(("a", "append"), ("s", "set note"),), + double((",.", "length"), ("<>", "triplet"),), + double(("[]", "phrase"), ("{}", "order"),), + ])) + } + fn stats <'a> (&'a self) -> impl Render + use<'a> { + row!([&self.cpu, &self.res, &self.size]) + } +} +impl Bar for ArrangerStatus { + type State = ArrangerTui; + fn hotkey_fg () -> Color { + TuiTheme::HOTKEY_FG + } + fn update (&mut self, _: &ArrangerTui) { + todo!() + } }