Support more complicated BoxShadows
What problem does this solve or what need does it fill?
Allow us to do things like https://www.tyleo.com/html-glass.html.
What solution would you like?
- [ ] Inset box shadows
- [ ] Per-side box shadows
- [ ] More than one box shadow per node
- [ ] Have border radius clip all of the above (not sure if it already does or not)
Inset box shadows
I only included drop shadow support as I wanted to keep the initial PR really simple but inset shadows should be really easy to add. If there's anyone looking for an idea for a simple side project, a 3rd party inset shadow crate shouldn't take much effort. I might make one myself if I run out of bevy PR ideas.
Per-side and multiple box shadows
The plugin just draws blurred rects from a list so we have support for per-side and multiple box shadows already, sort of. That requires users to write their own component and extraction function though, which isn't great.
Clipping
UI clipping only supports right angled, axis-aligned rectangles. It doesn't consider border radius at all, I guess we need some of compositing to implement it properly?
Elliptical border radius
Another missing feature for shadows we need is elliptical border radius support. The box shadow plugin only supports uniform scaling of node's shadows because inon-uniform scaling would require elliptical border radius support to draw the distorted rounded corners.
API
Something like this maybe:
#[derive(Component, Default, Clone, Debug, Reflect)]
#[reflect(Component, Default)]
#[cfg_attr(
feature = "serialize",
derive(serde::Serialize, serde::Deserialize),
reflect(Serialize, Deserialize)
)]
pub struct BoxShadow {
/// Shadows drawn according to their order in the vector, from back to front
shadows: Vec<ShadowStyle>,
}
// #[derive(Component, Copy, Clone, Debug, Default, PartialEq, Eq, Reflect)]
// #[reflect(Component, Default, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Reflect)]
pub enum ShadowStyle {
/// Shadow drawn beneath a UI node.
/// Position and size relative to the corresponding UI node.
Drop {
/// The shadow's color
color: Color,
/// Horizontal offset
x_offset: Val,
/// Vertical offset
y_offset: Val,
/// How much the shadow should spread outward.
///
/// Negative values will make the shadow shrink inwards.
/// Percentage values are based on the width of the UI node.
spread_radius: Val,
/// Blurriness of the shadow
blur_radius: Val,
},
/// Shadow drawn beneath its corresponding UI node.
/// Position is relative to its `Node` but with independent size and radius.
DropFree {
/// The shadow's color
color: Color,
/// Horizontal offset
x_offset: Val,
/// Vertical offset
y_offset: Val,
/// Shadow width,
width: Val,
/// Shadow height
height: Val,
/// radius of the corners
radius: BorderRadius,
/// Blurriness of the shadow
blur_radius: Val,
},
/// Inner shadow drawn on top of the node and inside the node's padding box, starting at the border-padding edge.
Inset {
/// The shadow's color
color: Color,
/// Horizontal offset.
/// Negative values move the shadow to the left, positive to the right.
x_offset: Val,
/// Vertical offset.
/// Negative values move the shadow to the left, positive to the right.
y_offset: Val,
/// Controls the size of the shadow. Positive values increase the size of the shadow,
/// covering more of the padding box.
spread_radius: Val,
/// Blurriness of the shadow
blur_radius: Val,
},
}
impl Default for ShadowStyle {
fn default() -> Self {
Self::Drop {
color: Color::BLACK,
x_offset: Val::Percent(20.),
y_offset: Val::Percent(20.),
spread_radius: Val::ZERO,
blur_radius: Val::Percent(10.),
}
}
}
- Don't like the name
DropFreevery much. Alternatives I can think of likeDropAbsolute,Absolute,DropIndependent,CustomDrop, don't seem much better though. - Could just have one
Dropvariant with aShadowSizeenum withSpreadRadiusandIndependent/Absolutevariants instead. - Might be cleaner to have seperate
DropShadowandInsetShadowcomponents instead of oneBoxShadowcomponent, each with their own seperate list of shadows.
Multiple shadow support #16502