Skip to main content

ferroui_base/media/effects/
i_effect.rs

1use crate::media::effects::{
2    BlurEffect, DropShadowDirectionEffect, DropShadowEffect, Effect, IBlurEffect, IDirectionDropShadowEffect,
3    IDropShadowEffect,
4};
5use crate::media::ref_adapter::RefAdapter;
6use crate::{FerroObject, ObjectType, Ref, Upcast};
7use std::any::Any;
8use std::rc::Rc;
9
10/// A bitmap effect.
11///
12/// Implemented by the immutable effect types and, through an adapter, by
13/// every class deriving from [`Effect`]: a handle of such a class converts to
14/// `Rc<dyn IEffect>` with `into()`. The `as_*` members replace interface
15/// casts (`effect as IBlurEffect`).
16pub trait IEffect: 'static {
17    /// The implementing value, for downcasts to immutable effect types. For
18    /// mutable effects use [`as_object`](Self::as_object).
19    fn as_any(&self) -> &dyn Any;
20
21    /// The object behind the effect when it is a mutable [`Effect`].
22    fn as_object(&self) -> Option<&FerroObject> {
23        None
24    }
25
26    /// The effect viewed as [`IBlurEffect`], when it is one.
27    fn as_blur_effect(&self) -> Option<&dyn IBlurEffect> {
28        None
29    }
30
31    /// The effect viewed as [`IDropShadowEffect`], when it is one.
32    fn as_drop_shadow_effect(&self) -> Option<&dyn IDropShadowEffect> {
33        None
34    }
35
36    /// The effect viewed as [`IDirectionDropShadowEffect`], when it is one.
37    fn as_direction_drop_shadow_effect(&self) -> Option<&dyn IDirectionDropShadowEffect> {
38        None
39    }
40
41    /// The effect viewed as [`IMutableEffect`], when it is one.
42    fn as_mutable_effect(&self) -> Option<&dyn IMutableEffect> {
43        None
44    }
45
46    /// The effect viewed as [`IImmutableEffect`], when it is one.
47    fn as_immutable_effect(&self) -> Option<&dyn IImmutableEffect> {
48        None
49    }
50
51    /// The effect as an [`IImmutableEffect`] handle, when it is immutable: a
52    /// copy in a handle that can be shared with the render thread (immutable
53    /// effects are values and compare structurally).
54    fn into_immutable_effect(self: Rc<Self>) -> Option<std::sync::Arc<dyn IImmutableEffect>> {
55        None
56    }
57
58    /// The identity of the effect, used for reference equality.
59    #[doc(hidden)]
60    fn reference_id(&self) -> *const () {
61        self as *const Self as *const ()
62    }
63}
64
65/// Effects compare by reference; structural comparison of immutable effects
66/// is [`IImmutableEffect::equals`].
67impl PartialEq for dyn IEffect {
68    #[inline]
69    fn eq(&self, other: &Self) -> bool {
70        self.reference_id() == other.reference_id()
71    }
72}
73
74impl std::fmt::Debug for dyn IEffect {
75    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76        if let Some(blur) = self.as_blur_effect() {
77            write!(f, "IEffect(blur({}))", blur.radius())
78        } else if let Some(shadow) = self.as_drop_shadow_effect() {
79            write!(
80                f,
81                "IEffect(drop-shadow({} {} {} {}))",
82                shadow.offset_x(),
83                shadow.offset_y(),
84                shadow.blur_radius(),
85                shadow.color()
86            )
87        } else {
88            f.write_str("IEffect")
89        }
90    }
91}
92
93/// A mutable effect which can return an immutable clone of itself.
94pub trait IMutableEffect: IEffect {
95    /// Creates an immutable clone of the effect.
96    fn to_immutable(&self) -> std::sync::Arc<dyn IImmutableEffect>;
97}
98
99/// An immutable effect, which compares structurally.
100pub trait IImmutableEffect: IEffect + Send + Sync {
101    /// Whether the effect has the same parameters as `other`.
102    fn equals(&self, other: Option<&dyn IEffect>) -> bool;
103}
104
105impl<T: ObjectType + Upcast<Effect>> IEffect for RefAdapter<T> {
106    fn as_any(&self) -> &dyn Any {
107        Upcast::<Effect>::upcast(&*self.0)
108    }
109
110    fn as_object(&self) -> Option<&FerroObject> {
111        Some(self.object())
112    }
113
114    fn as_blur_effect(&self) -> Option<&dyn IBlurEffect> {
115        if self.object().is::<BlurEffect>() {
116            Some(self)
117        } else {
118            None
119        }
120    }
121
122    fn as_drop_shadow_effect(&self) -> Option<&dyn IDropShadowEffect> {
123        if self.object().is::<DropShadowEffect>() || self.object().is::<DropShadowDirectionEffect>() {
124            Some(self)
125        } else {
126            None
127        }
128    }
129
130    fn as_direction_drop_shadow_effect(&self) -> Option<&dyn IDirectionDropShadowEffect> {
131        if self.object().is::<DropShadowDirectionEffect>() {
132            Some(self)
133        } else {
134            None
135        }
136    }
137
138    fn as_mutable_effect(&self) -> Option<&dyn IMutableEffect> {
139        if self.object().is::<BlurEffect>()
140            || self.object().is::<DropShadowEffect>()
141            || self.object().is::<DropShadowDirectionEffect>()
142        {
143            Some(self)
144        } else {
145            None
146        }
147    }
148
149    fn reference_id(&self) -> *const () {
150        RefAdapter::reference_id(self)
151    }
152}
153
154impl<T: ObjectType + Upcast<Effect>> IMutableEffect for RefAdapter<T> {
155    fn to_immutable(&self) -> std::sync::Arc<dyn IImmutableEffect> {
156        let object = self.object();
157        if let Some(blur) = object.downcast_ref::<BlurEffect>() {
158            blur.to_immutable()
159        } else if let Some(shadow) = object.downcast_ref::<DropShadowEffect>() {
160            shadow.to_immutable()
161        } else {
162            self.class::<DropShadowDirectionEffect>().to_immutable()
163        }
164    }
165}
166
167impl<T: ObjectType + Upcast<Effect>> From<Ref<T>> for Rc<dyn IEffect> {
168    #[inline]
169    fn from(value: Ref<T>) -> Self {
170        Rc::new(RefAdapter(value))
171    }
172}
173
174impl<T: ObjectType + Upcast<Effect>> From<&Ref<T>> for Rc<dyn IEffect> {
175    #[inline]
176    fn from(value: &Ref<T>) -> Self {
177        Rc::new(RefAdapter(value.clone()))
178    }
179}