updating phrase selector layout

This commit is contained in:
🪞👃🪞 2024-12-27 22:22:08 +01:00
parent 7e02a46beb
commit 774af02e5e
5 changed files with 83 additions and 70 deletions

View file

@ -1,7 +1,13 @@
use super::*;
mod phrase_length; pub(crate) use phrase_length::*;
mod phrase_rename; pub(crate) use phrase_rename::*;
pub mod phrase_length;
pub(crate) use phrase_length::*;
pub mod phrase_rename;
pub(crate) use phrase_rename::*;
pub mod phrase_selector;
pub(crate) use phrase_selector::*;
#[derive(Debug)]
pub struct PoolModel {
@ -244,64 +250,6 @@ render!(<Tui>|self: PoolView<'a>|{
add(&self.0.size)
}))
});
pub struct PhraseSelector {
pub(crate) title: &'static str,
pub(crate) name: String,
pub(crate) color: ItemPalette,
pub(crate) time: String,
}
// TODO: Display phrases always in order of appearance
render!(<Tui>|self: PhraseSelector|Fixed::wh(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!([
format!("{:8}", &self.name[0..8.min(self.name.len())]),
Tui::bg(self.color.dark.rgb, &self.time),
])),
])));
impl PhraseSelector {
// beats elapsed
pub fn play_phrase <T: HasPlayPhrase + HasClock> (state: &T) -> Self {
let (name, color) = if let Some((_, Some(phrase))) = state.play_phrase() {
let MidiClip { ref name, color, .. } = *phrase.read().unwrap();
(name.clone(), color)
} else {
("".to_string(), ItemPalette::from(TuiTheme::g(64)))
};
let time = if let Some(elapsed) = state.pulses_since_start_looped() {
format!("+{:>}", state.clock().timebase.format_beats_0(elapsed))
} else {
String::from(" ")
};
Self { title: " Now|", time, name, color, }
}
// beats until switchover
pub fn next_phrase <T: HasPlayPhrase> (state: &T) -> Self {
let (time, name, color) = if let Some((t, Some(phrase))) = state.next_phrase() {
let MidiClip { ref name, color, .. } = *phrase.read().unwrap();
let time = {
let target = t.pulse.get();
let current = state.clock().playhead.pulse.get();
if target > current {
let remaining = target - current;
format!("-{:>}", state.clock().timebase.format_beats_0(remaining))
} else {
String::new()
}
};
(time, name.clone(), color)
} else if let Some((_, Some(phrase))) = state.play_phrase() {
let phrase = phrase.read().unwrap();
if phrase.looped {
(" ".into(), phrase.name.clone(), phrase.color)
} else {
(" ".into(), " ".into(), TuiTheme::g(64).into())
}
} else {
(" ".into(), " ".into(), TuiTheme::g(64).into())
};
Self { title: " Next|", time, name, color, }
}
}
command!(|self: FileBrowserCommand, state: PoolModel|{
use PoolMode::*;
use FileBrowserCommand::*;

View file

@ -0,0 +1,65 @@
use crate::*;
pub struct PhraseSelector {
pub(crate) title: &'static str,
pub(crate) name: String,
pub(crate) color: ItemPalette,
pub(crate) time: String,
}
// TODO: Display phrases always in order of appearance
render!(<Tui>|self: PhraseSelector|Fixed::wh(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!([
format!("{:8}", &self.name[0..8.min(self.name.len())]),
Tui::bg(self.color.dark.rgb, &self.time),
])),
])));
impl PhraseSelector {
// beats elapsed
pub fn play_phrase <T: HasPlayPhrase + HasClock> (state: &T) -> Self {
let (name, color) = if let Some((_, Some(phrase))) = state.play_phrase() {
let MidiClip { ref name, color, .. } = *phrase.read().unwrap();
(name.clone(), color)
} else {
("".to_string(), ItemPalette::from(TuiTheme::g(64)))
};
let time = if let Some(elapsed) = state.pulses_since_start_looped() {
format!("+{:>}", state.clock().timebase.format_beats_0(elapsed))
} else {
String::from(" ")
};
Self { title: "Now:|", time, name, color, }
}
// beats until switchover
pub fn next_phrase <T: HasPlayPhrase> (state: &T) -> Self {
let (time, name, color) = if let Some((t, Some(phrase))) = state.next_phrase() {
let MidiClip { ref name, color, .. } = *phrase.read().unwrap();
let time = {
let target = t.pulse.get();
let current = state.clock().playhead.pulse.get();
if target > current {
let remaining = target - current;
format!("-{:>}", state.clock().timebase.format_beats_0(remaining))
} else {
String::new()
}
};
(time, name.clone(), color)
} else if let Some((_, Some(phrase))) = state.play_phrase() {
let phrase = phrase.read().unwrap();
if phrase.looped {
(" ".into(), phrase.name.clone(), phrase.color)
} else {
(" ".into(), " ".into(), TuiTheme::g(64).into())
}
} else {
(" ".into(), " ".into(), TuiTheme::g(64).into())
};
Self { title: " Next|", time, name, color, }
}
}

View file

@ -52,11 +52,12 @@ render!(<Tui>|self: SequencerTui|{
).flatten().clone();
let play = Fixed::wh(5, 2, PlayPause(self.clock.is_rolling()));
let transport = Fixed::h(2, TransportView::from((self, color, true)));
let toolbar = row!([play, col!([
let toolbar = row!([play, transport]);
let play_queue = row!([
PhraseSelector::play_phrase(&self.player),
PhraseSelector::next_phrase(&self.player),
]), transport]);
Tui::min_y(15, with_size(with_status(col!([ toolbar, editor, ]))))
]);
Tui::min_y(15, with_size(with_status(col!([ toolbar, play_queue, editor, ]))))
});
audio!(|self:SequencerTui, client, scope|{
// Start profiling cycle

View file

@ -99,10 +99,10 @@ render!(<Tui>|self: TransportView|{
//PlayPause(self.started), " ",
col!([
Field(" Beat", self.beat.as_str(), &color),
Field(" BPM", self.bpm.as_str(), &color),
Field(" Time", format!("{:.1}s", self.current_second).as_str(), &color),
]),
col!([
Field(" Time", format!("{:.1}s", self.current_second).as_str(), &color),
Field(" BPM", self.bpm.as_str(), &color),
//Field(" Smpl", format!("{:.1}k", self.current_sample).as_str(), &color),
Field(" Rate", format!("{}", self.sr).as_str(), &color),
//Field(" CPU%", format!("{:.1}ms", self.perf).as_str(), &color),

View file

@ -61,7 +61,6 @@ render!(<Tui>|self: PianoHorizontal|{
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.lighter.rgb, color.dark.rgb, &y),
]);
@ -79,10 +78,10 @@ render!(<Tui>|self: PianoHorizontal|{
with_border(lay!([
Tui::push_x(0, row!(![
" ",
field(" Edit", name.to_string()),
field(" Length", length.to_string()),
field(" Loop", looped.to_string())
//" ",
field("Edit:", name.to_string()), " ",
field("Length:", length.to_string()), " ",
field("Loop:", looped.to_string())
])),
Tui::inset_xy(0, 1, Fill::wh(Bsp::s(
Fixed::h(1, Bsp::e(