diff --git a/crates/tek/src/tui/app_sequencer.rs b/crates/tek/src/tui/app_sequencer.rs index 70df0ecc..9dc49c90 100644 --- a/crates/tek/src/tui/app_sequencer.rs +++ b/crates/tek/src/tui/app_sequencer.rs @@ -101,7 +101,7 @@ impl Audio for SequencerTui { render!(|self: SequencerTui|lay!([ self.size, - col!([ + Tui::shrink_y(1, col!([ TransportView::from((self, if let SequencerFocus::Transport(_) = self.focus.inner() { true } else { @@ -109,6 +109,11 @@ render!(|self: SequencerTui|lay!([ })), row!([ Tui::fixed_x(20, col!([ + PhraseSelector::edit_phrase( + &self.editor.phrase, + self.focused() == SequencerFocus::PhraseEditor, + self.entered() + ), PhraseSelector::play_phrase( &self.player, self.focused() == SequencerFocus::PhrasePlay, @@ -119,11 +124,11 @@ render!(|self: SequencerTui|lay!([ self.focused() == SequencerFocus::PhraseNext, self.entered() ), - PhraseListView::from(self) + PhraseListView::from(self), ])), PhraseView::from(self) ]) - ]), + ])), Tui::fill_xy(Tui::at_s(SequencerStatusBar::from(self))), ])); diff --git a/crates/tek/src/tui/app_transport.rs b/crates/tek/src/tui/app_transport.rs index 5cae58a5..9462e6c2 100644 --- a/crates/tek/src/tui/app_transport.rs +++ b/crates/tek/src/tui/app_transport.rs @@ -100,8 +100,8 @@ impl From<(&T, bool)> for TransportView { started: false, global_sample: format!("{:.0}k", clock.global.sample.get()/1000.), global_second: format!("{:.1}s", clock.global.usec.get()/1000000.), - current_sample: "".to_string(), - current_second: "".to_string(), + current_sample: "0".to_string(), + current_second: "0.0s".to_string(), } } } @@ -117,12 +117,10 @@ render!(|self: TransportField<'a>|{ render!(|self: TransportView|{ let border_style = Style::default() - .bg(TuiTheme::bg()) - .fg(TuiTheme::border_fg(true)); + .bg(if self.focused { TuiTheme::border_bg() } else { TuiTheme::bg() }) + .fg(TuiTheme::border_fg(self.focused)); 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!([ TransportField("Beat", "00X+0/0B+00/00P"), " ", @@ -130,9 +128,9 @@ render!(|self: TransportView|{ " ", col!(|add|{ if self.started { - add(&col!([Tui::fg(Color::Rgb(0, 255, 0), "▶ PLAYING "), ""])) + add(&col!([Tui::fg(Color::Rgb(0, 255, 0), "▶ PLAYING"), ""])) } else { - add(&col!(["", Tui::fg(Color::Rgb(255, 128, 0), "⏹ STOPPED ")])) + add(&col!(["", Tui::fg(Color::Rgb(255, 128, 0), "⏹ STOPPED")])) } }), " ", diff --git a/crates/tek/src/tui/phrase_editor.rs b/crates/tek/src/tui/phrase_editor.rs index 2fb5d888..6a0090fe 100644 --- a/crates/tek/src/tui/phrase_editor.rs +++ b/crates/tek/src/tui/phrase_editor.rs @@ -212,9 +212,9 @@ render!(|self: PhraseView<'a>|{ } = self; lay!([ lay!(move|add|{ - if *focused { + //if *focused { 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 upper_left = format!("{}", 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()), ) }; - 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::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)))))?; @@ -242,7 +242,7 @@ render!(|self: PhraseView<'a>|{ TuiTheme::bg() } else { 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|{ Ok(if to.area().h() >= 2 { view_mode.render_keys(to, *note_hi, *note_lo) }) }))), @@ -262,7 +262,7 @@ render!(|self: PhraseView<'a>|{ }) })) ])), - ]))) + ])))) ]) }); diff --git a/crates/tek/src/tui/phrase_list.rs b/crates/tek/src/tui/phrase_list.rs index a9ecaeea..fce3a86c 100644 --- a/crates/tek/src/tui/phrase_list.rs +++ b/crates/tek/src/tui/phrase_list.rs @@ -122,15 +122,15 @@ impl<'a, T: HasPhraseList> From<&'a T> for PhraseListView<'a> { // TODO: Display phrases always in order of appearance render!(|self: PhraseListView<'a>|{ 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 title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)}; let upper_left = format!("{title}"); let upper_right = format!("({})", phrases.len()); lay!(move|add|{ - if *focused { + //if *focused { add(&Lozenge(Style::default().bg(border_bg).fg(border_color)))?; - } + //} add(&Tui::inset_xy(0, 1, Tui::fill_xy(col!(move|add|match mode { Some(PhrasesMode::Import(_, ref browser)) => { add(browser) diff --git a/crates/tek/src/tui/phrase_select.rs b/crates/tek/src/tui/phrase_select.rs index 29cd34cc..8d16cb25 100644 --- a/crates/tek/src/tui/phrase_select.rs +++ b/crates/tek/src/tui/phrase_select.rs @@ -1,61 +1,81 @@ use crate::*; -pub struct PhraseSelector<'a> { +pub struct PhraseSelector { pub(crate) title: &'static str, - pub(crate) phrase: &'a Option<(Moment, Option>>)>, + pub(crate) phrase: Option<(Moment, Option>>)>, pub(crate) focused: 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 ( - state: &'a T, + state: &T, focused: bool, entered: bool, ) -> Self { Self { focused, entered: focused && entered, - phrase: state.next_phrase(), + phrase: state.play_phrase().clone(), title: "Now:", } } pub fn next_phrase ( - state: &'a T, + state: &T, focused: bool, entered: bool, ) -> Self { Self { focused, entered: focused && entered, - phrase: state.next_phrase(), + phrase: state.next_phrase().clone(), title: "Next:", } } -} - -// 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))?; + pub fn edit_phrase ( + phrase: &Option>>, + focused: bool, + entered: bool, + ) -> Self { + Self { + focused, + entered: focused && entered, + phrase: Some((Moment::default(), phrase.clone())), + title: "Edit:", } - 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))))) - })) -}); + } +}