Skip to main content

ferroui_base/media/effects/
i_drop_shadow_effect.rs

1use crate::media::effects::{
2    DropShadowDirectionEffect, DropShadowEffect, DropShadowEffectBase, Effect, IEffect, IImmutableEffect,
3};
4use crate::media::ref_adapter::RefAdapter;
5use crate::media::Color;
6use crate::{ObjectType, Upcast};
7use std::any::Any;
8use std::f64::consts::PI;
9use std::rc::Rc;
10
11/// An effect that draws a shadow behind its content.
12pub trait IDropShadowEffect: IEffect {
13    /// The horizontal offset of the shadow.
14    fn offset_x(&self) -> f64;
15
16    /// The vertical offset of the shadow.
17    fn offset_y(&self) -> f64;
18
19    /// The blur radius of the shadow.
20    fn blur_radius(&self) -> f64;
21
22    /// The color of the shadow.
23    fn color(&self) -> Color;
24
25    /// The opacity of the shadow.
26    fn opacity(&self) -> f64;
27}
28
29/// A drop shadow described by a direction and a depth.
30pub trait IDirectionDropShadowEffect: IDropShadowEffect {
31    /// The direction of the shadow, in degrees.
32    fn direction(&self) -> f64;
33
34    /// The distance of the shadow from the content.
35    fn shadow_depth(&self) -> f64;
36}
37
38fn drop_shadow_equals(this: &dyn IDropShadowEffect, other: Option<&dyn IEffect>) -> bool {
39    other.and_then(|other| other.as_drop_shadow_effect()).is_some_and(|d| {
40        d.offset_x() == this.offset_x()
41            && d.offset_y() == this.offset_y()
42            && d.blur_radius() == this.blur_radius()
43            && d.color() == this.color()
44            && d.opacity() == this.opacity()
45    })
46}
47
48/// An immutable drop shadow effect.
49#[derive(Clone, Copy, Debug)]
50pub struct ImmutableDropShadowEffect {
51    offset_x: f64,
52    offset_y: f64,
53    blur_radius: f64,
54    color: Color,
55    opacity: f64,
56}
57
58impl ImmutableDropShadowEffect {
59    pub fn new(offset_x: f64, offset_y: f64, blur_radius: f64, color: Color, opacity: f64) -> Self {
60        Self { offset_x, offset_y, blur_radius, color, opacity }
61    }
62
63    /// The horizontal offset of the shadow.
64    #[inline]
65    pub fn offset_x(&self) -> f64 {
66        self.offset_x
67    }
68
69    /// The vertical offset of the shadow.
70    #[inline]
71    pub fn offset_y(&self) -> f64 {
72        self.offset_y
73    }
74
75    /// The blur radius of the shadow.
76    #[inline]
77    pub fn blur_radius(&self) -> f64 {
78        self.blur_radius
79    }
80
81    /// The color of the shadow.
82    #[inline]
83    pub fn color(&self) -> Color {
84        self.color
85    }
86
87    /// The opacity of the shadow.
88    #[inline]
89    pub fn opacity(&self) -> f64 {
90        self.opacity
91    }
92}
93
94impl IEffect for ImmutableDropShadowEffect {
95    fn as_any(&self) -> &dyn Any {
96        self
97    }
98
99    fn as_drop_shadow_effect(&self) -> Option<&dyn IDropShadowEffect> {
100        Some(self)
101    }
102
103    fn as_immutable_effect(&self) -> Option<&dyn IImmutableEffect> {
104        Some(self)
105    }
106
107    fn into_immutable_effect(self: Rc<Self>) -> Option<std::sync::Arc<dyn IImmutableEffect>> {
108        Some(std::sync::Arc::new(*self))
109    }
110}
111
112impl IDropShadowEffect for ImmutableDropShadowEffect {
113    #[inline]
114    fn offset_x(&self) -> f64 {
115        self.offset_x
116    }
117
118    #[inline]
119    fn offset_y(&self) -> f64 {
120        self.offset_y
121    }
122
123    #[inline]
124    fn blur_radius(&self) -> f64 {
125        self.blur_radius
126    }
127
128    #[inline]
129    fn color(&self) -> Color {
130        self.color
131    }
132
133    #[inline]
134    fn opacity(&self) -> f64 {
135        self.opacity
136    }
137}
138
139impl IImmutableEffect for ImmutableDropShadowEffect {
140    fn equals(&self, other: Option<&dyn IEffect>) -> bool {
141        drop_shadow_equals(self, other)
142    }
143}
144
145/// An immutable drop shadow effect described by a direction and a depth.
146#[derive(Clone, Copy, Debug)]
147pub struct ImmutableDropShadowDirectionEffect {
148    direction: f64,
149    shadow_depth: f64,
150    blur_radius: f64,
151    color: Color,
152    opacity: f64,
153}
154
155impl ImmutableDropShadowDirectionEffect {
156    pub fn new(direction: f64, shadow_depth: f64, blur_radius: f64, color: Color, opacity: f64) -> Self {
157        Self { direction, shadow_depth, blur_radius, color, opacity }
158    }
159
160    /// The horizontal offset of the shadow.
161    pub fn offset_x(&self) -> f64 {
162        (self.direction * PI / 180.0).cos() * self.shadow_depth
163    }
164
165    /// The vertical offset of the shadow.
166    pub fn offset_y(&self) -> f64 {
167        (self.direction * PI / 180.0).sin() * self.shadow_depth
168    }
169
170    /// The direction of the shadow, in degrees.
171    #[inline]
172    pub fn direction(&self) -> f64 {
173        self.direction
174    }
175
176    /// The distance of the shadow from the content.
177    #[inline]
178    pub fn shadow_depth(&self) -> f64 {
179        self.shadow_depth
180    }
181
182    /// The blur radius of the shadow.
183    #[inline]
184    pub fn blur_radius(&self) -> f64 {
185        self.blur_radius
186    }
187
188    /// The color of the shadow.
189    #[inline]
190    pub fn color(&self) -> Color {
191        self.color
192    }
193
194    /// The opacity of the shadow.
195    #[inline]
196    pub fn opacity(&self) -> f64 {
197        self.opacity
198    }
199}
200
201impl IEffect for ImmutableDropShadowDirectionEffect {
202    fn as_any(&self) -> &dyn Any {
203        self
204    }
205
206    fn as_drop_shadow_effect(&self) -> Option<&dyn IDropShadowEffect> {
207        Some(self)
208    }
209
210    fn as_direction_drop_shadow_effect(&self) -> Option<&dyn IDirectionDropShadowEffect> {
211        Some(self)
212    }
213
214    fn as_immutable_effect(&self) -> Option<&dyn IImmutableEffect> {
215        Some(self)
216    }
217
218    fn into_immutable_effect(self: Rc<Self>) -> Option<std::sync::Arc<dyn IImmutableEffect>> {
219        Some(std::sync::Arc::new(*self))
220    }
221}
222
223impl IDropShadowEffect for ImmutableDropShadowDirectionEffect {
224    fn offset_x(&self) -> f64 {
225        ImmutableDropShadowDirectionEffect::offset_x(self)
226    }
227
228    fn offset_y(&self) -> f64 {
229        ImmutableDropShadowDirectionEffect::offset_y(self)
230    }
231
232    #[inline]
233    fn blur_radius(&self) -> f64 {
234        self.blur_radius
235    }
236
237    #[inline]
238    fn color(&self) -> Color {
239        self.color
240    }
241
242    #[inline]
243    fn opacity(&self) -> f64 {
244        self.opacity
245    }
246}
247
248impl IDirectionDropShadowEffect for ImmutableDropShadowDirectionEffect {
249    #[inline]
250    fn direction(&self) -> f64 {
251        self.direction
252    }
253
254    #[inline]
255    fn shadow_depth(&self) -> f64 {
256        self.shadow_depth
257    }
258}
259
260impl IImmutableEffect for ImmutableDropShadowDirectionEffect {
261    fn equals(&self, other: Option<&dyn IEffect>) -> bool {
262        drop_shadow_equals(self, other)
263    }
264}
265
266impl<T: ObjectType + Upcast<Effect>> IDropShadowEffect for RefAdapter<T> {
267    fn offset_x(&self) -> f64 {
268        match self.object().downcast_ref::<DropShadowEffect>() {
269            Some(shadow) => shadow.offset_x(),
270            None => self.class::<DropShadowDirectionEffect>().offset_x(),
271        }
272    }
273
274    fn offset_y(&self) -> f64 {
275        match self.object().downcast_ref::<DropShadowEffect>() {
276            Some(shadow) => shadow.offset_y(),
277            None => self.class::<DropShadowDirectionEffect>().offset_y(),
278        }
279    }
280
281    #[inline]
282    fn blur_radius(&self) -> f64 {
283        self.class::<DropShadowEffectBase>().blur_radius()
284    }
285
286    #[inline]
287    fn color(&self) -> Color {
288        self.class::<DropShadowEffectBase>().color()
289    }
290
291    #[inline]
292    fn opacity(&self) -> f64 {
293        self.class::<DropShadowEffectBase>().opacity()
294    }
295}
296
297impl<T: ObjectType + Upcast<Effect>> IDirectionDropShadowEffect for RefAdapter<T> {
298    #[inline]
299    fn direction(&self) -> f64 {
300        self.class::<DropShadowDirectionEffect>().direction()
301    }
302
303    #[inline]
304    fn shadow_depth(&self) -> f64 {
305        self.class::<DropShadowDirectionEffect>().shadow_depth()
306    }
307}