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