diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d6c7e3b2..5556755f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he - **core**: The `Render::dirty_phase` method has been added to allow widgets to mark only the paint phase as dirty when it is modified. (#689 @M-Adoo) - **core**: Supports `Provider` to dirty the tree if it's a state writer. (#689 @M-Adoo) +- **core**: Added the built-in field `providers` to provide data to its descendants. (#pr @M-Adoo) - **macros**: Added the `part_reader!` macro to generate a partial reader from a reference of a reader. (#688 @M-Adoo) - **macros**: The `simple_declare` now supports the `stateless` meta attribute, `#[simple_declare(stateless)]`. (#688 @M-Adoo) diff --git a/core/src/builtin_widgets.rs b/core/src/builtin_widgets.rs index 8ef34bb49..cc333e588 100644 --- a/core/src/builtin_widgets.rs +++ b/core/src/builtin_widgets.rs @@ -138,8 +138,9 @@ pub struct FatObj { painting_style: Option>, text_style: Option>, keep_alive: Option>, - tooltips: Option>, keep_alive_unsubscribe_handle: Option>, + tooltips: Option>, + providers: Option>, } /// Create a function widget that uses an empty `FatObj` as the host object. @@ -187,6 +188,7 @@ impl FatObj { tooltips: self.tooltips, keep_alive: self.keep_alive, keep_alive_unsubscribe_handle: self.keep_alive_unsubscribe_handle, + providers: self.providers, } } @@ -770,7 +772,7 @@ impl FatObj { self.declare_builtin_init(v, Self::get_fitted_box_widget, |m, v| m.box_fit = v) } - /// Initializes the painting style of this widget. + /// Provide a painting style to this widget. pub fn painting_style(self, v: impl DeclareInto) -> Self { self.declare_builtin_init(v, Self::get_painting_style_widget, |m, v| m.painting_style = v) } @@ -923,6 +925,16 @@ impl FatObj { self } + /// Initializes the providers of the widget. + pub fn providers(mut self, providers: impl Into>) -> Self { + if let Some(vec) = self.providers.as_mut() { + vec.extend(providers.into()); + } else { + self.providers = Some(providers.into()); + } + self + } + fn declare_builtin_init( mut self, init: impl DeclareInto, get_builtin: impl FnOnce(&mut Self) -> &State, set_value: fn(&mut B, V), @@ -964,7 +976,7 @@ where } impl<'a> FatObj> { - fn compose(self) -> Widget<'a> { + fn compose(mut self) -> Widget<'a> { macro_rules! compose_builtin_widgets { ($host: ident + [$($field: ident),*]) => { $( @@ -975,6 +987,19 @@ impl<'a> FatObj> { }; } let mut host = self.host; + if let Some(painting_style) = self.painting_style { + self + .providers + .get_or_insert_default() + .push(PaintingStyleWidget::into_provider(painting_style)); + } + if let Some(text_style) = self.text_style { + self + .providers + .get_or_insert_default() + .push(TextStyleWidget::into_provider(text_style)); + } + compose_builtin_widgets!( host + [ @@ -983,11 +1008,18 @@ impl<'a> FatObj> { fitted_box, foreground, box_decoration, - painting_style, - text_style, scrollable, layout_box, - class, + class + ] + ); + if let Some(providers) = self.providers { + host = Providers::new(providers).with_child(host); + } + + compose_builtin_widgets!( + host + + [ constrained_box, tooltips, margin, diff --git a/core/src/builtin_widgets/painting_style.rs b/core/src/builtin_widgets/painting_style.rs index 31477a276..c0d411514 100644 --- a/core/src/builtin_widgets/painting_style.rs +++ b/core/src/builtin_widgets/painting_style.rs @@ -17,17 +17,18 @@ impl<'c> ComposeChild<'c> for PaintingStyleWidget { type Child = Widget<'c>; fn compose_child(this: impl StateWriter, child: Self::Child) -> Widget<'c> { - // We need to provide the text style for the children to access. - let provider = match this.try_into_value() { + Providers::new([Self::into_provider(this)]).with_child(child) + } +} + +impl PaintingStyleWidget { + pub fn into_provider(this: impl StateWriter) -> Provider { + match this.try_into_value() { Ok(this) => Provider::new(this.painting_style), Err(this) => Provider::value_of_writer( this.map_writer(|w| PartData::from_ref_mut(&mut w.painting_style)), Some(DirtyPhase::LayoutSubtree), ), - }; - - Providers::new([provider]) - .with_child(child) - .into_widget() + } } } diff --git a/core/src/builtin_widgets/providers.rs b/core/src/builtin_widgets/providers.rs index 664f1026b..ed77742fc 100644 --- a/core/src/builtin_widgets/providers.rs +++ b/core/src/builtin_widgets/providers.rs @@ -141,7 +141,7 @@ pub struct Providers { providers: RefCell>, } -/// Macro used to generate a function widget using `BuildVariants` as the root +/// Macro used to generate a function widget using `Providers` as the root /// widget. #[macro_export] macro_rules! providers { @@ -297,9 +297,12 @@ impl Declare for Providers { } impl ProvidersDeclarer { - pub fn providers(mut self, variants: impl Into>) -> Self { - assert!(self.providers.is_none(), "Providers already initialized"); - self.providers = Some(variants.into()); + pub fn providers(mut self, providers: impl Into>) -> Self { + if let Some(vec) = self.providers.as_mut() { + vec.extend(providers.into()); + } else { + self.providers = Some(providers.into()); + } self } } diff --git a/core/src/builtin_widgets/text_style.rs b/core/src/builtin_widgets/text_style.rs index a77933f02..f6b928eaa 100644 --- a/core/src/builtin_widgets/text_style.rs +++ b/core/src/builtin_widgets/text_style.rs @@ -16,17 +16,18 @@ impl<'c> ComposeChild<'c> for TextStyleWidget { type Child = Widget<'c>; fn compose_child(this: impl StateWriter, child: Self::Child) -> Widget<'c> { - // We need to provide the text style for the children to access. - let provider = match this.try_into_value() { + Providers::new([Self::into_provider(this)]).with_child(child) + } +} + +impl TextStyleWidget { + pub fn into_provider(this: impl StateWriter) -> Provider { + match this.try_into_value() { Ok(this) => Provider::new(this.text_style), Err(this) => Provider::value_of_writer( this.map_writer(|w| PartData::from_ref_mut(&mut w.text_style)), Some(DirtyPhase::LayoutSubtree), ), - }; - - Providers::new([provider]) - .with_child(child) - .into_widget() + } } }