mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
updating phrase selector layout
This commit is contained in:
parent
7e02a46beb
commit
774af02e5e
5 changed files with 83 additions and 70 deletions
|
|
@ -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::*;
|
||||
|
|
|
|||
65
crates/tek/src/pool/phrase_selector.rs
Normal file
65
crates/tek/src/pool/phrase_selector.rs
Normal 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, }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue