ferroui_base/rendering/composition/generated/
composition_geometry.rs1use 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 #[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
54pub 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
72pub 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 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 pub fn initialize_defaults(&self, host: &dyn CompositionGeometryHooks) {
102 self.initialize_own_defaults(host);
103 }
104
105 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 pub fn trim_end(&self) -> f32 {
113 self.trim_end.get()
114 }
115
116 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 self.trim_end.set(value);
126 self.changed_fields_of_composition_geometry.set(self.changed_fields_of_composition_geometry.get() | CompositionGeometryChangedFields::TRIM_END);
128 host.register_for_serialization();
129 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 if let Some(animation) = host.implicit_animation("TrimEnd") {
134 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 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 pub fn trim_offset(&self) -> f32 {
154 self.trim_offset.get()
155 }
156
157 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 self.trim_offset.set(value);
167 self.changed_fields_of_composition_geometry.set(self.changed_fields_of_composition_geometry.get() | CompositionGeometryChangedFields::TRIM_OFFSET);
169 host.register_for_serialization();
170 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 if let Some(animation) = host.implicit_animation("TrimOffset") {
175 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 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 pub fn trim_start(&self) -> f32 {
195 self.trim_start.get()
196 }
197
198 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 self.trim_start.set(value);
208 self.changed_fields_of_composition_geometry.set(self.changed_fields_of_composition_geometry.get() | CompositionGeometryChangedFields::TRIM_START);
210 host.register_for_serialization();
211 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 if let Some(animation) = host.implicit_animation("TrimStart") {
216 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 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 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 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
292pub trait ServerCompositionGeometryHooks: IServerAnimatedPropertyHost {
295 fn deserialize_changes_extra(&self, _reader: &mut BatchStreamReader<'_>) {}
296 fn on_fields_deserialized(&self, _changed: CompositionGeometryChangedFields) {}
297}
298
299pub 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 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 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 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 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 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 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 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 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 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 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}