From 1cbf8de4e40f2040b5be09c8731049d4f01bdec5 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Tue, 10 Sep 2024 02:01:19 +0300 Subject: [PATCH] wip: closure-based collections --- crates/tek_core/src/engine/collect.rs | 14 +++++++ crates/tek_core/src/tui/tui_layout.rs | 28 ++++++++++++++ crates/tek_sequencer/src/transport_view.rs | 45 +++++----------------- crates/tek_test/src/main.rs | 41 ++++++++++---------- 4 files changed, 72 insertions(+), 56 deletions(-) diff --git a/crates/tek_core/src/engine/collect.rs b/crates/tek_core/src/engine/collect.rs index 7da4d05d..b831cfbb 100644 --- a/crates/tek_core/src/engine/collect.rs +++ b/crates/tek_core/src/engine/collect.rs @@ -54,6 +54,20 @@ impl<'a, E: Engine> Collect<'a, E> for Collection<'a, E> { pub struct Layers<'a, E: Engine, const N: usize>(pub [&'a dyn Widget;N]); +pub struct Layers2< + E: Engine, + F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> +>(pub F, PhantomData); + +impl< + E: Engine, + F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> +> Layers2 { + pub fn new (build: F) -> Self { + Self(build, Default::default()) + } +} + // this actually works, except for the type inference //pub struct Layers<'a, E: Engine + 'a, I: std::iter::IntoIterator>>( //pub &'a I diff --git a/crates/tek_core/src/tui/tui_layout.rs b/crates/tek_core/src/tui/tui_layout.rs index 98164271..62937def 100644 --- a/crates/tek_core/src/tui/tui_layout.rs +++ b/crates/tek_core/src/tui/tui_layout.rs @@ -79,6 +79,34 @@ impl<'a, const N: usize> Widget for Layers<'a, Tui, N> { } } +impl Widget for Layers2 +where + F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> +{ + type Engine = Tui; + fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { + let [x, y, ..] = area; + let mut w = 0; + let mut h = 0; + (self.0)(&mut |layer| { + if let Some(layer_area) = layer.layout(area)? { + w = w.max(layer_area.w()); + h = h.max(layer_area.h()); + } + Ok(()) + })?; + Ok(Some([x, y, w, h])) + } + fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> { + self.layout(to.area())? + .map(|area|(self.0)(&mut |layer| { + layer.render(to.with_rect(area))?; + Ok(()) + }).map(|_|area)) + .transpose() + } +} + impl> Widget for Align { type Engine = Tui; fn layout (&self, outer_area: [u16;4]) -> Perhaps<[u16;4]> { diff --git a/crates/tek_sequencer/src/transport_view.rs b/crates/tek_sequencer/src/transport_view.rs index 90343611..79a8a0bd 100644 --- a/crates/tek_sequencer/src/transport_view.rs +++ b/crates/tek_sequencer/src/transport_view.rs @@ -14,51 +14,24 @@ impl Content for TransportToolbar { } } -impl Widget for TransportPlayPauseButton { +impl Content for TransportPlayPauseButton { type Engine = Tui; - fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { - area.expect_min(10, 1)?; - Ok(Some([area.x(), area.y(), 10, 1])) - } - fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> { - let Self { value, focused, .. } = &self; - Layers([ - &focused.then_some(CORNERS), - &Inset::W(1, Styled(match value { + fn content (&self) -> impl Widget { + Layers2::new(|add|{ + //add(&self.focused.then_some(CORNERS))?; + add(&Styled(match self.value { Some(TransportState::Stopped) => Some(GRAY_DIM.bold()), Some(TransportState::Starting) => Some(GRAY_NOT_DIM_BOLD), Some(TransportState::Rolling) => Some(WHITE_NOT_DIM_BOLD), _ => unreachable!(), - }, match value { + }, match self.value { Some(TransportState::Rolling) => "▶ PLAYING", Some(TransportState::Starting) => "READY ...", Some(TransportState::Stopped) => "⏹ STOPPED", _ => unreachable!(), - })) - ]).render(to) - //let area = to.area(); - //let [x, y, ..] = area; - //let Self { value, focused } = &self; - //let style = Some(match value { - //Some(TransportState::Stopped) => GRAY_DIM.bold(), - //Some(TransportState::Starting) => GRAY_NOT_DIM_BOLD, - //Some(TransportState::Rolling) => WHITE_NOT_DIM_BOLD, - //_ => unreachable!(), - //}); - //let label = match value { - //Some(TransportState::Rolling) => "▶ PLAYING", - //Some(TransportState::Starting) => "READY ...", - //Some(TransportState::Stopped) => "⏹ STOPPED", - //_ => unreachable!(), - //}; - //let area = to.blit(&label, x + 1, y, style)?.unwrap(); - //let area = [area.x(), area.y(), area.w() + 1, area.h() + 1]; - //if *focused { - //let area = [area.x() - 1, area.y(), area.w() - 1, area.h() ]; - //CORNERS.draw(to)?; - //to.fill_bg(area, COLOR_BG1); - //} - //Ok(Some(area)) + }))?; + Ok(()) + }) } } diff --git a/crates/tek_test/src/main.rs b/crates/tek_test/src/main.rs index e4baf6ac..5b7c5127 100644 --- a/crates/tek_test/src/main.rs +++ b/crates/tek_test/src/main.rs @@ -13,32 +13,33 @@ pub struct Demo { impl Demo { fn new () -> Self { - let mut items: Vec>> = vec![]; - items.push(Box::new(tek_sequencer::TransportPlayPauseButton { - _engine: Default::default(), - value: Some(TransportState::Stopped), - focused: true - })); - items.push(Box::new(tek_sequencer::TransportPlayPauseButton { - _engine: Default::default(), - value: Some(TransportState::Rolling), - focused: false - })); - Self { index: 0, items } + Self { + index: 0, + items: vec![ + Box::new(tek_sequencer::TransportPlayPauseButton { + _engine: Default::default(), + value: Some(TransportState::Stopped), + focused: true + }), + Box::new(tek_sequencer::TransportPlayPauseButton { + _engine: Default::default(), + value: Some(TransportState::Rolling), + focused: false + }), + ] + } } } impl Content for Demo { type Engine = Tui; fn content (&self) -> impl Widget { - Align::Center(Layers([ - &Outset::WH(2, 1, FillBg(Color::Rgb(0,128,128))), - &self.items[self.index] - //&Layers(&[ - //&"---------", - //&Align::Center("...") - //]) - ])) + Layers2::new(|add|{ + add(&Align::Center("FOOBAR"))?; + add(&Align::Center("FOO"))?; + Ok(()) + }) + //Align::Center(&self.items[self.index] as &dyn Widget) } }