Skip to main content

ferroui_base/rendering/composition/generated/
composition_clip.rs

1// @generated by scripts/generate_composition.py — do not edit
2
3//! `CompositionClip`.
4//!
5//! Defined by the FerroUI overlay (scripts/composition-schema-winui.xml).
6//!
7//! Schema attributes: abstract.
8
9use bitflags::bitflags;
10use crate::Matrix;
11use crate::Vector;
12use crate::rendering::composition::ICompositionObjectHost;
13use crate::rendering::composition::animations::AnimationInstanceFactory;
14use crate::rendering::composition::animations::ICompositionAnimation;
15use crate::rendering::composition::expressions::ExpressionVariant;
16use crate::rendering::composition::server::CompositionProperty;
17use crate::rendering::composition::server::CompositionPropertyOf;
18use crate::rendering::composition::server::IServerAnimatedPropertyHost;
19use crate::rendering::composition::server::ServerPropertyValue;
20use crate::rendering::composition::server::props_of;
21use crate::rendering::composition::transport::BatchStreamReader;
22use crate::rendering::composition::transport::BatchStreamWriter;
23use crate::rendering::composition::transport::BatchValue;
24use crate::rendering::composition::transport::BatchValueReader;
25use std::any::Any;
26use std::any::TypeId;
27use std::cell::Cell;
28use std::sync::OnceLock;
29use std::time::Duration;
30
31bitflags! {
32    /// The fields of `CompositionClip` that changed since its last serialization.
33    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
34    pub struct CompositionClipChangedFields: u16 {
35        const ANCHOR_POINT = 1;
36        const ANCHOR_POINT_ANIMATED = 2;
37        const CENTER_POINT = 4;
38        const CENTER_POINT_ANIMATED = 8;
39        const OFFSET = 16;
40        const OFFSET_ANIMATED = 32;
41        const ROTATION_ANGLE = 64;
42        const ROTATION_ANGLE_ANIMATED = 128;
43        const SCALE = 256;
44        const SCALE_ANIMATED = 512;
45        const TRANSFORM_MATRIX = 1024;
46        const TRANSFORM_MATRIX_ANIMATED = 2048;
47    }
48}
49
50impl BatchValue for CompositionClipChangedFields {
51    #[inline]
52    fn write_to(&self, out: &mut Vec<u8>) {
53        self.bits().write_to(out);
54    }
55
56    #[inline]
57    fn read_from(input: &mut BatchValueReader<'_>) -> Self {
58        CompositionClipChangedFields::from_bits_retain(u16::read_from(input))
59    }
60}
61
62/// The partial methods of `CompositionClip`: implemented by the class that embeds
63/// [`CompositionClipProps`]. Every hook defaults to doing nothing.
64pub trait CompositionClipHooks: ICompositionObjectHost {
65    fn initialize_defaults_extra(&self) {}
66
67    fn validate_anchor_point_change(&self, _old_value: Vector, _new_value: Vector) {}
68    fn on_anchor_point_changed(&self) {}
69    fn on_anchor_point_changing(&self) {}
70
71    fn validate_center_point_change(&self, _old_value: Vector, _new_value: Vector) {}
72    fn on_center_point_changed(&self) {}
73    fn on_center_point_changing(&self) {}
74
75    fn validate_offset_change(&self, _old_value: Vector, _new_value: Vector) {}
76    fn on_offset_changed(&self) {}
77    fn on_offset_changing(&self) {}
78
79    fn validate_rotation_angle_change(&self, _old_value: f32, _new_value: f32) {}
80    fn on_rotation_angle_changed(&self) {}
81    fn on_rotation_angle_changing(&self) {}
82
83    fn validate_scale_change(&self, _old_value: Vector, _new_value: Vector) {}
84    fn on_scale_changed(&self) {}
85    fn on_scale_changing(&self) {}
86
87    fn validate_transform_matrix_change(&self, _old_value: Matrix, _new_value: Matrix) {}
88    fn on_transform_matrix_changed(&self) {}
89    fn on_transform_matrix_changing(&self) {}
90}
91
92/// The UI-thread properties of `CompositionClip`.
93pub struct CompositionClipProps {
94    changed_fields_of_composition_clip: Cell<CompositionClipChangedFields>,
95    anchor_point: Cell<Vector>,
96    center_point: Cell<Vector>,
97    offset: Cell<Vector>,
98    rotation_angle: Cell<f32>,
99    scale: Cell<Vector>,
100    transform_matrix: Cell<Matrix>,
101}
102
103impl Default for CompositionClipProps {
104    fn default() -> Self {
105        Self::new()
106    }
107}
108
109impl CompositionClipProps {
110    /// Creates the properties with every field at the default of its type.
111    /// The defaults of the schema are applied by
112    /// [`initialize_defaults`](Self::initialize_defaults).
113    pub fn new() -> Self {
114        Self {
115            changed_fields_of_composition_clip: Cell::new(CompositionClipChangedFields::empty()),
116            anchor_point: Cell::new(Default::default()),
117            center_point: Cell::new(Default::default()),
118            offset: Cell::new(Default::default()),
119            rotation_angle: Cell::new(Default::default()),
120            scale: Cell::new(Default::default()),
121            transform_matrix: Cell::new(Default::default()),
122        }
123    }
124
125    /// The `InitializeDefaults` calls of the constructor chain: the base
126    /// classes first, then this class.
127    pub fn initialize_defaults(&self, host: &dyn CompositionClipHooks) {
128        self.initialize_own_defaults(host);
129    }
130
131    /// `InitializeDefaults` of this class alone.
132    pub fn initialize_own_defaults(&self, host: &dyn CompositionClipHooks) {
133        CompositionClipHooks::initialize_defaults_extra(host);
134        self.set_scale(host, Vector::new(1.0, 1.0));
135        self.set_transform_matrix(host, Matrix::IDENTITY);
136    }
137
138    /// `AnchorPoint` (animated, FerroUI overlay).
139    pub fn anchor_point(&self) -> Vector {
140        self.anchor_point.get()
141    }
142
143    /// Sets `AnchorPoint` (animated, FerroUI overlay).
144    pub fn set_anchor_point(&self, host: &dyn CompositionClipHooks, value: Vector) {
145        let mut changed = false;
146        let old_value = self.anchor_point.get();
147        if old_value.differs(&value) {
148            CompositionClipHooks::validate_anchor_point_change(host, old_value, value);
149            CompositionClipHooks::on_anchor_point_changing(host);
150            changed = true;
151            // Update the backing value
152            self.anchor_point.set(value);
153            // Register object for serialization in the next batch
154            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::ANCHOR_POINT);
155            host.register_for_serialization();
156            // Reset previous animation if any
157            host.pending_animations().remove(ServerCompositionClipProps::id_of_anchor_point_property().base());
158            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() & !CompositionClipChangedFields::ANCHOR_POINT_ANIMATED);
159            // Check for implicit animations
160            if let Some(animation) = host.implicit_animation("AnchorPoint") {
161                // Animation affects only current property
162                if let Some(a) = animation.as_composition_animation() {
163                    self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::ANCHOR_POINT_ANIMATED);
164                    host.pending_animations().set(
165                        ServerCompositionClipProps::id_of_anchor_point_property().base(),
166                        a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
167                    );
168                }
169                // Animation is triggered by the current field, but does not necessary affects it
170                host.start_animation_group(&animation, "AnchorPoint", ExpressionVariant::create(value));
171            }
172        }
173        self.anchor_point.set(value);
174        if changed {
175            CompositionClipHooks::on_anchor_point_changed(host);
176        }
177    }
178
179    /// `CenterPoint` (animated, FerroUI overlay).
180    pub fn center_point(&self) -> Vector {
181        self.center_point.get()
182    }
183
184    /// Sets `CenterPoint` (animated, FerroUI overlay).
185    pub fn set_center_point(&self, host: &dyn CompositionClipHooks, value: Vector) {
186        let mut changed = false;
187        let old_value = self.center_point.get();
188        if old_value.differs(&value) {
189            CompositionClipHooks::validate_center_point_change(host, old_value, value);
190            CompositionClipHooks::on_center_point_changing(host);
191            changed = true;
192            // Update the backing value
193            self.center_point.set(value);
194            // Register object for serialization in the next batch
195            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::CENTER_POINT);
196            host.register_for_serialization();
197            // Reset previous animation if any
198            host.pending_animations().remove(ServerCompositionClipProps::id_of_center_point_property().base());
199            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() & !CompositionClipChangedFields::CENTER_POINT_ANIMATED);
200            // Check for implicit animations
201            if let Some(animation) = host.implicit_animation("CenterPoint") {
202                // Animation affects only current property
203                if let Some(a) = animation.as_composition_animation() {
204                    self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::CENTER_POINT_ANIMATED);
205                    host.pending_animations().set(
206                        ServerCompositionClipProps::id_of_center_point_property().base(),
207                        a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
208                    );
209                }
210                // Animation is triggered by the current field, but does not necessary affects it
211                host.start_animation_group(&animation, "CenterPoint", ExpressionVariant::create(value));
212            }
213        }
214        self.center_point.set(value);
215        if changed {
216            CompositionClipHooks::on_center_point_changed(host);
217        }
218    }
219
220    /// `Offset` (animated, FerroUI overlay).
221    pub fn offset(&self) -> Vector {
222        self.offset.get()
223    }
224
225    /// Sets `Offset` (animated, FerroUI overlay).
226    pub fn set_offset(&self, host: &dyn CompositionClipHooks, value: Vector) {
227        let mut changed = false;
228        let old_value = self.offset.get();
229        if old_value.differs(&value) {
230            CompositionClipHooks::validate_offset_change(host, old_value, value);
231            CompositionClipHooks::on_offset_changing(host);
232            changed = true;
233            // Update the backing value
234            self.offset.set(value);
235            // Register object for serialization in the next batch
236            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::OFFSET);
237            host.register_for_serialization();
238            // Reset previous animation if any
239            host.pending_animations().remove(ServerCompositionClipProps::id_of_offset_property().base());
240            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() & !CompositionClipChangedFields::OFFSET_ANIMATED);
241            // Check for implicit animations
242            if let Some(animation) = host.implicit_animation("Offset") {
243                // Animation affects only current property
244                if let Some(a) = animation.as_composition_animation() {
245                    self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::OFFSET_ANIMATED);
246                    host.pending_animations().set(
247                        ServerCompositionClipProps::id_of_offset_property().base(),
248                        a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
249                    );
250                }
251                // Animation is triggered by the current field, but does not necessary affects it
252                host.start_animation_group(&animation, "Offset", ExpressionVariant::create(value));
253            }
254        }
255        self.offset.set(value);
256        if changed {
257            CompositionClipHooks::on_offset_changed(host);
258        }
259    }
260
261    /// `RotationAngle` (animated, FerroUI overlay).
262    pub fn rotation_angle(&self) -> f32 {
263        self.rotation_angle.get()
264    }
265
266    /// Sets `RotationAngle` (animated, FerroUI overlay).
267    pub fn set_rotation_angle(&self, host: &dyn CompositionClipHooks, value: f32) {
268        let mut changed = false;
269        let old_value = self.rotation_angle.get();
270        if old_value.differs(&value) {
271            CompositionClipHooks::validate_rotation_angle_change(host, old_value, value);
272            CompositionClipHooks::on_rotation_angle_changing(host);
273            changed = true;
274            // Update the backing value
275            self.rotation_angle.set(value);
276            // Register object for serialization in the next batch
277            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::ROTATION_ANGLE);
278            host.register_for_serialization();
279            // Reset previous animation if any
280            host.pending_animations().remove(ServerCompositionClipProps::id_of_rotation_angle_property().base());
281            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() & !CompositionClipChangedFields::ROTATION_ANGLE_ANIMATED);
282            // Check for implicit animations
283            if let Some(animation) = host.implicit_animation("RotationAngle") {
284                // Animation affects only current property
285                if let Some(a) = animation.as_composition_animation() {
286                    self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::ROTATION_ANGLE_ANIMATED);
287                    host.pending_animations().set(
288                        ServerCompositionClipProps::id_of_rotation_angle_property().base(),
289                        a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
290                    );
291                }
292                // Animation is triggered by the current field, but does not necessary affects it
293                host.start_animation_group(&animation, "RotationAngle", ExpressionVariant::create(value));
294            }
295        }
296        self.rotation_angle.set(value);
297        if changed {
298            CompositionClipHooks::on_rotation_angle_changed(host);
299        }
300    }
301
302    /// `Scale` (animated, default `Vector::new(1.0, 1.0)`, FerroUI overlay).
303    pub fn scale(&self) -> Vector {
304        self.scale.get()
305    }
306
307    /// Sets `Scale` (animated, default `Vector::new(1.0, 1.0)`, FerroUI overlay).
308    pub fn set_scale(&self, host: &dyn CompositionClipHooks, value: Vector) {
309        let mut changed = false;
310        let old_value = self.scale.get();
311        if old_value.differs(&value) {
312            CompositionClipHooks::validate_scale_change(host, old_value, value);
313            CompositionClipHooks::on_scale_changing(host);
314            changed = true;
315            // Update the backing value
316            self.scale.set(value);
317            // Register object for serialization in the next batch
318            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::SCALE);
319            host.register_for_serialization();
320            // Reset previous animation if any
321            host.pending_animations().remove(ServerCompositionClipProps::id_of_scale_property().base());
322            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() & !CompositionClipChangedFields::SCALE_ANIMATED);
323            // Check for implicit animations
324            if let Some(animation) = host.implicit_animation("Scale") {
325                // Animation affects only current property
326                if let Some(a) = animation.as_composition_animation() {
327                    self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::SCALE_ANIMATED);
328                    host.pending_animations().set(
329                        ServerCompositionClipProps::id_of_scale_property().base(),
330                        a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
331                    );
332                }
333                // Animation is triggered by the current field, but does not necessary affects it
334                host.start_animation_group(&animation, "Scale", ExpressionVariant::create(value));
335            }
336        }
337        self.scale.set(value);
338        if changed {
339            CompositionClipHooks::on_scale_changed(host);
340        }
341    }
342
343    /// `TransformMatrix` (animated, default `Matrix::IDENTITY`, FerroUI overlay).
344    pub fn transform_matrix(&self) -> Matrix {
345        self.transform_matrix.get()
346    }
347
348    /// Sets `TransformMatrix` (animated, default `Matrix::IDENTITY`, FerroUI overlay).
349    pub fn set_transform_matrix(&self, host: &dyn CompositionClipHooks, value: Matrix) {
350        let mut changed = false;
351        let old_value = self.transform_matrix.get();
352        if old_value.differs(&value) {
353            CompositionClipHooks::validate_transform_matrix_change(host, old_value, value);
354            CompositionClipHooks::on_transform_matrix_changing(host);
355            changed = true;
356            // Update the backing value
357            self.transform_matrix.set(value);
358            // Register object for serialization in the next batch
359            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::TRANSFORM_MATRIX);
360            host.register_for_serialization();
361            // Reset previous animation if any
362            host.pending_animations().remove(ServerCompositionClipProps::id_of_transform_matrix_property().base());
363            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() & !CompositionClipChangedFields::TRANSFORM_MATRIX_ANIMATED);
364            // Check for implicit animations
365            if let Some(animation) = host.implicit_animation("TransformMatrix") {
366                // Animation affects only current property
367                if let Some(a) = animation.as_composition_animation() {
368                    self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::TRANSFORM_MATRIX_ANIMATED);
369                    host.pending_animations().set(
370                        ServerCompositionClipProps::id_of_transform_matrix_property().base(),
371                        a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
372                    );
373                }
374                // Animation is triggered by the current field, but does not necessary affects it
375                host.start_animation_group(&animation, "TransformMatrix", ExpressionVariant::create(value));
376            }
377        }
378        self.transform_matrix.set(value);
379        if changed {
380            CompositionClipHooks::on_transform_matrix_changed(host);
381        }
382    }
383
384    /// Connects an animation with the named property. Returns `false` when
385    /// neither this class nor its generated bases have an animated property
386    /// of that name: the caller continues with its hand-written base.
387    pub fn start_animation(
388        &self,
389        host: &dyn CompositionClipHooks,
390        property_name: &str,
391        animation: &dyn ICompositionAnimation,
392        final_value: Option<ExpressionVariant>,
393    ) -> bool {
394        if property_name == "AnchorPoint" {
395            let server = animation.create_instance(host.server(), final_value);
396            host.pending_animations().set(ServerCompositionClipProps::id_of_anchor_point_property().base(), server);
397            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::ANCHOR_POINT_ANIMATED);
398            host.register_for_serialization();
399            return true;
400        }
401        if property_name == "CenterPoint" {
402            let server = animation.create_instance(host.server(), final_value);
403            host.pending_animations().set(ServerCompositionClipProps::id_of_center_point_property().base(), server);
404            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::CENTER_POINT_ANIMATED);
405            host.register_for_serialization();
406            return true;
407        }
408        if property_name == "Offset" {
409            let server = animation.create_instance(host.server(), final_value);
410            host.pending_animations().set(ServerCompositionClipProps::id_of_offset_property().base(), server);
411            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::OFFSET_ANIMATED);
412            host.register_for_serialization();
413            return true;
414        }
415        if property_name == "RotationAngle" {
416            let server = animation.create_instance(host.server(), final_value);
417            host.pending_animations().set(ServerCompositionClipProps::id_of_rotation_angle_property().base(), server);
418            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::ROTATION_ANGLE_ANIMATED);
419            host.register_for_serialization();
420            return true;
421        }
422        if property_name == "Scale" {
423            let server = animation.create_instance(host.server(), final_value);
424            host.pending_animations().set(ServerCompositionClipProps::id_of_scale_property().base(), server);
425            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::SCALE_ANIMATED);
426            host.register_for_serialization();
427            return true;
428        }
429        if property_name == "TransformMatrix" {
430            let server = animation.create_instance(host.server(), final_value);
431            host.pending_animations().set(ServerCompositionClipProps::id_of_transform_matrix_property().base(), server);
432            self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::TRANSFORM_MATRIX_ANIMATED);
433            host.register_for_serialization();
434            return true;
435        }
436        false
437    }
438
439    /// Writes the changes of the object: the base class first, then the
440    /// changed-fields mask and the changed members of this class.
441    pub fn serialize_changes_core(&self, host: &dyn CompositionClipHooks, writer: &mut BatchStreamWriter<'_>) {
442        let changed = self.changed_fields_of_composition_clip.get();
443        writer.write(changed);
444        if changed.contains(CompositionClipChangedFields::ANCHOR_POINT_ANIMATED) {
445            writer.write_value(host.pending_animations().get_and_remove(ServerCompositionClipProps::id_of_anchor_point_property().base()));
446        } else if changed.contains(CompositionClipChangedFields::ANCHOR_POINT) {
447            writer.write(self.anchor_point.get());
448        }
449        if changed.contains(CompositionClipChangedFields::CENTER_POINT_ANIMATED) {
450            writer.write_value(host.pending_animations().get_and_remove(ServerCompositionClipProps::id_of_center_point_property().base()));
451        } else if changed.contains(CompositionClipChangedFields::CENTER_POINT) {
452            writer.write(self.center_point.get());
453        }
454        if changed.contains(CompositionClipChangedFields::OFFSET_ANIMATED) {
455            writer.write_value(host.pending_animations().get_and_remove(ServerCompositionClipProps::id_of_offset_property().base()));
456        } else if changed.contains(CompositionClipChangedFields::OFFSET) {
457            writer.write(self.offset.get());
458        }
459        if changed.contains(CompositionClipChangedFields::ROTATION_ANGLE_ANIMATED) {
460            writer.write_value(host.pending_animations().get_and_remove(ServerCompositionClipProps::id_of_rotation_angle_property().base()));
461        } else if changed.contains(CompositionClipChangedFields::ROTATION_ANGLE) {
462            writer.write(self.rotation_angle.get());
463        }
464        if changed.contains(CompositionClipChangedFields::SCALE_ANIMATED) {
465            writer.write_value(host.pending_animations().get_and_remove(ServerCompositionClipProps::id_of_scale_property().base()));
466        } else if changed.contains(CompositionClipChangedFields::SCALE) {
467            writer.write(self.scale.get());
468        }
469        if changed.contains(CompositionClipChangedFields::TRANSFORM_MATRIX_ANIMATED) {
470            writer.write_value(host.pending_animations().get_and_remove(ServerCompositionClipProps::id_of_transform_matrix_property().base()));
471        } else if changed.contains(CompositionClipChangedFields::TRANSFORM_MATRIX) {
472            writer.write(self.transform_matrix.get());
473        }
474        self.changed_fields_of_composition_clip.set(CompositionClipChangedFields::empty());
475    }
476}
477
478/// The partial methods of `ServerCompositionClip`: implemented by the class that embeds
479/// [`ServerCompositionClipProps`]. Every hook defaults to doing nothing.
480pub trait ServerCompositionClipHooks: IServerAnimatedPropertyHost {
481    fn deserialize_changes_extra(&self, _reader: &mut BatchStreamReader<'_>) {}
482    fn on_fields_deserialized(&self, _changed: CompositionClipChangedFields) {}
483}
484
485/// The server-side properties of `ServerCompositionClip`.
486pub struct ServerCompositionClipProps {
487    anchor_point: Cell<Vector>,
488    center_point: Cell<Vector>,
489    offset: Cell<Vector>,
490    rotation_angle: Cell<f32>,
491    scale: Cell<Vector>,
492    transform_matrix: Cell<Matrix>,
493}
494
495impl Default for ServerCompositionClipProps {
496    fn default() -> Self {
497        Self::new()
498    }
499}
500
501impl ServerCompositionClipProps {
502    /// Creates the properties with every field at the default of its type; the
503    /// values of the UI thread arrive with the first batch.
504    pub fn new() -> Self {
505        Self {
506            anchor_point: Cell::new(Default::default()),
507            center_point: Cell::new(Default::default()),
508            offset: Cell::new(Default::default()),
509            rotation_angle: Cell::new(Default::default()),
510            scale: Cell::new(Default::default()),
511            transform_matrix: Cell::new(Default::default()),
512        }
513    }
514
515    /// This block or the block of a base class, by type: what
516    /// `IServerObject::get_props` of the embedding class returns.
517    pub fn find_props(&self, type_id: TypeId) -> Option<&dyn Any> {
518        if type_id == TypeId::of::<Self>() {
519            return Some(self);
520        }
521        None
522    }
523
524    /// The composition property of `AnchorPoint`.
525    pub fn id_of_anchor_point_property() -> &'static CompositionPropertyOf<Vector> {
526        static PROPERTY: OnceLock<CompositionPropertyOf<Vector>> = OnceLock::new();
527        PROPERTY.get_or_init(|| {
528            CompositionProperty::register::<ServerCompositionClipProps, Vector>(
529                "AnchorPoint",
530                "ServerCompositionClip",
531                |obj| props_of::<ServerCompositionClipProps>(obj).anchor_point.get(),
532                |obj, v| props_of::<ServerCompositionClipProps>(obj).anchor_point.set(v),
533                Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionClipProps>(obj).anchor_point.get())),
534                Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionClipProps>(obj).anchor_point.set(v.cast_or_default::<Vector>())),
535            )
536        })
537    }
538
539    /// `AnchorPoint` (animated).
540    pub fn anchor_point(&self) -> Vector {
541        self.anchor_point.get()
542    }
543
544    pub fn set_anchor_point(&self, host: &dyn ServerCompositionClipHooks, value: Vector) {
545        self.anchor_point.set(value);
546        host.remove_animation_for_property(Self::id_of_anchor_point_property().base());
547    }
548
549    /// The composition property of `CenterPoint`.
550    pub fn id_of_center_point_property() -> &'static CompositionPropertyOf<Vector> {
551        static PROPERTY: OnceLock<CompositionPropertyOf<Vector>> = OnceLock::new();
552        PROPERTY.get_or_init(|| {
553            CompositionProperty::register::<ServerCompositionClipProps, Vector>(
554                "CenterPoint",
555                "ServerCompositionClip",
556                |obj| props_of::<ServerCompositionClipProps>(obj).center_point.get(),
557                |obj, v| props_of::<ServerCompositionClipProps>(obj).center_point.set(v),
558                Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionClipProps>(obj).center_point.get())),
559                Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionClipProps>(obj).center_point.set(v.cast_or_default::<Vector>())),
560            )
561        })
562    }
563
564    /// `CenterPoint` (animated).
565    pub fn center_point(&self) -> Vector {
566        self.center_point.get()
567    }
568
569    pub fn set_center_point(&self, host: &dyn ServerCompositionClipHooks, value: Vector) {
570        self.center_point.set(value);
571        host.remove_animation_for_property(Self::id_of_center_point_property().base());
572    }
573
574    /// The composition property of `Offset`.
575    pub fn id_of_offset_property() -> &'static CompositionPropertyOf<Vector> {
576        static PROPERTY: OnceLock<CompositionPropertyOf<Vector>> = OnceLock::new();
577        PROPERTY.get_or_init(|| {
578            CompositionProperty::register::<ServerCompositionClipProps, Vector>(
579                "Offset",
580                "ServerCompositionClip",
581                |obj| props_of::<ServerCompositionClipProps>(obj).offset.get(),
582                |obj, v| props_of::<ServerCompositionClipProps>(obj).offset.set(v),
583                Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionClipProps>(obj).offset.get())),
584                Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionClipProps>(obj).offset.set(v.cast_or_default::<Vector>())),
585            )
586        })
587    }
588
589    /// `Offset` (animated).
590    pub fn offset(&self) -> Vector {
591        self.offset.get()
592    }
593
594    pub fn set_offset(&self, host: &dyn ServerCompositionClipHooks, value: Vector) {
595        self.offset.set(value);
596        host.remove_animation_for_property(Self::id_of_offset_property().base());
597    }
598
599    /// The composition property of `RotationAngle`.
600    pub fn id_of_rotation_angle_property() -> &'static CompositionPropertyOf<f32> {
601        static PROPERTY: OnceLock<CompositionPropertyOf<f32>> = OnceLock::new();
602        PROPERTY.get_or_init(|| {
603            CompositionProperty::register::<ServerCompositionClipProps, f32>(
604                "RotationAngle",
605                "ServerCompositionClip",
606                |obj| props_of::<ServerCompositionClipProps>(obj).rotation_angle.get(),
607                |obj, v| props_of::<ServerCompositionClipProps>(obj).rotation_angle.set(v),
608                Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionClipProps>(obj).rotation_angle.get())),
609                Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionClipProps>(obj).rotation_angle.set(v.cast_or_default::<f32>())),
610            )
611        })
612    }
613
614    /// `RotationAngle` (animated).
615    pub fn rotation_angle(&self) -> f32 {
616        self.rotation_angle.get()
617    }
618
619    pub fn set_rotation_angle(&self, host: &dyn ServerCompositionClipHooks, value: f32) {
620        self.rotation_angle.set(value);
621        host.remove_animation_for_property(Self::id_of_rotation_angle_property().base());
622    }
623
624    /// The composition property of `Scale`.
625    pub fn id_of_scale_property() -> &'static CompositionPropertyOf<Vector> {
626        static PROPERTY: OnceLock<CompositionPropertyOf<Vector>> = OnceLock::new();
627        PROPERTY.get_or_init(|| {
628            CompositionProperty::register::<ServerCompositionClipProps, Vector>(
629                "Scale",
630                "ServerCompositionClip",
631                |obj| props_of::<ServerCompositionClipProps>(obj).scale.get(),
632                |obj, v| props_of::<ServerCompositionClipProps>(obj).scale.set(v),
633                Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionClipProps>(obj).scale.get())),
634                Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionClipProps>(obj).scale.set(v.cast_or_default::<Vector>())),
635            )
636        })
637    }
638
639    /// `Scale` (animated).
640    pub fn scale(&self) -> Vector {
641        self.scale.get()
642    }
643
644    pub fn set_scale(&self, host: &dyn ServerCompositionClipHooks, value: Vector) {
645        self.scale.set(value);
646        host.remove_animation_for_property(Self::id_of_scale_property().base());
647    }
648
649    /// The composition property of `TransformMatrix`.
650    pub fn id_of_transform_matrix_property() -> &'static CompositionPropertyOf<Matrix> {
651        static PROPERTY: OnceLock<CompositionPropertyOf<Matrix>> = OnceLock::new();
652        PROPERTY.get_or_init(|| {
653            CompositionProperty::register::<ServerCompositionClipProps, Matrix>(
654                "TransformMatrix",
655                "ServerCompositionClip",
656                |obj| props_of::<ServerCompositionClipProps>(obj).transform_matrix.get(),
657                |obj, v| props_of::<ServerCompositionClipProps>(obj).transform_matrix.set(v),
658                Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionClipProps>(obj).transform_matrix.get())),
659                Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionClipProps>(obj).transform_matrix.set(v.cast_or_default::<Matrix>())),
660            )
661        })
662    }
663
664    /// `TransformMatrix` (animated).
665    pub fn transform_matrix(&self) -> Matrix {
666        self.transform_matrix.get()
667    }
668
669    pub fn set_transform_matrix(&self, host: &dyn ServerCompositionClipHooks, value: Matrix) {
670        self.transform_matrix.set(value);
671        host.remove_animation_for_property(Self::id_of_transform_matrix_property().base());
672    }
673
674    /// Reads the changes of the object: the base class first, then the
675    /// changed-fields mask and the changed members of this class.
676    pub fn deserialize_changes_core(
677        &self,
678        host: &dyn ServerCompositionClipHooks,
679        reader: &mut BatchStreamReader<'_>,
680        committed_at: Duration,
681    ) {
682        ServerCompositionClipHooks::deserialize_changes_extra(host, reader);
683        let changed = reader.read::<CompositionClipChangedFields>();
684        if changed.contains(CompositionClipChangedFields::ANCHOR_POINT_ANIMATED) {
685            let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
686                panic!("a batch starts an animation of `AnchorPoint` without an animation instance");
687            };
688            host.set_animated_value(
689                Self::id_of_anchor_point_property().base(),
690                ExpressionVariant::create(self.anchor_point.get()),
691                committed_at,
692                animation,
693            );
694        } else if changed.contains(CompositionClipChangedFields::ANCHOR_POINT) {
695            let value = reader.read::<Vector>();
696            self.set_anchor_point(host, value);
697        }
698        if changed.contains(CompositionClipChangedFields::CENTER_POINT_ANIMATED) {
699            let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
700                panic!("a batch starts an animation of `CenterPoint` without an animation instance");
701            };
702            host.set_animated_value(
703                Self::id_of_center_point_property().base(),
704                ExpressionVariant::create(self.center_point.get()),
705                committed_at,
706                animation,
707            );
708        } else if changed.contains(CompositionClipChangedFields::CENTER_POINT) {
709            let value = reader.read::<Vector>();
710            self.set_center_point(host, value);
711        }
712        if changed.contains(CompositionClipChangedFields::OFFSET_ANIMATED) {
713            let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
714                panic!("a batch starts an animation of `Offset` without an animation instance");
715            };
716            host.set_animated_value(
717                Self::id_of_offset_property().base(),
718                ExpressionVariant::create(self.offset.get()),
719                committed_at,
720                animation,
721            );
722        } else if changed.contains(CompositionClipChangedFields::OFFSET) {
723            let value = reader.read::<Vector>();
724            self.set_offset(host, value);
725        }
726        if changed.contains(CompositionClipChangedFields::ROTATION_ANGLE_ANIMATED) {
727            let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
728                panic!("a batch starts an animation of `RotationAngle` without an animation instance");
729            };
730            host.set_animated_value(
731                Self::id_of_rotation_angle_property().base(),
732                ExpressionVariant::create(self.rotation_angle.get()),
733                committed_at,
734                animation,
735            );
736        } else if changed.contains(CompositionClipChangedFields::ROTATION_ANGLE) {
737            let value = reader.read::<f32>();
738            self.set_rotation_angle(host, value);
739        }
740        if changed.contains(CompositionClipChangedFields::SCALE_ANIMATED) {
741            let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
742                panic!("a batch starts an animation of `Scale` without an animation instance");
743            };
744            host.set_animated_value(
745                Self::id_of_scale_property().base(),
746                ExpressionVariant::create(self.scale.get()),
747                committed_at,
748                animation,
749            );
750        } else if changed.contains(CompositionClipChangedFields::SCALE) {
751            let value = reader.read::<Vector>();
752            self.set_scale(host, value);
753        }
754        if changed.contains(CompositionClipChangedFields::TRANSFORM_MATRIX_ANIMATED) {
755            let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
756                panic!("a batch starts an animation of `TransformMatrix` without an animation instance");
757            };
758            host.set_animated_value(
759                Self::id_of_transform_matrix_property().base(),
760                ExpressionVariant::create(self.transform_matrix.get()),
761                committed_at,
762                animation,
763            );
764        } else if changed.contains(CompositionClipChangedFields::TRANSFORM_MATRIX) {
765            let value = reader.read::<Matrix>();
766            self.set_transform_matrix(host, value);
767        }
768        ServerCompositionClipHooks::on_fields_deserialized(host, changed);
769    }
770
771    /// The composition property with the given name, among the properties
772    /// of this class and of its generated bases that have a variant form.
773    pub fn get_composition_property(name: &str) -> Option<&'static CompositionProperty> {
774        if name == "AnchorPoint" {
775            return Some(Self::id_of_anchor_point_property().base());
776        }
777        if name == "CenterPoint" {
778            return Some(Self::id_of_center_point_property().base());
779        }
780        if name == "Offset" {
781            return Some(Self::id_of_offset_property().base());
782        }
783        if name == "RotationAngle" {
784            return Some(Self::id_of_rotation_angle_property().base());
785        }
786        if name == "Scale" {
787            return Some(Self::id_of_scale_property().base());
788        }
789        if name == "TransformMatrix" {
790            return Some(Self::id_of_transform_matrix_property().base());
791        }
792        None
793    }
794}