ferroui_base/rendering/composition/brushes/
composition_gradient_winui.rs1use super::composition_brush::{CompositionBrush, CompositionBrushKind};
7use super::{CompositionGradientBrush, CompositionLinearGradientBrush, CompositionRadialGradientBrush};
8use crate::collections::FerroList;
9use crate::media::immutable::ImmutableTransform;
10use crate::media::{GradientSpreadMethod, IGradientStop, ITransform};
11use crate::rendering::composition::animations::CompositionColorSpace;
12use crate::rendering::composition::{CompositionGradientExtendMode, CompositionMappingMode};
13use crate::{Matrix, RelativePoint, RelativeScalar, RelativeUnit, Vector};
14use std::rc::Rc;
15
16fn unit_of(mode: CompositionMappingMode) -> RelativeUnit {
18 match mode {
19 CompositionMappingMode::Absolute => RelativeUnit::Absolute,
20 CompositionMappingMode::Relative => RelativeUnit::Relative,
21 }
22}
23
24fn point_of(value: Vector, unit: RelativeUnit) -> RelativePoint {
25 RelativePoint::new(value.x, value.y, unit)
26}
27
28fn vector_of(point: RelativePoint) -> Vector {
29 Vector::new(point.point.x, point.point.y)
30}
31
32macro_rules! with_gradient_props {
35 ($brush:expr, |$props:ident| $body:expr) => {
36 match &$brush.kind {
37 CompositionBrushKind::LinearGradient(_, $props) => $body,
38 CompositionBrushKind::RadialGradient(_, $props) => $body,
39 CompositionBrushKind::ConicGradient(_, $props) => $body,
40 _ => unreachable!("a gradient brush handle wraps a gradient brush"),
41 }
42 };
43}
44
45macro_rules! gradient_transform_members {
48 ($($(#[$meta:meta])* $get:ident / $set:ident : $ty:ty;)*) => {
49 impl CompositionGradientBrush {$(
50 $(#[$meta])*
51 pub fn $get(&self) -> $ty {
52 let brush: &CompositionBrush = self;
53 with_gradient_props!(brush, |props| props.$get())
54 }
55
56 pub fn $set(&self, value: $ty) {
57 let brush: &CompositionBrush = self;
58 with_gradient_props!(brush, |props| props.$set(brush, value))
59 }
60 )*}
61 };
62}
63
64gradient_transform_members! {
65 anchor_point / set_anchor_point: Vector;
68 center_point / set_center_point: Vector;
71 offset / set_offset: Vector;
73 rotation_angle / set_rotation_angle: f32;
76 scale / set_scale: Vector;
79 transform_matrix / set_transform_matrix: Matrix;
82}
83
84impl CompositionGradientBrush {
85 fn gradient_brush(&self) -> &CompositionBrush {
86 self
87 }
88
89 fn mapping_cell(&self) -> &std::cell::Cell<CompositionMappingMode> {
90 match &self.gradient_brush().kind {
91 CompositionBrushKind::LinearGradient(data, _)
92 | CompositionBrushKind::RadialGradient(data, _)
93 | CompositionBrushKind::ConicGradient(data, _) => &data.mapping_mode,
94 _ => unreachable!("a gradient brush handle wraps a gradient brush"),
95 }
96 }
97
98 fn interpolation_cell(&self) -> &std::cell::Cell<CompositionColorSpace> {
99 match &self.gradient_brush().kind {
100 CompositionBrushKind::LinearGradient(data, _)
101 | CompositionBrushKind::RadialGradient(data, _)
102 | CompositionBrushKind::ConicGradient(data, _) => &data.interpolation_space,
103 _ => unreachable!("a gradient brush handle wraps a gradient brush"),
104 }
105 }
106
107 pub fn rotation_angle_in_degrees(&self) -> f32 {
110 self.rotation_angle().to_degrees()
111 }
112
113 pub fn set_rotation_angle_in_degrees(&self, value: f32) {
114 self.set_rotation_angle(value.to_radians())
115 }
116
117 pub fn extend_mode(&self) -> CompositionGradientExtendMode {
121 match self.spread_method() {
122 GradientSpreadMethod::Pad => CompositionGradientExtendMode::Clamp,
123 GradientSpreadMethod::Repeat => CompositionGradientExtendMode::Wrap,
124 GradientSpreadMethod::Reflect => CompositionGradientExtendMode::Mirror,
125 }
126 }
127
128 pub fn set_extend_mode(&self, value: CompositionGradientExtendMode) {
129 self.set_spread_method(match value {
130 CompositionGradientExtendMode::Clamp => GradientSpreadMethod::Pad,
131 CompositionGradientExtendMode::Wrap => GradientSpreadMethod::Repeat,
132 CompositionGradientExtendMode::Mirror => GradientSpreadMethod::Reflect,
133 })
134 }
135
136 pub fn interpolation_space(&self) -> CompositionColorSpace {
141 self.interpolation_cell().get()
142 }
143
144 pub fn set_interpolation_space(&self, value: CompositionColorSpace) {
145 self.interpolation_cell().set(value)
146 }
147
148 pub fn mapping_mode(&self) -> CompositionMappingMode {
152 self.mapping_cell().get()
153 }
154
155 pub fn set_mapping_mode(&self, value: CompositionMappingMode) {
156 if self.mapping_cell().replace(value) == value {
157 return;
158 }
159 let unit = unit_of(value);
160 let brush = self.gradient_brush();
161 match &brush.kind {
162 CompositionBrushKind::LinearGradient(_, props) => {
163 props.set_start_point(brush, point_of(vector_of(props.start_point()), unit));
164 props.set_end_point(brush, point_of(vector_of(props.end_point()), unit));
165 }
166 CompositionBrushKind::RadialGradient(_, props) => {
167 props.set_center(brush, point_of(vector_of(props.center()), unit));
168 props.set_gradient_origin(brush, point_of(vector_of(props.gradient_origin()), unit));
169 props.set_radius_x(brush, RelativeScalar::new(props.radius_x().scalar, unit));
170 props.set_radius_y(brush, RelativeScalar::new(props.radius_y().scalar, unit));
171 }
172 CompositionBrushKind::ConicGradient(_, props) => {
173 props.set_center(brush, point_of(vector_of(props.center()), unit));
174 }
175 _ => {}
176 }
177 }
178
179 pub fn color_stops(&self) -> FerroList<Rc<dyn IGradientStop>> {
184 self.gradient_stops()
185 }
186
187 pub fn set_color_stops(&self, value: FerroList<Rc<dyn IGradientStop>>) {
188 self.set_gradient_stops(value)
189 }
190}
191
192impl CompositionLinearGradientBrush {
193 pub fn start_point_vector(&self) -> Vector {
200 vector_of(self.start_point())
201 }
202
203 pub fn set_start_point_vector(&self, value: Vector) {
204 self.set_start_point(point_of(value, unit_of(self.mapping_mode())))
205 }
206
207 pub fn end_point_vector(&self) -> Vector {
212 vector_of(self.end_point())
213 }
214
215 pub fn set_end_point_vector(&self, value: Vector) {
216 self.set_end_point(point_of(value, unit_of(self.mapping_mode())))
217 }
218}
219
220impl CompositionRadialGradientBrush {
221 pub fn ellipse_center(&self) -> Vector {
224 vector_of(self.center())
225 }
226
227 pub fn set_ellipse_center(&self, value: Vector) {
230 let offset = self.gradient_origin_offset();
231 let unit = unit_of(self.mapping_mode());
232 self.set_center(point_of(value, unit));
233 self.set_gradient_origin(point_of(value + offset, unit));
234 }
235
236 pub fn ellipse_radius(&self) -> Vector {
240 Vector::new(self.radius_x().scalar, self.radius_y().scalar)
241 }
242
243 pub fn set_ellipse_radius(&self, value: Vector) {
244 let unit = unit_of(self.mapping_mode());
245 self.set_radius_x(RelativeScalar::new(value.x, unit));
246 self.set_radius_y(RelativeScalar::new(value.y, unit));
247 }
248
249 pub fn gradient_origin_offset(&self) -> Vector {
254 vector_of(self.gradient_origin()) - vector_of(self.center())
255 }
256
257 pub fn set_gradient_origin_offset(&self, value: Vector) {
258 let unit = unit_of(self.mapping_mode());
259 self.set_gradient_origin(point_of(self.ellipse_center() + value, unit));
260 }
261}
262
263pub trait IServerBrushWinUiTransform {
269 fn winui_transform(&self) -> Option<Matrix> {
273 None
274 }
275
276 fn winui_anchor_point(&self) -> Vector {
278 Vector::default()
279 }
280}
281
282pub(crate) fn with_winui_transform(
289 upstream: Option<Rc<dyn ITransform>>,
290 winui: Option<Matrix>,
291) -> Option<Rc<dyn ITransform>> {
292 match (upstream, winui) {
293 (upstream, None) => upstream,
294 (None, Some(winui)) => Some(Rc::new(ImmutableTransform::new(winui))),
295 (Some(upstream), Some(winui)) => Some(Rc::new(ImmutableTransform::new(upstream.value() * winui))),
296 }
297}
298
299pub(crate) fn with_winui_anchor(upstream: Option<Rc<dyn ITransform>>, anchor: Vector) -> Option<Rc<dyn ITransform>> {
304 if anchor == Vector::default() {
305 return upstream;
306 }
307 let translation = Matrix::create_translation(-anchor.x, -anchor.y);
308 match upstream {
309 None => Some(Rc::new(ImmutableTransform::new(translation))),
310 Some(upstream) => Some(Rc::new(ImmutableTransform::new(upstream.value() * translation))),
311 }
312}