mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 20:56:43 +01:00
add edit phrase selector
This commit is contained in:
parent
5828214c6f
commit
a08067feba
5 changed files with 76 additions and 53 deletions
|
|
@ -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))),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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")]))
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
" ",
|
" ",
|
||||||
|
|
|
||||||
|
|
@ -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>|{
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
])),
|
])),
|
||||||
])))
|
]))))
|
||||||
])
|
])
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)))))
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue