From a43afc791e8f78b03d802f980a10f32dc932f0b2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 5 Mar 2024 22:38:27 +0100 Subject: Simplify theming for `Rule` widget --- widget/src/rule.rs | 159 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 130 insertions(+), 29 deletions(-) (limited to 'widget/src/rule.rs') diff --git a/widget/src/rule.rs b/widget/src/rule.rs index bca34541..1a1ba106 100644 --- a/widget/src/rule.rs +++ b/widget/src/rule.rs @@ -1,53 +1,53 @@ //! Display a horizontal or vertical rule for dividing content. +use crate::core::border::{self, Border}; use crate::core::layout; use crate::core::mouse; use crate::core::renderer; use crate::core::widget::Tree; use crate::core::{ - Border, Element, Layout, Length, Pixels, Rectangle, Size, Widget, + Color, Element, Layout, Length, Pixels, Rectangle, Size, Widget, }; - -pub use crate::style::rule::{Appearance, FillMode, StyleSheet}; +use crate::style::Theme; /// Display a horizontal or vertical rule for dividing content. #[allow(missing_debug_implementations)] -pub struct Rule -where - Theme: StyleSheet, -{ +pub struct Rule { width: Length, height: Length, is_horizontal: bool, - style: Theme::Style, + style: fn(&Theme) -> Appearance, } -impl Rule -where - Theme: StyleSheet, -{ +impl Rule { /// Creates a horizontal [`Rule`] with the given height. - pub fn horizontal(height: impl Into) -> Self { + pub fn horizontal(height: impl Into) -> Self + where + Theme: Style, + { Rule { width: Length::Fill, height: Length::Fixed(height.into().0), is_horizontal: true, - style: Default::default(), + style: Theme::style(), } } /// Creates a vertical [`Rule`] with the given width. - pub fn vertical(width: impl Into) -> Self { + pub fn vertical(width: impl Into) -> Self + where + Theme: Style, + { Rule { width: Length::Fixed(width.into().0), height: Length::Fill, is_horizontal: false, - style: Default::default(), + style: Theme::style(), } } /// Sets the style of the [`Rule`]. - pub fn style(mut self, style: impl Into) -> Self { - self.style = style.into(); + pub fn style(mut self, style: fn(&Theme) -> Appearance) -> Self { + self.style = style; self } } @@ -55,7 +55,6 @@ where impl Widget for Rule where Renderer: crate::core::Renderer, - Theme: StyleSheet, { fn size(&self) -> Size { Size { @@ -84,34 +83,35 @@ where _viewport: &Rectangle, ) { let bounds = layout.bounds(); - let style = theme.appearance(&self.style); + let appearance = (self.style)(theme); let bounds = if self.is_horizontal { let line_y = (bounds.y + (bounds.height / 2.0) - - (style.width as f32 / 2.0)) + - (appearance.width as f32 / 2.0)) .round(); - let (offset, line_width) = style.fill_mode.fill(bounds.width); + let (offset, line_width) = appearance.fill_mode.fill(bounds.width); let line_x = bounds.x + offset; Rectangle { x: line_x, y: line_y, width: line_width, - height: style.width as f32, + height: appearance.width as f32, } } else { let line_x = (bounds.x + (bounds.width / 2.0) - - (style.width as f32 / 2.0)) + - (appearance.width as f32 / 2.0)) .round(); - let (offset, line_height) = style.fill_mode.fill(bounds.height); + let (offset, line_height) = + appearance.fill_mode.fill(bounds.height); let line_y = bounds.y + offset; Rectangle { x: line_x, y: line_y, - width: style.width as f32, + width: appearance.width as f32, height: line_height, } }; @@ -119,10 +119,10 @@ where renderer.fill_quad( renderer::Quad { bounds, - border: Border::with_radius(style.radius), + border: Border::with_radius(appearance.radius), ..renderer::Quad::default() }, - style.color, + appearance.color, ); } } @@ -131,10 +131,111 @@ impl<'a, Message, Theme, Renderer> From> for Element<'a, Message, Theme, Renderer> where Message: 'a, - Theme: StyleSheet + 'a, + Theme: 'a, Renderer: 'a + crate::core::Renderer, { fn from(rule: Rule) -> Element<'a, Message, Theme, Renderer> { Element::new(rule) } } + +/// The appearance of a rule. +#[derive(Debug, Clone, Copy)] +pub struct Appearance { + /// The color of the rule. + pub color: Color, + /// The width (thickness) of the rule line. + pub width: u16, + /// The radius of the line corners. + pub radius: border::Radius, + /// The [`FillMode`] of the rule. + pub fill_mode: FillMode, +} + +/// The fill mode of a rule. +#[derive(Debug, Clone, Copy)] +pub enum FillMode { + /// Fill the whole length of the container. + Full, + /// Fill a percent of the length of the container. The rule + /// will be centered in that container. + /// + /// The range is `[0.0, 100.0]`. + Percent(f32), + /// Uniform offset from each end, length units. + Padded(u16), + /// Different offset on each end of the rule, length units. + /// First = top or left. + AsymmetricPadding(u16, u16), +} + +impl FillMode { + /// Return the starting offset and length of the rule. + /// + /// * `space` - The space to fill. + /// + /// # Returns + /// + /// * (`starting_offset`, `length`) + pub fn fill(&self, space: f32) -> (f32, f32) { + match *self { + FillMode::Full => (0.0, space), + FillMode::Percent(percent) => { + if percent >= 100.0 { + (0.0, space) + } else { + let percent_width = (space * percent / 100.0).round(); + + (((space - percent_width) / 2.0).round(), percent_width) + } + } + FillMode::Padded(padding) => { + if padding == 0 { + (0.0, space) + } else { + let padding = padding as f32; + let mut line_width = space - (padding * 2.0); + if line_width < 0.0 { + line_width = 0.0; + } + + (padding, line_width) + } + } + FillMode::AsymmetricPadding(first_pad, second_pad) => { + let first_pad = first_pad as f32; + let second_pad = second_pad as f32; + let mut line_width = space - first_pad - second_pad; + if line_width < 0.0 { + line_width = 0.0; + } + + (first_pad, line_width) + } + } + } +} + +/// The definiton of the default style of a [`Rule`]. +pub trait Style { + /// Returns the default style of a [`Rule`]. + fn style() -> fn(&Self) -> Appearance; +} + +impl Style for Theme { + fn style() -> fn(&Self) -> Appearance { + default + } +} + +/// The default styling of a [`Rule`]. +pub fn default(theme: &Theme) -> Appearance { + let palette = theme.extended_palette(); + + Appearance { + color: palette.background.strong.color, + width: 1, + radius: 0.0.into(), + fill_mode: FillMode::Full, + } +} -- cgit From 34e7c6593a9e0f56cee5db18b7258717cf6bc11b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 6 Mar 2024 20:30:58 +0100 Subject: Use `Style` struct pattern instead of trait for all widgets --- widget/src/rule.rs | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'widget/src/rule.rs') diff --git a/widget/src/rule.rs b/widget/src/rule.rs index 1a1ba106..53a077aa 100644 --- a/widget/src/rule.rs +++ b/widget/src/rule.rs @@ -15,39 +15,39 @@ pub struct Rule { width: Length, height: Length, is_horizontal: bool, - style: fn(&Theme) -> Appearance, + style: Style, } impl Rule { /// Creates a horizontal [`Rule`] with the given height. pub fn horizontal(height: impl Into) -> Self where - Theme: Style, + Style: Default, { Rule { width: Length::Fill, height: Length::Fixed(height.into().0), is_horizontal: true, - style: Theme::style(), + style: Style::default(), } } /// Creates a vertical [`Rule`] with the given width. pub fn vertical(width: impl Into) -> Self where - Theme: Style, + Style: Default, { Rule { width: Length::Fixed(width.into().0), height: Length::Fill, is_horizontal: false, - style: Theme::style(), + style: Style::default(), } } /// Sets the style of the [`Rule`]. pub fn style(mut self, style: fn(&Theme) -> Appearance) -> Self { - self.style = style; + self.style = Style(style); self } } @@ -83,7 +83,7 @@ where _viewport: &Rectangle, ) { let bounds = layout.bounds(); - let appearance = (self.style)(theme); + let appearance = (self.style.0)(theme); let bounds = if self.is_horizontal { let line_y = (bounds.y + (bounds.height / 2.0) @@ -216,15 +216,27 @@ impl FillMode { } } -/// The definiton of the default style of a [`Rule`]. -pub trait Style { - /// Returns the default style of a [`Rule`]. - fn style() -> fn(&Self) -> Appearance; +/// The style of a [`Rule`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style(fn(&Theme) -> Appearance); + +impl Clone for Style { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for Style {} + +impl Default for Style { + fn default() -> Self { + Style(default) + } } -impl Style for Theme { - fn style() -> fn(&Self) -> Appearance { - default +impl From Appearance> for Style { + fn from(f: fn(&Theme) -> Appearance) -> Self { + Style(f) } } -- cgit From 905f2160e6eb7504f52d9bd62c7bfa42c8ec2902 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 7 Mar 2024 00:14:41 +0100 Subject: Move `Theme` type to `iced_core` --- widget/src/rule.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'widget/src/rule.rs') diff --git a/widget/src/rule.rs b/widget/src/rule.rs index 53a077aa..19ad43f6 100644 --- a/widget/src/rule.rs +++ b/widget/src/rule.rs @@ -5,9 +5,8 @@ use crate::core::mouse; use crate::core::renderer; use crate::core::widget::Tree; use crate::core::{ - Color, Element, Layout, Length, Pixels, Rectangle, Size, Widget, + Color, Element, Layout, Length, Pixels, Rectangle, Size, Theme, Widget, }; -use crate::style::Theme; /// Display a horizontal or vertical rule for dividing content. #[allow(missing_debug_implementations)] -- cgit From 833538ee7f3a60a839304762dfc29b0881d19094 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 7 Mar 2024 20:11:32 +0100 Subject: Leverage `DefaultStyle` traits instead of `Default` --- widget/src/rule.rs | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'widget/src/rule.rs') diff --git a/widget/src/rule.rs b/widget/src/rule.rs index 19ad43f6..384baed4 100644 --- a/widget/src/rule.rs +++ b/widget/src/rule.rs @@ -21,32 +21,32 @@ impl Rule { /// Creates a horizontal [`Rule`] with the given height. pub fn horizontal(height: impl Into) -> Self where - Style: Default, + Theme: DefaultStyle, { Rule { width: Length::Fill, height: Length::Fixed(height.into().0), is_horizontal: true, - style: Style::default(), + style: Theme::default_style(), } } /// Creates a vertical [`Rule`] with the given width. pub fn vertical(width: impl Into) -> Self where - Style: Default, + Theme: DefaultStyle, { Rule { width: Length::Fixed(width.into().0), height: Length::Fill, is_horizontal: false, - style: Style::default(), + style: Theme::default_style(), } } /// Sets the style of the [`Rule`]. pub fn style(mut self, style: fn(&Theme) -> Appearance) -> Self { - self.style = Style(style); + self.style = style; self } } @@ -82,7 +82,7 @@ where _viewport: &Rectangle, ) { let bounds = layout.bounds(); - let appearance = (self.style.0)(theme); + let appearance = (self.style)(theme); let bounds = if self.is_horizontal { let line_y = (bounds.y + (bounds.height / 2.0) @@ -216,26 +216,23 @@ impl FillMode { } /// The style of a [`Rule`]. -#[derive(Debug, PartialEq, Eq)] -pub struct Style(fn(&Theme) -> Appearance); +pub type Style = fn(&Theme) -> Appearance; -impl Clone for Style { - fn clone(&self) -> Self { - *self - } +/// The default style of a [`Rule`]. +pub trait DefaultStyle { + /// Returns the default style of a [`Rule`]. + fn default_style() -> Style; } -impl Copy for Style {} - -impl Default for Style { - fn default() -> Self { - Style(default) +impl DefaultStyle for Theme { + fn default_style() -> Style { + default } } -impl From Appearance> for Style { - fn from(f: fn(&Theme) -> Appearance) -> Self { - Style(f) +impl DefaultStyle for Appearance { + fn default_style() -> Style { + |appearance| *appearance } } -- cgit From 7ece5eea509f3595432babfc7729701f2e063b21 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 7 Mar 2024 21:02:17 +0100 Subject: Implement additional helpers for `Border` and `container::Appearance` --- widget/src/rule.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'widget/src/rule.rs') diff --git a/widget/src/rule.rs b/widget/src/rule.rs index 384baed4..8580d4c7 100644 --- a/widget/src/rule.rs +++ b/widget/src/rule.rs @@ -118,7 +118,7 @@ where renderer.fill_quad( renderer::Quad { bounds, - border: Border::with_radius(appearance.radius), + border: Border::rounded(appearance.radius), ..renderer::Quad::default() }, appearance.color, -- cgit