mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
add arranger help; don't rollover, just stup
This commit is contained in:
parent
47c13e1901
commit
32c9654a0c
7 changed files with 192 additions and 144 deletions
122
.scratch.rs
Normal file
122
.scratch.rs
Normal 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,
|
||||
//}
|
||||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue