diff --git a/src/style.rs b/src/style.rs index b84eca6a..7cdd2658 100644 --- a/src/style.rs +++ b/src/style.rs @@ -76,6 +76,21 @@ pub enum CursorStyle { pub struct BoxShadow { pub blur_radius: f64, pub color: Color, + pub spread: f64, + pub h_offset: f64, + pub v_offset: f64, +} + +impl Default for BoxShadow { + fn default() -> Self { + Self { + blur_radius: 0.0, + color: Color::BLACK, + spread: 0.0, + h_offset: 0.0, + v_offset: 0.0, + } + } } /// The value for a [`Style`] property @@ -615,7 +630,7 @@ impl Style { self.box_shadow = Some(BoxShadow { blur_radius, - color: Color::BLACK, + ..Default::default() }) .into(); self @@ -630,8 +645,56 @@ impl Style { } self.box_shadow = Some(BoxShadow { - blur_radius: 0.0, color, + ..Default::default() + }) + .into(); + self + } + + pub fn box_shadow_spread(mut self, spread: f64) -> Self { + if let Some(box_shadow) = self.box_shadow.as_mut() { + if let Some(box_shadow) = box_shadow.as_mut() { + box_shadow.spread = spread; + return self; + } + } + + self.box_shadow = Some(BoxShadow { + spread, + ..Default::default() + }) + .into(); + self + } + + pub fn box_shadow_h_offset(mut self, h_offset: f64) -> Self { + if let Some(box_shadow) = self.box_shadow.as_mut() { + if let Some(box_shadow) = box_shadow.as_mut() { + box_shadow.h_offset = h_offset; + return self; + } + } + + self.box_shadow = Some(BoxShadow { + h_offset, + ..Default::default() + }) + .into(); + self + } + + pub fn box_shadow_v_offset(mut self, v_offset: f64) -> Self { + if let Some(box_shadow) = self.box_shadow.as_mut() { + if let Some(box_shadow) = box_shadow.as_mut() { + box_shadow.v_offset = v_offset; + return self; + } + } + + self.box_shadow = Some(BoxShadow { + v_offset, + ..Default::default() }) .into(); self diff --git a/src/view.rs b/src/view.rs index 55a4c22c..02718eed 100644 --- a/src/view.rs +++ b/src/view.rs @@ -87,7 +87,7 @@ use std::any::Any; use bitflags::bitflags; use floem_renderer::Renderer; -use kurbo::{Affine, Circle, Line, Point, Rect, Size}; +use kurbo::{Affine, Circle, Insets, Line, Point, Rect, RoundedRect, Size}; use taffy::prelude::Node; use crate::{ @@ -795,24 +795,16 @@ fn paint_bg(cx: &mut PaintCx, style: &ComputedStyle, size: Size) { }; cx.fill(&circle, bg, 0.0); } else { - let rect = rect.to_rounded_rect(radius as f64); - if let Some(shadow) = style.box_shadow.as_ref() { - if shadow.blur_radius > 0.0 { - cx.fill(&rect, shadow.color, shadow.blur_radius); - } - } + paint_box_shadow(cx, style, rect, Some(radius as f64)); let bg = match style.background { Some(color) => color, None => return, }; - cx.fill(&rect, bg, 0.0); + let rounded_rect = rect.to_rounded_rect(radius as f64); + cx.fill(&rounded_rect, bg, 0.0); } } else { - if let Some(shadow) = style.box_shadow.as_ref() { - if shadow.blur_radius > 0.0 { - cx.fill(&size.to_rect(), shadow.color, shadow.blur_radius); - } - } + paint_box_shadow(cx, style, size.to_rect(), None); let bg = match style.background { Some(color) => color, None => return, @@ -821,6 +813,24 @@ fn paint_bg(cx: &mut PaintCx, style: &ComputedStyle, size: Size) { } } +fn paint_box_shadow(cx: &mut PaintCx, style: &ComputedStyle, rect: Rect, rect_radius: Option) { + if let Some(shadow) = style.box_shadow.as_ref() { + let inset = Insets::new( + -shadow.h_offset / 2.0, + -shadow.v_offset / 2.0, + shadow.h_offset / 2.0, + shadow.v_offset / 2.0, + ); + let rect = rect.inflate(shadow.spread, shadow.spread).inset(inset); + if let Some(radii) = rect_radius { + let rounded_rect = RoundedRect::from_rect(rect, radii + shadow.spread); + cx.fill(&rounded_rect, shadow.color, shadow.blur_radius); + } else { + cx.fill(&rect, shadow.color, shadow.blur_radius); + } + } +} + fn paint_outline(cx: &mut PaintCx, style: &ComputedStyle, size: Size) { if style.outline == 0. { // TODO: we should warn! when outline is < 0