epaint/
shadow.rs

1use crate::{Color32, CornerRadius, Marginf, Rect, RectShape, Vec2};
2
3/// The color and fuzziness of a fuzzy shape.
4///
5/// Can be used for a rectangular shadow with a soft penumbra.
6///
7/// Very similar to a box-shadow in CSS.
8#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
9#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
10pub struct Shadow {
11    /// Move the shadow by this much.
12    ///
13    /// For instance, a value of `[1.0, 2.0]` will move the shadow 1 point to the right and 2 points down,
14    /// causing a drop-shadow effect.
15    pub offset: [i8; 2],
16
17    /// The width of the blur, i.e. the width of the fuzzy penumbra.
18    ///
19    /// A value of 0 means a sharp shadow.
20    pub blur: u8,
21
22    /// Expand the shadow in all directions by this much.
23    pub spread: u8,
24
25    /// Color of the opaque center of the shadow.
26    pub color: Color32,
27}
28
29#[test]
30fn shadow_size() {
31    assert_eq!(
32        std::mem::size_of::<Shadow>(), 8,
33        "Shadow changed size! If it shrank - good! Update this test. If it grew - bad! Try to find a way to avoid it."
34    );
35}
36
37impl Shadow {
38    /// No shadow at all.
39    pub const NONE: Self = Self {
40        offset: [0, 0],
41        blur: 0,
42        spread: 0,
43        color: Color32::TRANSPARENT,
44    };
45
46    /// The argument is the rectangle of the shadow caster.
47    pub fn as_shape(&self, rect: Rect, corner_radius: impl Into<CornerRadius>) -> RectShape {
48        // tessellator.clip_rect = clip_rect; // TODO(emilk): culling
49
50        let Self {
51            offset,
52            blur,
53            spread,
54            color,
55        } = *self;
56        let [offset_x, offset_y] = offset;
57
58        let rect = rect
59            .translate(Vec2::new(offset_x as _, offset_y as _))
60            .expand(spread as _);
61        let corner_radius = corner_radius.into() + CornerRadius::from(spread);
62
63        RectShape::filled(rect, corner_radius, color).with_blur_width(blur as _)
64    }
65
66    /// How much larger than the parent rect are we in each direction?
67    pub fn margin(&self) -> Marginf {
68        let Self {
69            offset,
70            blur,
71            spread,
72            color: _,
73        } = *self;
74        let spread = spread as f32;
75        let blur = blur as f32;
76        let [offset_x, offset_y] = offset;
77        Marginf {
78            left: spread + 0.5 * blur - offset_x as f32,
79            right: spread + 0.5 * blur + offset_x as f32,
80            top: spread + 0.5 * blur - offset_y as f32,
81            bottom: spread + 0.5 * blur + offset_y as f32,
82        }
83    }
84}