add edit phrase selector

This commit is contained in:
🪞👃🪞 2024-12-10 17:13:30 +01:00
parent 5828214c6f
commit a08067feba
5 changed files with 76 additions and 53 deletions

View file

@ -101,7 +101,7 @@ impl Audio for SequencerTui {
render!(|self: SequencerTui|lay!([ render!(|self: SequencerTui|lay!([
self.size, self.size,
col!([ Tui::shrink_y(1, col!([
TransportView::from((self, if let SequencerFocus::Transport(_) = self.focus.inner() { TransportView::from((self, if let SequencerFocus::Transport(_) = self.focus.inner() {
true true
} else { } else {
@ -109,6 +109,11 @@ render!(|self: SequencerTui|lay!([
})), })),
row!([ row!([
Tui::fixed_x(20, col!([ Tui::fixed_x(20, col!([
PhraseSelector::edit_phrase(
&self.editor.phrase,
self.focused() == SequencerFocus::PhraseEditor,
self.entered()
),
PhraseSelector::play_phrase( PhraseSelector::play_phrase(
&self.player, &self.player,
self.focused() == SequencerFocus::PhrasePlay, self.focused() == SequencerFocus::PhrasePlay,
@ -119,11 +124,11 @@ render!(|self: SequencerTui|lay!([
self.focused() == SequencerFocus::PhraseNext, self.focused() == SequencerFocus::PhraseNext,
self.entered() self.entered()
), ),
PhraseListView::from(self) PhraseListView::from(self),
])), ])),
PhraseView::from(self) PhraseView::from(self)
]) ])
]), ])),
Tui::fill_xy(Tui::at_s(SequencerStatusBar::from(self))), Tui::fill_xy(Tui::at_s(SequencerStatusBar::from(self))),
])); ]));

View file

@ -100,8 +100,8 @@ impl<T: HasClock> From<(&T, bool)> for TransportView {
started: false, started: false,
global_sample: format!("{:.0}k", clock.global.sample.get()/1000.), global_sample: format!("{:.0}k", clock.global.sample.get()/1000.),
global_second: format!("{:.1}s", clock.global.usec.get()/1000000.), global_second: format!("{:.1}s", clock.global.usec.get()/1000000.),
current_sample: "".to_string(), current_sample: "0".to_string(),
current_second: "".to_string(), current_second: "0.0s".to_string(),
} }
} }
} }
@ -117,12 +117,10 @@ render!(|self: TransportField<'a>|{
render!(|self: TransportView|{ render!(|self: TransportView|{
let border_style = Style::default() let border_style = Style::default()
.bg(TuiTheme::bg()) .bg(if self.focused { TuiTheme::border_bg() } else { TuiTheme::bg() })
.fg(TuiTheme::border_fg(true)); .fg(TuiTheme::border_fg(self.focused));
lay!(move|add|{ lay!(move|add|{
if self.focused {
add(&Tui::fill_x(Lozenge(border_style)))?; add(&Tui::fill_x(Lozenge(border_style)))?;
}
add(&Tui::outset_x(1, row!([ add(&Tui::outset_x(1, row!([
TransportField("Beat", "00X+0/0B+00/00P"), TransportField("Beat", "00X+0/0B+00/00P"),
" ", " ",
@ -130,9 +128,9 @@ render!(|self: TransportView|{
" ", " ",
col!(|add|{ col!(|add|{
if self.started { if self.started {
add(&col!([Tui::fg(Color::Rgb(0, 255, 0), "▶ PLAYING "), ""])) add(&col!([Tui::fg(Color::Rgb(0, 255, 0), "▶ PLAYING"), ""]))
} else { } else {
add(&col!(["", Tui::fg(Color::Rgb(255, 128, 0), "⏹ STOPPED ")])) add(&col!(["", Tui::fg(Color::Rgb(255, 128, 0), "⏹ STOPPED")]))
} }
}), }),
" ", " ",

View file

@ -212,9 +212,9 @@ render!(|self: PhraseView<'a>|{
} = self; } = self;
lay!([ lay!([
lay!(move|add|{ lay!(move|add|{
if *focused { //if *focused {
add(&Lozenge(Style::default().bg(Color::Rgb(40, 50, 30)).fg(TuiTheme::border_fg(true))))?; add(&Lozenge(Style::default().bg(Color::Rgb(40, 50, 30)).fg(TuiTheme::border_fg(true))))?;
} //}
let title_color = if *focused{Color::Rgb(150, 160, 90)}else{Color::Rgb(120, 130, 100)}; let title_color = if *focused{Color::Rgb(150, 160, 90)}else{Color::Rgb(120, 130, 100)};
let upper_left = format!("{}", let upper_left = format!("{}",
phrase.as_ref().map(|p|p.read().unwrap().name.clone()).unwrap_or(String::new()) phrase.as_ref().map(|p|p.read().unwrap().name.clone()).unwrap_or(String::new())
@ -232,7 +232,7 @@ render!(|self: PhraseView<'a>|{
time_point, phrase.read().unwrap().length, pulses_to_name(view_mode.time_zoom()), time_point, phrase.read().unwrap().length, pulses_to_name(view_mode.time_zoom()),
) )
}; };
add(&Tui::at_nw(Tui::fg(title_color, upper_left)))?; add(&Tui::push_x(1, Tui::at_nw(Tui::fg(title_color, upper_left))))?;
add(&Tui::at_sw(Tui::fg(title_color, lower_left)))?; add(&Tui::at_sw(Tui::fg(title_color, lower_left)))?;
add(&Tui::fill_xy(Tui::at_ne(Tui::pull_x(1, Tui::fg(title_color, upper_right)))))?; add(&Tui::fill_xy(Tui::at_ne(Tui::pull_x(1, Tui::fg(title_color, upper_right)))))?;
add(&Tui::fill_xy(Tui::at_se(Tui::pull_x(1, Tui::fg(title_color, lower_right)))))?; add(&Tui::fill_xy(Tui::at_se(Tui::pull_x(1, Tui::fg(title_color, lower_right)))))?;
@ -242,7 +242,7 @@ render!(|self: PhraseView<'a>|{
TuiTheme::bg() TuiTheme::bg()
} else { } else {
Color::Reset Color::Reset
}, Tui::fill_x(row!([ }, Tui::inset_x(1, Tui::fill_x(row!([
Tui::push_y(1, Tui::fill_y(Widget::new(|to:[u16;2]|Ok(Some(to.clip_w(5))), move|to: &mut TuiOutput|{ Tui::push_y(1, Tui::fill_y(Widget::new(|to:[u16;2]|Ok(Some(to.clip_w(5))), move|to: &mut TuiOutput|{
Ok(if to.area().h() >= 2 { view_mode.render_keys(to, *note_hi, *note_lo) }) Ok(if to.area().h() >= 2 { view_mode.render_keys(to, *note_hi, *note_lo) })
}))), }))),
@ -262,7 +262,7 @@ render!(|self: PhraseView<'a>|{
}) })
})) }))
])), ])),
]))) ]))))
]) ])
}); });

View file

@ -122,15 +122,15 @@ impl<'a, T: HasPhraseList> From<&'a T> for PhraseListView<'a> {
// TODO: Display phrases always in order of appearance // TODO: Display phrases always in order of appearance
render!(|self: PhraseListView<'a>|{ render!(|self: PhraseListView<'a>|{
let Self { title, focused, entered, phrases, index, mode } = self; let Self { title, focused, entered, phrases, index, mode } = self;
let border_bg = if *entered {Color::Rgb(40, 50, 30)} else {TuiTheme::bg()}; let border_bg = if *entered {Color::Rgb(40, 50, 30)} else {Color::Reset};
let border_color = if *entered {Color::Rgb(100, 110, 40)} else {Color::Rgb(70, 80, 50)}; let border_color = if *entered {Color::Rgb(100, 110, 40)} else {Color::Rgb(70, 80, 50)};
let title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)}; let title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)};
let upper_left = format!("{title}"); let upper_left = format!("{title}");
let upper_right = format!("({})", phrases.len()); let upper_right = format!("({})", phrases.len());
lay!(move|add|{ lay!(move|add|{
if *focused { //if *focused {
add(&Lozenge(Style::default().bg(border_bg).fg(border_color)))?; add(&Lozenge(Style::default().bg(border_bg).fg(border_color)))?;
} //}
add(&Tui::inset_xy(0, 1, Tui::fill_xy(col!(move|add|match mode { add(&Tui::inset_xy(0, 1, Tui::fill_xy(col!(move|add|match mode {
Some(PhrasesMode::Import(_, ref browser)) => { Some(PhrasesMode::Import(_, ref browser)) => {
add(browser) add(browser)

View file

@ -1,61 +1,81 @@
use crate::*; use crate::*;
pub struct PhraseSelector<'a> { pub struct PhraseSelector {
pub(crate) title: &'static str, pub(crate) title: &'static str,
pub(crate) phrase: &'a Option<(Moment, Option<Arc<RwLock<Phrase>>>)>, pub(crate) phrase: Option<(Moment, Option<Arc<RwLock<Phrase>>>)>,
pub(crate) focused: bool, pub(crate) focused: bool,
pub(crate) entered: bool, pub(crate) entered: bool,
} }
impl<'a> PhraseSelector<'a> { // TODO: Display phrases always in order of appearance
render!(|self: PhraseSelector|{
let Self { title, phrase, focused, entered } = self;
let border_bg = if *focused {Color::Rgb(40, 50, 30)} else { Color::Reset };
let border_color = if *focused {Color::Rgb(100, 110, 40)} else {Color::Rgb(70, 80, 50)};
let border = Lozenge(Style::default().bg(border_bg).fg(border_color));
let title_color = if phrase.is_some() {
Color::Rgb(200,200,200)
} else if *focused {
Color::Rgb(150, 160, 90)
} else {
Color::Rgb(120, 130, 100)
};
Tui::fixed_y(2, lay!(move|add|{
//if phrase.is_none() {
add(&Tui::fill_x(border))?;
//}
add(&Tui::push_x(1, Tui::fg(title_color, *title)))?;
add(&Tui::push_y(0, Tui::fill_xy(Layers::new(move|add|{
if let Some((instant, Some(phrase))) = phrase {
let Phrase { ref name, color, length, .. } = *phrase.read().unwrap();
add(&Tui::pull_y(0, Tui::inset_x(0, Tui::bg(color.dark.rgb, Tui::fill_x(col!([
Tui::fill_x(lay!([
Tui::fill_x(Tui::at_w(Tui::fg(Color::Rgb(255,255,255), format!(" ")))),
Tui::fill_x(Tui::at_e(Tui::fg(Color::Rgb(255,255,255), PhraseLength::new(length, None))))
])),
Tui::bold(true, Tui::fg(Color::Rgb(255,255,255), format!(" {name}")))
]))))))?;
}
Ok(())
}))))
}))
});
impl PhraseSelector {
pub fn play_phrase <T: HasPlayPhrase> ( pub fn play_phrase <T: HasPlayPhrase> (
state: &'a T, state: &T,
focused: bool, focused: bool,
entered: bool, entered: bool,
) -> Self { ) -> Self {
Self { Self {
focused, focused,
entered: focused && entered, entered: focused && entered,
phrase: state.next_phrase(), phrase: state.play_phrase().clone(),
title: "Now:", title: "Now:",
} }
} }
pub fn next_phrase <T: HasPlayPhrase> ( pub fn next_phrase <T: HasPlayPhrase> (
state: &'a T, state: &T,
focused: bool, focused: bool,
entered: bool, entered: bool,
) -> Self { ) -> Self {
Self { Self {
focused, focused,
entered: focused && entered, entered: focused && entered,
phrase: state.next_phrase(), phrase: state.next_phrase().clone(),
title: "Next:", title: "Next:",
} }
} }
pub fn edit_phrase (
phrase: &Option<Arc<RwLock<Phrase>>>,
focused: bool,
entered: bool,
) -> Self {
Self {
focused,
entered: focused && entered,
phrase: Some((Moment::default(), phrase.clone())),
title: "Edit:",
}
}
} }
// TODO: Display phrases always in order of appearance
render!(|self: PhraseSelector<'a>|{
let Self { title, phrase, focused, entered } = self;
let border_color = if *focused {Color::Rgb(100, 110, 40)} else {Color::Rgb(70, 80, 50)};
let border = Lozenge(Style::default().bg(Color::Rgb(40, 50, 30)).fg(border_color));
let title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)};
Tui::fixed_y(3, lay!(move|add|{
if *focused {
add(&Tui::fill_x(border))?;
}
add(&Tui::fill_xy(Layers::new(move|add|{
if let Some((instant, Some(phrase))) = phrase {
let Phrase { ref name, color, length, .. } = *phrase.read().unwrap();
let length = PhraseLength::new(length, None);
let length = Tui::fill_x(Tui::at_e(length));
let row1 = Tui::fill_x(lay!([Tui::fill_x(Tui::at_w(format!(" "))), length]));
let row2 = format!(" {name}");
let row2 = Tui::bold(true, row2);
add(&Tui::bg(color.base.rgb, Tui::fill_x(col!([row1, row2]))))?;
}
Ok(())
})))?;
add(&Tui::fill_xy(Tui::at_nw(Tui::push_x(1, Tui::fg(title_color, *title)))))
}))
});