diff --git a/core/src/border.rs b/core/src/border.rs new file mode 100644 index 0000000000..2182334129 --- /dev/null +++ b/core/src/border.rs @@ -0,0 +1,54 @@ +//! Draw lines around containers. +use crate::Color; + +/// A border. +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct Border { + /// The color of the border. + pub color: Color, + + /// The width of the border. + pub width: f32, + + /// The radius of the border. + pub radius: Radius, +} + +impl Border { + /// Creates a new default [`Border`] with the given [`Radius`]. + pub fn with_radius(radius: impl Into) -> Self { + Self { + radius: radius.into(), + ..Self::default() + } + } +} + +/// The border radii for the corners of a graphics primitive in the order: +/// top-left, top-right, bottom-right, bottom-left. +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct Radius([f32; 4]); + +impl From for Radius { + fn from(w: f32) -> Self { + Self([w; 4]) + } +} + +impl From for Radius { + fn from(w: u8) -> Self { + Self([f32::from(w); 4]) + } +} + +impl From<[f32; 4]> for Radius { + fn from(radi: [f32; 4]) -> Self { + Self(radi) + } +} + +impl From for [f32; 4] { + fn from(radi: Radius) -> Self { + radi.0 + } +} diff --git a/core/src/element.rs b/core/src/element.rs index 8b5102186a..4d4bfa369d 100644 --- a/core/src/element.rs +++ b/core/src/element.rs @@ -6,7 +6,8 @@ use crate::renderer; use crate::widget; use crate::widget::tree::{self, Tree}; use crate::{ - Clipboard, Color, Layout, Length, Rectangle, Shell, Size, Vector, Widget, + Border, Clipboard, Color, Layout, Length, Rectangle, Shell, Size, Vector, + Widget, }; use std::any::Any; @@ -537,9 +538,12 @@ where renderer.fill_quad( renderer::Quad { bounds: layout.bounds(), - border_color: color, - border_width: 1.0, - border_radius: 0.0.into(), + border: Border { + color, + width: 1.0, + ..Border::default() + }, + ..renderer::Quad::default() }, Color::TRANSPARENT, ); diff --git a/core/src/lib.rs b/core/src/lib.rs index 864df6e6c3..bbc973f053 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -17,6 +17,7 @@ rustdoc::broken_intra_doc_links )] pub mod alignment; +pub mod border; pub mod clipboard; pub mod event; pub mod font; @@ -36,7 +37,6 @@ pub mod window; mod angle; mod background; -mod border_radius; mod color; mod content_fit; mod element; @@ -46,6 +46,7 @@ mod padding; mod pixels; mod point; mod rectangle; +mod shadow; mod shell; mod size; mod vector; @@ -53,7 +54,7 @@ mod vector; pub use alignment::Alignment; pub use angle::{Degrees, Radians}; pub use background::Background; -pub use border_radius::BorderRadius; +pub use border::Border; pub use clipboard::Clipboard; pub use color::Color; pub use content_fit::ContentFit; @@ -70,6 +71,7 @@ pub use pixels::Pixels; pub use point::Point; pub use rectangle::Rectangle; pub use renderer::Renderer; +pub use shadow::Shadow; pub use shell::Shell; pub use size::Size; pub use text::Text; diff --git a/core/src/renderer.rs b/core/src/renderer.rs index 1b327e563c..a2a66aa86a 100644 --- a/core/src/renderer.rs +++ b/core/src/renderer.rs @@ -5,7 +5,7 @@ mod null; #[cfg(debug_assertions)] pub use null::Null; -use crate::{Background, BorderRadius, Color, Rectangle, Vector}; +use crate::{Background, Border, Color, Rectangle, Shadow, Size, Vector}; /// A component that can be used by widgets to draw themselves on a screen. pub trait Renderer: Sized { @@ -37,14 +37,21 @@ pub struct Quad { /// The bounds of the [`Quad`]. pub bounds: Rectangle, - /// The border radius of the [`Quad`]. - pub border_radius: BorderRadius, + /// The [`Border`] of the [`Quad`]. + pub border: Border, - /// The border width of the [`Quad`]. - pub border_width: f32, + /// The [`Shadow`] of the [`Quad`]. + pub shadow: Shadow, +} - /// The border color of the [`Quad`]. - pub border_color: Color, +impl Default for Quad { + fn default() -> Self { + Self { + bounds: Rectangle::with_size(Size::ZERO), + border: Border::default(), + shadow: Shadow::default(), + } + } } /// The styling attributes of a [`Renderer`]. diff --git a/core/src/shadow.rs b/core/src/shadow.rs new file mode 100644 index 0000000000..803101edd5 --- /dev/null +++ b/core/src/shadow.rs @@ -0,0 +1,14 @@ +use crate::{Color, Vector}; + +/// A shadow. +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct Shadow { + /// The color of the shadow. + pub color: Color, + + /// The offset of the shadow. + pub offset: Vector, + + /// The blur radius of the shadow. + pub blur_radius: f32, +} diff --git a/examples/custom_quad/src/main.rs b/examples/custom_quad/src/main.rs index cc9ad528a7..14f62caa1d 100644 --- a/examples/custom_quad/src/main.rs +++ b/examples/custom_quad/src/main.rs @@ -4,20 +4,27 @@ mod quad { use iced::advanced::renderer; use iced::advanced::widget::{self, Widget}; use iced::mouse; - use iced::{Color, Element, Length, Rectangle, Size}; + use iced::{Border, Color, Element, Length, Rectangle, Shadow, Size}; pub struct CustomQuad { size: f32, radius: [f32; 4], border_width: f32, + shadow: Shadow, } impl CustomQuad { - pub fn new(size: f32, radius: [f32; 4], border_width: f32) -> Self { + pub fn new( + size: f32, + radius: [f32; 4], + border_width: f32, + shadow: Shadow, + ) -> Self { Self { size, radius, border_width, + shadow, } } } @@ -55,9 +62,12 @@ mod quad { renderer.fill_quad( renderer::Quad { bounds: layout.bounds(), - border_radius: self.radius.into(), - border_width: self.border_width, - border_color: Color::from_rgb(1.0, 0.0, 0.0), + border: Border { + radius: self.radius.into(), + width: self.border_width, + color: Color::from_rgb(1.0, 0.0, 0.0), + }, + shadow: self.shadow, }, Color::BLACK, ); @@ -75,7 +85,9 @@ mod quad { } use iced::widget::{column, container, slider, text}; -use iced::{Alignment, Element, Length, Sandbox, Settings}; +use iced::{ + Alignment, Color, Element, Length, Sandbox, Settings, Shadow, Vector, +}; pub fn main() -> iced::Result { Example::run(Settings::default()) @@ -84,6 +96,7 @@ pub fn main() -> iced::Result { struct Example { radius: [f32; 4], border_width: f32, + shadow: Shadow, } #[derive(Debug, Clone, Copy)] @@ -94,6 +107,9 @@ enum Message { RadiusBottomRightChanged(f32), RadiusBottomLeftChanged(f32), BorderWidthChanged(f32), + ShadowXOffsetChanged(f32), + ShadowYOffsetChanged(f32), + ShadowBlurRadiusChanged(f32), } impl Sandbox for Example { @@ -103,6 +119,11 @@ impl Sandbox for Example { Self { radius: [50.0; 4], border_width: 0.0, + shadow: Shadow { + color: Color::from_rgba(0.0, 0.0, 0.0, 0.8), + offset: Vector::new(0.0, 8.0), + blur_radius: 16.0, + }, } } @@ -128,14 +149,33 @@ impl Sandbox for Example { Message::BorderWidthChanged(width) => { self.border_width = width; } + Message::ShadowXOffsetChanged(x) => { + self.shadow.offset.x = x; + } + Message::ShadowYOffsetChanged(y) => { + self.shadow.offset.y = y; + } + Message::ShadowBlurRadiusChanged(s) => { + self.shadow.blur_radius = s; + } } } fn view(&self) -> Element { let [tl, tr, br, bl] = self.radius; + let Shadow { + offset: Vector { x: sx, y: sy }, + blur_radius: sr, + .. + } = self.shadow; let content = column![ - quad::CustomQuad::new(200.0, self.radius, self.border_width), + quad::CustomQuad::new( + 200.0, + self.radius, + self.border_width, + self.shadow + ), text(format!("Radius: {tl:.2}/{tr:.2}/{br:.2}/{bl:.2}")), slider(1.0..=100.0, tl, Message::RadiusTopLeftChanged).step(0.01), slider(1.0..=100.0, tr, Message::RadiusTopRightChanged).step(0.01), @@ -145,6 +185,13 @@ impl Sandbox for Example { .step(0.01), slider(1.0..=10.0, self.border_width, Message::BorderWidthChanged) .step(0.01), + text(format!("Shadow: {sx:.2}x{sy:.2}, {sr:.2}")), + slider(-100.0..=100.0, sx, Message::ShadowXOffsetChanged) + .step(0.01), + slider(-100.0..=100.0, sy, Message::ShadowYOffsetChanged) + .step(0.01), + slider(0.0..=100.0, sr, Message::ShadowBlurRadiusChanged) + .step(0.01), ] .padding(20) .spacing(20) diff --git a/examples/custom_widget/src/main.rs b/examples/custom_widget/src/main.rs index 7ffb4cd018..d5ecebaf8d 100644 --- a/examples/custom_widget/src/main.rs +++ b/examples/custom_widget/src/main.rs @@ -13,7 +13,7 @@ mod circle { use iced::advanced::renderer; use iced::advanced::widget::{self, Widget}; use iced::mouse; - use iced::{Color, Element, Length, Rectangle, Size}; + use iced::{Border, Color, Element, Length, Rectangle, Size}; pub struct Circle { radius: f32, @@ -62,9 +62,8 @@ mod circle { renderer.fill_quad( renderer::Quad { bounds: layout.bounds(), - border_radius: self.radius.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(self.radius), + ..renderer::Quad::default() }, Color::BLACK, ); diff --git a/examples/loading_spinners/src/linear.rs b/examples/loading_spinners/src/linear.rs index 497e0834ee..03aee9b191 100644 --- a/examples/loading_spinners/src/linear.rs +++ b/examples/loading_spinners/src/linear.rs @@ -225,9 +225,7 @@ where width: bounds.width, height: bounds.height, }, - border_radius: 0.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + ..renderer::Quad::default() }, Background::Color(custom_style.track_color), ); @@ -241,9 +239,7 @@ where width: self.easing.y_at_x(*progress) * bounds.width, height: bounds.height, }, - border_radius: 0.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + ..renderer::Quad::default() }, Background::Color(custom_style.bar_color), ), @@ -258,9 +254,7 @@ where * bounds.width, height: bounds.height, }, - border_radius: 0.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + ..renderer::Quad::default() }, Background::Color(custom_style.bar_color), ), @@ -288,7 +282,7 @@ pub struct Appearance { pub bar_color: Color, } -impl std::default::Default for Appearance { +impl Default for Appearance { fn default() -> Self { Self { track_color: Color::TRANSPARENT, diff --git a/examples/modal/src/main.rs b/examples/modal/src/main.rs index 963c839ea6..c9d5df2977 100644 --- a/examples/modal/src/main.rs +++ b/examples/modal/src/main.rs @@ -231,10 +231,7 @@ mod modal { use iced::alignment::Alignment; use iced::event; use iced::mouse; - use iced::{ - BorderRadius, Color, Element, Event, Length, Point, Rectangle, Size, - Vector, - }; + use iced::{Color, Element, Event, Length, Point, Rectangle, Size, Vector}; /// A widget that centers a modal element over some base element pub struct Modal<'a, Message, Renderer> { @@ -474,9 +471,7 @@ mod modal { renderer.fill_quad( renderer::Quad { bounds: layout.bounds(), - border_radius: BorderRadius::default(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + ..renderer::Quad::default() }, Color { a: 0.80, diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs index d5e5bcbec8..742dc344c7 100644 --- a/examples/pane_grid/src/main.rs +++ b/examples/pane_grid/src/main.rs @@ -348,7 +348,7 @@ fn view_controls<'a>( mod style { use iced::widget::container; - use iced::Theme; + use iced::{Border, Theme}; pub fn title_bar_active(theme: &Theme) -> container::Appearance { let palette = theme.extended_palette(); @@ -375,8 +375,11 @@ mod style { container::Appearance { background: Some(palette.background.weak.color.into()), - border_width: 2.0, - border_color: palette.background.strong.color, + border: Border { + width: 2.0, + color: palette.background.strong.color, + ..Border::default() + }, ..Default::default() } } @@ -386,8 +389,11 @@ mod style { container::Appearance { background: Some(palette.background.weak.color.into()), - border_width: 2.0, - border_color: palette.primary.strong.color, + border: Border { + width: 2.0, + color: palette.primary.strong.color, + ..Border::default() + }, ..Default::default() } } diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs index 4b57a5a4f6..ff69191724 100644 --- a/examples/scrollable/src/main.rs +++ b/examples/scrollable/src/main.rs @@ -1,10 +1,14 @@ +use iced::executor; +use iced::theme; use iced::widget::scrollable::{Properties, Scrollbar, Scroller}; use iced::widget::{ button, column, container, horizontal_space, progress_bar, radio, row, scrollable, slider, text, vertical_space, }; -use iced::{executor, theme, Alignment, Color}; -use iced::{Application, Command, Element, Length, Settings, Theme}; +use iced::{ + Alignment, Application, Border, Color, Command, Element, Length, Settings, + Theme, +}; use once_cell::sync::Lazy; @@ -373,14 +377,10 @@ impl scrollable::StyleSheet for ScrollbarCustomStyle { background: style .active(&theme::Scrollable::default()) .background, - border_radius: 2.0.into(), - border_width: 0.0, - border_color: Color::default(), + border: Border::with_radius(2), scroller: Scroller { color: Color::from_rgb8(250, 85, 134), - border_radius: 2.0.into(), - border_width: 0.0, - border_color: Color::default(), + border: Border::with_radius(2), }, } } else { diff --git a/graphics/src/damage.rs b/graphics/src/damage.rs index 59e9f5b4c0..ba9192efcc 100644 --- a/graphics/src/damage.rs +++ b/graphics/src/damage.rs @@ -78,6 +78,20 @@ impl Damage for Primitive { // damage bounds (?) raw.clip_bounds.expand(1.5) } + Self::Quad { bounds, shadow, .. } if shadow.color.a > 0.0 => { + let bounds_with_shadow = Rectangle { + x: bounds.x + shadow.offset.x.min(0.0) - shadow.blur_radius, + y: bounds.y + shadow.offset.y.min(0.0) - shadow.blur_radius, + width: bounds.width + + shadow.offset.x.abs() + + shadow.blur_radius * 2.0, + height: bounds.height + + shadow.offset.y.abs() + + shadow.blur_radius * 2.0, + }; + + bounds_with_shadow.expand(1.0) + } Self::Quad { bounds, .. } | Self::Image { bounds, .. } | Self::Svg { bounds, .. } => bounds.expand(1.0), diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index 20affaaf66..aed59e1a91 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -3,7 +3,9 @@ use crate::core::alignment; use crate::core::image; use crate::core::svg; use crate::core::text; -use crate::core::{Background, Color, Font, Pixels, Point, Rectangle, Vector}; +use crate::core::{ + Background, Border, Color, Font, Pixels, Point, Rectangle, Shadow, Vector, +}; use crate::text::editor; use crate::text::paragraph; @@ -65,12 +67,10 @@ pub enum Primitive { bounds: Rectangle, /// The background of the quad background: Background, - /// The border radii of the quad - border_radius: [f32; 4], - /// The border width of the quad - border_width: f32, - /// The border color of the quad - border_color: Color, + /// The [`Border`] of the quad + border: Border, + /// The [`Shadow`] of the quad + shadow: Shadow, }, /// An image primitive Image { diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs index 1b0f5c5b3a..3ba41c3feb 100644 --- a/graphics/src/renderer.rs +++ b/graphics/src/renderer.rs @@ -124,9 +124,8 @@ impl iced_core::Renderer for Renderer { self.primitives.push(Primitive::Quad { bounds: quad.bounds, background: background.into(), - border_radius: quad.border_radius.into(), - border_width: quad.border_width, - border_color: quad.border_color, + border: quad.border, + shadow: quad.shadow, }); } diff --git a/src/lib.rs b/src/lib.rs index 446590ec7c..eb1bd3bda7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -188,10 +188,12 @@ pub mod multi_window; pub use style::theme; pub use crate::core::alignment; +pub use crate::core::border; +pub use crate::core::color; pub use crate::core::gradient; pub use crate::core::{ - color, Alignment, Background, BorderRadius, Color, ContentFit, Degrees, - Gradient, Length, Padding, Pixels, Point, Radians, Rectangle, Size, Vector, + Alignment, Background, Border, Color, ContentFit, Degrees, Gradient, + Length, Padding, Pixels, Point, Radians, Rectangle, Shadow, Size, Vector, }; pub mod clipboard { diff --git a/style/src/button.rs b/style/src/button.rs index e49ad94ac1..0d7a668aca 100644 --- a/style/src/button.rs +++ b/style/src/button.rs @@ -1,5 +1,5 @@ //! Change the apperance of a button. -use iced_core::{Background, BorderRadius, Color, Vector}; +use iced_core::{Background, Border, Color, Shadow, Vector}; /// The appearance of a button. #[derive(Debug, Clone, Copy)] @@ -8,14 +8,12 @@ pub struct Appearance { pub shadow_offset: Vector, /// The [`Background`] of the button. pub background: Option, - /// The border radius of the button. - pub border_radius: BorderRadius, - /// The border width of the button. - pub border_width: f32, - /// The border [`Color`] of the button. - pub border_color: Color, /// The text [`Color`] of the button. pub text_color: Color, + /// The [`Border`] of the buton. + pub border: Border, + /// The [`Shadow`] of the butoon. + pub shadow: Shadow, } impl std::default::Default for Appearance { @@ -23,10 +21,9 @@ impl std::default::Default for Appearance { Self { shadow_offset: Vector::default(), background: None, - border_radius: 0.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, text_color: Color::BLACK, + border: Border::default(), + shadow: Shadow::default(), } } } diff --git a/style/src/checkbox.rs b/style/src/checkbox.rs index cf52c05d63..d96ea4adb9 100644 --- a/style/src/checkbox.rs +++ b/style/src/checkbox.rs @@ -1,5 +1,5 @@ //! Change the appearance of a checkbox. -use iced_core::{Background, BorderRadius, Color}; +use iced_core::{Background, Border, Color}; /// The appearance of a checkbox. #[derive(Debug, Clone, Copy)] @@ -8,12 +8,8 @@ pub struct Appearance { pub background: Background, /// The icon [`Color`] of the checkbox. pub icon_color: Color, - /// The border radius of the checkbox. - pub border_radius: BorderRadius, - /// The border width of the checkbox. - pub border_width: f32, - /// The border [`Color`] of the checkbox. - pub border_color: Color, + /// The [`Border`] of hte checkbox. + pub border: Border, /// The text [`Color`] of the checkbox. pub text_color: Option, } diff --git a/style/src/container.rs b/style/src/container.rs index 490a9dabea..00649c25eb 100644 --- a/style/src/container.rs +++ b/style/src/container.rs @@ -1,19 +1,17 @@ //! Change the appearance of a container. -use crate::core::{Background, BorderRadius, Color, Pixels}; +use crate::core::{Background, Border, Color, Pixels, Shadow}; /// The appearance of a container. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Default)] pub struct Appearance { /// The text [`Color`] of the container. pub text_color: Option, /// The [`Background`] of the container. pub background: Option, - /// The border radius of the container. - pub border_radius: BorderRadius, - /// The border width of the container. - pub border_width: f32, - /// The border [`Color`] of the container. - pub border_color: Color, + /// The [`Border`] of the container. + pub border: Border, + /// The [`Shadow`] of the container. + pub shadow: Shadow, } impl Appearance { @@ -25,8 +23,11 @@ impl Appearance { width: impl Into, ) -> Self { Self { - border_color: color.into(), - border_width: width.into().0, + border: Border { + color: color.into(), + width: width.into().0, + ..Border::default() + }, ..self } } @@ -40,18 +41,6 @@ impl Appearance { } } -impl std::default::Default for Appearance { - fn default() -> Self { - Self { - text_color: None, - background: None, - border_radius: 0.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, - } - } -} - /// A set of rules that dictate the [`Appearance`] of a container. pub trait StyleSheet { /// The supported style of the [`StyleSheet`]. diff --git a/style/src/menu.rs b/style/src/menu.rs index dbf19dae37..be60a3f8f6 100644 --- a/style/src/menu.rs +++ b/style/src/menu.rs @@ -1,5 +1,5 @@ //! Change the appearance of menus. -use iced_core::{Background, BorderRadius, Color}; +use iced_core::{Background, Border, Color}; /// The appearance of a menu. #[derive(Debug, Clone, Copy)] @@ -8,12 +8,8 @@ pub struct Appearance { pub text_color: Color, /// The [`Background`] of the menu. pub background: Background, - /// The border width of the menu. - pub border_width: f32, - /// The border radius of the menu. - pub border_radius: BorderRadius, - /// The border [`Color`] of the menu. - pub border_color: Color, + /// The [`Border`] of the menu. + pub border: Border, /// The text [`Color`] of a selected option in the menu. pub selected_text_color: Color, /// The background [`Color`] of a selected option in the menu. diff --git a/style/src/pane_grid.rs b/style/src/pane_grid.rs index dfdc918666..3557058435 100644 --- a/style/src/pane_grid.rs +++ b/style/src/pane_grid.rs @@ -1,17 +1,13 @@ //! Change the appearance of a pane grid. -use iced_core::{Background, BorderRadius, Color}; +use iced_core::{Background, Border, Color}; /// The appearance of the hovered region of a pane grid. #[derive(Debug, Clone, Copy)] pub struct Appearance { - /// The [`Background`] of the hovered pane region. + /// The [`Background`] of the pane region. pub background: Background, - /// The border width of the hovered pane region. - pub border_width: f32, - /// The border [`Color`] of the hovered pane region. - pub border_color: Color, - /// The border radius of the hovered pane region. - pub border_radius: BorderRadius, + /// The [`Border`] of the pane region. + pub border: Border, } /// A line. diff --git a/style/src/pick_list.rs b/style/src/pick_list.rs index 961c1e939e..8f008f4a31 100644 --- a/style/src/pick_list.rs +++ b/style/src/pick_list.rs @@ -1,5 +1,5 @@ //! Change the appearance of a pick list. -use iced_core::{Background, BorderRadius, Color}; +use iced_core::{Background, Border, Color}; /// The appearance of a pick list. #[derive(Debug, Clone, Copy)] @@ -12,12 +12,8 @@ pub struct Appearance { pub handle_color: Color, /// The [`Background`] of the pick list. pub background: Background, - /// The border radius of the pick list. - pub border_radius: BorderRadius, - /// The border width of the pick list. - pub border_width: f32, - /// The border color of the pick list. - pub border_color: Color, + /// The [`Border`] of the pick list. + pub border: Border, } /// A set of rules that dictate the style of a container. diff --git a/style/src/progress_bar.rs b/style/src/progress_bar.rs index c05a6ee473..b62512d8a5 100644 --- a/style/src/progress_bar.rs +++ b/style/src/progress_bar.rs @@ -1,5 +1,6 @@ //! Change the appearance of a progress bar. -use iced_core::{Background, BorderRadius}; +use crate::core::border; +use crate::core::Background; /// The appearance of a progress bar. #[derive(Debug, Clone, Copy)] @@ -9,7 +10,7 @@ pub struct Appearance { /// The [`Background`] of the bar of the progress bar. pub bar: Background, /// The border radius of the progress bar. - pub border_radius: BorderRadius, + pub border_radius: border::Radius, } /// A set of rules that dictate the style of a progress bar. diff --git a/style/src/rule.rs b/style/src/rule.rs index efbe74447f..12980da7cb 100644 --- a/style/src/rule.rs +++ b/style/src/rule.rs @@ -1,5 +1,6 @@ //! Change the appearance of a rule. -use iced_core::{BorderRadius, Color}; +use crate::core::border; +use crate::core::Color; /// The appearance of a rule. #[derive(Debug, Clone, Copy)] @@ -9,7 +10,7 @@ pub struct Appearance { /// The width (thickness) of the rule line. pub width: u16, /// The radius of the line corners. - pub radius: BorderRadius, + pub radius: border::Radius, /// The [`FillMode`] of the rule. pub fill_mode: FillMode, } diff --git a/style/src/scrollable.rs b/style/src/scrollable.rs index 952c11e18c..6f37305f12 100644 --- a/style/src/scrollable.rs +++ b/style/src/scrollable.rs @@ -1,17 +1,13 @@ //! Change the appearance of a scrollable. -use iced_core::{Background, BorderRadius, Color}; +use crate::core::{Background, Border, Color}; /// The appearance of a scrollable. #[derive(Debug, Clone, Copy)] pub struct Scrollbar { /// The [`Background`] of a scrollable. pub background: Option, - /// The border radius of a scrollable. - pub border_radius: BorderRadius, - /// The border width of a scrollable. - pub border_width: f32, - /// The border [`Color`] of a scrollable. - pub border_color: Color, + /// The [`Border`] of a scrollable. + pub border: Border, /// The appearance of the [`Scroller`] of a scrollable. pub scroller: Scroller, } @@ -21,12 +17,8 @@ pub struct Scrollbar { pub struct Scroller { /// The [`Color`] of the scroller. pub color: Color, - /// The border radius of the scroller. - pub border_radius: BorderRadius, - /// The border width of the scroller. - pub border_width: f32, - /// The border [`Color`] of the scroller. - pub border_color: Color, + /// The [`Border`] of the scroller. + pub border: Border, } /// A set of rules that dictate the style of a scrollable. diff --git a/style/src/slider.rs b/style/src/slider.rs index f006855883..bf1c732961 100644 --- a/style/src/slider.rs +++ b/style/src/slider.rs @@ -1,5 +1,6 @@ //! Change the apperance of a slider. -use iced_core::{BorderRadius, Color}; +use crate::core::border; +use crate::core::Color; /// The appearance of a slider. #[derive(Debug, Clone, Copy)] @@ -18,7 +19,7 @@ pub struct Rail { /// The width of the stroke of a slider rail. pub width: f32, /// The border radius of the corners of the rail. - pub border_radius: BorderRadius, + pub border_radius: border::Radius, } /// The appearance of the handle of a slider. @@ -47,7 +48,7 @@ pub enum HandleShape { /// The width of the rectangle. width: u16, /// The border radius of the corners of the rectangle. - border_radius: BorderRadius, + border_radius: border::Radius, }, } diff --git a/style/src/text_editor.rs b/style/src/text_editor.rs index f6bae7e674..87f481e30b 100644 --- a/style/src/text_editor.rs +++ b/style/src/text_editor.rs @@ -1,17 +1,13 @@ //! Change the appearance of a text editor. -use crate::core::{Background, BorderRadius, Color}; +use crate::core::{Background, Border, Color}; /// The appearance of a text input. #[derive(Debug, Clone, Copy)] pub struct Appearance { - /// The [`Background`] of the text input. + /// The [`Background`] of the text editor. pub background: Background, - /// The border radius of the text input. - pub border_radius: BorderRadius, - /// The border width of the text input. - pub border_width: f32, - /// The border [`Color`] of the text input. - pub border_color: Color, + /// The [`Border`] of the text editor. + pub border: Border, } /// A set of rules that dictate the style of a text input. diff --git a/style/src/text_input.rs b/style/src/text_input.rs index 90251b5cba..8ba9957f51 100644 --- a/style/src/text_input.rs +++ b/style/src/text_input.rs @@ -1,17 +1,13 @@ //! Change the appearance of a text input. -use iced_core::{Background, BorderRadius, Color}; +use iced_core::{Background, Border, Color}; /// The appearance of a text input. #[derive(Debug, Clone, Copy)] pub struct Appearance { /// The [`Background`] of the text input. pub background: Background, - /// The border radius of the text input. - pub border_radius: BorderRadius, - /// The border width of the text input. - pub border_width: f32, - /// The border [`Color`] of the text input. - pub border_color: Color, + /// The [`Border`] of the text input. + pub border: Border, /// The icon [`Color`] of the text input. pub icon_color: Color, } diff --git a/style/src/theme.rs b/style/src/theme.rs index f78587e5db..8d1ff23779 100644 --- a/style/src/theme.rs +++ b/style/src/theme.rs @@ -21,7 +21,7 @@ use crate::text_editor; use crate::text_input; use crate::toggler; -use iced_core::{Background, Color, Vector}; +use crate::core::{Background, Border, Color, Shadow, Vector}; use std::fmt; use std::rc::Rc; @@ -199,7 +199,7 @@ impl button::StyleSheet for Theme { let palette = self.extended_palette(); let appearance = button::Appearance { - border_radius: 2.0.into(), + border: Border::with_radius(2), ..button::Appearance::default() }; @@ -388,9 +388,11 @@ fn checkbox_appearance( base.color }), icon_color, - border_radius: 2.0.into(), - border_width: 1.0, - border_color: accent.color, + border: Border { + radius: 2.0.into(), + width: 1.0, + color: accent.color, + }, text_color: None, } } @@ -431,9 +433,8 @@ impl container::StyleSheet for Theme { container::Appearance { text_color: None, background: Some(palette.background.weak.color.into()), - border_radius: 2.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(2), + shadow: Shadow::default(), } } Container::Custom(custom) => custom.appearance(self), @@ -555,9 +556,11 @@ impl menu::StyleSheet for Theme { menu::Appearance { text_color: palette.background.weak.text, background: palette.background.weak.color.into(), - border_width: 1.0, - border_radius: 0.0.into(), - border_color: palette.background.strong.color, + border: Border { + width: 1.0, + radius: 0.0.into(), + color: palette.background.strong.color, + }, selected_text_color: palette.primary.strong.text, selected_background: palette.primary.strong.color.into(), } @@ -602,9 +605,11 @@ impl pick_list::StyleSheet for Theme { background: palette.background.weak.color.into(), placeholder_color: palette.background.strong.color, handle_color: palette.background.weak.text, - border_radius: 2.0.into(), - border_width: 1.0, - border_color: palette.background.strong.color, + border: Border { + radius: 2.0.into(), + width: 1.0, + color: palette.background.strong.color, + }, } } PickList::Custom(custom, _) => custom.active(self), @@ -621,9 +626,11 @@ impl pick_list::StyleSheet for Theme { background: palette.background.weak.color.into(), placeholder_color: palette.background.strong.color, handle_color: palette.background.weak.text, - border_radius: 2.0.into(), - border_width: 1.0, - border_color: palette.primary.strong.color, + border: Border { + radius: 2.0.into(), + width: 1.0, + color: palette.primary.strong.color, + }, } } PickList::Custom(custom, _) => custom.hovered(self), @@ -776,9 +783,11 @@ impl pane_grid::StyleSheet for Theme { a: 0.5, ..palette.primary.base.color }), - border_width: 2.0, - border_color: palette.primary.strong.color, - border_radius: 0.0.into(), + border: Border { + width: 2.0, + color: palette.primary.strong.color, + radius: 0.0.into(), + }, } } PaneGrid::Custom(custom) => custom.hovered_region(self), @@ -986,14 +995,10 @@ impl scrollable::StyleSheet for Theme { scrollable::Scrollbar { background: Some(palette.background.weak.color.into()), - border_radius: 2.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(2), scroller: scrollable::Scroller { color: palette.background.strong.color, - border_radius: 2.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(2), }, } } @@ -1013,14 +1018,10 @@ impl scrollable::StyleSheet for Theme { scrollable::Scrollbar { background: Some(palette.background.weak.color.into()), - border_radius: 2.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(2), scroller: scrollable::Scroller { color: palette.primary.strong.color, - border_radius: 2.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(2), }, } } else { @@ -1120,9 +1121,11 @@ impl text_input::StyleSheet for Theme { text_input::Appearance { background: palette.background.base.color.into(), - border_radius: 2.0.into(), - border_width: 1.0, - border_color: palette.background.strong.color, + border: Border { + radius: 2.0.into(), + width: 1.0, + color: palette.background.strong.color, + }, icon_color: palette.background.weak.text, } } @@ -1136,9 +1139,11 @@ impl text_input::StyleSheet for Theme { text_input::Appearance { background: palette.background.base.color.into(), - border_radius: 2.0.into(), - border_width: 1.0, - border_color: palette.background.base.text, + border: Border { + radius: 2.0.into(), + width: 1.0, + color: palette.background.base.text, + }, icon_color: palette.background.weak.text, } } @@ -1152,9 +1157,11 @@ impl text_input::StyleSheet for Theme { text_input::Appearance { background: palette.background.base.color.into(), - border_radius: 2.0.into(), - border_width: 1.0, - border_color: palette.primary.strong.color, + border: Border { + radius: 2.0.into(), + width: 1.0, + color: palette.primary.strong.color, + }, icon_color: palette.background.weak.text, } } @@ -1198,9 +1205,11 @@ impl text_input::StyleSheet for Theme { text_input::Appearance { background: palette.background.weak.color.into(), - border_radius: 2.0.into(), - border_width: 1.0, - border_color: palette.background.strong.color, + border: Border { + radius: 2.0.into(), + width: 1.0, + color: palette.background.strong.color, + }, icon_color: palette.background.strong.color, } } @@ -1236,9 +1245,11 @@ impl text_editor::StyleSheet for Theme { text_editor::Appearance { background: palette.background.base.color.into(), - border_radius: 2.0.into(), - border_width: 1.0, - border_color: palette.background.strong.color, + border: Border { + radius: 2.0.into(), + width: 1.0, + color: palette.background.strong.color, + }, } } @@ -1251,9 +1262,11 @@ impl text_editor::StyleSheet for Theme { text_editor::Appearance { background: palette.background.base.color.into(), - border_radius: 2.0.into(), - border_width: 1.0, - border_color: palette.background.base.text, + border: Border { + radius: 2.0.into(), + width: 1.0, + color: palette.background.base.text, + }, } } @@ -1266,9 +1279,11 @@ impl text_editor::StyleSheet for Theme { text_editor::Appearance { background: palette.background.base.color.into(), - border_radius: 2.0.into(), - border_width: 1.0, - border_color: palette.primary.strong.color, + border: Border { + radius: 2.0.into(), + width: 1.0, + color: palette.primary.strong.color, + }, } } @@ -1311,9 +1326,11 @@ impl text_editor::StyleSheet for Theme { text_editor::Appearance { background: palette.background.weak.color.into(), - border_radius: 2.0.into(), - border_width: 1.0, - border_color: palette.background.strong.color, + border: Border { + radius: 2.0.into(), + width: 1.0, + color: palette.background.strong.color, + }, } } diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index d1393b4d7a..ea4a3ec6fe 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,3 +1,5 @@ +use tiny_skia::Size; + use crate::core::{Background, Color, Gradient, Rectangle, Vector}; use crate::graphics::backend; use crate::graphics::text; @@ -150,9 +152,8 @@ impl Backend { Primitive::Quad { bounds, background, - border_radius, - border_width, - border_color, + border, + shadow, } => { let physical_bounds = (*bounds + translation) * scale_factor; @@ -170,11 +171,12 @@ impl Backend { .post_scale(scale_factor, scale_factor); // Make sure the border radius is not larger than the bounds - let border_width = border_width + let border_width = border + .width .min(bounds.width / 2.0) .min(bounds.height / 2.0); - let mut fill_border_radius = *border_radius; + let mut fill_border_radius = <[f32; 4]>::from(border.radius); for radius in &mut fill_border_radius { *radius = (*radius) .min(bounds.width / 2.0) @@ -182,6 +184,81 @@ impl Backend { } let path = rounded_rectangle(*bounds, fill_border_radius); + if shadow.color.a > 0.0 { + let shadow_bounds = (Rectangle { + x: bounds.x + shadow.offset.x - shadow.blur_radius, + y: bounds.y + shadow.offset.y - shadow.blur_radius, + width: bounds.width + shadow.blur_radius * 2.0, + height: bounds.height + shadow.blur_radius * 2.0, + } + translation) + * scale_factor; + + let radii = fill_border_radius + .into_iter() + .map(|radius| radius * scale_factor) + .collect::>(); + let (x, y, width, height) = ( + shadow_bounds.x as u32, + shadow_bounds.y as u32, + shadow_bounds.width as u32, + shadow_bounds.height as u32, + ); + let half_width = physical_bounds.width / 2.0; + let half_height = physical_bounds.height / 2.0; + + let colors = (y..y + height) + .flat_map(|y| { + (x..x + width).map(move |x| (x as f32, y as f32)) + }) + .filter_map(|(x, y)| { + Size::from_wh(half_width, half_height).map(|size| { + let shadow_distance = rounded_box_sdf( + Vector::new( + x - physical_bounds.position().x + - (shadow.offset.x * scale_factor) + - half_width, + y - physical_bounds.position().y + - (shadow.offset.y * scale_factor) + - half_height, + ), + size, + &radii, + ); + let shadow_alpha = 1.0 + - smoothstep( + -shadow.blur_radius * scale_factor, + shadow.blur_radius * scale_factor, + shadow_distance, + ); + + let mut color = into_color(shadow.color); + color.apply_opacity(shadow_alpha); + + color.to_color_u8().premultiply() + }) + }) + .collect(); + + if let Some(pixmap) = tiny_skia::IntSize::from_wh( + width, height, + ) + .and_then(|size| { + tiny_skia::Pixmap::from_vec( + bytemuck::cast_vec(colors), + size, + ) + }) { + pixels.draw_pixmap( + x as i32, + y as i32, + pixmap.as_ref(), + &tiny_skia::PixmapPaint::default(), + tiny_skia::Transform::default(), + None, + ); + } + } + pixels.fill_path( &path, &tiny_skia::Paint { @@ -252,7 +329,7 @@ impl Backend { }; // Make sure the border radius is correct - let mut border_radius = *border_radius; + let mut border_radius = <[f32; 4]>::from(border.radius); let mut is_simple_border = true; for radius in &mut border_radius { @@ -278,7 +355,7 @@ impl Backend { &border_path, &tiny_skia::Paint { shader: tiny_skia::Shader::SolidColor( - into_color(*border_color), + into_color(border.color), ), anti_alias: true, ..tiny_skia::Paint::default() @@ -334,7 +411,7 @@ impl Backend { &border_radius_path, &tiny_skia::Paint { shader: tiny_skia::Shader::SolidColor( - into_color(*border_color), + into_color(border.color), ), anti_alias: true, ..tiny_skia::Paint::default() @@ -864,6 +941,26 @@ fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) { ); } +fn smoothstep(a: f32, b: f32, x: f32) -> f32 { + let x = ((x - a) / (b - a)).clamp(0.0, 1.0); + + x * x * (3.0 - 2.0 * x) +} + +fn rounded_box_sdf(to_center: Vector, size: Size, radii: &[f32]) -> f32 { + let radius = match (to_center.x > 0.0, to_center.y > 0.0) { + (true, true) => radii[2], + (true, false) => radii[1], + (false, true) => radii[3], + (false, false) => radii[0], + }; + + let x = (to_center.x.abs() - size.width() + radius).max(0.0); + let y = (to_center.y.abs() - size.height() + radius).max(0.0); + + (x.powf(2.0) + y.powf(2.0)).sqrt() - radius +} + impl iced_graphics::Backend for Backend { type Primitive = primitive::Custom; } diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 4ad12a883c..e213c95f18 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -195,9 +195,8 @@ impl<'a> Layer<'a> { Primitive::Quad { bounds, background, - border_radius, - border_width, - border_color, + border, + shadow, } => { let layer = &mut layers[current_layer]; @@ -207,9 +206,12 @@ impl<'a> Layer<'a> { bounds.y + translation.y, ], size: [bounds.width, bounds.height], - border_color: color::pack(*border_color), - border_radius: *border_radius, - border_width: *border_width, + border_color: color::pack(border.color), + border_radius: border.radius.into(), + border_width: border.width, + shadow_color: shadow.color.into_linear(), + shadow_offset: shadow.offset.into(), + shadow_blur_radius: shadow.blur_radius, }; layer.quads.add(quad, background); diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 4bcf9a6658..cda1bec974 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -201,6 +201,15 @@ pub struct Quad { /// The border width of the [`Quad`]. pub border_width: f32, + + /// The shadow color of the [`Quad`]. + pub shadow_color: [f32; 4], + + /// The shadow offset of the [`Quad`]. + pub shadow_offset: [f32; 2], + + /// The shadow blur radius of the [`Quad`]. + pub shadow_blur_radius: f32, } /// A group of [`Quad`]s rendered together. diff --git a/wgpu/src/quad/solid.rs b/wgpu/src/quad/solid.rs index 90e7f98e3d..771eee34fb 100644 --- a/wgpu/src/quad/solid.rs +++ b/wgpu/src/quad/solid.rs @@ -105,6 +105,12 @@ impl Pipeline { 4 => Float32x4, // Border width 5 => Float32, + // Shadow color + 6 => Float32x4, + // Shadow offset + 7 => Float32x2, + // Shadow blur radius + 8 => Float32, ), }], }, diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index f919cfe24e..4de7336267 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -11,19 +11,15 @@ fn distance_alg( size: vec2, radius: f32 ) -> f32 { - var inner_size: vec2 = size - vec2(radius, radius) * 2.0; + var inner_half_size: vec2 = (size - vec2(radius, radius) * 2.0) / 2.0; var top_left: vec2 = position + vec2(radius, radius); - var bottom_right: vec2 = top_left + inner_size; - - var top_left_distance: vec2 = top_left - frag_coord; - var bottom_right_distance: vec2 = frag_coord - bottom_right; - - var dist: vec2 = vec2( - max(max(top_left_distance.x, bottom_right_distance.x), 0.0), - max(max(top_left_distance.y, bottom_right_distance.y), 0.0) - ); + return rounded_box_sdf(frag_coord - top_left - inner_half_size, inner_half_size, 0.0); +} - return sqrt(dist.x * dist.x + dist.y * dist.y); +// Given a vector from a point to the center of a rounded rectangle of the given `size` and +// border `radius`, determines the point's distance from the nearest edge of the rounded rectangle +fn rounded_box_sdf(to_center: vec2, size: vec2, radius: f32) -> f32 { + return length(max(abs(to_center) - size + vec2(radius, radius), vec2(0.0, 0.0))) - radius; } // Based on the fragement position and the center of the quad, select one of the 4 radi. diff --git a/wgpu/src/shader/quad/solid.wgsl b/wgpu/src/shader/quad/solid.wgsl index f84dd7abb7..1274f81481 100644 --- a/wgpu/src/shader/quad/solid.wgsl +++ b/wgpu/src/shader/quad/solid.wgsl @@ -6,6 +6,9 @@ struct SolidVertexInput { @location(3) border_color: vec4, @location(4) border_radius: vec4, @location(5) border_width: f32, + @location(6) shadow_color: vec4, + @location(7) shadow_offset: vec2, + @location(8) shadow_blur_radius: f32, } struct SolidVertexOutput { @@ -16,14 +19,17 @@ struct SolidVertexOutput { @location(3) scale: vec2, @location(4) border_radius: vec4, @location(5) border_width: f32, + @location(6) shadow_color: vec4, + @location(7) shadow_offset: vec2, + @location(8) shadow_blur_radius: f32, } @vertex fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput { var out: SolidVertexOutput; - var pos: vec2 = input.pos * globals.scale; - var scale: vec2 = input.scale * globals.scale; + var pos: vec2 = (input.pos + min(input.shadow_offset, vec2(0.0, 0.0)) - input.shadow_blur_radius) * globals.scale; + var scale: vec2 = (input.scale + vec2(abs(input.shadow_offset.x), abs(input.shadow_offset.y)) + input.shadow_blur_radius * 2.0) * globals.scale; var min_border_radius = min(input.scale.x, input.scale.y) * 0.5; var border_radius: vec4 = vec4( @@ -43,10 +49,13 @@ fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput { out.position = globals.transform * transform * vec4(vertex_position(input.vertex_index), 0.0, 1.0); out.color = input.color; out.border_color = input.border_color; - out.pos = pos; - out.scale = scale; + out.pos = input.pos * globals.scale; + out.scale = input.scale * globals.scale; out.border_radius = border_radius * globals.scale; out.border_width = input.border_width * globals.scale; + out.shadow_color = input.shadow_color; + out.shadow_offset = input.shadow_offset * globals.scale; + out.shadow_blur_radius = input.shadow_blur_radius * globals.scale; return out; } @@ -95,5 +104,20 @@ fn solid_fs_main( dist ); - return vec4(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); + let quad_color = vec4(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); + + if input.shadow_color.a > 0.0 { + let shadow_distance = rounded_box_sdf(input.position.xy - input.pos - input.shadow_offset - (input.scale / 2.0), input.scale / 2.0, border_radius); + let shadow_alpha = 1.0 - smoothstep(-input.shadow_blur_radius, input.shadow_blur_radius, shadow_distance); + let shadow_color = input.shadow_color; + let base_color = select( + vec4(shadow_color.x, shadow_color.y, shadow_color.z, 0.0), + quad_color, + quad_color.a > 0.0 + ); + + return mix(base_color, shadow_color, (1.0 - radius_alpha) * shadow_alpha); + } else { + return quad_color; + } } diff --git a/widget/src/button.rs b/widget/src/button.rs index 0ebb8dcc39..14626dd378 100644 --- a/widget/src/button.rs +++ b/widget/src/button.rs @@ -11,7 +11,7 @@ use crate::core::widget::tree::{self, Tree}; use crate::core::widget::Operation; use crate::core::{ Background, Clipboard, Color, Element, Layout, Length, Padding, Rectangle, - Shell, Size, Vector, Widget, + Shell, Size, Widget, }; pub use iced_style::button::{Appearance, StyleSheet}; @@ -391,30 +391,15 @@ where style_sheet.active(style) }; - if styling.background.is_some() || styling.border_width > 0.0 { - if styling.shadow_offset != Vector::default() { - // TODO: Implement proper shadow support - renderer.fill_quad( - renderer::Quad { - bounds: Rectangle { - x: bounds.x + styling.shadow_offset.x, - y: bounds.y + styling.shadow_offset.y, - ..bounds - }, - border_radius: styling.border_radius, - border_width: 0.0, - border_color: Color::TRANSPARENT, - }, - Background::Color([0.0, 0.0, 0.0, 0.5].into()), - ); - } - + if styling.background.is_some() + || styling.border.width > 0.0 + || styling.shadow.color.a > 0.0 + { renderer.fill_quad( renderer::Quad { bounds, - border_radius: styling.border_radius, - border_width: styling.border_width, - border_color: styling.border_color, + border: styling.border, + shadow: styling.shadow, }, styling .background diff --git a/widget/src/checkbox.rs b/widget/src/checkbox.rs index 0353b3adb7..762683143f 100644 --- a/widget/src/checkbox.rs +++ b/widget/src/checkbox.rs @@ -284,9 +284,8 @@ where renderer.fill_quad( renderer::Quad { bounds, - border_radius: custom_style.border_radius, - border_width: custom_style.border_width, - border_color: custom_style.border_color, + border: custom_style.border, + ..renderer::Quad::default() }, custom_style.background, ); diff --git a/widget/src/container.rs b/widget/src/container.rs index cffb0458a9..f2d1aabaa9 100644 --- a/widget/src/container.rs +++ b/widget/src/container.rs @@ -337,13 +337,15 @@ pub fn draw_background( ) where Renderer: crate::core::Renderer, { - if appearance.background.is_some() || appearance.border_width > 0.0 { + if appearance.background.is_some() + || appearance.border.width > 0.0 + || appearance.shadow.color.a > 0.0 + { renderer.fill_quad( renderer::Quad { bounds, - border_radius: appearance.border_radius, - border_width: appearance.border_width, - border_color: appearance.border_color, + border: appearance.border, + shadow: appearance.shadow, }, appearance .background diff --git a/widget/src/overlay/menu.rs b/widget/src/overlay/menu.rs index f83eebea37..678bb7b52d 100644 --- a/widget/src/overlay/menu.rs +++ b/widget/src/overlay/menu.rs @@ -10,7 +10,7 @@ use crate::core::text::{self, Text}; use crate::core::touch; use crate::core::widget::Tree; use crate::core::{ - Clipboard, Color, Length, Padding, Pixels, Point, Rectangle, Size, Vector, + Border, Clipboard, Length, Padding, Pixels, Point, Rectangle, Size, Vector, }; use crate::core::{Element, Shell, Widget}; use crate::scrollable::{self, Scrollable}; @@ -306,9 +306,8 @@ where renderer.fill_quad( renderer::Quad { bounds, - border_color: appearance.border_color, - border_width: appearance.border_width, - border_radius: appearance.border_radius, + border: appearance.border, + ..renderer::Quad::default() }, appearance.background, ); @@ -512,13 +511,12 @@ where renderer.fill_quad( renderer::Quad { bounds: Rectangle { - x: bounds.x + appearance.border_width, - width: bounds.width - appearance.border_width * 2.0, + x: bounds.x + appearance.border.width, + width: bounds.width - appearance.border.width * 2.0, ..bounds }, - border_color: Color::TRANSPARENT, - border_width: 0.0, - border_radius: appearance.border_radius, + border: Border::with_radius(appearance.border.radius), + ..renderer::Quad::default() }, appearance.selected_background, ); diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs index cf1f0455e4..3fda0e32f7 100644 --- a/widget/src/pane_grid.rs +++ b/widget/src/pane_grid.rs @@ -42,8 +42,8 @@ use crate::core::touch; use crate::core::widget; use crate::core::widget::tree::{self, Tree}; use crate::core::{ - Clipboard, Color, Element, Layout, Length, Pixels, Point, Rectangle, Shell, - Size, Vector, Widget, + Clipboard, Element, Layout, Length, Pixels, Point, Rectangle, Shell, Size, + Vector, Widget, }; /// A collection of panes distributed using either vertical or horizontal splits @@ -917,10 +917,8 @@ pub fn draw( renderer.fill_quad( renderer::Quad { bounds, - border_radius: hovered_region_style - .border_radius, - border_width: hovered_region_style.border_width, - border_color: hovered_region_style.border_color, + border: hovered_region_style.border, + ..renderer::Quad::default() }, theme.hovered_region(style).background, ); @@ -947,9 +945,8 @@ pub fn draw( renderer.fill_quad( renderer::Quad { bounds, - border_radius: hovered_region_style.border_radius, - border_width: hovered_region_style.border_width, - border_color: hovered_region_style.border_color, + border: hovered_region_style.border, + ..renderer::Quad::default() }, theme.hovered_region(style).background, ); @@ -1010,9 +1007,7 @@ pub fn draw( height: split_region.height, }, }, - border_radius: 0.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + ..renderer::Quad::default() }, highlight.color, ); diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs index 2e3aab6fe9..4d4e14d355 100644 --- a/widget/src/pick_list.rs +++ b/widget/src/pick_list.rs @@ -653,9 +653,8 @@ pub fn draw<'a, T, Renderer>( renderer.fill_quad( renderer::Quad { bounds, - border_color: style.border_color, - border_width: style.border_width, - border_radius: style.border_radius, + border: style.border, + ..renderer::Quad::default() }, style.background, ); diff --git a/widget/src/progress_bar.rs b/widget/src/progress_bar.rs index 15f1277b8a..eb15644e6c 100644 --- a/widget/src/progress_bar.rs +++ b/widget/src/progress_bar.rs @@ -3,7 +3,7 @@ use crate::core::layout; use crate::core::mouse; use crate::core::renderer; use crate::core::widget::Tree; -use crate::core::{Color, Element, Layout, Length, Rectangle, Size, Widget}; +use crate::core::{Border, Element, Layout, Length, Rectangle, Size, Widget}; use std::ops::RangeInclusive; @@ -130,9 +130,8 @@ where renderer.fill_quad( renderer::Quad { bounds: Rectangle { ..bounds }, - border_radius: style.border_radius, - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(style.border_radius), + ..renderer::Quad::default() }, style.background, ); @@ -144,9 +143,8 @@ where width: active_progress_width, ..bounds }, - border_radius: style.border_radius, - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(style.border_radius), + ..renderer::Quad::default() }, style.bar, ); diff --git a/widget/src/radio.rs b/widget/src/radio.rs index f91b20b159..ceb51eadff 100644 --- a/widget/src/radio.rs +++ b/widget/src/radio.rs @@ -9,7 +9,7 @@ use crate::core::touch; use crate::core::widget; use crate::core::widget::tree::{self, Tree}; use crate::core::{ - Clipboard, Color, Element, Layout, Length, Pixels, Rectangle, Shell, Size, + Border, Clipboard, Element, Layout, Length, Pixels, Rectangle, Shell, Size, Widget, }; @@ -312,9 +312,12 @@ where renderer.fill_quad( renderer::Quad { bounds, - border_radius: (size / 2.0).into(), - border_width: custom_style.border_width, - border_color: custom_style.border_color, + border: Border { + radius: (size / 2.0).into(), + width: custom_style.border_width, + color: custom_style.border_color, + }, + ..renderer::Quad::default() }, custom_style.background, ); @@ -328,9 +331,8 @@ where width: bounds.width - dot_size, height: bounds.height - dot_size, }, - border_radius: (dot_size / 2.0).into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(dot_size / 2.0), + ..renderer::Quad::default() }, custom_style.dot_color, ); diff --git a/widget/src/rule.rs b/widget/src/rule.rs index cded9cb1d1..c958c44d96 100644 --- a/widget/src/rule.rs +++ b/widget/src/rule.rs @@ -4,7 +4,7 @@ use crate::core::mouse; use crate::core::renderer; use crate::core::widget::Tree; use crate::core::{ - Color, Element, Layout, Length, Pixels, Rectangle, Size, Widget, + Border, Element, Layout, Length, Pixels, Rectangle, Size, Widget, }; pub use crate::style::rule::{Appearance, FillMode, StyleSheet}; @@ -124,9 +124,8 @@ where renderer.fill_quad( renderer::Quad { bounds, - border_radius: style.radius, - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(style.radius), + ..renderer::Quad::default() }, style.color, ); diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 70db490a96..b7b6c3d282 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -903,15 +903,14 @@ pub fn draw( if scrollbar.bounds.width > 0.0 && scrollbar.bounds.height > 0.0 && (style.background.is_some() - || (style.border_color != Color::TRANSPARENT - && style.border_width > 0.0)) + || (style.border.color != Color::TRANSPARENT + && style.border.width > 0.0)) { renderer.fill_quad( renderer::Quad { bounds: scrollbar.bounds, - border_radius: style.border_radius, - border_width: style.border_width, - border_color: style.border_color, + border: style.border, + ..renderer::Quad::default() }, style .background @@ -923,15 +922,14 @@ pub fn draw( if scrollbar.scroller.bounds.width > 0.0 && scrollbar.scroller.bounds.height > 0.0 && (style.scroller.color != Color::TRANSPARENT - || (style.scroller.border_color != Color::TRANSPARENT - && style.scroller.border_width > 0.0)) + || (style.scroller.border.color != Color::TRANSPARENT + && style.scroller.border.width > 0.0)) { renderer.fill_quad( renderer::Quad { bounds: scrollbar.scroller.bounds, - border_radius: style.scroller.border_radius, - border_width: style.scroller.border_width, - border_color: style.scroller.border_color, + border: style.scroller.border, + ..renderer::Quad::default() }, style.scroller.color, ); diff --git a/widget/src/slider.rs b/widget/src/slider.rs index 1bc946611d..79b0a7d866 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -8,8 +8,8 @@ use crate::core::renderer; use crate::core::touch; use crate::core::widget::tree::{self, Tree}; use crate::core::{ - Clipboard, Color, Element, Layout, Length, Pixels, Point, Rectangle, Shell, - Size, Widget, + Border, Clipboard, Element, Layout, Length, Pixels, Point, Rectangle, + Shell, Size, Widget, }; use std::ops::RangeInclusive; @@ -398,9 +398,8 @@ pub fn draw( width: offset + handle_width / 2.0, height: style.rail.width, }, - border_radius: style.rail.border_radius, - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(style.rail.border_radius), + ..renderer::Quad::default() }, style.rail.colors.0, ); @@ -413,9 +412,8 @@ pub fn draw( width: bounds.width - offset - handle_width / 2.0, height: style.rail.width, }, - border_radius: style.rail.border_radius, - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(style.rail.border_radius), + ..renderer::Quad::default() }, style.rail.colors.1, ); @@ -428,9 +426,12 @@ pub fn draw( width: handle_width, height: handle_height, }, - border_radius: handle_border_radius, - border_width: style.handle.border_width, - border_color: style.handle.border_color, + border: Border { + radius: handle_border_radius, + width: style.handle.border_width, + color: style.handle.border_color, + }, + ..renderer::Quad::default() }, style.handle.color, ); diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index 09a0cac0bf..6b71623847 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -10,8 +10,7 @@ use crate::core::text::highlighter::{self, Highlighter}; use crate::core::text::{self, LineHeight}; use crate::core::widget::{self, Widget}; use crate::core::{ - Clipboard, Color, Element, Length, Padding, Pixels, Rectangle, Shell, Size, - Vector, + Clipboard, Element, Length, Padding, Pixels, Rectangle, Shell, Size, Vector, }; use std::cell::RefCell; @@ -467,9 +466,8 @@ where renderer.fill_quad( renderer::Quad { bounds, - border_radius: appearance.border_radius, - border_width: appearance.border_width, - border_color: appearance.border_color, + border: appearance.border, + ..renderer::Quad::default() }, appearance.background, ); @@ -508,9 +506,7 @@ where ) .into(), }, - border_radius: 0.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + ..renderer::Quad::default() }, theme.value_color(&self.style), ); @@ -523,9 +519,7 @@ where renderer.fill_quad( renderer::Quad { bounds: range, - border_radius: 0.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + ..renderer::Quad::default() }, theme.selection_color(&self.style), ); diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs index c3dce8bef6..02715989ea 100644 --- a/widget/src/text_input.rs +++ b/widget/src/text_input.rs @@ -26,8 +26,8 @@ use crate::core::widget::operation::{self, Operation}; use crate::core::widget::tree::{self, Tree}; use crate::core::window; use crate::core::{ - Clipboard, Color, Element, Layout, Length, Padding, Pixels, Point, - Rectangle, Shell, Size, Vector, Widget, + Clipboard, Element, Layout, Length, Padding, Pixels, Point, Rectangle, + Shell, Size, Vector, Widget, }; use crate::runtime::Command; @@ -1082,9 +1082,8 @@ pub fn draw( renderer.fill_quad( renderer::Quad { bounds, - border_radius: appearance.border_radius, - border_width: appearance.border_width, - border_color: appearance.border_color, + border: appearance.border, + ..renderer::Quad::default() }, appearance.background, ); @@ -1131,9 +1130,7 @@ pub fn draw( width: 1.0, height: text_bounds.height, }, - border_radius: 0.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + ..renderer::Quad::default() }, theme.value_color(style), )) @@ -1172,9 +1169,7 @@ pub fn draw( width, height: text_bounds.height, }, - border_radius: 0.0.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, + ..renderer::Quad::default() }, theme.selection_color(style), )), diff --git a/widget/src/toggler.rs b/widget/src/toggler.rs index 941159ea6a..58cd38ab74 100644 --- a/widget/src/toggler.rs +++ b/widget/src/toggler.rs @@ -9,8 +9,8 @@ use crate::core::touch; use crate::core::widget; use crate::core::widget::tree::{self, Tree}; use crate::core::{ - Clipboard, Element, Event, Layout, Length, Pixels, Rectangle, Shell, Size, - Widget, + Border, Clipboard, Element, Event, Layout, Length, Pixels, Rectangle, + Shell, Size, Widget, }; pub use crate::style::toggler::{Appearance, StyleSheet}; @@ -312,11 +312,12 @@ where renderer.fill_quad( renderer::Quad { bounds: toggler_background_bounds, - border_radius: border_radius.into(), - border_width: 1.0, - border_color: style - .background_border - .unwrap_or(style.background), + border: Border { + radius: border_radius.into(), + width: 1.0, + color: style.background_border.unwrap_or(style.background), + }, + ..renderer::Quad::default() }, style.background, ); @@ -336,11 +337,12 @@ where renderer.fill_quad( renderer::Quad { bounds: toggler_foreground_bounds, - border_radius: border_radius.into(), - border_width: 1.0, - border_color: style - .foreground_border - .unwrap_or(style.foreground), + border: Border { + radius: border_radius.into(), + width: 1.0, + color: style.foreground_border.unwrap_or(style.foreground), + }, + ..renderer::Quad::default() }, style.foreground, ); diff --git a/widget/src/vertical_slider.rs b/widget/src/vertical_slider.rs index a3029d766b..52428c10b6 100644 --- a/widget/src/vertical_slider.rs +++ b/widget/src/vertical_slider.rs @@ -13,7 +13,7 @@ use crate::core::renderer; use crate::core::touch; use crate::core::widget::tree::{self, Tree}; use crate::core::{ - Clipboard, Color, Element, Length, Pixels, Point, Rectangle, Shell, Size, + Border, Clipboard, Element, Length, Pixels, Point, Rectangle, Shell, Size, Widget, }; @@ -397,9 +397,8 @@ pub fn draw( width: style.rail.width, height: offset + handle_width / 2.0, }, - border_radius: style.rail.border_radius, - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(style.rail.border_radius), + ..renderer::Quad::default() }, style.rail.colors.1, ); @@ -412,9 +411,8 @@ pub fn draw( width: style.rail.width, height: bounds.height - offset - handle_width / 2.0, }, - border_radius: style.rail.border_radius, - border_width: 0.0, - border_color: Color::TRANSPARENT, + border: Border::with_radius(style.rail.border_radius), + ..renderer::Quad::default() }, style.rail.colors.0, ); @@ -427,9 +425,12 @@ pub fn draw( width: handle_height, height: handle_width, }, - border_radius: handle_border_radius, - border_width: style.handle.border_width, - border_color: style.handle.border_color, + border: Border { + radius: handle_border_radius, + width: style.handle.border_width, + color: style.handle.border_color, + }, + ..renderer::Quad::default() }, style.handle.color, );