diff --git a/CHANGELOG.md b/CHANGELOG.md index 507f2c333..9534b3061 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ You can find its changes [documented below](#082---2023-01-27). ### Added +- `foreground`, `set_foreground`, and `clear_foreground` methods to `Container` and `WidgetExt::foreground` method for convenience. ([#2346] by [@giannissc]) + ### Changed ### Deprecated @@ -760,6 +762,7 @@ Last release without a changelog :( [@liias]: https://github.com/liias [@lzhoucs]: https://github.com/lzhoucs [@ratmice]: https://github.com/ratmice +[@giannissc]: https://github.com/giannissc [#599]: https://github.com/linebender/druid/pull/599 [#611]: https://github.com/linebender/druid/pull/611 @@ -1194,6 +1197,7 @@ Last release without a changelog :( [#2340]: https://github.com/linebender/druid/pull/2340 [#2343]: https://github.com/linebender/druid/pull/2343 [#2345]: https://github.com/linebender/druid/pull/2345 +[#2346]: https://github.com/linebender/druid/pull/2346 [#2347]: https://github.com/linebender/druid/pull/2347 [#2348]: https://github.com/linebender/druid/pull/2348 [#2351]: https://github.com/linebender/druid/pull/2351 diff --git a/druid/src/widget/container.rs b/druid/src/widget/container.rs index 36acd1705..20573af69 100644 --- a/druid/src/widget/container.rs +++ b/druid/src/widget/container.rs @@ -30,6 +30,7 @@ struct BorderStyle { /// A widget that provides simple visual styling options to a child. pub struct Container { background: Option>, + foreground: Option>, border: Option, corner_radius: KeyOrValue, @@ -41,6 +42,7 @@ impl Container { pub fn new(child: impl Widget + 'static) -> Self { Self { background: None, + foreground: None, border: None, corner_radius: 0.0.into(), child: WidgetPod::new(child).boxed(), @@ -77,6 +79,36 @@ impl Container { self.background = None; } + /// Builder-style method for setting the foreground for this widget. + /// + /// This can be passed anything which can be represented by a [`BackgroundBrush`]; + /// notably, it can be any [`Color`], a [`Key`] resolvable in the [`Env`], + /// any gradient, or a fully custom [`Painter`] widget. + /// + /// [`Key`]: crate::Key + /// [`Painter`]: super::Painter + pub fn foreground(mut self, brush: impl Into>) -> Self { + self.set_foreground(brush); + self + } + + /// Set the foreground for this widget. + /// + /// This can be passed anything which can be represented by a [`BackgroundBrush`]; + /// notably, it can be any [`Color`], a [`Key`] resolvable in the [`Env`], + /// any gradient, or a fully custom [`Painter`] widget. + /// + /// [`Key`]: crate::Key + /// [`Painter`]: super::Painter + pub fn set_foreground(&mut self, brush: impl Into>) { + self.foreground = Some(brush.into()); + } + + /// Clears foreground. + pub fn clear_foreground(&mut self) { + self.foreground = None; + } + /// Builder-style method for painting a border around the widget with a color and width. /// /// Arguments can be either concrete values, or a [`Key`] of the respective @@ -130,6 +162,11 @@ impl Container { self.background.is_some() } + #[cfg(test)] + pub(crate) fn foreground_is_some(&self) -> bool { + self.foreground.is_some() + } + #[cfg(test)] pub(crate) fn border_is_some(&self) -> bool { self.border.is_some() @@ -158,6 +195,11 @@ impl Widget for Container { brush.update(ctx, old_data, data, env); }); } + if let Some(brush) = self.foreground.as_mut() { + trace_span!("update foreground").in_scope(|| { + brush.update(ctx, old_data, data, env); + }); + } if let Some(border) = &self.border { if ctx.env_key_changed(&border.width) { ctx.request_layout(); @@ -228,6 +270,17 @@ impl Widget for Container { }; self.child.paint(ctx, data, env); + + if let Some(foreground) = self.foreground.as_mut() { + let panel = ctx.size().to_rounded_rect(corner_radius); + + trace_span!("paint foreground").in_scope(|| { + ctx.with_save(|ctx| { + ctx.clip(panel); + foreground.paint(ctx, data, env); + }); + }); + } } fn debug_state(&self, data: &T) -> DebugState { diff --git a/druid/src/widget/widget_ext.rs b/druid/src/widget/widget_ext.rs index 5d96de2d6..0fcb23a7a 100644 --- a/druid/src/widget/widget_ext.rs +++ b/druid/src/widget/widget_ext.rs @@ -108,13 +108,20 @@ pub trait WidgetExt: Widget + Sized + 'static { SizedBox::new(self).expand_height() } - /// Wrap this widget in a [`Container`] with the provided `background`. + /// Wrap this widget in a [`Container`] with the provided background `brush`. /// /// See [`Container::background`] for more information. fn background(self, brush: impl Into>) -> Container { Container::new(self).background(brush) } + /// Wrap this widget in a [`Container`] with the provided foreground `brush`. + /// + /// See [`Container::foreground`] for more information. + fn foreground(self, brush: impl Into>) -> Container { + Container::new(self).foreground(brush) + } + /// Wrap this widget in a [`Container`] with the given border. /// /// Arguments can be either concrete values, or a [`Key`] of the respective @@ -302,17 +309,21 @@ mod tests { // this should be Container>> let widget = Slider::new() .background(Color::BLACK) + .foreground(Color::WHITE) .align_left() .border(Color::BLACK, 1.0); assert!(widget.border_is_some()); assert!(!widget.background_is_some()); + assert!(!widget.foreground_is_some()); // this should be Container let widget = Slider::new() .background(Color::BLACK) - .border(Color::BLACK, 1.0); + .border(Color::BLACK, 1.0) + .foreground(Color::WHITE); assert!(widget.background_is_some()); assert!(widget.border_is_some()); + assert!(widget.foreground_is_some()); } #[test]