Skip to main content

ferroui_base/media/immutable/
immutable_gradient_brush.rs

1use crate::media::immutable::{ImmutableGradientStop, ImmutableTransform};
2use crate::media::{GradientBrush, GradientSpreadMethod, IGradientStop, ITransform, TransformExtensions};
3use crate::RelativePoint;
4use std::rc::Rc;
5
6/// The data shared by all immutable gradient brushes.
7#[derive(Clone)]
8pub struct ImmutableGradientBrush {
9    gradient_stops: Vec<Rc<dyn IGradientStop>>,
10    opacity: f64,
11    transform: Option<Rc<dyn ITransform>>,
12    transform_origin: RelativePoint,
13    spread_method: GradientSpreadMethod,
14    relative_transform: Option<Rc<dyn ITransform>>,
15    /// The form sent to the render thread, created on first use.
16    pub(crate) shared: std::sync::OnceLock<Option<crate::media::SharedBrush>>,
17}
18
19impl ImmutableGradientBrush {
20    /// Creates the gradient brush data. `transform_origin` defaults to the
21    /// top left corner.
22    pub fn new(
23        gradient_stops: &[ImmutableGradientStop],
24        opacity: f64,
25        transform: Option<Rc<ImmutableTransform>>,
26        transform_origin: Option<RelativePoint>,
27        spread_method: GradientSpreadMethod,
28        relative_transform: Option<Rc<ImmutableTransform>>,
29    ) -> Self {
30        Self {
31            gradient_stops: gradient_stops.iter().map(|stop| Rc::new(*stop) as Rc<dyn IGradientStop>).collect(),
32            opacity,
33            transform: transform.map(|t| t as Rc<dyn ITransform>),
34            transform_origin: transform_origin.unwrap_or(RelativePoint::TOP_LEFT),
35            spread_method,
36            relative_transform: relative_transform.map(|t| t as Rc<dyn ITransform>),
37            shared: std::sync::OnceLock::new(),
38        }
39    }
40
41    /// Creates an immutable copy of the gradient data of `source`.
42    pub fn from_brush(source: &GradientBrush) -> Self {
43        Self::new(
44            &source.gradient_stops().to_immutable(),
45            source.opacity(),
46            source.transform().map(|t| Rc::new(TransformExtensions::to_immutable(&*t))),
47            Some(source.transform_origin()),
48            source.spread_method(),
49            source.relative_transform().map(|t| Rc::new(TransformExtensions::to_immutable(&*t))),
50        )
51    }
52
53    /// The brush's gradient stops.
54    #[inline]
55    pub fn gradient_stops(&self) -> &[Rc<dyn IGradientStop>] {
56        &self.gradient_stops
57    }
58
59    /// The opacity of the brush.
60    #[inline]
61    pub fn opacity(&self) -> f64 {
62        self.opacity
63    }
64
65    /// The transform of the brush.
66    #[inline]
67    pub fn transform(&self) -> Option<Rc<dyn ITransform>> {
68        self.transform.clone()
69    }
70
71    /// The transform origin of the brush.
72    #[inline]
73    pub fn transform_origin(&self) -> RelativePoint {
74        self.transform_origin
75    }
76
77    /// The brush's spread method.
78    #[inline]
79    pub fn spread_method(&self) -> GradientSpreadMethod {
80        self.spread_method
81    }
82
83    /// The transform of the brush, relative to the bounds of the painted
84    /// area.
85    #[inline]
86    pub fn relative_transform(&self) -> Option<Rc<dyn ITransform>> {
87        self.relative_transform.clone()
88    }
89}
90
91/// Implements the brush interfaces of an immutable gradient brush whose
92/// `base` field is an [`ImmutableGradientBrush`].
93macro_rules! immutable_gradient_brush_interfaces {
94    ($name:ty, $as_fn:ident, $iface:path) => {
95        impl ::std::ops::Deref for $name {
96            type Target = $crate::media::immutable::ImmutableGradientBrush;
97            #[inline]
98            fn deref(&self) -> &Self::Target {
99                &self.base
100            }
101        }
102
103        impl $crate::media::IBrush for $name {
104            #[inline]
105            fn opacity(&self) -> f64 {
106                self.base.opacity()
107            }
108
109            fn transform(&self) -> Option<::std::rc::Rc<dyn $crate::media::ITransform>> {
110                self.base.transform()
111            }
112
113            #[inline]
114            fn transform_origin(&self) -> $crate::RelativePoint {
115                self.base.transform_origin()
116            }
117
118            fn relative_transform(&self) -> Option<::std::rc::Rc<dyn $crate::media::ITransform>> {
119                self.base.relative_transform()
120            }
121
122            fn as_immutable_brush(&self) -> Option<&dyn $crate::media::IImmutableBrush> {
123                Some(self)
124            }
125
126            fn as_any(&self) -> &dyn ::std::any::Any {
127                self
128            }
129
130            fn as_gradient_brush(&self) -> Option<&dyn $crate::media::IGradientBrush> {
131                Some(self)
132            }
133
134            fn $as_fn(&self) -> Option<&dyn $iface> {
135                Some(self)
136            }
137
138            fn into_immutable_brush(
139                self: ::std::rc::Rc<Self>,
140            ) -> Option<::std::rc::Rc<dyn $crate::media::IImmutableBrush>> {
141                Some(self)
142            }
143
144            fn to_shared(&self) -> Option<$crate::media::SharedBrush> {
145                self.base.shared.get_or_init(|| $crate::media::SharedBrush::from_brush(self)).clone()
146            }
147        }
148
149        impl $crate::media::IGradientBrush for $name {
150            fn gradient_stops(&self) -> Vec<::std::rc::Rc<dyn $crate::media::IGradientStop>> {
151                self.base.gradient_stops().to_vec()
152            }
153
154            #[inline]
155            fn spread_method(&self) -> $crate::media::GradientSpreadMethod {
156                self.base.spread_method()
157            }
158        }
159
160        impl $crate::media::IImmutableBrush for $name {}
161    };
162}
163
164pub(crate) use immutable_gradient_brush_interfaces;