Skip to main content

ferroui_base/rendering/composition/generated/
composition_brush.rs

1// @generated by scripts/generate_composition.py — do not edit
2
3//! `CompositionBrush`.
4
5use bitflags::bitflags;
6use crate::RelativePoint;
7use crate::media::ITransform;
8use crate::rendering::composition::ICompositionObjectHost;
9use crate::rendering::composition::animations::AnimationInstanceFactory;
10use crate::rendering::composition::animations::ICompositionAnimation;
11use crate::rendering::composition::expressions::ExpressionVariant;
12use crate::rendering::composition::server::AsServerRenderResource;
13use crate::rendering::composition::server::CompositionProperty;
14use crate::rendering::composition::server::CompositionPropertyOf;
15use crate::rendering::composition::server::IServerAnimatedPropertyHost;
16use crate::rendering::composition::server::ServerPropertyValue;
17use crate::rendering::composition::server::ServerResourceRef;
18use crate::rendering::composition::server::ServerValueChange;
19use crate::rendering::composition::server::props_of;
20use crate::rendering::composition::server::read_resource;
21use crate::rendering::composition::transport::BatchResource;
22use crate::rendering::composition::transport::BatchStreamReader;
23use crate::rendering::composition::transport::BatchStreamWriter;
24use crate::rendering::composition::transport::BatchValue;
25use crate::rendering::composition::transport::BatchValueReader;
26use std::any::Any;
27use std::any::TypeId;
28use std::cell::Cell;
29use std::cell::RefCell;
30use std::sync::OnceLock;
31use std::time::Duration;
32
33bitflags! {
34    /// The fields of `CompositionBrush` that changed since its last serialization.
35    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
36    pub struct CompositionBrushChangedFields: u8 {
37        const OPACITY = 1;
38        const OPACITY_ANIMATED = 2;
39        const TRANSFORM_ORIGIN = 4;
40        const TRANSFORM = 8;
41        const RELATIVE_TRANSFORM = 16;
42    }
43}
44
45impl BatchValue for CompositionBrushChangedFields {
46    #[inline]
47    fn write_to(&self, out: &mut Vec<u8>) {
48        self.bits().write_to(out);
49    }
50
51    #[inline]
52    fn read_from(input: &mut BatchValueReader<'_>) -> Self {
53        CompositionBrushChangedFields::from_bits_retain(u8::read_from(input))
54    }
55}
56
57/// The partial methods of `CompositionBrush`: implemented by the class that embeds
58/// [`CompositionBrushProps`]. Every hook defaults to doing nothing.
59pub trait CompositionBrushHooks: ICompositionObjectHost {
60    fn initialize_defaults_extra(&self) {}
61
62    fn validate_opacity_change(&self, _old_value: f64, _new_value: f64) {}
63    fn on_opacity_changed(&self) {}
64    fn on_opacity_changing(&self) {}
65
66    fn validate_transform_origin_change(&self, _old_value: RelativePoint, _new_value: RelativePoint) {}
67    fn on_transform_origin_changed(&self) {}
68    fn on_transform_origin_changing(&self) {}
69
70    fn validate_transform_change(&self, _old_value: &Option<BatchResource<dyn ITransform>>, _new_value: &Option<BatchResource<dyn ITransform>>) {}
71    fn on_transform_changed(&self) {}
72    fn on_transform_changing(&self) {}
73
74    fn validate_relative_transform_change(&self, _old_value: &Option<BatchResource<dyn ITransform>>, _new_value: &Option<BatchResource<dyn ITransform>>) {}
75    fn on_relative_transform_changed(&self) {}
76    fn on_relative_transform_changing(&self) {}
77}
78
79/// The UI-thread properties of `CompositionBrush`.
80pub struct CompositionBrushProps {
81    changed_fields_of_composition_brush: Cell<CompositionBrushChangedFields>,
82    opacity: Cell<f64>,
83    transform_origin: Cell<RelativePoint>,
84    transform: RefCell<Option<BatchResource<dyn ITransform>>>,
85    relative_transform: RefCell<Option<BatchResource<dyn ITransform>>>,
86}
87
88impl Default for CompositionBrushProps {
89    fn default() -> Self {
90        Self::new()
91    }
92}
93
94impl CompositionBrushProps {
95    /// Creates the properties with every field at the default of its type.
96    /// The defaults of the schema are applied by
97    /// [`initialize_defaults`](Self::initialize_defaults).
98    pub fn new() -> Self {
99        Self {
100            changed_fields_of_composition_brush: Cell::new(CompositionBrushChangedFields::empty()),
101            opacity: Cell::new(Default::default()),
102            transform_origin: Cell::new(Default::default()),
103            transform: RefCell::new(None),
104            relative_transform: RefCell::new(None),
105        }
106    }
107
108    /// The `InitializeDefaults` calls of the constructor chain: the base
109    /// classes first, then this class.
110    pub fn initialize_defaults(&self, host: &dyn CompositionBrushHooks) {
111        self.initialize_own_defaults(host);
112    }
113
114    /// `InitializeDefaults` of this class alone.
115    pub fn initialize_own_defaults(&self, host: &dyn CompositionBrushHooks) {
116        CompositionBrushHooks::initialize_defaults_extra(host);
117        self.set_opacity(host, 1.0);
118    }
119
120    /// `Opacity` (animated, default `1.0`).
121    pub fn opacity(&self) -> f64 {
122        self.opacity.get()
123    }
124
125    /// Sets `Opacity` (animated, default `1.0`).
126    pub fn set_opacity(&self, host: &dyn CompositionBrushHooks, value: f64) {
127        let mut changed = false;
128        let old_value = self.opacity.get();
129        if old_value.differs(&value) {
130            CompositionBrushHooks::validate_opacity_change(host, old_value, value);
131            CompositionBrushHooks::on_opacity_changing(host);
132            changed = true;
133            // Update the backing value
134            self.opacity.set(value);
135            // Register object for serialization in the next batch
136            self.changed_fields_of_composition_brush.set(self.changed_fields_of_composition_brush.get() | CompositionBrushChangedFields::OPACITY);
137            host.register_for_serialization();
138            // Reset previous animation if any
139            host.pending_animations().remove(ServerCompositionBrushProps::id_of_opacity_property().base());
140            self.changed_fields_of_composition_brush.set(self.changed_fields_of_composition_brush.get() & !CompositionBrushChangedFields::OPACITY_ANIMATED);
141            // Check for implicit animations
142            if let Some(animation) = host.implicit_animation("Opacity") {
143                // Animation affects only current property
144                if let Some(a) = animation.as_composition_animation() {
145                    self.changed_fields_of_composition_brush.set(self.changed_fields_of_composition_brush.get() | CompositionBrushChangedFields::OPACITY_ANIMATED);
146                    host.pending_animations().set(
147                        ServerCompositionBrushProps::id_of_opacity_property().base(),
148                        a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
149                    );
150                }
151                // Animation is triggered by the current field, but does not necessary affects it
152                host.start_animation_group(&animation, "Opacity", ExpressionVariant::create(value));
153            }
154        }
155        self.opacity.set(value);
156        if changed {
157            CompositionBrushHooks::on_opacity_changed(host);
158        }
159    }
160
161    /// `TransformOrigin`.
162    pub fn transform_origin(&self) -> RelativePoint {
163        self.transform_origin.get()
164    }
165
166    /// Sets `TransformOrigin`.
167    pub fn set_transform_origin(&self, host: &dyn CompositionBrushHooks, value: RelativePoint) {
168        let mut changed = false;
169        let old_value = self.transform_origin.get();
170        if old_value.differs(&value) {
171            CompositionBrushHooks::validate_transform_origin_change(host, old_value, value);
172            CompositionBrushHooks::on_transform_origin_changing(host);
173            changed = true;
174            // Update the backing value
175            self.transform_origin.set(value);
176            // Register object for serialization in the next batch
177            self.changed_fields_of_composition_brush.set(self.changed_fields_of_composition_brush.get() | CompositionBrushChangedFields::TRANSFORM_ORIGIN);
178            host.register_for_serialization();
179        }
180        self.transform_origin.set(value);
181        if changed {
182            CompositionBrushHooks::on_transform_origin_changed(host);
183        }
184    }
185
186    /// `Transform`.
187    pub fn transform(&self) -> Option<BatchResource<dyn ITransform>> {
188        self.transform.borrow().clone()
189    }
190
191    /// Sets `Transform`.
192    pub fn set_transform(&self, host: &dyn CompositionBrushHooks, value: Option<BatchResource<dyn ITransform>>) {
193        let mut changed = false;
194        let old_value = self.transform.borrow().clone();
195        if old_value.differs(&value) {
196            CompositionBrushHooks::validate_transform_change(host, &old_value, &value);
197            CompositionBrushHooks::on_transform_changing(host);
198            changed = true;
199            // Update the backing value
200            *self.transform.borrow_mut() = value.clone();
201            // Register object for serialization in the next batch
202            self.changed_fields_of_composition_brush.set(self.changed_fields_of_composition_brush.get() | CompositionBrushChangedFields::TRANSFORM);
203            host.register_for_serialization();
204        }
205        *self.transform.borrow_mut() = value;
206        if changed {
207            CompositionBrushHooks::on_transform_changed(host);
208        }
209    }
210
211    /// `RelativeTransform`.
212    pub fn relative_transform(&self) -> Option<BatchResource<dyn ITransform>> {
213        self.relative_transform.borrow().clone()
214    }
215
216    /// Sets `RelativeTransform`.
217    pub fn set_relative_transform(&self, host: &dyn CompositionBrushHooks, value: Option<BatchResource<dyn ITransform>>) {
218        let mut changed = false;
219        let old_value = self.relative_transform.borrow().clone();
220        if old_value.differs(&value) {
221            CompositionBrushHooks::validate_relative_transform_change(host, &old_value, &value);
222            CompositionBrushHooks::on_relative_transform_changing(host);
223            changed = true;
224            // Update the backing value
225            *self.relative_transform.borrow_mut() = value.clone();
226            // Register object for serialization in the next batch
227            self.changed_fields_of_composition_brush.set(self.changed_fields_of_composition_brush.get() | CompositionBrushChangedFields::RELATIVE_TRANSFORM);
228            host.register_for_serialization();
229        }
230        *self.relative_transform.borrow_mut() = value;
231        if changed {
232            CompositionBrushHooks::on_relative_transform_changed(host);
233        }
234    }
235
236    /// Connects an animation with the named property. Returns `false` when
237    /// neither this class nor its generated bases have an animated property
238    /// of that name: the caller continues with its hand-written base.
239    pub fn start_animation(
240        &self,
241        host: &dyn CompositionBrushHooks,
242        property_name: &str,
243        animation: &dyn ICompositionAnimation,
244        final_value: Option<ExpressionVariant>,
245    ) -> bool {
246        if property_name == "Opacity" {
247            let server = animation.create_instance(host.server(), final_value);
248            host.pending_animations().set(ServerCompositionBrushProps::id_of_opacity_property().base(), server);
249            self.changed_fields_of_composition_brush.set(self.changed_fields_of_composition_brush.get() | CompositionBrushChangedFields::OPACITY_ANIMATED);
250            host.register_for_serialization();
251            return true;
252        }
253        false
254    }
255
256    /// Writes the changes of the object: the base class first, then the
257    /// changed-fields mask and the changed members of this class.
258    pub fn serialize_changes_core(&self, host: &dyn CompositionBrushHooks, writer: &mut BatchStreamWriter<'_>) {
259        let changed = self.changed_fields_of_composition_brush.get();
260        writer.write(changed);
261        if changed.contains(CompositionBrushChangedFields::OPACITY_ANIMATED) {
262            writer.write_value(host.pending_animations().get_and_remove(ServerCompositionBrushProps::id_of_opacity_property().base()));
263        } else if changed.contains(CompositionBrushChangedFields::OPACITY) {
264            writer.write(self.opacity.get());
265        }
266        if changed.contains(CompositionBrushChangedFields::TRANSFORM_ORIGIN) {
267            writer.write(self.transform_origin.get());
268        }
269        if changed.contains(CompositionBrushChangedFields::TRANSFORM) {
270            writer.write_resource(self.transform.borrow().clone());
271        }
272        if changed.contains(CompositionBrushChangedFields::RELATIVE_TRANSFORM) {
273            writer.write_resource(self.relative_transform.borrow().clone());
274        }
275        self.changed_fields_of_composition_brush.set(CompositionBrushChangedFields::empty());
276    }
277}
278
279/// The partial methods of `ServerCompositionBrush`: implemented by the class that embeds
280/// [`ServerCompositionBrushProps`]. Every hook defaults to doing nothing.
281pub trait ServerCompositionBrushHooks: IServerAnimatedPropertyHost {
282    fn deserialize_changes_extra(&self, _reader: &mut BatchStreamReader<'_>) {}
283    fn on_fields_deserialized(&self, _changed: CompositionBrushChangedFields) {}
284
285    fn on_transform_origin_changed(&self) {}
286    fn on_transform_origin_changing(&self) {}
287
288    fn on_transform_changed(&self) {}
289    fn on_transform_changing(&self) {}
290
291    fn on_relative_transform_changed(&self) {}
292    fn on_relative_transform_changing(&self) {}
293}
294
295/// The server-side properties of `ServerCompositionBrush`.
296pub struct ServerCompositionBrushProps {
297    opacity: Cell<f64>,
298    transform_origin: Cell<RelativePoint>,
299    transform: RefCell<Option<ServerResourceRef<dyn ITransform>>>,
300    relative_transform: RefCell<Option<ServerResourceRef<dyn ITransform>>>,
301}
302
303impl Default for ServerCompositionBrushProps {
304    fn default() -> Self {
305        Self::new()
306    }
307}
308
309impl ServerCompositionBrushProps {
310    /// Creates the properties with every field at the default of its type; the
311    /// values of the UI thread arrive with the first batch.
312    pub fn new() -> Self {
313        Self {
314            opacity: Cell::new(Default::default()),
315            transform_origin: Cell::new(Default::default()),
316            transform: RefCell::new(None),
317            relative_transform: RefCell::new(None),
318        }
319    }
320
321    /// This block or the block of a base class, by type: what
322    /// `IServerObject::get_props` of the embedding class returns.
323    pub fn find_props(&self, type_id: TypeId) -> Option<&dyn Any> {
324        if type_id == TypeId::of::<Self>() {
325            return Some(self);
326        }
327        None
328    }
329
330    /// The composition property of `Opacity`.
331    pub fn id_of_opacity_property() -> &'static CompositionPropertyOf<f64> {
332        static PROPERTY: OnceLock<CompositionPropertyOf<f64>> = OnceLock::new();
333        PROPERTY.get_or_init(|| {
334            CompositionProperty::register::<ServerCompositionBrushProps, f64>(
335                "Opacity",
336                "ServerCompositionBrush",
337                |obj| props_of::<ServerCompositionBrushProps>(obj).opacity.get(),
338                |obj, v| props_of::<ServerCompositionBrushProps>(obj).opacity.set(v),
339                Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionBrushProps>(obj).opacity.get())),
340                Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionBrushProps>(obj).opacity.set(v.cast_or_default::<f64>())),
341            )
342        })
343    }
344
345    /// `Opacity` (animated).
346    pub fn opacity(&self) -> f64 {
347        self.opacity.get()
348    }
349
350    pub fn set_opacity(&self, host: &dyn ServerCompositionBrushHooks, value: f64) {
351        self.opacity.set(value);
352        host.remove_animation_for_property(Self::id_of_opacity_property().base());
353    }
354
355    /// The composition property of `TransformOrigin`.
356    pub fn id_of_transform_origin_property() -> &'static CompositionPropertyOf<RelativePoint> {
357        static PROPERTY: OnceLock<CompositionPropertyOf<RelativePoint>> = OnceLock::new();
358        PROPERTY.get_or_init(|| {
359            CompositionProperty::register::<ServerCompositionBrushProps, RelativePoint>(
360                "TransformOrigin",
361                "ServerCompositionBrush",
362                |obj| props_of::<ServerCompositionBrushProps>(obj).transform_origin.get(),
363                |obj, v| props_of::<ServerCompositionBrushProps>(obj).transform_origin.set(v),
364                None,
365                None,
366            )
367        })
368    }
369
370    /// `TransformOrigin`.
371    pub fn transform_origin(&self) -> RelativePoint {
372        self.transform_origin.get()
373    }
374
375    pub fn set_transform_origin(&self, host: &dyn ServerCompositionBrushHooks, value: RelativePoint) {
376        let old_value = self.transform_origin.get();
377        let mut changed = false;
378        if old_value.differs(&value) {
379            ServerCompositionBrushHooks::on_transform_origin_changing(host);
380            changed = true;
381        }
382        host.set_value(
383            Self::id_of_transform_origin_property().base(),
384            ServerValueChange {
385                equal: old_value.default_equals(&value),
386                old_resource: None,
387                new_resource: None,
388                assign: &mut || self.transform_origin.set(value),
389            },
390        );
391        if changed {
392            ServerCompositionBrushHooks::on_transform_origin_changed(host);
393        }
394    }
395
396    /// The composition property of `Transform`.
397    pub fn id_of_transform_property() -> &'static CompositionPropertyOf<Option<ServerResourceRef<dyn ITransform>>> {
398        static PROPERTY: OnceLock<CompositionPropertyOf<Option<ServerResourceRef<dyn ITransform>>>> = OnceLock::new();
399        PROPERTY.get_or_init(|| {
400            CompositionProperty::register::<ServerCompositionBrushProps, Option<ServerResourceRef<dyn ITransform>>>(
401                "Transform",
402                "ServerCompositionBrush",
403                |obj| props_of::<ServerCompositionBrushProps>(obj).transform.borrow().clone(),
404                |obj, v| *props_of::<ServerCompositionBrushProps>(obj).transform.borrow_mut() = v,
405                None,
406                None,
407            )
408        })
409    }
410
411    /// `Transform`.
412    pub fn transform(&self) -> Option<ServerResourceRef<dyn ITransform>> {
413        self.transform.borrow().clone()
414    }
415
416    pub fn set_transform(&self, host: &dyn ServerCompositionBrushHooks, value: Option<ServerResourceRef<dyn ITransform>>) {
417        let old_value = self.transform.borrow().clone();
418        let mut changed = false;
419        if old_value.differs(&value) {
420            ServerCompositionBrushHooks::on_transform_changing(host);
421            changed = true;
422        }
423        host.set_value(
424            Self::id_of_transform_property().base(),
425            ServerValueChange {
426                equal: old_value.default_equals(&value),
427                old_resource: old_value.as_server_render_resource(),
428                new_resource: value.as_server_render_resource(),
429                assign: &mut || *self.transform.borrow_mut() = value.clone(),
430            },
431        );
432        if changed {
433            ServerCompositionBrushHooks::on_transform_changed(host);
434        }
435    }
436
437    /// The composition property of `RelativeTransform`.
438    pub fn id_of_relative_transform_property() -> &'static CompositionPropertyOf<Option<ServerResourceRef<dyn ITransform>>> {
439        static PROPERTY: OnceLock<CompositionPropertyOf<Option<ServerResourceRef<dyn ITransform>>>> = OnceLock::new();
440        PROPERTY.get_or_init(|| {
441            CompositionProperty::register::<ServerCompositionBrushProps, Option<ServerResourceRef<dyn ITransform>>>(
442                "RelativeTransform",
443                "ServerCompositionBrush",
444                |obj| props_of::<ServerCompositionBrushProps>(obj).relative_transform.borrow().clone(),
445                |obj, v| *props_of::<ServerCompositionBrushProps>(obj).relative_transform.borrow_mut() = v,
446                None,
447                None,
448            )
449        })
450    }
451
452    /// `RelativeTransform`.
453    pub fn relative_transform(&self) -> Option<ServerResourceRef<dyn ITransform>> {
454        self.relative_transform.borrow().clone()
455    }
456
457    pub fn set_relative_transform(&self, host: &dyn ServerCompositionBrushHooks, value: Option<ServerResourceRef<dyn ITransform>>) {
458        let old_value = self.relative_transform.borrow().clone();
459        let mut changed = false;
460        if old_value.differs(&value) {
461            ServerCompositionBrushHooks::on_relative_transform_changing(host);
462            changed = true;
463        }
464        host.set_value(
465            Self::id_of_relative_transform_property().base(),
466            ServerValueChange {
467                equal: old_value.default_equals(&value),
468                old_resource: old_value.as_server_render_resource(),
469                new_resource: value.as_server_render_resource(),
470                assign: &mut || *self.relative_transform.borrow_mut() = value.clone(),
471            },
472        );
473        if changed {
474            ServerCompositionBrushHooks::on_relative_transform_changed(host);
475        }
476    }
477
478    /// Reads the changes of the object: the base class first, then the
479    /// changed-fields mask and the changed members of this class.
480    pub fn deserialize_changes_core(
481        &self,
482        host: &dyn ServerCompositionBrushHooks,
483        reader: &mut BatchStreamReader<'_>,
484        committed_at: Duration,
485    ) {
486        let compositor = host.server_compositor();
487        ServerCompositionBrushHooks::deserialize_changes_extra(host, reader);
488        let changed = reader.read::<CompositionBrushChangedFields>();
489        if changed.contains(CompositionBrushChangedFields::OPACITY_ANIMATED) {
490            let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
491                panic!("a batch starts an animation of `Opacity` without an animation instance");
492            };
493            host.set_animated_value(
494                Self::id_of_opacity_property().base(),
495                ExpressionVariant::create(self.opacity.get()),
496                committed_at,
497                animation,
498            );
499        } else if changed.contains(CompositionBrushChangedFields::OPACITY) {
500            let value = reader.read::<f64>();
501            self.set_opacity(host, value);
502        }
503        if changed.contains(CompositionBrushChangedFields::TRANSFORM_ORIGIN) {
504            let value = reader.read::<RelativePoint>();
505            self.set_transform_origin(host, value);
506        }
507        if changed.contains(CompositionBrushChangedFields::TRANSFORM) {
508            let value = read_resource(reader, compositor.as_ref(), |o| o.as_transform());
509            self.set_transform(host, value);
510        }
511        if changed.contains(CompositionBrushChangedFields::RELATIVE_TRANSFORM) {
512            let value = read_resource(reader, compositor.as_ref(), |o| o.as_transform());
513            self.set_relative_transform(host, value);
514        }
515        ServerCompositionBrushHooks::on_fields_deserialized(host, changed);
516    }
517
518    /// The composition property with the given name, among the properties
519    /// of this class and of its generated bases that have a variant form.
520    pub fn get_composition_property(name: &str) -> Option<&'static CompositionProperty> {
521        if name == "Opacity" {
522            return Some(Self::id_of_opacity_property().base());
523        }
524        None
525    }
526}