1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! Shadow configuration models used by drop/inner shadow modifiers.
use crate::{BlendMode, Brush, Color, Density, Dp, Point};
/// Density-independent offset for shadows.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct DpOffset {
/// Horizontal distance, positive to the right.
pub x: Dp,
/// Vertical distance, positive downward.
pub y: Dp,
}
impl DpOffset {
/// Creates an offset from a horizontal and a vertical distance.
pub const fn new(x: Dp, y: Dp) -> Self {
Self { x, y }
}
/// An offset of zero in both directions.
pub const ZERO: DpOffset = DpOffset {
x: Dp(0.0),
y: Dp(0.0),
};
/// Converts both components to pixels at `density`.
pub fn to_px(self, density: Density) -> Point {
Point::new(self.x.to_px(density).0, self.y.to_px(density).0)
}
}
impl Default for DpOffset {
fn default() -> Self {
Self::ZERO
}
}
/// Static shadow configuration.
///
/// This mirrors Compose's static `Shadow` object where radius/spread/offset
/// are provided in density-independent units and converted to pixels at draw time.
#[derive(Clone, Debug, PartialEq)]
pub struct Shadow {
/// Blur radius. Negative values count as 0.
pub radius: Dp,
/// Growth of the shadow shape before blurring. Negative values shrink it.
pub spread: Dp,
/// Shift of the shadow relative to the element.
pub offset: DpOffset,
/// Shadow color, used when `brush` is `None`.
pub color: Color,
/// Paint for the shadow, used instead of `color` when set.
pub brush: Option<Brush>,
/// Opacity from 0.0 to 1.0. A value of 0.0 or less draws no shadow.
pub alpha: f32,
/// How the shadow combines with what is already drawn.
pub blend_mode: BlendMode,
/// Knocks the unoffset, unspread shape out of the shadow silhouette
/// before blurring, leaving shadow only OUTSIDE the element. Required
/// for translucent surfaces (glass): a backdrop-sampling material must
/// not refract its own shadow.
pub cutout: bool,
}
impl Default for Shadow {
fn default() -> Self {
Self {
radius: Dp(0.0),
spread: Dp(0.0),
offset: DpOffset::ZERO,
color: Color::BLACK,
brush: None,
alpha: 1.0,
blend_mode: BlendMode::SrcOver,
cutout: false,
}
}
}
impl Shadow {
/// Converts the lengths to pixels at `density`.
pub fn to_scope(&self, density: Density) -> ShadowScope {
ShadowScope {
radius: self.radius.to_px(density).0,
spread: self.spread.to_px(density).0,
offset: self.offset.to_px(density),
color: self.color,
brush: self.brush.clone(),
alpha: self.alpha,
blend_mode: self.blend_mode,
cutout: self.cutout,
}
}
}
/// Pixel-space shadow scope used by block-based APIs.
#[derive(Clone, Debug, PartialEq)]
pub struct ShadowScope {
/// Blur radius, in pixels. Negative values count as 0.0.
pub radius: f32,
/// Growth of the shadow shape before blurring, in pixels. Negative values shrink it.
pub spread: f32,
/// Shift of the shadow relative to the element, in pixels.
pub offset: Point,
/// Shadow color, used when `brush` is `None`.
pub color: Color,
/// Paint for the shadow, used instead of `color` when set.
pub brush: Option<Brush>,
/// Opacity from 0.0 to 1.0. A value of 0.0 or less draws no shadow.
pub alpha: f32,
/// How the shadow combines with what is already drawn.
pub blend_mode: BlendMode,
/// See [`Shadow::cutout`]: knock the element's own shape out of the
/// silhouette so the shadow exists only outside it.
pub cutout: bool,
}
impl Default for ShadowScope {
fn default() -> Self {
Self {
radius: 0.0,
spread: 0.0,
offset: Point::ZERO,
color: Color::BLACK,
brush: None,
alpha: 1.0,
blend_mode: BlendMode::SrcOver,
cutout: false,
}
}
}
#[cfg(test)]
#[path = "tests/shadow_tests.rs"]
mod tests;