diff --git a/crates/tek_core/src/focus.rs b/crates/tek_core/src/focus.rs index 395980c7..b153cfde 100644 --- a/crates/tek_core/src/focus.rs +++ b/crates/tek_core/src/focus.rs @@ -125,7 +125,8 @@ pub trait FocusGrid: HasFocus { let next_x = if self.focus_layout()[y].len() == self.focus_layout()[next_y].len() { x } else { - ((x as f32 / self.focus_layout()[original_y].len() as f32) * self.focus_layout()[next_y].len() as f32) as usize + ((x as f32 / self.focus_layout()[original_y].len() as f32) + * self.focus_layout()[next_y].len() as f32) as usize }; *self.focus_cursor_mut() = (next_x, next_y); if self.focus_current() != original_focused { @@ -150,7 +151,8 @@ pub trait FocusGrid: HasFocus { let next_x = if self.focus_layout()[y].len() == self.focus_layout()[next_y].len() { x } else { - ((x as f32 / self.focus_layout()[original_y].len() as f32) * self.focus_layout()[next_y].len() as f32) as usize + ((x as f32 / self.focus_layout()[original_y].len() as f32) + * self.focus_layout()[next_y].len() as f32) as usize }; *self.focus_cursor_mut() = (next_x, next_y); if self.focus_current() != original_focused { diff --git a/crates/tek_core/src/test.rs b/crates/tek_core/src/test.rs index 67f6865e..211233b2 100644 --- a/crates/tek_core/src/test.rs +++ b/crates/tek_core/src/test.rs @@ -1,190 +1,190 @@ use crate::*; -//struct TestEngine([u16;4], Vec>); +struct TestEngine([u16;4], Vec>); -//impl Engine for TestEngine { - //type Unit = u16; - //type Size = [Self::Unit;2]; - //type Area = [Self::Unit;4]; - //type Input = Self; - //type Handled = bool; - //fn exited (&self) -> bool { - //true - //} - //fn area (&self) -> Self::Area { - //self.0 - //} - //fn area_mut (&mut self) -> &mut Self::Area { - //&mut self.0 - //} -//} +impl Engine for TestEngine { + type Unit = u16; + type Size = [Self::Unit;2]; + type Area = [Self::Unit;4]; + type Input = Self; + type Handled = bool; + fn exited (&self) -> bool { + true + } + fn area (&self) -> Self::Area { + self.0 + } + fn area_mut (&mut self) -> &mut Self::Area { + &mut self.0 + } +} -//#[derive(Copy, Clone)] -//struct TestArea(u16, u16); +#[derive(Copy, Clone)] +struct TestArea(u16, u16); -//impl Widget for TestArea { - //type Engine = TestEngine; - //fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> { - //Ok(Some([to[0], to[1], self.0, self.1])) - //} - //fn render (&self, to: &mut Self::Engine) -> Perhaps<[u16;4]> { - //if let Some(layout) = self.layout(to.area())? { - //for y in layout.y()..layout.y()+layout.h()-1 { - //for x in layout.x()..layout.x()+layout.w()-1 { - //to.1[y as usize][x as usize] = '*'; - //} - //} - //Ok(Some(layout)) - //} else { - //Ok(None) - //} - //} -//} +impl Widget for TestArea { + type Engine = TestEngine; + fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> { + Ok(Some([to[0], to[1], self.0, self.1])) + } + fn render (&self, to: &mut Self::Engine) -> Perhaps<[u16;4]> { + if let Some(layout) = self.layout(to.area())? { + for y in layout.y()..layout.y()+layout.h()-1 { + for x in layout.x()..layout.x()+layout.w()-1 { + to.1[y as usize][x as usize] = '*'; + } + } + Ok(Some(layout)) + } else { + Ok(None) + } + } +} + +#[test] +fn test_plus_minus () -> Usually<()> { + let area = [0, 0, 10, 10]; + let engine = TestEngine(area, vec![vec![' ';10];10]); + let test = TestArea(4, 4); + assert_eq!(test.layout(area)?, Some([0, 0, 4, 4])); + assert_eq!(Push::X(1, test).layout(area)?, Some([1, 0, 4, 4])); + Ok(()) +} + +#[test] +fn test_outset_align () -> Usually<()> { + let area = [0, 0, 10, 10]; + let engine = TestEngine(area, vec![vec![' ';10];10]); + let test = TestArea(4, 4); + assert_eq!(test.layout(area)?, Some([0, 0, 4, 4])); + assert_eq!(Outset::X(1, test).layout(area)?, Some([0, 0, 6, 4])); + assert_eq!(Align::X(test).layout(area)?, Some([3, 0, 4, 4])); + assert_eq!(Align::X(Outset::X(1, test)).layout(area)?, Some([2, 0, 6, 4])); + assert_eq!(Outset::X(1, Align::X(test)).layout(area)?, Some([2, 0, 6, 4])); + Ok(()) +} //#[test] -//fn test_plus_minus () -> Usually<()> { - //let area = [0, 0, 10, 10]; - //let engine = TestEngine(area, vec![vec![' ';10];10]); - //let test = TestArea(4, 4); - //assert_eq!(test.layout(area)?, Some([0, 0, 4, 4])); - //assert_eq!(Push::X(1, test).layout(area)?, Some([1, 0, 4, 4])); +//fn test_misc () -> Usually<()> { + //let area: [u16;4] = [0, 0, 10, 10]; + //let test = TestArea(4, 4); + //assert_eq!(test.layout(area)?, + //Some([0, 0, 4, 4])); + //assert_eq!(Align::Center(test).layout(area)?, + //Some([3, 3, 4, 4])); + //assert_eq!(Align::Center(Stack::down(|add|{ + //add(&test)?; + //add(&test) + //})).layout(area)?, + //Some([3, 1, 4, 8])); + //assert_eq!(Align::Center(Stack::down(|add|{ + //add(&Outset::XY(2, 2, test))?; + //add(&test) + //})).layout(area)?, + //Some([2, 0, 6, 10])); + //assert_eq!(Align::Center(Stack::down(|add|{ + //add(&Outset::XY(2, 2, test))?; + //add(&Inset::XY(2, 2, test)) + //})).layout(area)?, + //Some([2, 1, 6, 8])); + //assert_eq!(Stack::down(|add|{ + //add(&Outset::XY(2, 2, test))?; + //add(&Inset::XY(2, 2, test)) + //}).layout(area)?, + //Some([0, 0, 6, 8])); + //assert_eq!(Stack::right(|add|{ + //add(&Stack::down(|add|{ + //add(&Outset::XY(2, 2, test))?; + //add(&Inset::XY(2, 2, test)) + //}))?; + //add(&Align::Center(TestArea(2 ,2))) + //}).layout(area)?, + //Some([0, 0, 8, 8])); //Ok(()) //} //#[test] -//fn test_outset_align () -> Usually<()> { - //let area = [0, 0, 10, 10]; - //let engine = TestEngine(area, vec![vec![' ';10];10]); - //let test = TestArea(4, 4); - //assert_eq!(test.layout(area)?, Some([0, 0, 4, 4])); - //assert_eq!(Outset::X(1, test).layout(area)?, Some([0, 0, 6, 4])); - //assert_eq!(Align::X(test).layout(area)?, Some([3, 0, 4, 4])); - //assert_eq!(Align::X(Outset::X(1, test)).layout(area)?, Some([2, 0, 6, 4])); - //assert_eq!(Outset::X(1, Align::X(test)).layout(area)?, Some([2, 0, 6, 4])); +//fn test_offset () -> Usually<()> { + //let area: [u16;4] = [50, 50, 100, 100]; + //let test = TestArea(3, 3); + //assert_eq!(Push::X(1, test).layout(area)?, Some([51, 50, 3, 3])); + //assert_eq!(Push::Y(1, test).layout(area)?, Some([50, 51, 3, 3])); + //assert_eq!(Push::XY(1, 1, test).layout(area)?, Some([51, 51, 3, 3])); //Ok(()) //} -////#[test] -////fn test_misc () -> Usually<()> { - ////let area: [u16;4] = [0, 0, 10, 10]; - ////let test = TestArea(4, 4); - ////assert_eq!(test.layout(area)?, - ////Some([0, 0, 4, 4])); - ////assert_eq!(Align::Center(test).layout(area)?, - ////Some([3, 3, 4, 4])); - ////assert_eq!(Align::Center(Stack::down(|add|{ - ////add(&test)?; - ////add(&test) - ////})).layout(area)?, - ////Some([3, 1, 4, 8])); - ////assert_eq!(Align::Center(Stack::down(|add|{ - ////add(&Outset::XY(2, 2, test))?; - ////add(&test) - ////})).layout(area)?, - ////Some([2, 0, 6, 10])); - ////assert_eq!(Align::Center(Stack::down(|add|{ - ////add(&Outset::XY(2, 2, test))?; - ////add(&Inset::XY(2, 2, test)) - ////})).layout(area)?, - ////Some([2, 1, 6, 8])); - ////assert_eq!(Stack::down(|add|{ - ////add(&Outset::XY(2, 2, test))?; - ////add(&Inset::XY(2, 2, test)) - ////}).layout(area)?, - ////Some([0, 0, 6, 8])); - ////assert_eq!(Stack::right(|add|{ - ////add(&Stack::down(|add|{ - ////add(&Outset::XY(2, 2, test))?; - ////add(&Inset::XY(2, 2, test)) - ////}))?; - ////add(&Align::Center(TestArea(2 ,2))) - ////}).layout(area)?, - ////Some([0, 0, 8, 8])); - ////Ok(()) -////} +//#[test] +//fn test_outset () -> Usually<()> { + //let area: [u16;4] = [50, 50, 100, 100]; + //let test = TestArea(3, 3); + //assert_eq!(Outset::X(1, test).layout(area)?, Some([49, 50, 5, 3])); + //assert_eq!(Outset::Y(1, test).layout(area)?, Some([50, 49, 3, 5])); + //assert_eq!(Outset::XY(1, 1, test).layout(area)?, Some([49, 49, 5, 5])); + //Ok(()) +//} -////#[test] -////fn test_offset () -> Usually<()> { - ////let area: [u16;4] = [50, 50, 100, 100]; - ////let test = TestArea(3, 3); - ////assert_eq!(Push::X(1, test).layout(area)?, Some([51, 50, 3, 3])); - ////assert_eq!(Push::Y(1, test).layout(area)?, Some([50, 51, 3, 3])); - ////assert_eq!(Push::XY(1, 1, test).layout(area)?, Some([51, 51, 3, 3])); - ////Ok(()) -////} +//#[test] +//fn test_inset () -> Usually<()> { + //let area: [u16;4] = [50, 50, 100, 100]; + //let test = TestArea(3, 3); + //assert_eq!(Inset::X(1, test).layout(area)?, Some([51, 50, 1, 3])); + //assert_eq!(Inset::Y(1, test).layout(area)?, Some([50, 51, 3, 1])); + //assert_eq!(Inset::XY(1, 1, test).layout(area)?, Some([51, 51, 1, 1])); + //Ok(()) +//} -////#[test] -////fn test_outset () -> Usually<()> { - ////let area: [u16;4] = [50, 50, 100, 100]; - ////let test = TestArea(3, 3); - ////assert_eq!(Outset::X(1, test).layout(area)?, Some([49, 50, 5, 3])); - ////assert_eq!(Outset::Y(1, test).layout(area)?, Some([50, 49, 3, 5])); - ////assert_eq!(Outset::XY(1, 1, test).layout(area)?, Some([49, 49, 5, 5])); - ////Ok(()) -////} - -////#[test] -////fn test_inset () -> Usually<()> { - ////let area: [u16;4] = [50, 50, 100, 100]; - ////let test = TestArea(3, 3); - ////assert_eq!(Inset::X(1, test).layout(area)?, Some([51, 50, 1, 3])); - ////assert_eq!(Inset::Y(1, test).layout(area)?, Some([50, 51, 3, 1])); - ////assert_eq!(Inset::XY(1, 1, test).layout(area)?, Some([51, 51, 1, 1])); - ////Ok(()) -////} - -////#[test] -////fn test_stuff () -> Usually<()> { - ////let area: [u16;4] = [0, 0, 100, 100]; - ////assert_eq!("1".layout(area)?, - ////Some([0, 0, 1, 1])); - ////assert_eq!("333".layout(area)?, - ////Some([0, 0, 3, 1])); - ////assert_eq!(Layers::new(|add|{add(&"1")?;add(&"333")}).layout(area)?, - ////Some([0, 0, 3, 1])); - ////assert_eq!(Stack::down(|add|{add(&"1")?;add(&"333")}).layout(area)?, - ////Some([0, 0, 3, 2])); - ////assert_eq!(Stack::right(|add|{add(&"1")?;add(&"333")}).layout(area)?, - ////Some([0, 0, 4, 1])); - ////assert_eq!(Stack::down(|add|{ - ////add(&Stack::right(|add|{add(&"1")?;add(&"333")}))?; - ////add(&"55555") - ////}).layout(area)?, - ////Some([0, 0, 5, 2])); - ////let area: [u16;4] = [1, 1, 100, 100]; - ////assert_eq!(Outset::X(1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, - ////Some([0, 1, 6, 1])); - ////assert_eq!(Outset::Y(1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, - ////Some([1, 0, 4, 3])); - ////assert_eq!(Outset::XY(1, 1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, - ////Some([0, 0, 6, 3])); - ////assert_eq!(Stack::down(|add|{ - ////add(&Outset::XY(1, 1, "1"))?; - ////add(&Outset::XY(1, 1, "333")) - ////}).layout(area)?, - ////Some([1, 1, 5, 6])); - ////let area: [u16;4] = [1, 1, 95, 100]; - ////assert_eq!(Align::Center(Stack::down(|add|{ - ////add(&Outset::XY(1, 1, "1"))?; - ////add(&Outset::XY(1, 1, "333")) - ////})).layout(area)?, - ////Some([46, 48, 5, 6])); - ////assert_eq!(Align::Center(Stack::down(|add|{ - ////add(&Layers::new(|add|{ - //////add(&Outset::XY(1, 1, Background(Color::Rgb(0,128,0))))?; - ////add(&Outset::XY(1, 1, "1"))?; - ////add(&Outset::XY(1, 1, "333"))?; - //////add(&Background(Color::Rgb(0,128,0)))?; - ////Ok(()) - ////}))?; - ////add(&Layers::new(|add|{ - //////add(&Outset::XY(1, 1, Background(Color::Rgb(0,0,128))))?; - ////add(&Outset::XY(1, 1, "555"))?; - ////add(&Outset::XY(1, 1, "777777"))?; - //////add(&Background(Color::Rgb(0,0,128)))?; - ////Ok(()) - ////})) - ////})).layout(area)?, - ////Some([46, 48, 5, 6])); - ////Ok(()) -////} +//#[test] +//fn test_stuff () -> Usually<()> { + //let area: [u16;4] = [0, 0, 100, 100]; + //assert_eq!("1".layout(area)?, + //Some([0, 0, 1, 1])); + //assert_eq!("333".layout(area)?, + //Some([0, 0, 3, 1])); + //assert_eq!(Layers::new(|add|{add(&"1")?;add(&"333")}).layout(area)?, + //Some([0, 0, 3, 1])); + //assert_eq!(Stack::down(|add|{add(&"1")?;add(&"333")}).layout(area)?, + //Some([0, 0, 3, 2])); + //assert_eq!(Stack::right(|add|{add(&"1")?;add(&"333")}).layout(area)?, + //Some([0, 0, 4, 1])); + //assert_eq!(Stack::down(|add|{ + //add(&Stack::right(|add|{add(&"1")?;add(&"333")}))?; + //add(&"55555") + //}).layout(area)?, + //Some([0, 0, 5, 2])); + //let area: [u16;4] = [1, 1, 100, 100]; + //assert_eq!(Outset::X(1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, + //Some([0, 1, 6, 1])); + //assert_eq!(Outset::Y(1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, + //Some([1, 0, 4, 3])); + //assert_eq!(Outset::XY(1, 1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, + //Some([0, 0, 6, 3])); + //assert_eq!(Stack::down(|add|{ + //add(&Outset::XY(1, 1, "1"))?; + //add(&Outset::XY(1, 1, "333")) + //}).layout(area)?, + //Some([1, 1, 5, 6])); + //let area: [u16;4] = [1, 1, 95, 100]; + //assert_eq!(Align::Center(Stack::down(|add|{ + //add(&Outset::XY(1, 1, "1"))?; + //add(&Outset::XY(1, 1, "333")) + //})).layout(area)?, + //Some([46, 48, 5, 6])); + //assert_eq!(Align::Center(Stack::down(|add|{ + //add(&Layers::new(|add|{ + ////add(&Outset::XY(1, 1, Background(Color::Rgb(0,128,0))))?; + //add(&Outset::XY(1, 1, "1"))?; + //add(&Outset::XY(1, 1, "333"))?; + ////add(&Background(Color::Rgb(0,128,0)))?; + //Ok(()) + //}))?; + //add(&Layers::new(|add|{ + ////add(&Outset::XY(1, 1, Background(Color::Rgb(0,0,128))))?; + //add(&Outset::XY(1, 1, "555"))?; + //add(&Outset::XY(1, 1, "777777"))?; + ////add(&Background(Color::Rgb(0,0,128)))?; + //Ok(()) + //})) + //})).layout(area)?, + //Some([46, 48, 5, 6])); + //Ok(()) +//} diff --git a/crates/tek_tui/src/lib.rs b/crates/tek_tui/src/lib.rs index b022cacc..576ba8a1 100644 --- a/crates/tek_tui/src/lib.rs +++ b/crates/tek_tui/src/lib.rs @@ -40,6 +40,7 @@ submod! { tui_view_phrase_editor tui_view_phrase_length tui_view_phrase_list + tui_view_phrase_selector tui_view_sequencer tui_view_transport } diff --git a/crates/tek_tui/src/tui_app_sequencer.rs b/crates/tek_tui/src/tui_app_sequencer.rs index 2fbf52a8..9af929de 100644 --- a/crates/tek_tui/src/tui_app_sequencer.rs +++ b/crates/tek_tui/src/tui_app_sequencer.rs @@ -79,7 +79,9 @@ impl_focus!(SequencerTui SequencerFocus [ /// Status bar for sequencer app #[derive(Clone)] pub struct SequencerStatusBar { - pub(crate) cpu: Option + pub(crate) cpu: Option, + pub(crate) size: String, + pub(crate) sr: String, } impl StatusBar for SequencerStatusBar { @@ -95,7 +97,9 @@ impl StatusBar for SequencerStatusBar { impl From<&SequencerTui> for SequencerStatusBar { fn from (state: &SequencerTui) -> Self { Self { - cpu: state.perf.percentage().map(|cpu|format!("{cpu:.03}%")) + cpu: state.perf.percentage().map(|cpu|format!(" {cpu:.01}% ")), + size: format!(" {}x{} ", state.size.w(), state.size.h()), + sr: format!(" {}Hz ", state.clock.current.timebase.sr.get()) } } } diff --git a/crates/tek_tui/src/tui_control_phrase_editor.rs b/crates/tek_tui/src/tui_control_phrase_editor.rs index d98857fe..5cbc86d3 100644 --- a/crates/tek_tui/src/tui_control_phrase_editor.rs +++ b/crates/tek_tui/src/tui_control_phrase_editor.rs @@ -110,7 +110,7 @@ impl Command for PhraseCommand { } } -pub trait PhraseEditorControl: HasFocus { +pub trait PhraseEditorControl { fn edit_phrase (&mut self, phrase: Option>>); fn phrase_to_edit (&self) -> Option>>; fn phrase_editing (&self) -> &Option>>; diff --git a/crates/tek_tui/src/tui_view_phrase_list.rs b/crates/tek_tui/src/tui_view_phrase_list.rs index 1e5e59d0..770b0809 100644 --- a/crates/tek_tui/src/tui_view_phrase_list.rs +++ b/crates/tek_tui/src/tui_view_phrase_list.rs @@ -1,6 +1,7 @@ use crate::*; pub struct PhraseListView<'a> { + pub(crate) title: &'static str, pub(crate) focused: bool, pub(crate) entered: bool, pub(crate) phrases: &'a Vec>>, @@ -11,6 +12,7 @@ pub struct PhraseListView<'a> { impl<'a, T: HasPhraseList> From<&'a T> for PhraseListView<'a> { fn from (state: &'a T) -> Self { Self { + title: "Phrases", focused: state.phrases_focused(), entered: state.phrases_entered(), phrases: state.phrases(), @@ -24,7 +26,7 @@ impl<'a, T: HasPhraseList> From<&'a T> for PhraseListView<'a> { impl<'a> Content for PhraseListView<'a> { type Engine = Tui; fn content (&self) -> impl Widget { - let Self { focused, entered, phrases, index, mode } = self; + let Self { title, focused, entered, phrases, index, mode } = self; let content = Stack::down(move|add|match mode { Some(PhrasesMode::Import(_, ref browser)) => { add(browser) @@ -66,7 +68,7 @@ impl<'a> Content for PhraseListView<'a> { let border = Lozenge(Style::default().bg(Color::Rgb(40, 50, 30)).fg(border_color)); let content = content.fill_xy().bg(Color::Rgb(28, 35, 25)).border(border); let title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)}; - let upper_left = format!("[{}] Phrases", if *entered {"■"} else {" "}); + let upper_left = format!("[{}] {title}", if *entered {"■"} else {" "}); let upper_right = format!("({})", phrases.len()); lay!( content, diff --git a/crates/tek_tui/src/tui_view_phrase_selector.rs b/crates/tek_tui/src/tui_view_phrase_selector.rs new file mode 100644 index 00000000..4f420151 --- /dev/null +++ b/crates/tek_tui/src/tui_view_phrase_selector.rs @@ -0,0 +1,56 @@ +use crate::*; + +pub struct PhraseSelector<'a> { + pub(crate) title: &'static str, + pub(crate) phrase: &'a Option<(Instant, Option>>)>, + pub(crate) focused: bool, + pub(crate) entered: bool, +} + +impl<'a> PhraseSelector<'a> { + pub fn play_phrase (state: &'a T) -> Self { + Self { + title: "Now:", + phrase: state.play_phrase(), + focused: false, + entered: false, + } + } + pub fn next_phrase (state: &'a T) -> Self { + Self { + title: "Next:", + phrase: state.next_phrase(), + focused: false, + entered: false, + } + } +} + +// TODO: Display phrases always in order of appearance +impl<'a> Content for PhraseSelector<'a> { + type Engine = Tui; + fn content (&self) -> impl Widget { + let Self { title, phrase, focused, entered } = self; + let content = 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 = length.align_e().fill_x(); + let row1 = lay!(format!(" ").align_w().fill_x(), length).fill_x(); + let row2 = format!(" {name}"); + let row2 = TuiStyle::bold(row2, true); + add(&col!(row1, row2).fill_x().bg(color.base.rgb))?; + } + Ok(()) + }); + 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 content = content.fill_xy().bg(Color::Rgb(28, 35, 25)).border(border); + let title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)}; + let upper_left = format!("[{}] {title}", if *entered {"■"} else {" "}); + lay!( + content, + TuiStyle::fg(upper_left.to_string(), title_color).push_x(1).align_nw().fill_xy(), + ) + } +} diff --git a/crates/tek_tui/src/tui_view_sequencer.rs b/crates/tek_tui/src/tui_view_sequencer.rs index 5473217e..20886bb8 100644 --- a/crates/tek_tui/src/tui_view_sequencer.rs +++ b/crates/tek_tui/src/tui_view_sequencer.rs @@ -3,19 +3,27 @@ use crate::*; impl Content for SequencerTui { type Engine = Tui; fn content (&self) -> impl Widget { - SequencerStatusBar::with(self, col!( + lay!(self.size, SequencerStatusBar::with(self, col!( TransportView::from(self), Split::right(20, - PhraseListView::from(self), + col_up!( + PhraseSelector::play_phrase(&self.player).fixed_y(4), + PhraseSelector::next_phrase(&self.player).fixed_y(4), + PhraseListView::from(self), + ), PhraseView::from(self), ).min_y(20) - )) + ))) } } impl Content for SequencerStatusBar { type Engine = Tui; fn content (&self) -> impl Widget { - widget(&self.cpu).fg(Color::Rgb(255,128,0)).align_se().fill_x() + row!( + widget(&self.cpu).fg(Color::Rgb(255,128,0)), + widget(&self.sr).fg(Color::Rgb(255,128,0)), + widget(&self.size).fg(Color::Rgb(255,128,0)), + ).align_se().fill_x() } }