Skip to main content

ferroui_base/media/effects/
effect_extensions.rs

1use crate::media::effects::{IEffect, IImmutableEffect};
2use crate::{Rect, Thickness, Vector};
3use std::rc::Rc;
4
5/// Extension methods for effects.
6pub struct EffectExtensions;
7
8impl EffectExtensions {
9    fn adjust_padding_radius(radius: f64) -> f64 {
10        if radius <= 0.0 {
11            return 0.0;
12        }
13        radius.ceil() + 1.0
14    }
15
16    /// How far the output of the effect extends beyond the bounds of the
17    /// content it is applied to.
18    ///
19    /// Panics for an effect of an unknown kind.
20    pub fn get_effect_output_padding(effect: Option<&dyn IEffect>) -> Thickness {
21        let Some(effect) = effect else { return Thickness::default() };
22        if let Some(blur) = effect.as_blur_effect() {
23            return Thickness::uniform(Self::adjust_padding_radius(blur.radius()));
24        }
25        if let Some(drop_shadow_effect) = effect.as_drop_shadow_effect() {
26            let radius = Self::adjust_padding_radius(drop_shadow_effect.blur_radius());
27            let rc = Rect::new(-radius, -radius, radius * 2.0, radius * 2.0);
28            let rc = rc.translate(Vector::new(drop_shadow_effect.offset_x(), drop_shadow_effect.offset_y()));
29            return Thickness::new(
30                f64::max(0.0, 0.0 - rc.x),
31                f64::max(0.0, 0.0 - rc.y),
32                f64::max(0.0, rc.right()),
33                f64::max(0.0, rc.bottom()),
34            );
35        }
36
37        panic!("Unknown effect type");
38    }
39
40    /// Converts an effect to an immutable effect: the result of
41    /// [`IMutableEffect::to_immutable`](crate::media::effects::IMutableEffect::to_immutable)
42    /// if the effect is mutable, otherwise the effect itself.
43    pub fn to_immutable(effect: &Rc<dyn IEffect>) -> std::sync::Arc<dyn IImmutableEffect> {
44        if let Some(mutable) = effect.as_mutable_effect() {
45            return mutable.to_immutable();
46        }
47        effect.clone().into_immutable_effect().expect("an effect is either mutable or immutable")
48    }
49
50    /// Whether an immutable effect and another effect are both absent or
51    /// structurally equal.
52    pub fn effect_equals(immutable: Option<&dyn IImmutableEffect>, right: Option<&dyn IEffect>) -> bool {
53        match (immutable, right) {
54            (None, None) => true,
55            (Some(immutable), Some(right)) => immutable.equals(Some(right)),
56            _ => false,
57        }
58    }
59}