ferroui_base/rendering/composition/brushes/
server_composition_brush.rs1use crate::media::{
4 Color, GradientSpreadMethod, IBrush, IConicGradientBrush, IGradientBrush, IGradientStop, ILinearGradientBrush,
5 IRadialGradientBrush, ISolidColorBrush, ITransform,
6};
7use crate::rendering::composition::generated::{
8 ServerCompositionBrushHooks, ServerCompositionBrushProps,
9 ServerCompositionConicGradientBrushHooks, ServerCompositionConicGradientBrushProps,
10 ServerCompositionLinearGradientBrushHooks, ServerCompositionLinearGradientBrushProps,
11 ServerCompositionRadialGradientBrushHooks, ServerCompositionRadialGradientBrushProps,
12 ServerCompositionSolidColorBrushHooks, ServerCompositionSolidColorBrushProps,
13};
14use crate::rendering::composition::server::{
15 impl_server_render_resource, props_of, resolve_resource, CompositionProperty, CompositionPropertyOf,
16 IAnimatedServerObject, IServerObject, IServerRenderResource, IServerRenderResourceHost, ServerCompositor,
17 ServerRenderResource, ServerRenderResourceCore, ServerResourceRef,
18};
19use super::composition_gradient_winui::{with_winui_anchor, with_winui_transform, IServerBrushWinUiTransform};
20use crate::rendering::composition::server::composition_transform;
21use crate::rendering::composition::transport::BatchStreamReader;
22use crate::{Matrix, RelativePoint, RelativeScalar, Vector};
23use std::any::{Any, TypeId};
24use std::cell::{Cell, RefCell};
25use std::rc::{Rc, Weak};
26use std::sync::OnceLock;
27use std::time::Duration;
28
29pub struct ServerCompositionGradientBrush {
34 brush: ServerCompositionBrushProps,
35 gradient_stops: RefCell<Vec<ServerResourceRef<dyn IGradientStop>>>,
36 spread_method: Cell<GradientSpreadMethod>,
37}
38
39impl Default for ServerCompositionGradientBrush {
40 fn default() -> Self {
41 Self::new()
42 }
43}
44
45impl ServerCompositionGradientBrush {
46 pub fn new() -> Self {
47 Self {
48 brush: ServerCompositionBrushProps::new(),
49 gradient_stops: RefCell::new(Vec::new()),
50 spread_method: Cell::new(GradientSpreadMethod::default()),
51 }
52 }
53
54 pub fn brush(&self) -> &ServerCompositionBrushProps {
56 &self.brush
57 }
58
59 pub fn find_props(&self, type_id: TypeId) -> Option<&dyn Any> {
61 if type_id == TypeId::of::<Self>() {
62 return Some(self);
63 }
64 self.brush.find_props(type_id)
65 }
66
67 pub fn id_of_gradient_stops_property() -> &'static CompositionPropertyOf<Vec<Rc<dyn IGradientStop>>> {
69 static PROPERTY: OnceLock<CompositionPropertyOf<Vec<Rc<dyn IGradientStop>>>> = OnceLock::new();
70 PROPERTY.get_or_init(|| {
71 CompositionProperty::register::<ServerCompositionGradientBrush, Vec<Rc<dyn IGradientStop>>>(
72 "GradientStops",
73 "ServerCompositionGradientBrush",
74 |obj| props_of::<ServerCompositionGradientBrush>(obj).gradient_stops(),
75 |obj, v| {
76 *props_of::<ServerCompositionGradientBrush>(obj).gradient_stops.borrow_mut() =
77 v.into_iter().map(ServerResourceRef::from_value).collect()
78 },
79 None,
80 None,
81 )
82 })
83 }
84
85 pub fn gradient_stops(&self) -> Vec<Rc<dyn IGradientStop>> {
86 self.gradient_stops.borrow().iter().map(|stop| stop.value.clone()).collect()
87 }
88
89 pub fn set_gradient_stops(
92 &self,
93 host: &dyn IServerRenderResourceHost,
94 core: &ServerRenderResourceCore,
95 value: Vec<ServerResourceRef<dyn IGradientStop>>,
96 ) {
97 let old_children = self.gradient_stops.borrow().iter().filter_map(|stop| stop.resource.clone()).collect();
100 let new_children = value.iter().filter_map(|stop| stop.resource.clone()).collect();
101 let mut value = Some(value);
102 core.set_list_value(host, old_children, new_children, &mut || {
103 if let Some(value) = value.take() {
104 *self.gradient_stops.borrow_mut() = value;
105 }
106 });
107 }
108
109 pub fn spread_method(&self) -> GradientSpreadMethod {
110 self.spread_method.get()
111 }
112
113 pub fn deserialize_changes_core(
116 &self,
117 host: &dyn ServerCompositionBrushHooks,
118 resource: &dyn IServerRenderResourceHost,
119 core: &ServerRenderResourceCore,
120 reader: &mut BatchStreamReader<'_>,
121 committed_at: Duration,
122 ) {
123 self.brush.deserialize_changes_core(host, reader, committed_at);
124 self.spread_method.set(reader.read::<GradientSpreadMethod>());
125 let compositor = host.server_compositor();
126 let count = reader.read::<i32>();
127 let mut stops = Vec::with_capacity(count.max(0) as usize);
128 for _ in 0..count {
129 let read = resolve_resource(reader.read_resource::<dyn IGradientStop>(), compositor.as_ref(), |o| {
130 o.as_gradient_stop()
131 });
132 match read {
133 Some(read) => stops.push(read),
134 None => panic!("a batch lists a null gradient stop"),
135 }
136 }
137 self.set_gradient_stops(resource, core, stops);
138 }
139}
140
141macro_rules! server_composition_brush {
144 (
145 $(#[$meta:meta])*
146 $name:ident { $($field:ident : $field_ty:ty = $field_init:expr),* $(,)? }
147 brush: |$b:ident| $brush:expr;
148 deserialize: |$d:ident, $reader:ident, $committed_at:ident| $deserialize:expr;
149 find: |$f:ident, $type_id:ident| $find:expr;
150 composition_property: $get:expr;
151 as: { $($as_fn:ident -> $as_trait:path),* $(,)? }
152 ) => {
153 $(#[$meta])*
154 pub struct $name {
155 base: ServerRenderResource,
156 $($field: $field_ty,)*
157 }
158
159 impl $name {
160 pub fn new(compositor: &Rc<ServerCompositor>) -> Rc<$name> {
164 let brush = Rc::new_cyclic(|this: &Weak<$name>| $name {
165 base: ServerRenderResource::new(
166 compositor,
167 this.clone() as Weak<dyn IAnimatedServerObject>,
168 this.clone() as Weak<dyn IServerRenderResource>,
169 ),
170 $($field: $field_init,)*
171 });
172 brush.base.object().activate();
173 brush
174 }
175
176 pub fn is_disposed(&self) -> bool {
177 self.base.is_disposed()
178 }
179
180 pub fn brush_props(&self) -> &ServerCompositionBrushProps {
182 let $b = self;
183 $brush
184 }
185 }
186
187 impl_server_render_resource!($name, base, composition_property: $get);
188
189 impl ServerCompositionBrushHooks for $name {}
190
191 impl IServerObject for $name {
192 fn deserialize_changes_core(&self, $reader: &mut BatchStreamReader<'_>, $committed_at: Duration) {
193 let $d = self;
194 $deserialize
195 }
196
197 fn values_invalidated(&self) {
198 self.base.core().invalidated(self);
199 }
200
201 fn dispose(&self) {
202 self.base.core().dispose();
203 }
204
205 fn as_render_resource(self: Rc<Self>) -> Option<Rc<dyn IServerRenderResource>> {
206 Some(self)
207 }
208
209 fn as_brush(self: Rc<Self>) -> Option<Rc<dyn IBrush>> {
210 Some(self)
211 }
212
213 fn as_animated(self: Rc<Self>) -> Option<Rc<dyn IAnimatedServerObject>> {
214 Some(self)
215 }
216
217 fn get_props(&self, $type_id: TypeId) -> Option<&dyn Any> {
218 let $f = self;
219 $find
220 }
221
222 fn as_any(&self) -> &dyn Any {
223 self
224 }
225
226 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
227 self
228 }
229 }
230
231 impl IBrush for $name {
232 fn opacity(&self) -> f64 {
233 self.brush_props().opacity()
234 }
235
236 fn transform(&self) -> Option<Rc<dyn ITransform>> {
239 with_winui_transform(
240 self.brush_props().transform().map(|transform| transform.value),
241 IServerBrushWinUiTransform::winui_transform(self),
242 )
243 }
244
245 fn transform_origin(&self) -> RelativePoint {
246 self.brush_props().transform_origin()
247 }
248
249 fn relative_transform(&self) -> Option<Rc<dyn ITransform>> {
252 with_winui_anchor(
253 self.brush_props().relative_transform().map(|transform| transform.value),
254 IServerBrushWinUiTransform::winui_anchor_point(self),
255 )
256 }
257
258 fn as_any(&self) -> &dyn Any {
259 self
260 }
261
262 $(
263 fn $as_fn(&self) -> Option<&dyn $as_trait> {
264 Some(self)
265 }
266 )*
267 }
268 };
269}
270
271server_composition_brush! {
272 ServerCompositionSolidColorBrush {
275 props: ServerCompositionSolidColorBrushProps = ServerCompositionSolidColorBrushProps::new(),
276 }
277 brush: |b| b.props.base();
278 deserialize: |d, reader, committed_at| d.props.deserialize_changes_core(d, reader, committed_at);
279 find: |f, type_id| f.props.find_props(type_id);
280 composition_property: ServerCompositionSolidColorBrushProps::get_composition_property;
281 as: { as_solid_color_brush -> ISolidColorBrush }
282}
283
284impl ServerCompositionSolidColorBrushHooks for ServerCompositionSolidColorBrush {}
285
286impl IServerBrushWinUiTransform for ServerCompositionSolidColorBrush {}
288
289impl ServerCompositionSolidColorBrush {
290 pub fn props(&self) -> &ServerCompositionSolidColorBrushProps {
292 &self.props
293 }
294}
295
296impl ISolidColorBrush for ServerCompositionSolidColorBrush {
297 fn color(&self) -> Color {
298 self.props.color()
299 }
300}
301
302macro_rules! server_composition_gradient_brush {
305 ($(#[$meta:meta])* $name:ident, $props:ident, $hooks:ident, $as_fn:ident -> $as_trait:path) => {
306 server_composition_brush! {
307 $(#[$meta])*
308 $name {
309 gradient: ServerCompositionGradientBrush = ServerCompositionGradientBrush::new(),
310 props: $props = $props::new(),
311 }
312 brush: |b| b.gradient.brush();
313 deserialize: |d, reader, committed_at| d.props.deserialize_changes_core(d, reader, committed_at);
314 find: |f, type_id| f.props.find_props(type_id).or_else(|| f.gradient.find_props(type_id));
315 composition_property: |name: &str| {
316 $props::get_composition_property(name).or_else(|| ServerCompositionBrushProps::get_composition_property(name))
317 };
318 as: { as_gradient_brush -> IGradientBrush, $as_fn -> $as_trait }
319 }
320
321 impl $hooks for $name {
322 fn base_deserialize_changes_core(&self, reader: &mut BatchStreamReader<'_>, committed_at: Duration) {
323 self.gradient.deserialize_changes_core(self, self, self.base.core(), reader, committed_at);
324 }
325 }
326
327 impl $name {
328 pub fn props(&self) -> &$props {
330 &self.props
331 }
332
333 pub fn gradient(&self) -> &ServerCompositionGradientBrush {
335 &self.gradient
336 }
337
338 pub fn gradient_stops(&self) -> Vec<Rc<dyn IGradientStop>> {
339 self.gradient.gradient_stops()
340 }
341
342 pub fn spread_method(&self) -> GradientSpreadMethod {
343 self.gradient.spread_method()
344 }
345 }
346
347 impl IServerBrushWinUiTransform for $name {
349 fn winui_transform(&self) -> Option<Matrix> {
350 composition_transform(
351 Vector::default(),
352 Vector::default(),
353 self.props.center_point(),
354 self.props.transform_matrix(),
355 self.props.scale(),
356 self.props.rotation_angle(),
357 self.props.offset(),
358 )
359 }
360
361 fn winui_anchor_point(&self) -> Vector {
362 self.props.anchor_point()
363 }
364 }
365
366 impl IGradientBrush for $name {
367 fn gradient_stops(&self) -> Vec<Rc<dyn IGradientStop>> {
368 self.gradient.gradient_stops()
369 }
370
371 fn spread_method(&self) -> GradientSpreadMethod {
372 self.gradient.spread_method()
373 }
374 }
375 };
376}
377
378server_composition_gradient_brush!(
379 ServerCompositionConicGradientBrush,
382 ServerCompositionConicGradientBrushProps,
383 ServerCompositionConicGradientBrushHooks,
384 as_conic_gradient_brush -> IConicGradientBrush
385);
386
387impl IConicGradientBrush for ServerCompositionConicGradientBrush {
388 fn center(&self) -> RelativePoint {
389 self.props.center()
390 }
391
392 fn angle(&self) -> f64 {
393 self.props.angle()
394 }
395}
396
397server_composition_gradient_brush!(
398 ServerCompositionLinearGradientBrush,
401 ServerCompositionLinearGradientBrushProps,
402 ServerCompositionLinearGradientBrushHooks,
403 as_linear_gradient_brush -> ILinearGradientBrush
404);
405
406impl ILinearGradientBrush for ServerCompositionLinearGradientBrush {
407 fn start_point(&self) -> RelativePoint {
408 self.props.start_point()
409 }
410
411 fn end_point(&self) -> RelativePoint {
412 self.props.end_point()
413 }
414}
415
416server_composition_gradient_brush!(
417 ServerCompositionRadialGradientBrush,
420 ServerCompositionRadialGradientBrushProps,
421 ServerCompositionRadialGradientBrushHooks,
422 as_radial_gradient_brush -> IRadialGradientBrush
423);
424
425impl ServerCompositionRadialGradientBrush {
426 pub fn radius(&self) -> f64 {
427 self.props.radius_x().scalar
428 }
429}
430
431impl IRadialGradientBrush for ServerCompositionRadialGradientBrush {
432 fn center(&self) -> RelativePoint {
433 self.props.center()
434 }
435
436 fn gradient_origin(&self) -> RelativePoint {
437 self.props.gradient_origin()
438 }
439
440 fn radius_x(&self) -> RelativeScalar {
441 self.props.radius_x()
442 }
443
444 fn radius_y(&self) -> RelativeScalar {
445 self.props.radius_y()
446 }
447}
448