Skip to main content

ferroui_base/media/
i_brush.rs

1use crate::media::ref_adapter::RefAdapter;
2use crate::media::{
3    Brush, Color, ConicGradientBrush, DrawingBrush, GradientBrush, GradientSpreadMethod, IConicGradientBrush, IGradientBrush,
4    IGradientStop, IImageBrush, IImmutableBrush, ILinearGradientBrush, IMutableBrush, IRadialGradientBrush,
5    ISceneBrush, ISolidColorBrush, ITileBrush, ITransform, ImageBrush, LinearGradientBrush, RadialGradientBrush,
6    SolidColorBrush, TileBrush, VisualBrush,
7};
8use crate::{FerroObject, ObjectType, Ref, RelativePoint, RelativeScalar, Upcast};
9use std::any::Any;
10use std::rc::Rc;
11
12/// Describes how an area is painted.
13///
14/// Implemented by the immutable brush types and, through an adapter, by
15/// every class deriving from [`Brush`]: a handle of such a class converts to
16/// `Rc<dyn IBrush>` with `into()`, so a value of that type can hold either
17/// kind of brush. The `as_*` members replace interface casts
18/// (`brush as ISolidColorBrush`).
19pub trait IBrush: 'static {
20    /// The opacity of the brush.
21    fn opacity(&self) -> f64;
22
23    /// The transform of the brush.
24    fn transform(&self) -> Option<Rc<dyn ITransform>>;
25
26    /// The origin of the brush [`transform`](Self::transform).
27    fn transform_origin(&self) -> RelativePoint;
28
29    /// The transform of the brush, relative to the bounds of the painted
30    /// area.
31    fn relative_transform(&self) -> Option<Rc<dyn ITransform>>;
32
33    /// The implementing value, for downcasts to immutable brush types. For
34    /// mutable brushes use [`as_object`](Self::as_object).
35    fn as_any(&self) -> &dyn Any;
36
37    /// The object behind the brush when it is a mutable [`Brush`].
38    fn as_object(&self) -> Option<&FerroObject> {
39        None
40    }
41
42    /// The brush viewed as [`ISolidColorBrush`], when it is one.
43    fn as_solid_color_brush(&self) -> Option<&dyn ISolidColorBrush> {
44        None
45    }
46
47    /// The brush viewed as [`IGradientBrush`], when it is one.
48    fn as_gradient_brush(&self) -> Option<&dyn IGradientBrush> {
49        None
50    }
51
52    /// The brush viewed as [`ILinearGradientBrush`], when it is one.
53    fn as_linear_gradient_brush(&self) -> Option<&dyn ILinearGradientBrush> {
54        None
55    }
56
57    /// The brush viewed as [`IRadialGradientBrush`], when it is one.
58    fn as_radial_gradient_brush(&self) -> Option<&dyn IRadialGradientBrush> {
59        None
60    }
61
62    /// The brush viewed as [`IConicGradientBrush`], when it is one.
63    fn as_conic_gradient_brush(&self) -> Option<&dyn IConicGradientBrush> {
64        None
65    }
66
67    /// The brush viewed as [`ITileBrush`], when it is one.
68    fn as_tile_brush(&self) -> Option<&dyn ITileBrush> {
69        None
70    }
71
72    /// The brush viewed as [`IImageBrush`], when it is one.
73    fn as_image_brush(&self) -> Option<&dyn IImageBrush> {
74        None
75    }
76
77    /// The brush viewed as [`ISceneBrush`], when it is one.
78    fn as_scene_brush(&self) -> Option<&dyn ISceneBrush> {
79        None
80    }
81
82    /// The brush viewed as [`IMutableBrush`], when it is one.
83    fn as_mutable_brush(&self) -> Option<&dyn IMutableBrush> {
84        None
85    }
86
87    /// The brush viewed as [`IImmutableBrush`], when it is one (the `is
88    /// IImmutableBrush` test of upstream).
89    fn as_immutable_brush(&self) -> Option<&dyn IImmutableBrush> {
90        None
91    }
92
93    /// The composition render resource behind the object, if it is a
94    /// mutable object with server-side counterparts on the compositors it
95    /// is drawn with.
96    fn as_composition_render_resource(
97        &self,
98    ) -> Option<&dyn crate::rendering::composition::drawing::ICompositionRenderResource> {
99        None
100    }
101
102    /// The brush as a composition brush, when it is one (the `is
103    /// CompositionBrush` test of upstream).
104    fn as_composition_brush(&self) -> Option<&crate::rendering::composition::CompositionBrush> {
105        None
106    }
107
108    /// The brush as an [`IImmutableBrush`] handle, when it is immutable.
109    fn into_immutable_brush(self: Rc<Self>) -> Option<Rc<dyn IImmutableBrush>> {
110        None
111    }
112
113    /// The form of the brush that is sent to the render thread, when the
114    /// type keeps one: see [`SharedBrush`](crate::media::SharedBrush). An
115    /// immutable brush creates it once, so its identity is stable.
116    fn to_shared(&self) -> Option<crate::media::SharedBrush> {
117        None
118    }
119
120    /// The identity of the brush, used for reference equality.
121    #[doc(hidden)]
122    fn reference_id(&self) -> *const () {
123        self as *const Self as *const ()
124    }
125
126    /// Whether the brush equals `other`. Brushes compare by reference unless
127    /// the type defines structural equality (immutable solid color brushes).
128    fn equals(&self, other: &dyn IBrush) -> bool {
129        self.reference_id() == other.reference_id()
130    }
131}
132
133impl PartialEq for dyn IBrush {
134    #[inline]
135    fn eq(&self, other: &Self) -> bool {
136        self.equals(other)
137    }
138}
139
140impl std::fmt::Debug for dyn IBrush {
141    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142        match self.as_solid_color_brush() {
143            Some(solid) => write!(f, "IBrush({})", solid.color()),
144            None => f.write_str("IBrush"),
145        }
146    }
147}
148
149impl<T: ObjectType + Upcast<Brush>> RefAdapter<T> {
150    #[inline]
151    fn brush(&self) -> &Brush {
152        (*self.0).upcast()
153    }
154}
155
156impl<T: ObjectType + Upcast<Brush>> IBrush for RefAdapter<T> {
157    #[inline]
158    fn opacity(&self) -> f64 {
159        self.brush().opacity()
160    }
161
162    #[inline]
163    fn transform(&self) -> Option<Rc<dyn ITransform>> {
164        self.brush().transform()
165    }
166
167    #[inline]
168    fn transform_origin(&self) -> RelativePoint {
169        self.brush().transform_origin()
170    }
171
172    #[inline]
173    fn relative_transform(&self) -> Option<Rc<dyn ITransform>> {
174        self.brush().relative_transform()
175    }
176
177    fn as_any(&self) -> &dyn Any {
178        self.brush()
179    }
180
181    fn as_object(&self) -> Option<&FerroObject> {
182        Some(self.object())
183    }
184
185    fn as_solid_color_brush(&self) -> Option<&dyn ISolidColorBrush> {
186        if self.object().is::<SolidColorBrush>() {
187            Some(self)
188        } else {
189            None
190        }
191    }
192
193    fn as_gradient_brush(&self) -> Option<&dyn IGradientBrush> {
194        if self.object().is::<GradientBrush>() {
195            Some(self)
196        } else {
197            None
198        }
199    }
200
201    fn as_linear_gradient_brush(&self) -> Option<&dyn ILinearGradientBrush> {
202        if self.object().is::<LinearGradientBrush>() {
203            Some(self)
204        } else {
205            None
206        }
207    }
208
209    fn as_radial_gradient_brush(&self) -> Option<&dyn IRadialGradientBrush> {
210        if self.object().is::<RadialGradientBrush>() {
211            Some(self)
212        } else {
213            None
214        }
215    }
216
217    fn as_conic_gradient_brush(&self) -> Option<&dyn IConicGradientBrush> {
218        if self.object().is::<ConicGradientBrush>() {
219            Some(self)
220        } else {
221            None
222        }
223    }
224
225    fn as_tile_brush(&self) -> Option<&dyn ITileBrush> {
226        if self.object().is::<TileBrush>() {
227            Some(self)
228        } else {
229            None
230        }
231    }
232
233    fn as_image_brush(&self) -> Option<&dyn IImageBrush> {
234        if self.object().is::<ImageBrush>() {
235            Some(self)
236        } else {
237            None
238        }
239    }
240
241    fn as_scene_brush(&self) -> Option<&dyn ISceneBrush> {
242        if self.object().is::<VisualBrush>() || self.object().is::<DrawingBrush>() {
243            Some(self)
244        } else {
245            None
246        }
247    }
248
249    fn as_mutable_brush(&self) -> Option<&dyn IMutableBrush> {
250        if self.object().is::<SolidColorBrush>()
251            || self.object().is::<GradientBrush>()
252            || self.object().is::<ImageBrush>()
253        {
254            Some(self)
255        } else {
256            None
257        }
258    }
259
260    fn as_composition_render_resource(
261        &self,
262    ) -> Option<&dyn crate::rendering::composition::drawing::ICompositionRenderResource> {
263        // Every brush class that can be instantiated has a server-side
264        // counterpart; only the abstract classes have no factory.
265        let brush = self.brush();
266        brush.factory().map(|_| brush as &dyn crate::rendering::composition::drawing::ICompositionRenderResource)
267    }
268
269    fn reference_id(&self) -> *const () {
270        RefAdapter::reference_id(self)
271    }
272}
273
274impl<T: ObjectType + Upcast<Brush>> ISolidColorBrush for RefAdapter<T> {
275    #[inline]
276    fn color(&self) -> Color {
277        self.class::<SolidColorBrush>().color()
278    }
279}
280
281impl<T: ObjectType + Upcast<Brush>> IGradientBrush for RefAdapter<T> {
282    fn gradient_stops(&self) -> Vec<Rc<dyn IGradientStop>> {
283        self.class::<GradientBrush>().gradient_stops().iter().map(Into::into).collect()
284    }
285
286    #[inline]
287    fn spread_method(&self) -> GradientSpreadMethod {
288        self.class::<GradientBrush>().spread_method()
289    }
290}
291
292impl<T: ObjectType + Upcast<Brush>> ILinearGradientBrush for RefAdapter<T> {
293    #[inline]
294    fn start_point(&self) -> RelativePoint {
295        self.class::<LinearGradientBrush>().start_point()
296    }
297
298    #[inline]
299    fn end_point(&self) -> RelativePoint {
300        self.class::<LinearGradientBrush>().end_point()
301    }
302}
303
304impl<T: ObjectType + Upcast<Brush>> IRadialGradientBrush for RefAdapter<T> {
305    #[inline]
306    fn center(&self) -> RelativePoint {
307        self.class::<RadialGradientBrush>().center()
308    }
309
310    #[inline]
311    fn gradient_origin(&self) -> RelativePoint {
312        self.class::<RadialGradientBrush>().gradient_origin()
313    }
314
315    #[inline]
316    fn radius_x(&self) -> RelativeScalar {
317        self.class::<RadialGradientBrush>().radius_x()
318    }
319
320    #[inline]
321    fn radius_y(&self) -> RelativeScalar {
322        self.class::<RadialGradientBrush>().radius_y()
323    }
324}
325
326impl<T: ObjectType + Upcast<Brush>> IConicGradientBrush for RefAdapter<T> {
327    #[inline]
328    fn center(&self) -> RelativePoint {
329        self.class::<ConicGradientBrush>().center()
330    }
331
332    #[inline]
333    fn angle(&self) -> f64 {
334        self.class::<ConicGradientBrush>().angle()
335    }
336}
337
338impl<T: ObjectType + Upcast<Brush>> IMutableBrush for RefAdapter<T> {
339    fn to_immutable(&self) -> Rc<dyn IImmutableBrush> {
340        let object = self.object();
341        if let Some(solid) = object.downcast_ref::<SolidColorBrush>() {
342            solid.to_immutable()
343        } else if let Some(image) = object.downcast_ref::<ImageBrush>() {
344            image.to_immutable()
345        } else {
346            self.class::<GradientBrush>().to_immutable()
347        }
348    }
349}
350
351impl<T: ObjectType + Upcast<Brush>> From<Ref<T>> for Rc<dyn IBrush> {
352    #[inline]
353    fn from(value: Ref<T>) -> Self {
354        Rc::new(RefAdapter(value))
355    }
356}
357
358impl<T: ObjectType + Upcast<Brush>> From<&Ref<T>> for Rc<dyn IBrush> {
359    #[inline]
360    fn from(value: &Ref<T>) -> Self {
361        Rc::new(RefAdapter(value.clone()))
362    }
363}