From 60e85c78d04ff0b71ef1944245734c8ff9cba681 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Fri, 10 Nov 2023 15:11:46 -0800 Subject: [PATCH 01/15] Resize exact fix, stack overflow now works --- src/widgets/resize.rs | 17 +++++++++++++---- src/widgets/stack.rs | 26 ++++++++++++-------------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/widgets/resize.rs b/src/widgets/resize.rs index af7b5ae..7dc81e3 100644 --- a/src/widgets/resize.rs +++ b/src/widgets/resize.rs @@ -1,3 +1,4 @@ +use kludgine::figures::units::UPx; use kludgine::figures::{Fraction, IntoSigned, IntoUnsigned, Rect, ScreenScale, Size}; use crate::context::{AsEventContext, LayoutContext}; @@ -81,7 +82,12 @@ impl WrapperWidget for Resize { ); context.for_other(&child).layout(available_space) }; - Rect::from(size.into_signed()) + Size::::new( + self.width.clamp(size.width, context.gfx.scale()), + self.height.clamp(size.height, context.gfx.scale()), + ) + .into_signed() + .into() } } @@ -92,8 +98,11 @@ fn override_constraint( ) -> ConstraintLimit { match constraint { ConstraintLimit::Known(size) => ConstraintLimit::Known(range.clamp(size, scale)), - ConstraintLimit::ClippedAfter(clipped_after) => { - ConstraintLimit::ClippedAfter(range.clamp(clipped_after, scale)) - } + ConstraintLimit::ClippedAfter(clipped_after) => match (range.minimum(), range.maximum()) { + (Some(min), Some(max)) if min == max => { + ConstraintLimit::Known(min.into_px(scale).into_unsigned()) + } + _ => ConstraintLimit::ClippedAfter(range.clamp(clipped_after, scale)), + }, } } diff --git a/src/widgets/stack.rs b/src/widgets/stack.rs index 0dc1d51..e3a9e84 100644 --- a/src/widgets/stack.rs +++ b/src/widgets/stack.rs @@ -403,18 +403,14 @@ impl Layout { // Measure the children that fit their content for &id in &self.measured { let index = self.children.index_of_id(id).expect("child not found"); - if remaining > 0 { - let (measured, _) = self.orientation.split_size(measure( - index, - self.orientation - .make_size(ConstraintLimit::ClippedAfter(remaining), other_constraint), - false, - )); - self.layouts[index].size = measured; - remaining = remaining.saturating_sub(measured); - } else { - self.layouts[index].size = UPx(0); - } + let (measured, _) = self.orientation.split_size(measure( + index, + self.orientation + .make_size(ConstraintLimit::ClippedAfter(remaining), other_constraint), + false, + )); + self.layouts[index].size = measured; + remaining = remaining.saturating_sub(measured); } // Measure the weighted children within the remaining space @@ -449,15 +445,17 @@ impl Layout { offset += self.layouts[index].size; let (_, measured) = self.orientation.split_size(measure( index, - self.orientation.make_size( + dbg!(self.orientation.make_size( ConstraintLimit::Known(self.layouts[index].size.into_px(scale).into_unsigned()), other_constraint, - ), + )), true, )); self.other = self.other.max(measured); } + println!("Total height: {offset}"); + self.other = match other_constraint { ConstraintLimit::Known(max) => self.other.max(max), ConstraintLimit::ClippedAfter(clip_limit) => self.other.min(clip_limit), From 244be0cf064ed0ec67f7ad03b7ef9c7805ebd0f4 Mon Sep 17 00:00:00 2001 From: Roland Fredenhagen Date: Sat, 11 Nov 2023 00:31:03 +0100 Subject: [PATCH 02/15] Support transparent windows --- Cargo.lock | 2 +- src/window.rs | 33 ++++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d49972b..0c43f53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -880,7 +880,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "kludgine" version = "0.1.0" -source = "git+https://github.com/khonsulabs/kludgine#a88961b726101ef9bb46bdae4737308d2dcb12a0" +source = "git+https://github.com/khonsulabs/kludgine#0239b35d765e37fbcc74a4f6dcd319622d221aa9" dependencies = [ "ahash", "alot", diff --git a/src/window.rs b/src/window.rs index 520b97a..3cbdaca 100644 --- a/src/window.rs +++ b/src/window.rs @@ -19,6 +19,7 @@ use kludgine::app::WindowBehavior as _; use kludgine::figures::units::{Px, UPx}; use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size}; use kludgine::render::Drawing; +use kludgine::wgpu::CompositeAlphaMode; use kludgine::Kludgine; use tracing::Level; @@ -201,6 +202,7 @@ where GooeyWindow::::run_with(AssertUnwindSafe(sealed::Context { user: self.context, settings: RefCell::new(sealed::WindowSettings { + transparent: self.attributes.transparent, attributes: Some(self.attributes), occluded: self.occluded, focused: self.focused, @@ -258,6 +260,7 @@ struct GooeyWindow { max_inner_size: Option>, theme: Option>, current_theme: ThemePair, + transparent: bool, } impl GooeyWindow @@ -405,6 +408,7 @@ where .theme .take() .expect("theme always present"); + let transparent = context.settings.borrow().transparent; let mut behavior = T::initialize( &mut RunningWindow::new(window, &focused, &occluded), context.user, @@ -435,6 +439,7 @@ where max_inner_size: None, current_theme, theme, + transparent, } } @@ -473,8 +478,11 @@ where let mut layout_context = LayoutContext::new(&mut context); let window_size = layout_context.gfx.size(); - let background_color = layout_context.theme().surface.color; - layout_context.graphics.gfx.fill(background_color); + if !self.transparent { + let background_color = layout_context.theme().surface.color; + layout_context.graphics.gfx.fill(background_color); + } + let actual_size = layout_context.layout(if is_expanded { Size::new( ConstraintLimit::Known(window_size.width), @@ -577,9 +585,23 @@ where // wgpu::Limits::downlevel_webgl2_defaults().using_resolution(adapter_limits) // } - // fn clear_color() -> Option { - // Some(kludgine::Color::BLACK) - // } + fn clear_color(&self) -> Option { + Some(if self.transparent { + kludgine::Color::CLEAR_BLACK + } else { + kludgine::Color::BLACK + }) + } + + fn composite_alpha_mode(&self, supported_modes: &[CompositeAlphaMode]) -> CompositeAlphaMode { + if dbg!(self.transparent) + && dbg!(supported_modes).contains(&CompositeAlphaMode::PreMultiplied) + { + CompositeAlphaMode::PreMultiplied + } else { + CompositeAlphaMode::Auto + } + } // fn focus_changed(&mut self, window: kludgine::app::Window<'_, ()>) {} @@ -967,6 +989,7 @@ pub(crate) mod sealed { pub occluded: Option>, pub focused: Option>, pub theme: Option>, + pub transparent: bool, } pub enum WindowCommand { From 95c1f2a01a69e85aa922c8072d4a8f1e687ccaf9 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Fri, 10 Nov 2023 15:46:38 -0800 Subject: [PATCH 03/15] Fixing DimensionRange for ..= --- src/styles.rs | 2 +- src/widgets/stack.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/styles.rs b/src/styles.rs index 346a0db..1151866 100644 --- a/src/styles.rs +++ b/src/styles.rs @@ -458,7 +458,7 @@ where fn from(value: RangeInclusive) -> Self { Self { start: Bound::Included(value.start().clone().into()), - end: Bound::Excluded(value.end().clone().into()), + end: Bound::Included(value.end().clone().into()), } } } diff --git a/src/widgets/stack.rs b/src/widgets/stack.rs index e3a9e84..ba39154 100644 --- a/src/widgets/stack.rs +++ b/src/widgets/stack.rs @@ -445,10 +445,10 @@ impl Layout { offset += self.layouts[index].size; let (_, measured) = self.orientation.split_size(measure( index, - dbg!(self.orientation.make_size( + self.orientation.make_size( ConstraintLimit::Known(self.layouts[index].size.into_px(scale).into_unsigned()), other_constraint, - )), + ), true, )); self.other = self.other.max(measured); From e471cb0ea5bf72c26dbfa659f5b1a1d65821fc8c Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Fri, 10 Nov 2023 15:55:23 -0800 Subject: [PATCH 04/15] Removing debug statements --- src/widgets/stack.rs | 2 -- src/window.rs | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/widgets/stack.rs b/src/widgets/stack.rs index ba39154..7f38052 100644 --- a/src/widgets/stack.rs +++ b/src/widgets/stack.rs @@ -454,8 +454,6 @@ impl Layout { self.other = self.other.max(measured); } - println!("Total height: {offset}"); - self.other = match other_constraint { ConstraintLimit::Known(max) => self.other.max(max), ConstraintLimit::ClippedAfter(clip_limit) => self.other.min(clip_limit), diff --git a/src/window.rs b/src/window.rs index 3cbdaca..4128090 100644 --- a/src/window.rs +++ b/src/window.rs @@ -594,9 +594,7 @@ where } fn composite_alpha_mode(&self, supported_modes: &[CompositeAlphaMode]) -> CompositeAlphaMode { - if dbg!(self.transparent) - && dbg!(supported_modes).contains(&CompositeAlphaMode::PreMultiplied) - { + if self.transparent && supported_modes.contains(&CompositeAlphaMode::PreMultiplied) { CompositeAlphaMode::PreMultiplied } else { CompositeAlphaMode::Auto From 81f6f8c4d3b439dccd8a54810d20ebe79bf3473c Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Fri, 10 Nov 2023 18:11:31 -0800 Subject: [PATCH 05/15] Theme example reacts --- Cargo.lock | 2 +- examples/theme.rs | 243 ++++++++++++++++++++++++++++++------------- src/context.rs | 12 +++ src/styles.rs | 39 ------- src/widget.rs | 4 +- src/widgets/stack.rs | 2 +- 6 files changed, 185 insertions(+), 117 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c43f53..1b73ab4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,7 +105,7 @@ dependencies = [ [[package]] name = "appit" version = "0.1.0" -source = "git+https://github.com/khonsulabs/appit#043bfe2c78524d6a06ed159289ea1cd7a62b0fec" +source = "git+https://github.com/khonsulabs/appit#5ed0d923ded6520950d14b3b869cbcac89452f5c" dependencies = [ "raw-window-handle 0.5.2", "winit", diff --git a/examples/theme.rs b/examples/theme.rs index 29bcbb1..7b52618 100644 --- a/examples/theme.rs +++ b/examples/theme.rs @@ -1,30 +1,97 @@ use gooey::styles::components::TextColor; -use gooey::styles::{ColorTheme, FixedTheme, InverseTheme, SurfaceTheme, Theme, ThemePair}; +use gooey::styles::{ColorSource, ColorTheme, FixedTheme, SurfaceTheme, Theme, ThemePair}; +use gooey::value::{Dynamic, MapEach}; use gooey::widget::MakeWidget; use gooey::widgets::label::LabelBackground; -use gooey::widgets::{Label, Stack}; +use gooey::widgets::{Input, Label, Stack}; use gooey::Run; use kludgine::Color; +const PRIMARY_HUE: f32 = -120.; +const SECONDARY_HUE: f32 = 0.; +const TERTIARY_HUE: f32 = -30.; +const ERROR_HUE: f32 = 30.; + fn main() -> gooey::Result { - let default_theme = ThemePair::default(); - Stack::columns( - theme(default_theme.dark, "Dark") - .and(theme(default_theme.light, "Light")) - .and(fixed_themes( - default_theme.primary_fixed, - default_theme.secondary_fixed, - default_theme.tertiary_fixed, - )), + let (primary, primary_editor) = color_editor(PRIMARY_HUE, 0.8, "Primary"); + let (secondary, secondary_editor) = color_editor(SECONDARY_HUE, 0.3, "Secondary"); + let (tertiary, tertiary_editor) = color_editor(TERTIARY_HUE, 0.3, "Tertiary"); + let (error, error_editor) = color_editor(ERROR_HUE, 0.8, "Error"); + let (neutral, neutral_editor) = color_editor(PRIMARY_HUE, 0.001, "Neutral"); + let (neutral_variant, neutral_variant_editor) = + color_editor(PRIMARY_HUE, 0.001, "Neutral Variant"); + + let default_theme = ( + &primary, + &secondary, + &tertiary, + &error, + &neutral, + &neutral_variant, + ) + .map_each( + |(primary, secondary, tertiary, error, neutral, neutral_variant)| { + ThemePair::from_sources( + *primary, + *secondary, + *tertiary, + *error, + *neutral, + *neutral_variant, + ) + }, + ); + + Stack::rows( + Stack::columns( + primary_editor + .and(secondary_editor) + .and(tertiary_editor) + .and(error_editor) + .and(neutral_editor) + .and(neutral_variant_editor), + ) + .and(Stack::columns( + theme(default_theme.map_each(|theme| theme.dark), "Dark") + .and(theme(default_theme.map_each(|theme| theme.light), "Light")) + .and(fixed_themes( + default_theme.map_each(|theme| theme.primary_fixed), + default_theme.map_each(|theme| theme.secondary_fixed), + default_theme.map_each(|theme| theme.tertiary_fixed), + )), + )), ) .expand() .run() } +fn color_editor( + initial_hue: f32, + initial_saturation: f32, + label: &str, +) -> (Dynamic, impl MakeWidget) { + let hue_text = Dynamic::new(initial_hue.to_string()); + let hue = hue_text.map_each(|hue| hue.parse::().unwrap_or_default()); + let saturation_text = Dynamic::new(initial_saturation.to_string()); + let saturation = saturation_text.map_each(|sat| sat.parse::().unwrap_or_default()); + let color = + (&hue, &saturation).map_each(|(hue, saturation)| ColorSource::new(*hue, *saturation)); + + ( + color, + Stack::rows( + Label::new(label) + .and(Input::new(hue_text)) + .and(Input::new(saturation_text)), + ) + .expand(), + ) +} + fn fixed_themes( - primary: FixedTheme, - secondary: FixedTheme, - tertiary: FixedTheme, + primary: Dynamic, + secondary: Dynamic, + tertiary: Dynamic, ) -> impl MakeWidget { Stack::rows( Label::new("Fixed") @@ -35,85 +102,118 @@ fn fixed_themes( .expand() } -fn fixed_theme(theme: FixedTheme, label: &str) -> impl MakeWidget { +fn fixed_theme(theme: Dynamic, label: &str) -> impl MakeWidget { + let color = theme.map_each(|theme| theme.color); + let on_color = theme.map_each(|theme| theme.on_color); Stack::columns( - swatch(theme.color, &format!("{label} Fixed"), theme.on_color) + swatch(color.clone(), &format!("{label} Fixed"), on_color.clone()) .and(swatch( - theme.dim_color, + theme.map_each(|theme| theme.dim_color), &format!("Dim {label}"), - theme.on_color, + on_color.clone(), )) .and(swatch( - theme.on_color, + on_color.clone(), &format!("On {label} Fixed"), - theme.color, + color.clone(), )) .and(swatch( - theme.on_color_variant, + theme.map_each(|theme| theme.on_color_variant), &format!("Variant On {label} Fixed"), - theme.color, + color, )), ) .expand() } -fn theme(theme: Theme, label: &str) -> impl MakeWidget { +fn theme(theme: Dynamic, label: &str) -> impl MakeWidget { Stack::rows( Label::new(label) .and( Stack::columns( - color_theme(theme.primary, "Primary") - .and(color_theme(theme.secondary, "Secondary")) - .and(color_theme(theme.tertiary, "Tertiary")) - .and(color_theme(theme.error, "Error")), + color_theme(theme.map_each(|theme| theme.primary), "Primary") + .and(color_theme( + theme.map_each(|theme| theme.secondary), + "Secondary", + )) + .and(color_theme( + theme.map_each(|theme| theme.tertiary), + "Tertiary", + )) + .and(color_theme(theme.map_each(|theme| theme.error), "Error")), ) .expand(), ) - .and(surface_and_inverse_themes(theme.surface, theme.inverse)), + .and(surface_theme(theme.map_each(|theme| theme.surface))), ) .expand() } -fn surface_and_inverse_themes(theme: SurfaceTheme, inverse: InverseTheme) -> impl MakeWidget { +fn surface_theme(theme: Dynamic) -> impl MakeWidget { + let color = theme.map_each(|theme| theme.color); + let on_color = theme.map_each(|theme| theme.on_color); Stack::rows( Stack::columns( - swatch(theme.color, "Surface", theme.on_color) - .and(swatch(theme.dim_color, "Dim Surface", theme.on_color)) - .and(swatch(theme.bright_color, "Bright Surface", theme.on_color)), + swatch(color.clone(), "Surface", on_color.clone()) + .and(swatch( + theme.map_each(|theme| theme.dim_color), + "Dim Surface", + on_color.clone(), + )) + .and(swatch( + theme.map_each(|theme| theme.bright_color), + "Bright Surface", + on_color.clone(), + )), ) .expand() - .and(inverse_theme(inverse)) .and( Stack::columns( - swatch(theme.lowest_container, "Lowest Container", theme.on_color) - .and(swatch(theme.low_container, "Low Container", theme.on_color)) - .and(swatch(theme.container, "Container", theme.on_color)) - .and(swatch( - theme.high_container, - "High Container", - theme.on_color, - )) - .and(swatch( - theme.highest_container, - "Highest Container", - theme.on_color, - )), + swatch( + theme.map_each(|theme| theme.lowest_container), + "Lowest Container", + on_color.clone(), + ) + .and(swatch( + theme.map_each(|theme| theme.low_container), + "Low Container", + on_color.clone(), + )) + .and(swatch( + theme.map_each(|theme| theme.container), + "Container", + on_color.clone(), + )) + .and(swatch( + theme.map_each(|theme| theme.high_container), + "High Container", + on_color.clone(), + )) + .and(swatch( + theme.map_each(|theme| theme.highest_container), + "Highest Container", + on_color.clone(), + )), ) .expand(), ) .and( Stack::columns( - swatch(theme.on_color, "On Surface", theme.color) + swatch(on_color.clone(), "On Surface", color.clone()) .and(swatch( - theme.on_color_variant, + theme.map_each(|theme| theme.on_color_variant), "On Color Variant", - theme.color, + color.clone(), )) - .and(swatch(theme.outline, "Outline", theme.color)) .and(swatch( - theme.outline_variant, + theme.map_each(|theme| theme.outline), + "Outline", + color.clone(), + )) + .and(swatch( + theme.map_each(|theme| theme.outline_variant), "Outline Variant", - theme.color, + color, )), ) .expand(), @@ -122,38 +222,33 @@ fn surface_and_inverse_themes(theme: SurfaceTheme, inverse: InverseTheme) -> imp .expand() } -fn inverse_theme(theme: InverseTheme) -> impl MakeWidget { - Stack::columns( - swatch(theme.surface, "Inverse Surface", theme.on_surface) - .and(swatch( - theme.on_surface, - "On Inverse Surface", - theme.surface, - )) - .and(swatch(theme.primary, "Inverse Primary", theme.surface)), - ) - .expand() -} - -fn color_theme(theme: ColorTheme, label: &str) -> impl MakeWidget { +fn color_theme(theme: Dynamic, label: &str) -> impl MakeWidget { + let color = theme.map_each(|theme| theme.color); + let on_color = theme.map_each(|theme| theme.on_color); + let container = theme.map_each(|theme| theme.container); + let on_container = theme.map_each(|theme| theme.on_container); Stack::rows( - swatch(theme.color, label, theme.on_color) - .and(swatch(theme.on_color, &format!("On {label}"), theme.color)) + swatch(color.clone(), label, on_color.clone()) .and(swatch( - theme.container, - &format!("{label} Container"), - theme.on_container, + on_color.clone(), + &format!("On {label}"), + color.clone(), )) .and(swatch( - theme.on_container, + container.clone(), + &format!("{label} Container"), + on_container.clone(), + )) + .and(swatch( + on_container, &format!("On {label} Container"), - theme.container, + container, )), ) .expand() } -fn swatch(background: Color, label: &str, text: Color) -> impl MakeWidget { +fn swatch(background: Dynamic, label: &str, text: Dynamic) -> impl MakeWidget { Label::new(label) .fit_horizontally() .fit_vertically() diff --git a/src/context.rs b/src/context.rs index 594eb0b..fd2add8 100644 --- a/src/context.rs +++ b/src/context.rs @@ -349,6 +349,9 @@ impl<'context, 'window> EventContext<'context, 'window> { /// /// This widget does not need to be focused. pub fn advance_focus(&mut self, direction: VisualOrder) { + // TODO check to see if the current node has an explicit next_focus (or + // if we're going in the opposite direction, previous_focus). + self.pending_state.focus = self.next_focus_after(self.current_node.clone(), direction); } } @@ -930,6 +933,15 @@ impl<'context, 'window> WidgetContext<'context, 'window> { window::Theme::Dark => &self.theme.dark, } } + + /// Returns the opposite theme of [`Self::theme()`]. + #[must_use] + pub fn inverse_theme(&self) -> &Theme { + match self.window.theme() { + window::Theme::Light => &self.theme.dark, + window::Theme::Dark => &self.theme.light, + } + } } pub(crate) struct WindowHandle { diff --git a/src/styles.rs b/src/styles.rs index 1151866..7c1c209 100644 --- a/src/styles.rs +++ b/src/styles.rs @@ -920,9 +920,6 @@ pub struct Theme { /// The theme to color surfaces. pub surface: SurfaceTheme, - - /// A theme of inverse colors to provide high contrast to other elements. - pub inverse: InverseTheme, } impl Theme { @@ -942,7 +939,6 @@ impl Theme { tertiary: ColorTheme::light_from_source(tertiary), error: ColorTheme::light_from_source(error), surface: SurfaceTheme::light_from_sources(neutral, neutral_variant), - inverse: InverseTheme::light_from_sources(primary, neutral), } } @@ -962,7 +958,6 @@ impl Theme { tertiary: ColorTheme::dark_from_source(tertiary), error: ColorTheme::dark_from_source(error), surface: SurfaceTheme::dark_from_sources(neutral, neutral_variant), - inverse: InverseTheme::dark_from_sources(primary, neutral), } } } @@ -1105,40 +1100,6 @@ impl FixedTheme { } } -/// An inverse color theme for displaying highly contrasted elements. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct InverseTheme { - /// An inverse surface color. - pub surface: Color, - /// The default color for content atop an inverted surface. - pub on_surface: Color, - /// The inverted primary color. - pub primary: Color, - // TODO why not inverse for the other colorthemes? -} - -impl InverseTheme { - /// Returns the light-mode, inverse theme for given sources. - #[must_use] - pub fn light_from_sources(primary: ColorSource, surface: ColorSource) -> Self { - Self { - surface: surface.color(30), - on_surface: surface.color(90), - primary: primary.color(80), - } - } - - /// Returns the dark-mode, inverse theme for given sources. - #[must_use] - pub fn dark_from_sources(primary: ColorSource, surface: ColorSource) -> Self { - Self { - surface: surface.color(90), - on_surface: surface.color(10), - primary: primary.color(40), - } - } -} - /// A source for [`Color`]s. /// /// This type is a combination of an [`OklabHue`] and a saturation ranging from diff --git a/src/widget.rs b/src/widget.rs index 9cf564c..0ec309c 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -16,7 +16,7 @@ use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, Size}; use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext}; use crate::styles::components::VisualOrder; -use crate::styles::{Component, NamedComponent, Styles}; +use crate::styles::{IntoComponentValue, NamedComponent, Styles}; use crate::tree::Tree; use crate::value::{IntoValue, Value}; use crate::widgets::{Align, Expand, Scroll, Style}; @@ -456,7 +456,7 @@ pub trait MakeWidget: Sized { } /// Associates a style component with `self`. - fn with(self, name: &impl NamedComponent, component: impl Into) -> Style { + fn with(self, name: &impl NamedComponent, component: impl IntoComponentValue) -> Style { let mut styles = Styles::new(); styles.insert(name, component); Style::new(styles, self) diff --git a/src/widgets/stack.rs b/src/widgets/stack.rs index 7f38052..d47a899 100644 --- a/src/widgets/stack.rs +++ b/src/widgets/stack.rs @@ -89,7 +89,7 @@ impl Stack { if let Some(expand) = guard.downcast_ref::() { let weight = expand.weight; ( - WidgetRef::Unmounted(widget.clone()), + expand.child().clone(), StackDimension::Fractional { weight }, ) } else if let Some((child, size)) = From d844a44b335b4fd044a45662f56d4e5e5eb7ba24 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Fri, 10 Nov 2023 18:15:45 -0800 Subject: [PATCH 06/15] Refactored LabelBackground to WidgetBackground --- examples/theme.rs | 7 +++---- src/context.rs | 5 ++++- src/styles/components.rs | 18 ++++++++++++++++++ src/widgets/label.rs | 30 +++--------------------------- 4 files changed, 28 insertions(+), 32 deletions(-) diff --git a/examples/theme.rs b/examples/theme.rs index 7b52618..2bd8cd5 100644 --- a/examples/theme.rs +++ b/examples/theme.rs @@ -1,8 +1,7 @@ -use gooey::styles::components::TextColor; +use gooey::styles::components::{TextColor, WidgetBackground}; use gooey::styles::{ColorSource, ColorTheme, FixedTheme, SurfaceTheme, Theme, ThemePair}; use gooey::value::{Dynamic, MapEach}; use gooey::widget::MakeWidget; -use gooey::widgets::label::LabelBackground; use gooey::widgets::{Input, Label, Stack}; use gooey::Run; use kludgine::Color; @@ -250,9 +249,9 @@ fn color_theme(theme: Dynamic, label: &str) -> impl MakeWidget { fn swatch(background: Dynamic, label: &str, text: Dynamic) -> impl MakeWidget { Label::new(label) + .with(&TextColor, text) + .with(&WidgetBackground, background) .fit_horizontally() .fit_vertically() - .with(&TextColor, text) - .with(&LabelBackground, background) .expand() } diff --git a/src/context.rs b/src/context.rs index fd2add8..018a6dc 100644 --- a/src/context.rs +++ b/src/context.rs @@ -13,7 +13,7 @@ use kludgine::shapes::{Shape, StrokeOptions}; use kludgine::Kludgine; use crate::graphics::Graphics; -use crate::styles::components::{HighlightColor, VisualOrder}; +use crate::styles::components::{HighlightColor, VisualOrder, WidgetBackground}; use crate::styles::{ComponentDefaultvalue, ComponentDefinition, Styles, Theme, ThemePair}; use crate::value::Dynamic; use crate::widget::{EventHandling, ManagedWidget, WidgetId, WidgetInstance, WidgetRef}; @@ -488,6 +488,9 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, ' "redraw called without set_widget_layout" ); + let background = self.query_style(&WidgetBackground); + self.gfx.fill(background); + self.current_node .tree .note_widget_rendered(self.current_node.id()); diff --git a/src/styles/components.rs b/src/styles/components.rs index 43a33bb..aa8078e 100644 --- a/src/styles/components.rs +++ b/src/styles/components.rs @@ -376,3 +376,21 @@ impl FocusableWidgets { matches!(self, Self::OnlyTextual) } } + +/// A [`Color`] to be used as a highlight color. +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub struct WidgetBackground; + +impl NamedComponent for WidgetBackground { + fn name(&self) -> Cow<'_, ComponentName> { + Cow::Owned(ComponentName::named::("widget_background_color")) + } +} + +impl ComponentDefinition for WidgetBackground { + type ComponentType = Color; + + fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Color { + Color::CLEAR_WHITE + } +} diff --git a/src/widgets/label.rs b/src/widgets/label.rs index e3c77d5..416e67d 100644 --- a/src/widgets/label.rs +++ b/src/widgets/label.rs @@ -1,14 +1,12 @@ //! A read-only text widget. -use std::borrow::Cow; use kludgine::figures::units::{Px, UPx}; use kludgine::figures::{IntoUnsigned, Point, ScreenScale, Size}; use kludgine::text::{MeasuredText, Text, TextOrigin}; -use kludgine::Color; -use crate::context::{GraphicsContext, LayoutContext, WidgetContext}; +use crate::context::{GraphicsContext, LayoutContext}; use crate::styles::components::{IntrinsicPadding, TextColor}; -use crate::styles::{ComponentDefinition, ComponentGroup, ComponentName, NamedComponent}; +use crate::styles::ComponentGroup; use crate::value::{IntoValue, Value}; use crate::widget::Widget; use crate::{ConstraintLimit, Name}; @@ -37,17 +35,13 @@ impl Widget for Label { let size = context.gfx.region().size; let center = Point::from(size) / 2; - let styles = context.query_styles(&[&TextColor, &LabelBackground]); - - let background = styles.get(&LabelBackground, context); - context.gfx.fill(background); if let Some(measured) = &self.prepared_text { context .gfx .draw_measured_text(measured, TextOrigin::Center, center, None, None); } else { - let text_color = styles.get(&TextColor, context); + let text_color = context.query_style(&TextColor); self.text.map(|contents| { context.gfx.draw_text( Text::new(contents, text_color) @@ -90,21 +84,3 @@ impl ComponentGroup for Label { Name::new("Label") } } - -/// A [`Color`] to be used as a highlight color. -#[derive(Clone, Copy, Eq, PartialEq, Debug)] -pub struct LabelBackground; - -impl NamedComponent for LabelBackground { - fn name(&self) -> Cow<'_, ComponentName> { - Cow::Owned(ComponentName::named::