add arranger help; don't rollover, just stup

This commit is contained in:
🪞👃🪞 2024-12-23 22:03:34 +01:00
parent 47c13e1901
commit 32c9654a0c
7 changed files with 192 additions and 144 deletions

122
.scratch.rs Normal file
View file

@ -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!(<Tui>|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,
//}

View file

@ -108,7 +108,7 @@ render!(<Tui>|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]);

View file

@ -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)),

View file

@ -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(),

View file

@ -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)),

View file

@ -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)),

View file

@ -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!(<Tui>|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<Tui> + 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!(<Tui>|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<String>,
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!(<Tui>|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<Tui> {
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<Tui> + 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!()
}
}