1use 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 #[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
62pub 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
92pub 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 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 pub fn initialize_defaults(&self, host: &dyn CompositionClipHooks) {
128 self.initialize_own_defaults(host);
129 }
130
131 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 pub fn anchor_point(&self) -> Vector {
140 self.anchor_point.get()
141 }
142
143 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 self.anchor_point.set(value);
153 self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::ANCHOR_POINT);
155 host.register_for_serialization();
156 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 if let Some(animation) = host.implicit_animation("AnchorPoint") {
161 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 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 pub fn center_point(&self) -> Vector {
181 self.center_point.get()
182 }
183
184 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 self.center_point.set(value);
194 self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::CENTER_POINT);
196 host.register_for_serialization();
197 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 if let Some(animation) = host.implicit_animation("CenterPoint") {
202 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 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 pub fn offset(&self) -> Vector {
222 self.offset.get()
223 }
224
225 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 self.offset.set(value);
235 self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::OFFSET);
237 host.register_for_serialization();
238 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 if let Some(animation) = host.implicit_animation("Offset") {
243 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 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 pub fn rotation_angle(&self) -> f32 {
263 self.rotation_angle.get()
264 }
265
266 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 self.rotation_angle.set(value);
276 self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::ROTATION_ANGLE);
278 host.register_for_serialization();
279 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 if let Some(animation) = host.implicit_animation("RotationAngle") {
284 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 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 pub fn scale(&self) -> Vector {
304 self.scale.get()
305 }
306
307 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 self.scale.set(value);
317 self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::SCALE);
319 host.register_for_serialization();
320 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 if let Some(animation) = host.implicit_animation("Scale") {
325 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 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 pub fn transform_matrix(&self) -> Matrix {
345 self.transform_matrix.get()
346 }
347
348 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 self.transform_matrix.set(value);
358 self.changed_fields_of_composition_clip.set(self.changed_fields_of_composition_clip.get() | CompositionClipChangedFields::TRANSFORM_MATRIX);
360 host.register_for_serialization();
361 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 if let Some(animation) = host.implicit_animation("TransformMatrix") {
366 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 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 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 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
478pub trait ServerCompositionClipHooks: IServerAnimatedPropertyHost {
481 fn deserialize_changes_extra(&self, _reader: &mut BatchStreamReader<'_>) {}
482 fn on_fields_deserialized(&self, _changed: CompositionClipChangedFields) {}
483}
484
485pub 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}