1use bitflags::bitflags;
8use crate::Vector;
9use crate::rendering::composition::animations::AnimationInstanceFactory;
10use crate::rendering::composition::animations::ICompositionAnimation;
11use crate::rendering::composition::expressions::ExpressionVariant;
12use crate::rendering::composition::server::CompositionProperty;
13use crate::rendering::composition::server::CompositionPropertyOf;
14use crate::rendering::composition::server::ServerPropertyValue;
15use crate::rendering::composition::server::props_of;
16use crate::rendering::composition::transport::BatchStreamReader;
17use crate::rendering::composition::transport::BatchStreamWriter;
18use crate::rendering::composition::transport::BatchValue;
19use crate::rendering::composition::transport::BatchValueReader;
20use std::any::Any;
21use std::any::TypeId;
22use std::cell::Cell;
23use std::sync::OnceLock;
24use std::time::Duration;
25use super::CompositionClipHooks;
26use super::CompositionClipProps;
27use super::ServerCompositionClipHooks;
28use super::ServerCompositionClipProps;
29
30bitflags! {
31 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
33 pub struct RectangleClipChangedFields: u16 {
34 const LEFT = 1;
35 const LEFT_ANIMATED = 2;
36 const TOP = 4;
37 const TOP_ANIMATED = 8;
38 const RIGHT = 16;
39 const RIGHT_ANIMATED = 32;
40 const BOTTOM = 64;
41 const BOTTOM_ANIMATED = 128;
42 const TOP_LEFT_RADIUS = 256;
43 const TOP_LEFT_RADIUS_ANIMATED = 512;
44 const TOP_RIGHT_RADIUS = 1024;
45 const TOP_RIGHT_RADIUS_ANIMATED = 2048;
46 const BOTTOM_LEFT_RADIUS = 4096;
47 const BOTTOM_LEFT_RADIUS_ANIMATED = 8192;
48 const BOTTOM_RIGHT_RADIUS = 16384;
49 const BOTTOM_RIGHT_RADIUS_ANIMATED = 32768;
50 }
51}
52
53impl BatchValue for RectangleClipChangedFields {
54 #[inline]
55 fn write_to(&self, out: &mut Vec<u8>) {
56 self.bits().write_to(out);
57 }
58
59 #[inline]
60 fn read_from(input: &mut BatchValueReader<'_>) -> Self {
61 RectangleClipChangedFields::from_bits_retain(u16::read_from(input))
62 }
63}
64
65pub trait RectangleClipHooks: CompositionClipHooks {
68 fn initialize_defaults_extra(&self) {}
69
70 fn validate_left_change(&self, _old_value: f32, _new_value: f32) {}
71 fn on_left_changed(&self) {}
72 fn on_left_changing(&self) {}
73
74 fn validate_top_change(&self, _old_value: f32, _new_value: f32) {}
75 fn on_top_changed(&self) {}
76 fn on_top_changing(&self) {}
77
78 fn validate_right_change(&self, _old_value: f32, _new_value: f32) {}
79 fn on_right_changed(&self) {}
80 fn on_right_changing(&self) {}
81
82 fn validate_bottom_change(&self, _old_value: f32, _new_value: f32) {}
83 fn on_bottom_changed(&self) {}
84 fn on_bottom_changing(&self) {}
85
86 fn validate_top_left_radius_change(&self, _old_value: Vector, _new_value: Vector) {}
87 fn on_top_left_radius_changed(&self) {}
88 fn on_top_left_radius_changing(&self) {}
89
90 fn validate_top_right_radius_change(&self, _old_value: Vector, _new_value: Vector) {}
91 fn on_top_right_radius_changed(&self) {}
92 fn on_top_right_radius_changing(&self) {}
93
94 fn validate_bottom_left_radius_change(&self, _old_value: Vector, _new_value: Vector) {}
95 fn on_bottom_left_radius_changed(&self) {}
96 fn on_bottom_left_radius_changing(&self) {}
97
98 fn validate_bottom_right_radius_change(&self, _old_value: Vector, _new_value: Vector) {}
99 fn on_bottom_right_radius_changed(&self) {}
100 fn on_bottom_right_radius_changing(&self) {}
101}
102
103pub struct RectangleClipProps {
105 base: CompositionClipProps,
106 changed_fields_of_rectangle_clip: Cell<RectangleClipChangedFields>,
107 left: Cell<f32>,
108 top: Cell<f32>,
109 right: Cell<f32>,
110 bottom: Cell<f32>,
111 top_left_radius: Cell<Vector>,
112 top_right_radius: Cell<Vector>,
113 bottom_left_radius: Cell<Vector>,
114 bottom_right_radius: Cell<Vector>,
115}
116
117impl Default for RectangleClipProps {
118 fn default() -> Self {
119 Self::new()
120 }
121}
122
123impl RectangleClipProps {
124 pub fn new() -> Self {
128 Self {
129 base: CompositionClipProps::new(),
130 changed_fields_of_rectangle_clip: Cell::new(RectangleClipChangedFields::empty()),
131 left: Cell::new(Default::default()),
132 top: Cell::new(Default::default()),
133 right: Cell::new(Default::default()),
134 bottom: Cell::new(Default::default()),
135 top_left_radius: Cell::new(Default::default()),
136 top_right_radius: Cell::new(Default::default()),
137 bottom_left_radius: Cell::new(Default::default()),
138 bottom_right_radius: Cell::new(Default::default()),
139 }
140 }
141
142 pub fn base(&self) -> &CompositionClipProps {
144 &self.base
145 }
146
147 pub fn initialize_defaults(&self, host: &dyn RectangleClipHooks) {
150 self.base.initialize_defaults(host);
151 self.initialize_own_defaults(host);
152 }
153
154 pub fn initialize_own_defaults(&self, host: &dyn RectangleClipHooks) {
156 RectangleClipHooks::initialize_defaults_extra(host);
157 }
158
159 pub fn left(&self) -> f32 {
161 self.left.get()
162 }
163
164 pub fn set_left(&self, host: &dyn RectangleClipHooks, value: f32) {
166 let mut changed = false;
167 let old_value = self.left.get();
168 if old_value.differs(&value) {
169 RectangleClipHooks::validate_left_change(host, old_value, value);
170 RectangleClipHooks::on_left_changing(host);
171 changed = true;
172 self.left.set(value);
174 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::LEFT);
176 host.register_for_serialization();
177 host.pending_animations().remove(ServerRectangleClipProps::id_of_left_property().base());
179 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() & !RectangleClipChangedFields::LEFT_ANIMATED);
180 if let Some(animation) = host.implicit_animation("Left") {
182 if let Some(a) = animation.as_composition_animation() {
184 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::LEFT_ANIMATED);
185 host.pending_animations().set(
186 ServerRectangleClipProps::id_of_left_property().base(),
187 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
188 );
189 }
190 host.start_animation_group(&animation, "Left", ExpressionVariant::create(value));
192 }
193 }
194 self.left.set(value);
195 if changed {
196 RectangleClipHooks::on_left_changed(host);
197 }
198 }
199
200 pub fn top(&self) -> f32 {
202 self.top.get()
203 }
204
205 pub fn set_top(&self, host: &dyn RectangleClipHooks, value: f32) {
207 let mut changed = false;
208 let old_value = self.top.get();
209 if old_value.differs(&value) {
210 RectangleClipHooks::validate_top_change(host, old_value, value);
211 RectangleClipHooks::on_top_changing(host);
212 changed = true;
213 self.top.set(value);
215 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::TOP);
217 host.register_for_serialization();
218 host.pending_animations().remove(ServerRectangleClipProps::id_of_top_property().base());
220 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() & !RectangleClipChangedFields::TOP_ANIMATED);
221 if let Some(animation) = host.implicit_animation("Top") {
223 if let Some(a) = animation.as_composition_animation() {
225 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::TOP_ANIMATED);
226 host.pending_animations().set(
227 ServerRectangleClipProps::id_of_top_property().base(),
228 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
229 );
230 }
231 host.start_animation_group(&animation, "Top", ExpressionVariant::create(value));
233 }
234 }
235 self.top.set(value);
236 if changed {
237 RectangleClipHooks::on_top_changed(host);
238 }
239 }
240
241 pub fn right(&self) -> f32 {
243 self.right.get()
244 }
245
246 pub fn set_right(&self, host: &dyn RectangleClipHooks, value: f32) {
248 let mut changed = false;
249 let old_value = self.right.get();
250 if old_value.differs(&value) {
251 RectangleClipHooks::validate_right_change(host, old_value, value);
252 RectangleClipHooks::on_right_changing(host);
253 changed = true;
254 self.right.set(value);
256 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::RIGHT);
258 host.register_for_serialization();
259 host.pending_animations().remove(ServerRectangleClipProps::id_of_right_property().base());
261 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() & !RectangleClipChangedFields::RIGHT_ANIMATED);
262 if let Some(animation) = host.implicit_animation("Right") {
264 if let Some(a) = animation.as_composition_animation() {
266 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::RIGHT_ANIMATED);
267 host.pending_animations().set(
268 ServerRectangleClipProps::id_of_right_property().base(),
269 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
270 );
271 }
272 host.start_animation_group(&animation, "Right", ExpressionVariant::create(value));
274 }
275 }
276 self.right.set(value);
277 if changed {
278 RectangleClipHooks::on_right_changed(host);
279 }
280 }
281
282 pub fn bottom(&self) -> f32 {
284 self.bottom.get()
285 }
286
287 pub fn set_bottom(&self, host: &dyn RectangleClipHooks, value: f32) {
289 let mut changed = false;
290 let old_value = self.bottom.get();
291 if old_value.differs(&value) {
292 RectangleClipHooks::validate_bottom_change(host, old_value, value);
293 RectangleClipHooks::on_bottom_changing(host);
294 changed = true;
295 self.bottom.set(value);
297 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::BOTTOM);
299 host.register_for_serialization();
300 host.pending_animations().remove(ServerRectangleClipProps::id_of_bottom_property().base());
302 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() & !RectangleClipChangedFields::BOTTOM_ANIMATED);
303 if let Some(animation) = host.implicit_animation("Bottom") {
305 if let Some(a) = animation.as_composition_animation() {
307 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::BOTTOM_ANIMATED);
308 host.pending_animations().set(
309 ServerRectangleClipProps::id_of_bottom_property().base(),
310 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
311 );
312 }
313 host.start_animation_group(&animation, "Bottom", ExpressionVariant::create(value));
315 }
316 }
317 self.bottom.set(value);
318 if changed {
319 RectangleClipHooks::on_bottom_changed(host);
320 }
321 }
322
323 pub fn top_left_radius(&self) -> Vector {
325 self.top_left_radius.get()
326 }
327
328 pub fn set_top_left_radius(&self, host: &dyn RectangleClipHooks, value: Vector) {
330 let mut changed = false;
331 let old_value = self.top_left_radius.get();
332 if old_value.differs(&value) {
333 RectangleClipHooks::validate_top_left_radius_change(host, old_value, value);
334 RectangleClipHooks::on_top_left_radius_changing(host);
335 changed = true;
336 self.top_left_radius.set(value);
338 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::TOP_LEFT_RADIUS);
340 host.register_for_serialization();
341 host.pending_animations().remove(ServerRectangleClipProps::id_of_top_left_radius_property().base());
343 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() & !RectangleClipChangedFields::TOP_LEFT_RADIUS_ANIMATED);
344 if let Some(animation) = host.implicit_animation("TopLeftRadius") {
346 if let Some(a) = animation.as_composition_animation() {
348 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::TOP_LEFT_RADIUS_ANIMATED);
349 host.pending_animations().set(
350 ServerRectangleClipProps::id_of_top_left_radius_property().base(),
351 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
352 );
353 }
354 host.start_animation_group(&animation, "TopLeftRadius", ExpressionVariant::create(value));
356 }
357 }
358 self.top_left_radius.set(value);
359 if changed {
360 RectangleClipHooks::on_top_left_radius_changed(host);
361 }
362 }
363
364 pub fn top_right_radius(&self) -> Vector {
366 self.top_right_radius.get()
367 }
368
369 pub fn set_top_right_radius(&self, host: &dyn RectangleClipHooks, value: Vector) {
371 let mut changed = false;
372 let old_value = self.top_right_radius.get();
373 if old_value.differs(&value) {
374 RectangleClipHooks::validate_top_right_radius_change(host, old_value, value);
375 RectangleClipHooks::on_top_right_radius_changing(host);
376 changed = true;
377 self.top_right_radius.set(value);
379 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::TOP_RIGHT_RADIUS);
381 host.register_for_serialization();
382 host.pending_animations().remove(ServerRectangleClipProps::id_of_top_right_radius_property().base());
384 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() & !RectangleClipChangedFields::TOP_RIGHT_RADIUS_ANIMATED);
385 if let Some(animation) = host.implicit_animation("TopRightRadius") {
387 if let Some(a) = animation.as_composition_animation() {
389 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::TOP_RIGHT_RADIUS_ANIMATED);
390 host.pending_animations().set(
391 ServerRectangleClipProps::id_of_top_right_radius_property().base(),
392 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
393 );
394 }
395 host.start_animation_group(&animation, "TopRightRadius", ExpressionVariant::create(value));
397 }
398 }
399 self.top_right_radius.set(value);
400 if changed {
401 RectangleClipHooks::on_top_right_radius_changed(host);
402 }
403 }
404
405 pub fn bottom_left_radius(&self) -> Vector {
407 self.bottom_left_radius.get()
408 }
409
410 pub fn set_bottom_left_radius(&self, host: &dyn RectangleClipHooks, value: Vector) {
412 let mut changed = false;
413 let old_value = self.bottom_left_radius.get();
414 if old_value.differs(&value) {
415 RectangleClipHooks::validate_bottom_left_radius_change(host, old_value, value);
416 RectangleClipHooks::on_bottom_left_radius_changing(host);
417 changed = true;
418 self.bottom_left_radius.set(value);
420 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::BOTTOM_LEFT_RADIUS);
422 host.register_for_serialization();
423 host.pending_animations().remove(ServerRectangleClipProps::id_of_bottom_left_radius_property().base());
425 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() & !RectangleClipChangedFields::BOTTOM_LEFT_RADIUS_ANIMATED);
426 if let Some(animation) = host.implicit_animation("BottomLeftRadius") {
428 if let Some(a) = animation.as_composition_animation() {
430 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::BOTTOM_LEFT_RADIUS_ANIMATED);
431 host.pending_animations().set(
432 ServerRectangleClipProps::id_of_bottom_left_radius_property().base(),
433 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
434 );
435 }
436 host.start_animation_group(&animation, "BottomLeftRadius", ExpressionVariant::create(value));
438 }
439 }
440 self.bottom_left_radius.set(value);
441 if changed {
442 RectangleClipHooks::on_bottom_left_radius_changed(host);
443 }
444 }
445
446 pub fn bottom_right_radius(&self) -> Vector {
448 self.bottom_right_radius.get()
449 }
450
451 pub fn set_bottom_right_radius(&self, host: &dyn RectangleClipHooks, value: Vector) {
453 let mut changed = false;
454 let old_value = self.bottom_right_radius.get();
455 if old_value.differs(&value) {
456 RectangleClipHooks::validate_bottom_right_radius_change(host, old_value, value);
457 RectangleClipHooks::on_bottom_right_radius_changing(host);
458 changed = true;
459 self.bottom_right_radius.set(value);
461 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::BOTTOM_RIGHT_RADIUS);
463 host.register_for_serialization();
464 host.pending_animations().remove(ServerRectangleClipProps::id_of_bottom_right_radius_property().base());
466 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() & !RectangleClipChangedFields::BOTTOM_RIGHT_RADIUS_ANIMATED);
467 if let Some(animation) = host.implicit_animation("BottomRightRadius") {
469 if let Some(a) = animation.as_composition_animation() {
471 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::BOTTOM_RIGHT_RADIUS_ANIMATED);
472 host.pending_animations().set(
473 ServerRectangleClipProps::id_of_bottom_right_radius_property().base(),
474 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
475 );
476 }
477 host.start_animation_group(&animation, "BottomRightRadius", ExpressionVariant::create(value));
479 }
480 }
481 self.bottom_right_radius.set(value);
482 if changed {
483 RectangleClipHooks::on_bottom_right_radius_changed(host);
484 }
485 }
486
487 pub fn start_animation(
491 &self,
492 host: &dyn RectangleClipHooks,
493 property_name: &str,
494 animation: &dyn ICompositionAnimation,
495 final_value: Option<ExpressionVariant>,
496 ) -> bool {
497 if property_name == "Left" {
498 let server = animation.create_instance(host.server(), final_value);
499 host.pending_animations().set(ServerRectangleClipProps::id_of_left_property().base(), server);
500 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::LEFT_ANIMATED);
501 host.register_for_serialization();
502 return true;
503 }
504 if property_name == "Top" {
505 let server = animation.create_instance(host.server(), final_value);
506 host.pending_animations().set(ServerRectangleClipProps::id_of_top_property().base(), server);
507 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::TOP_ANIMATED);
508 host.register_for_serialization();
509 return true;
510 }
511 if property_name == "Right" {
512 let server = animation.create_instance(host.server(), final_value);
513 host.pending_animations().set(ServerRectangleClipProps::id_of_right_property().base(), server);
514 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::RIGHT_ANIMATED);
515 host.register_for_serialization();
516 return true;
517 }
518 if property_name == "Bottom" {
519 let server = animation.create_instance(host.server(), final_value);
520 host.pending_animations().set(ServerRectangleClipProps::id_of_bottom_property().base(), server);
521 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::BOTTOM_ANIMATED);
522 host.register_for_serialization();
523 return true;
524 }
525 if property_name == "TopLeftRadius" {
526 let server = animation.create_instance(host.server(), final_value);
527 host.pending_animations().set(ServerRectangleClipProps::id_of_top_left_radius_property().base(), server);
528 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::TOP_LEFT_RADIUS_ANIMATED);
529 host.register_for_serialization();
530 return true;
531 }
532 if property_name == "TopRightRadius" {
533 let server = animation.create_instance(host.server(), final_value);
534 host.pending_animations().set(ServerRectangleClipProps::id_of_top_right_radius_property().base(), server);
535 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::TOP_RIGHT_RADIUS_ANIMATED);
536 host.register_for_serialization();
537 return true;
538 }
539 if property_name == "BottomLeftRadius" {
540 let server = animation.create_instance(host.server(), final_value);
541 host.pending_animations().set(ServerRectangleClipProps::id_of_bottom_left_radius_property().base(), server);
542 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::BOTTOM_LEFT_RADIUS_ANIMATED);
543 host.register_for_serialization();
544 return true;
545 }
546 if property_name == "BottomRightRadius" {
547 let server = animation.create_instance(host.server(), final_value);
548 host.pending_animations().set(ServerRectangleClipProps::id_of_bottom_right_radius_property().base(), server);
549 self.changed_fields_of_rectangle_clip.set(self.changed_fields_of_rectangle_clip.get() | RectangleClipChangedFields::BOTTOM_RIGHT_RADIUS_ANIMATED);
550 host.register_for_serialization();
551 return true;
552 }
553 self.base.start_animation(host, property_name, animation, final_value)
554 }
555
556 pub fn serialize_changes_core(&self, host: &dyn RectangleClipHooks, writer: &mut BatchStreamWriter<'_>) {
559 self.base.serialize_changes_core(host, writer);
560 let changed = self.changed_fields_of_rectangle_clip.get();
561 writer.write(changed);
562 if changed.contains(RectangleClipChangedFields::LEFT_ANIMATED) {
563 writer.write_value(host.pending_animations().get_and_remove(ServerRectangleClipProps::id_of_left_property().base()));
564 } else if changed.contains(RectangleClipChangedFields::LEFT) {
565 writer.write(self.left.get());
566 }
567 if changed.contains(RectangleClipChangedFields::TOP_ANIMATED) {
568 writer.write_value(host.pending_animations().get_and_remove(ServerRectangleClipProps::id_of_top_property().base()));
569 } else if changed.contains(RectangleClipChangedFields::TOP) {
570 writer.write(self.top.get());
571 }
572 if changed.contains(RectangleClipChangedFields::RIGHT_ANIMATED) {
573 writer.write_value(host.pending_animations().get_and_remove(ServerRectangleClipProps::id_of_right_property().base()));
574 } else if changed.contains(RectangleClipChangedFields::RIGHT) {
575 writer.write(self.right.get());
576 }
577 if changed.contains(RectangleClipChangedFields::BOTTOM_ANIMATED) {
578 writer.write_value(host.pending_animations().get_and_remove(ServerRectangleClipProps::id_of_bottom_property().base()));
579 } else if changed.contains(RectangleClipChangedFields::BOTTOM) {
580 writer.write(self.bottom.get());
581 }
582 if changed.contains(RectangleClipChangedFields::TOP_LEFT_RADIUS_ANIMATED) {
583 writer.write_value(host.pending_animations().get_and_remove(ServerRectangleClipProps::id_of_top_left_radius_property().base()));
584 } else if changed.contains(RectangleClipChangedFields::TOP_LEFT_RADIUS) {
585 writer.write(self.top_left_radius.get());
586 }
587 if changed.contains(RectangleClipChangedFields::TOP_RIGHT_RADIUS_ANIMATED) {
588 writer.write_value(host.pending_animations().get_and_remove(ServerRectangleClipProps::id_of_top_right_radius_property().base()));
589 } else if changed.contains(RectangleClipChangedFields::TOP_RIGHT_RADIUS) {
590 writer.write(self.top_right_radius.get());
591 }
592 if changed.contains(RectangleClipChangedFields::BOTTOM_LEFT_RADIUS_ANIMATED) {
593 writer.write_value(host.pending_animations().get_and_remove(ServerRectangleClipProps::id_of_bottom_left_radius_property().base()));
594 } else if changed.contains(RectangleClipChangedFields::BOTTOM_LEFT_RADIUS) {
595 writer.write(self.bottom_left_radius.get());
596 }
597 if changed.contains(RectangleClipChangedFields::BOTTOM_RIGHT_RADIUS_ANIMATED) {
598 writer.write_value(host.pending_animations().get_and_remove(ServerRectangleClipProps::id_of_bottom_right_radius_property().base()));
599 } else if changed.contains(RectangleClipChangedFields::BOTTOM_RIGHT_RADIUS) {
600 writer.write(self.bottom_right_radius.get());
601 }
602 self.changed_fields_of_rectangle_clip.set(RectangleClipChangedFields::empty());
603 }
604}
605
606pub trait ServerRectangleClipHooks: ServerCompositionClipHooks {
609 fn deserialize_changes_extra(&self, _reader: &mut BatchStreamReader<'_>) {}
610 fn on_fields_deserialized(&self, _changed: RectangleClipChangedFields) {}
611}
612
613pub struct ServerRectangleClipProps {
615 base: ServerCompositionClipProps,
616 left: Cell<f32>,
617 top: Cell<f32>,
618 right: Cell<f32>,
619 bottom: Cell<f32>,
620 top_left_radius: Cell<Vector>,
621 top_right_radius: Cell<Vector>,
622 bottom_left_radius: Cell<Vector>,
623 bottom_right_radius: Cell<Vector>,
624}
625
626impl Default for ServerRectangleClipProps {
627 fn default() -> Self {
628 Self::new()
629 }
630}
631
632impl ServerRectangleClipProps {
633 pub fn new() -> Self {
636 Self {
637 base: ServerCompositionClipProps::new(),
638 left: Cell::new(Default::default()),
639 top: Cell::new(Default::default()),
640 right: Cell::new(Default::default()),
641 bottom: Cell::new(Default::default()),
642 top_left_radius: Cell::new(Default::default()),
643 top_right_radius: Cell::new(Default::default()),
644 bottom_left_radius: Cell::new(Default::default()),
645 bottom_right_radius: Cell::new(Default::default()),
646 }
647 }
648
649 pub fn base(&self) -> &ServerCompositionClipProps {
651 &self.base
652 }
653
654 pub fn find_props(&self, type_id: TypeId) -> Option<&dyn Any> {
657 if type_id == TypeId::of::<Self>() {
658 return Some(self);
659 }
660 self.base.find_props(type_id)
661 }
662
663 pub fn id_of_left_property() -> &'static CompositionPropertyOf<f32> {
665 static PROPERTY: OnceLock<CompositionPropertyOf<f32>> = OnceLock::new();
666 PROPERTY.get_or_init(|| {
667 CompositionProperty::register::<ServerRectangleClipProps, f32>(
668 "Left",
669 "ServerRectangleClip",
670 |obj| props_of::<ServerRectangleClipProps>(obj).left.get(),
671 |obj, v| props_of::<ServerRectangleClipProps>(obj).left.set(v),
672 Some(|obj| ExpressionVariant::create(props_of::<ServerRectangleClipProps>(obj).left.get())),
673 Some(|obj, v: ExpressionVariant| props_of::<ServerRectangleClipProps>(obj).left.set(v.cast_or_default::<f32>())),
674 )
675 })
676 }
677
678 pub fn left(&self) -> f32 {
680 self.left.get()
681 }
682
683 pub fn set_left(&self, host: &dyn ServerRectangleClipHooks, value: f32) {
684 self.left.set(value);
685 host.remove_animation_for_property(Self::id_of_left_property().base());
686 }
687
688 pub fn id_of_top_property() -> &'static CompositionPropertyOf<f32> {
690 static PROPERTY: OnceLock<CompositionPropertyOf<f32>> = OnceLock::new();
691 PROPERTY.get_or_init(|| {
692 CompositionProperty::register::<ServerRectangleClipProps, f32>(
693 "Top",
694 "ServerRectangleClip",
695 |obj| props_of::<ServerRectangleClipProps>(obj).top.get(),
696 |obj, v| props_of::<ServerRectangleClipProps>(obj).top.set(v),
697 Some(|obj| ExpressionVariant::create(props_of::<ServerRectangleClipProps>(obj).top.get())),
698 Some(|obj, v: ExpressionVariant| props_of::<ServerRectangleClipProps>(obj).top.set(v.cast_or_default::<f32>())),
699 )
700 })
701 }
702
703 pub fn top(&self) -> f32 {
705 self.top.get()
706 }
707
708 pub fn set_top(&self, host: &dyn ServerRectangleClipHooks, value: f32) {
709 self.top.set(value);
710 host.remove_animation_for_property(Self::id_of_top_property().base());
711 }
712
713 pub fn id_of_right_property() -> &'static CompositionPropertyOf<f32> {
715 static PROPERTY: OnceLock<CompositionPropertyOf<f32>> = OnceLock::new();
716 PROPERTY.get_or_init(|| {
717 CompositionProperty::register::<ServerRectangleClipProps, f32>(
718 "Right",
719 "ServerRectangleClip",
720 |obj| props_of::<ServerRectangleClipProps>(obj).right.get(),
721 |obj, v| props_of::<ServerRectangleClipProps>(obj).right.set(v),
722 Some(|obj| ExpressionVariant::create(props_of::<ServerRectangleClipProps>(obj).right.get())),
723 Some(|obj, v: ExpressionVariant| props_of::<ServerRectangleClipProps>(obj).right.set(v.cast_or_default::<f32>())),
724 )
725 })
726 }
727
728 pub fn right(&self) -> f32 {
730 self.right.get()
731 }
732
733 pub fn set_right(&self, host: &dyn ServerRectangleClipHooks, value: f32) {
734 self.right.set(value);
735 host.remove_animation_for_property(Self::id_of_right_property().base());
736 }
737
738 pub fn id_of_bottom_property() -> &'static CompositionPropertyOf<f32> {
740 static PROPERTY: OnceLock<CompositionPropertyOf<f32>> = OnceLock::new();
741 PROPERTY.get_or_init(|| {
742 CompositionProperty::register::<ServerRectangleClipProps, f32>(
743 "Bottom",
744 "ServerRectangleClip",
745 |obj| props_of::<ServerRectangleClipProps>(obj).bottom.get(),
746 |obj, v| props_of::<ServerRectangleClipProps>(obj).bottom.set(v),
747 Some(|obj| ExpressionVariant::create(props_of::<ServerRectangleClipProps>(obj).bottom.get())),
748 Some(|obj, v: ExpressionVariant| props_of::<ServerRectangleClipProps>(obj).bottom.set(v.cast_or_default::<f32>())),
749 )
750 })
751 }
752
753 pub fn bottom(&self) -> f32 {
755 self.bottom.get()
756 }
757
758 pub fn set_bottom(&self, host: &dyn ServerRectangleClipHooks, value: f32) {
759 self.bottom.set(value);
760 host.remove_animation_for_property(Self::id_of_bottom_property().base());
761 }
762
763 pub fn id_of_top_left_radius_property() -> &'static CompositionPropertyOf<Vector> {
765 static PROPERTY: OnceLock<CompositionPropertyOf<Vector>> = OnceLock::new();
766 PROPERTY.get_or_init(|| {
767 CompositionProperty::register::<ServerRectangleClipProps, Vector>(
768 "TopLeftRadius",
769 "ServerRectangleClip",
770 |obj| props_of::<ServerRectangleClipProps>(obj).top_left_radius.get(),
771 |obj, v| props_of::<ServerRectangleClipProps>(obj).top_left_radius.set(v),
772 Some(|obj| ExpressionVariant::create(props_of::<ServerRectangleClipProps>(obj).top_left_radius.get())),
773 Some(|obj, v: ExpressionVariant| props_of::<ServerRectangleClipProps>(obj).top_left_radius.set(v.cast_or_default::<Vector>())),
774 )
775 })
776 }
777
778 pub fn top_left_radius(&self) -> Vector {
780 self.top_left_radius.get()
781 }
782
783 pub fn set_top_left_radius(&self, host: &dyn ServerRectangleClipHooks, value: Vector) {
784 self.top_left_radius.set(value);
785 host.remove_animation_for_property(Self::id_of_top_left_radius_property().base());
786 }
787
788 pub fn id_of_top_right_radius_property() -> &'static CompositionPropertyOf<Vector> {
790 static PROPERTY: OnceLock<CompositionPropertyOf<Vector>> = OnceLock::new();
791 PROPERTY.get_or_init(|| {
792 CompositionProperty::register::<ServerRectangleClipProps, Vector>(
793 "TopRightRadius",
794 "ServerRectangleClip",
795 |obj| props_of::<ServerRectangleClipProps>(obj).top_right_radius.get(),
796 |obj, v| props_of::<ServerRectangleClipProps>(obj).top_right_radius.set(v),
797 Some(|obj| ExpressionVariant::create(props_of::<ServerRectangleClipProps>(obj).top_right_radius.get())),
798 Some(|obj, v: ExpressionVariant| props_of::<ServerRectangleClipProps>(obj).top_right_radius.set(v.cast_or_default::<Vector>())),
799 )
800 })
801 }
802
803 pub fn top_right_radius(&self) -> Vector {
805 self.top_right_radius.get()
806 }
807
808 pub fn set_top_right_radius(&self, host: &dyn ServerRectangleClipHooks, value: Vector) {
809 self.top_right_radius.set(value);
810 host.remove_animation_for_property(Self::id_of_top_right_radius_property().base());
811 }
812
813 pub fn id_of_bottom_left_radius_property() -> &'static CompositionPropertyOf<Vector> {
815 static PROPERTY: OnceLock<CompositionPropertyOf<Vector>> = OnceLock::new();
816 PROPERTY.get_or_init(|| {
817 CompositionProperty::register::<ServerRectangleClipProps, Vector>(
818 "BottomLeftRadius",
819 "ServerRectangleClip",
820 |obj| props_of::<ServerRectangleClipProps>(obj).bottom_left_radius.get(),
821 |obj, v| props_of::<ServerRectangleClipProps>(obj).bottom_left_radius.set(v),
822 Some(|obj| ExpressionVariant::create(props_of::<ServerRectangleClipProps>(obj).bottom_left_radius.get())),
823 Some(|obj, v: ExpressionVariant| props_of::<ServerRectangleClipProps>(obj).bottom_left_radius.set(v.cast_or_default::<Vector>())),
824 )
825 })
826 }
827
828 pub fn bottom_left_radius(&self) -> Vector {
830 self.bottom_left_radius.get()
831 }
832
833 pub fn set_bottom_left_radius(&self, host: &dyn ServerRectangleClipHooks, value: Vector) {
834 self.bottom_left_radius.set(value);
835 host.remove_animation_for_property(Self::id_of_bottom_left_radius_property().base());
836 }
837
838 pub fn id_of_bottom_right_radius_property() -> &'static CompositionPropertyOf<Vector> {
840 static PROPERTY: OnceLock<CompositionPropertyOf<Vector>> = OnceLock::new();
841 PROPERTY.get_or_init(|| {
842 CompositionProperty::register::<ServerRectangleClipProps, Vector>(
843 "BottomRightRadius",
844 "ServerRectangleClip",
845 |obj| props_of::<ServerRectangleClipProps>(obj).bottom_right_radius.get(),
846 |obj, v| props_of::<ServerRectangleClipProps>(obj).bottom_right_radius.set(v),
847 Some(|obj| ExpressionVariant::create(props_of::<ServerRectangleClipProps>(obj).bottom_right_radius.get())),
848 Some(|obj, v: ExpressionVariant| props_of::<ServerRectangleClipProps>(obj).bottom_right_radius.set(v.cast_or_default::<Vector>())),
849 )
850 })
851 }
852
853 pub fn bottom_right_radius(&self) -> Vector {
855 self.bottom_right_radius.get()
856 }
857
858 pub fn set_bottom_right_radius(&self, host: &dyn ServerRectangleClipHooks, value: Vector) {
859 self.bottom_right_radius.set(value);
860 host.remove_animation_for_property(Self::id_of_bottom_right_radius_property().base());
861 }
862
863 pub fn deserialize_changes_core(
866 &self,
867 host: &dyn ServerRectangleClipHooks,
868 reader: &mut BatchStreamReader<'_>,
869 committed_at: Duration,
870 ) {
871 self.base.deserialize_changes_core(host, reader, committed_at);
872 ServerRectangleClipHooks::deserialize_changes_extra(host, reader);
873 let changed = reader.read::<RectangleClipChangedFields>();
874 if changed.contains(RectangleClipChangedFields::LEFT_ANIMATED) {
875 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
876 panic!("a batch starts an animation of `Left` without an animation instance");
877 };
878 host.set_animated_value(
879 Self::id_of_left_property().base(),
880 ExpressionVariant::create(self.left.get()),
881 committed_at,
882 animation,
883 );
884 } else if changed.contains(RectangleClipChangedFields::LEFT) {
885 let value = reader.read::<f32>();
886 self.set_left(host, value);
887 }
888 if changed.contains(RectangleClipChangedFields::TOP_ANIMATED) {
889 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
890 panic!("a batch starts an animation of `Top` without an animation instance");
891 };
892 host.set_animated_value(
893 Self::id_of_top_property().base(),
894 ExpressionVariant::create(self.top.get()),
895 committed_at,
896 animation,
897 );
898 } else if changed.contains(RectangleClipChangedFields::TOP) {
899 let value = reader.read::<f32>();
900 self.set_top(host, value);
901 }
902 if changed.contains(RectangleClipChangedFields::RIGHT_ANIMATED) {
903 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
904 panic!("a batch starts an animation of `Right` without an animation instance");
905 };
906 host.set_animated_value(
907 Self::id_of_right_property().base(),
908 ExpressionVariant::create(self.right.get()),
909 committed_at,
910 animation,
911 );
912 } else if changed.contains(RectangleClipChangedFields::RIGHT) {
913 let value = reader.read::<f32>();
914 self.set_right(host, value);
915 }
916 if changed.contains(RectangleClipChangedFields::BOTTOM_ANIMATED) {
917 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
918 panic!("a batch starts an animation of `Bottom` without an animation instance");
919 };
920 host.set_animated_value(
921 Self::id_of_bottom_property().base(),
922 ExpressionVariant::create(self.bottom.get()),
923 committed_at,
924 animation,
925 );
926 } else if changed.contains(RectangleClipChangedFields::BOTTOM) {
927 let value = reader.read::<f32>();
928 self.set_bottom(host, value);
929 }
930 if changed.contains(RectangleClipChangedFields::TOP_LEFT_RADIUS_ANIMATED) {
931 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
932 panic!("a batch starts an animation of `TopLeftRadius` without an animation instance");
933 };
934 host.set_animated_value(
935 Self::id_of_top_left_radius_property().base(),
936 ExpressionVariant::create(self.top_left_radius.get()),
937 committed_at,
938 animation,
939 );
940 } else if changed.contains(RectangleClipChangedFields::TOP_LEFT_RADIUS) {
941 let value = reader.read::<Vector>();
942 self.set_top_left_radius(host, value);
943 }
944 if changed.contains(RectangleClipChangedFields::TOP_RIGHT_RADIUS_ANIMATED) {
945 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
946 panic!("a batch starts an animation of `TopRightRadius` without an animation instance");
947 };
948 host.set_animated_value(
949 Self::id_of_top_right_radius_property().base(),
950 ExpressionVariant::create(self.top_right_radius.get()),
951 committed_at,
952 animation,
953 );
954 } else if changed.contains(RectangleClipChangedFields::TOP_RIGHT_RADIUS) {
955 let value = reader.read::<Vector>();
956 self.set_top_right_radius(host, value);
957 }
958 if changed.contains(RectangleClipChangedFields::BOTTOM_LEFT_RADIUS_ANIMATED) {
959 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
960 panic!("a batch starts an animation of `BottomLeftRadius` without an animation instance");
961 };
962 host.set_animated_value(
963 Self::id_of_bottom_left_radius_property().base(),
964 ExpressionVariant::create(self.bottom_left_radius.get()),
965 committed_at,
966 animation,
967 );
968 } else if changed.contains(RectangleClipChangedFields::BOTTOM_LEFT_RADIUS) {
969 let value = reader.read::<Vector>();
970 self.set_bottom_left_radius(host, value);
971 }
972 if changed.contains(RectangleClipChangedFields::BOTTOM_RIGHT_RADIUS_ANIMATED) {
973 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
974 panic!("a batch starts an animation of `BottomRightRadius` without an animation instance");
975 };
976 host.set_animated_value(
977 Self::id_of_bottom_right_radius_property().base(),
978 ExpressionVariant::create(self.bottom_right_radius.get()),
979 committed_at,
980 animation,
981 );
982 } else if changed.contains(RectangleClipChangedFields::BOTTOM_RIGHT_RADIUS) {
983 let value = reader.read::<Vector>();
984 self.set_bottom_right_radius(host, value);
985 }
986 ServerRectangleClipHooks::on_fields_deserialized(host, changed);
987 }
988
989 pub fn get_composition_property(name: &str) -> Option<&'static CompositionProperty> {
992 if name == "Left" {
993 return Some(Self::id_of_left_property().base());
994 }
995 if name == "Top" {
996 return Some(Self::id_of_top_property().base());
997 }
998 if name == "Right" {
999 return Some(Self::id_of_right_property().base());
1000 }
1001 if name == "Bottom" {
1002 return Some(Self::id_of_bottom_property().base());
1003 }
1004 if name == "TopLeftRadius" {
1005 return Some(Self::id_of_top_left_radius_property().base());
1006 }
1007 if name == "TopRightRadius" {
1008 return Some(Self::id_of_top_right_radius_property().base());
1009 }
1010 if name == "BottomLeftRadius" {
1011 return Some(Self::id_of_bottom_left_radius_property().base());
1012 }
1013 if name == "BottomRightRadius" {
1014 return Some(Self::id_of_bottom_right_radius_property().base());
1015 }
1016 ServerCompositionClipProps::get_composition_property(name)
1017 }
1018}