Skip to main content

ferroui_base/rendering/composition/generated/
composition_geometry.rs

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