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::*;
|
use super::*;
|
||||||
|
|
||||||
mod phrase_length; pub(crate) use phrase_length::*;
|
pub mod phrase_length;
|
||||||
mod phrase_rename; pub(crate) use phrase_rename::*;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct PoolModel {
|
pub struct PoolModel {
|
||||||
|
|
@ -244,64 +250,6 @@ render!(<Tui>|self: PoolView<'a>|{
|
||||||
add(&self.0.size)
|
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|{
|
command!(|self: FileBrowserCommand, state: PoolModel|{
|
||||||
use PoolMode::*;
|
use PoolMode::*;
|
||||||
use FileBrowserCommand::*;
|
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();
|
).flatten().clone();
|
||||||
let play = Fixed::wh(5, 2, PlayPause(self.clock.is_rolling()));
|
let play = Fixed::wh(5, 2, PlayPause(self.clock.is_rolling()));
|
||||||
let transport = Fixed::h(2, TransportView::from((self, color, true)));
|
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::play_phrase(&self.player),
|
||||||
PhraseSelector::next_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|{
|
audio!(|self:SequencerTui, client, scope|{
|
||||||
// Start profiling cycle
|
// Start profiling cycle
|
||||||
|
|
|
||||||
|
|
@ -99,10 +99,10 @@ render!(<Tui>|self: TransportView|{
|
||||||
//PlayPause(self.started), " ",
|
//PlayPause(self.started), " ",
|
||||||
col!([
|
col!([
|
||||||
Field(" Beat", self.beat.as_str(), &color),
|
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!([
|
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(" Smpl", format!("{:.1}k", self.current_sample).as_str(), &color),
|
||||||
Field(" Rate", format!("{}", self.sr).as_str(), &color),
|
Field(" Rate", format!("{}", self.sr).as_str(), &color),
|
||||||
//Field(" CPU%", format!("{:.1}ms", self.perf).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!([
|
let field = move|x, y|row!([
|
||||||
Tui::fg_bg(color.lighter.rgb, color.darker.rgb, Tui::bold(true, x)),
|
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),
|
Tui::fg_bg(color.lighter.rgb, color.dark.rgb, &y),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -79,10 +78,10 @@ render!(<Tui>|self: PianoHorizontal|{
|
||||||
|
|
||||||
with_border(lay!([
|
with_border(lay!([
|
||||||
Tui::push_x(0, row!(![
|
Tui::push_x(0, row!(![
|
||||||
" ",
|
//" ",
|
||||||
field(" Edit", name.to_string()),
|
field("Edit:", name.to_string()), " ",
|
||||||
field(" Length", length.to_string()),
|
field("Length:", length.to_string()), " ",
|
||||||
field(" Loop", looped.to_string())
|
field("Loop:", looped.to_string())
|
||||||
])),
|
])),
|
||||||
Tui::inset_xy(0, 1, Fill::wh(Bsp::s(
|
Tui::inset_xy(0, 1, Fill::wh(Bsp::s(
|
||||||
Fixed::h(1, Bsp::e(
|
Fixed::h(1, Bsp::e(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue