1use super::composition_object_impls::composition_object_impls;
12use super::generated::{
13 CompositionContainerShapeHooks, CompositionContainerShapeProps, CompositionShapeCollectionHooks,
14 CompositionShapeCollectionProps, CompositionShapeHooks, CompositionShapeProps, CompositionSpriteShapeHooks,
15 CompositionSpriteShapeProps, ServerCompositionContainerShapeProps, ServerCompositionSpriteShapeProps,
16};
17use super::server::{
18 IServerObject, ServerCompositionContainerShape, ServerCompositionShapeCollection, ServerCompositionSpriteShape,
19 ServerCompositor, ServerObjectId, ServerPropertyValue,
20};
21use super::transport::{BatchValue, BatchValueReader};
22use super::{CompositionBrush, CompositionGeometry, CompositionObject, Compositor, ICompositionObject};
23use crate::media::{PenLineCap, PenLineJoin};
24use crate::{Matrix, Vector};
25use std::ops::Deref;
26use std::rc::{Rc, Weak};
27use std::sync::Arc;
28
29#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
34#[repr(i32)]
35pub enum CompositionStrokeCap {
36 #[default]
38 Flat = 0,
39 Square = 1,
41 Round = 2,
43 Triangle = 3,
45}
46
47impl CompositionStrokeCap {
48 pub fn to_pen_line_cap(self) -> PenLineCap {
54 match self {
55 CompositionStrokeCap::Flat => PenLineCap::Flat,
56 CompositionStrokeCap::Square => PenLineCap::Square,
57 CompositionStrokeCap::Round | CompositionStrokeCap::Triangle => PenLineCap::Round,
58 }
59 }
60}
61
62impl BatchValue for CompositionStrokeCap {
63 fn write_to(&self, out: &mut Vec<u8>) {
64 (*self as i32).write_to(out);
65 }
66
67 fn read_from(input: &mut BatchValueReader<'_>) -> Self {
68 match i32::read_from(input) {
69 0 => Self::Flat,
70 1 => Self::Square,
71 2 => Self::Round,
72 3 => Self::Triangle,
73 value => panic!("the batch value stream holds {value}, which is not a CompositionStrokeCap"),
74 }
75 }
76}
77
78impl ServerPropertyValue for CompositionStrokeCap {
79 fn differs(&self, other: &Self) -> bool {
80 self != other
81 }
82}
83
84#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
87#[repr(i32)]
88pub enum CompositionStrokeLineJoin {
89 #[default]
91 Miter = 0,
92 Bevel = 1,
94 Round = 2,
96 MiterOrBevel = 3,
98}
99
100impl CompositionStrokeLineJoin {
101 pub fn to_pen_line_join(self) -> PenLineJoin {
107 match self {
108 CompositionStrokeLineJoin::Miter | CompositionStrokeLineJoin::MiterOrBevel => PenLineJoin::Miter,
109 CompositionStrokeLineJoin::Bevel => PenLineJoin::Bevel,
110 CompositionStrokeLineJoin::Round => PenLineJoin::Round,
111 }
112 }
113}
114
115impl BatchValue for CompositionStrokeLineJoin {
116 fn write_to(&self, out: &mut Vec<u8>) {
117 (*self as i32).write_to(out);
118 }
119
120 fn read_from(input: &mut BatchValueReader<'_>) -> Self {
121 match i32::read_from(input) {
122 0 => Self::Miter,
123 1 => Self::Bevel,
124 2 => Self::Round,
125 3 => Self::MiterOrBevel,
126 value => panic!("the batch value stream holds {value}, which is not a CompositionStrokeLineJoin"),
127 }
128 }
129}
130
131impl ServerPropertyValue for CompositionStrokeLineJoin {
132 fn differs(&self, other: &Self) -> bool {
133 self != other
134 }
135}
136
137pub struct CompositionShapeCollection {
142 this: Weak<CompositionShapeCollection>,
143 object: CompositionObject,
144 props: CompositionShapeCollectionProps<CompositionShape>,
145}
146
147impl CompositionShapeCollection {
148 pub(crate) fn new(compositor: &Rc<Compositor>) -> Rc<CompositionShapeCollection> {
149 let server = compositor.create_server_object(|compositor, _| ServerCompositionShapeCollection::new(compositor));
150 let collection = Rc::new_cyclic(|this: &Weak<CompositionShapeCollection>| CompositionShapeCollection {
151 this: this.clone(),
152 object: CompositionObject::new(compositor, Some(server)),
153 props: CompositionShapeCollectionProps::new(),
154 });
155 collection.props.initialize_defaults(&*collection);
156 collection
157 }
158
159 pub fn server(&self) -> ServerObjectId {
161 self.object.required_server()
162 }
163
164 pub fn items(&self) -> Vec<Rc<CompositionShape>> {
166 self.props.items()
167 }
168
169 pub fn append(&self, item: Rc<CompositionShape>) {
171 self.add(item);
172 }
173
174 pub fn add(&self, item: Rc<CompositionShape>) {
175 self.props.add(self, item);
176 }
177
178 pub fn clear(&self) {
179 self.props.clear(self);
180 }
181
182 pub fn contains(&self, item: &Rc<CompositionShape>) -> bool {
183 self.props.contains(item)
184 }
185
186 pub fn remove(&self, item: &Rc<CompositionShape>) -> bool {
187 self.props.remove(self, item)
188 }
189
190 pub fn count(&self) -> usize {
192 self.props.count()
193 }
194
195 pub fn index_of(&self, item: &Rc<CompositionShape>) -> Option<usize> {
196 self.props.index_of(item)
197 }
198
199 pub fn insert(&self, index: usize, item: Rc<CompositionShape>) {
200 self.props.insert(self, index, item);
201 }
202
203 pub fn remove_at(&self, index: usize) {
204 self.props.remove_at(self, index);
205 }
206
207 pub fn get(&self, index: usize) -> Rc<CompositionShape> {
208 self.props.get(index)
209 }
210
211 pub fn set(&self, index: usize, value: Rc<CompositionShape>) {
212 self.props.set(self, index, value);
213 }
214}
215
216impl CompositionShapeCollectionHooks<CompositionShape> for CompositionShapeCollection {}
217
218composition_object_impls!(
219 CompositionShapeCollection, "CompositionShapeCollection",
220 serialize: |this, writer| this.props.serialize_changes_core(this, writer),
221 start_animation: |_this, _name, _animation, _final_value| false,
222 composition_property: |_this, _name| None,
223);
224
225pub(crate) enum CompositionShapeKind {
229 Sprite(CompositionSpriteShapeProps),
230 Container(CompositionContainerShapeProps),
231}
232
233pub struct CompositionShape {
240 this: Weak<CompositionShape>,
241 object: CompositionObject,
242 kind: CompositionShapeKind,
243 shapes: Option<Rc<CompositionShapeCollection>>,
245}
246
247impl CompositionShape {
248 fn create(
249 compositor: &Rc<Compositor>,
250 kind: CompositionShapeKind,
251 shapes: Option<Rc<CompositionShapeCollection>>,
252 server: impl FnOnce(&Rc<ServerCompositor>) -> Rc<dyn IServerObject> + Send + 'static,
253 ) -> Rc<CompositionShape> {
254 let server = compositor.create_server_object(move |compositor, _| server(compositor));
255 let shape = Rc::new_cyclic(|this: &Weak<CompositionShape>| CompositionShape {
256 this: this.clone(),
257 object: CompositionObject::new(compositor, Some(server)),
258 kind,
259 shapes,
260 });
261 match &shape.kind {
262 CompositionShapeKind::Sprite(props) => props.initialize_defaults(&*shape),
263 CompositionShapeKind::Container(props) => {
264 props.initialize_defaults(&*shape);
265 let shapes = shape.shapes.clone().map(|shapes| shapes as Rc<dyn ICompositionObject>);
266 props.set_shapes(&*shape, shapes);
267 }
268 }
269 shape
270 }
271
272 pub fn shape_props(&self) -> &CompositionShapeProps {
274 match &self.kind {
275 CompositionShapeKind::Sprite(props) => props.base(),
276 CompositionShapeKind::Container(props) => props.base(),
277 }
278 }
279
280 pub fn compositor(&self) -> &Rc<Compositor> {
281 self.object.compositor()
282 }
283
284 pub fn object(&self) -> &CompositionObject {
286 &self.object
287 }
288
289 pub fn server(&self) -> ServerObjectId {
291 self.object.required_server()
292 }
293
294 pub fn is_disposed(&self) -> bool {
295 self.object.is_disposed()
296 }
297
298 pub fn dispose(&self) {
299 self.object.dispose();
300 }
301
302 pub fn type_name(&self) -> &'static str {
304 match &self.kind {
305 CompositionShapeKind::Sprite(_) => "CompositionSpriteShape",
306 CompositionShapeKind::Container(_) => "CompositionContainerShape",
307 }
308 }
309
310 pub fn center_point(&self) -> Vector {
312 self.shape_props().center_point()
313 }
314
315 pub fn set_center_point(&self, value: Vector) {
316 self.shape_props().set_center_point(self, value)
317 }
318
319 pub fn offset(&self) -> Vector {
321 self.shape_props().offset()
322 }
323
324 pub fn set_offset(&self, value: Vector) {
325 self.shape_props().set_offset(self, value)
326 }
327
328 pub fn rotation_angle(&self) -> f32 {
330 self.shape_props().rotation_angle()
331 }
332
333 pub fn set_rotation_angle(&self, value: f32) {
334 self.shape_props().set_rotation_angle(self, value)
335 }
336
337 pub fn rotation_angle_in_degrees(&self) -> f32 {
343 self.rotation_angle().to_degrees()
344 }
345
346 pub fn set_rotation_angle_in_degrees(&self, value: f32) {
347 self.set_rotation_angle(value.to_radians())
348 }
349
350 pub fn scale(&self) -> Vector {
352 self.shape_props().scale()
353 }
354
355 pub fn set_scale(&self, value: Vector) {
356 self.shape_props().set_scale(self, value)
357 }
358
359 pub fn transform_matrix(&self) -> Matrix {
361 self.shape_props().transform_matrix()
362 }
363
364 pub fn set_transform_matrix(&self, value: Matrix) {
365 self.shape_props().set_transform_matrix(self, value)
366 }
367}
368
369impl CompositionShapeHooks for CompositionShape {}
370
371impl CompositionSpriteShapeHooks for CompositionShape {}
372
373impl CompositionContainerShapeHooks for CompositionShape {}
374
375composition_object_impls!(
376 CompositionShape, "CompositionShape",
377 serialize: |this, writer| match &this.kind {
378 CompositionShapeKind::Sprite(props) => props.serialize_changes_core(this, writer),
379 CompositionShapeKind::Container(props) => props.serialize_changes_core(this, writer),
380 },
381 start_animation: |this, name, animation, final_value| match &this.kind {
382 CompositionShapeKind::Sprite(props) => props.start_animation(this, name, animation, final_value),
383 CompositionShapeKind::Container(props) => props.start_animation(this, name, animation, final_value),
384 },
385 composition_property: |this, name| match &this.kind {
386 CompositionShapeKind::Sprite(_) => ServerCompositionSpriteShapeProps::get_composition_property(name),
387 CompositionShapeKind::Container(_) => ServerCompositionContainerShapeProps::get_composition_property(name),
388 },
389);
390
391#[derive(Clone)]
408pub struct CompositionSpriteShape(Rc<CompositionShape>);
409
410impl Deref for CompositionSpriteShape {
411 type Target = Rc<CompositionShape>;
412
413 fn deref(&self) -> &Rc<CompositionShape> {
414 &self.0
415 }
416}
417
418impl CompositionSpriteShape {
419 pub(crate) fn new(compositor: &Rc<Compositor>) -> CompositionSpriteShape {
420 CompositionSpriteShape(CompositionShape::create(
421 compositor,
422 CompositionShapeKind::Sprite(CompositionSpriteShapeProps::new()),
423 None,
424 |c| ServerCompositionSpriteShape::new(c),
425 ))
426 }
427
428 pub(crate) fn with_geometry(
429 compositor: &Rc<Compositor>,
430 geometry: Option<Rc<CompositionGeometry>>,
431 ) -> CompositionSpriteShape {
432 let shape = Self::new(compositor);
433 shape.set_geometry(geometry);
434 shape
435 }
436
437 pub fn from_shape(shape: &Rc<CompositionShape>) -> Option<CompositionSpriteShape> {
439 matches!(shape.kind, CompositionShapeKind::Sprite(_)).then(|| CompositionSpriteShape(shape.clone()))
440 }
441
442 pub fn shape(&self) -> &Rc<CompositionShape> {
444 &self.0
445 }
446
447 fn props(&self) -> &CompositionSpriteShapeProps {
448 match &self.0.kind {
449 CompositionShapeKind::Sprite(props) => props,
450 _ => unreachable!("a sprite shape handle wraps a sprite shape"),
451 }
452 }
453
454 pub fn fill_brush(&self) -> Option<Rc<CompositionBrush>> {
456 self.props().fill_brush().and_then(|brush| brush.into_any_rc().downcast::<CompositionBrush>().ok())
457 }
458
459 pub fn set_fill_brush(&self, value: Option<Rc<CompositionBrush>>) {
460 self.props().set_fill_brush(&*self.0, value.map(|brush| brush as Rc<dyn ICompositionObject>))
461 }
462
463 pub fn geometry(&self) -> Option<Rc<CompositionGeometry>> {
465 self.props().geometry().and_then(|geometry| geometry.into_any_rc().downcast::<CompositionGeometry>().ok())
466 }
467
468 pub fn set_geometry(&self, value: Option<Rc<CompositionGeometry>>) {
469 self.props().set_geometry(&*self.0, value.map(|geometry| geometry as Rc<dyn ICompositionObject>))
470 }
471
472 pub fn is_stroke_non_scaling(&self) -> bool {
475 self.props().is_stroke_non_scaling()
476 }
477
478 pub fn set_is_stroke_non_scaling(&self, value: bool) {
479 self.props().set_is_stroke_non_scaling(&*self.0, value)
480 }
481
482 pub fn stroke_brush(&self) -> Option<Rc<CompositionBrush>> {
484 self.props().stroke_brush().and_then(|brush| brush.into_any_rc().downcast::<CompositionBrush>().ok())
485 }
486
487 pub fn set_stroke_brush(&self, value: Option<Rc<CompositionBrush>>) {
488 self.props().set_stroke_brush(&*self.0, value.map(|brush| brush as Rc<dyn ICompositionObject>))
489 }
490
491 pub fn stroke_dash_array(&self) -> Vec<f32> {
498 self.props().stroke_dash_array().map(|dashes| (*dashes).clone()).unwrap_or_default()
499 }
500
501 pub fn set_stroke_dash_array(&self, value: Vec<f32>) {
502 let value = if value.is_empty() { None } else { Some(Arc::new(value)) };
503 self.props().set_stroke_dash_array(&*self.0, value)
504 }
505
506 pub fn stroke_dash_cap(&self) -> CompositionStrokeCap {
508 self.props().stroke_dash_cap()
509 }
510
511 pub fn set_stroke_dash_cap(&self, value: CompositionStrokeCap) {
512 self.props().set_stroke_dash_cap(&*self.0, value)
513 }
514
515 pub fn stroke_dash_offset(&self) -> f32 {
518 self.props().stroke_dash_offset()
519 }
520
521 pub fn set_stroke_dash_offset(&self, value: f32) {
522 self.props().set_stroke_dash_offset(&*self.0, value)
523 }
524
525 pub fn stroke_end_cap(&self) -> CompositionStrokeCap {
527 self.props().stroke_end_cap()
528 }
529
530 pub fn set_stroke_end_cap(&self, value: CompositionStrokeCap) {
531 self.props().set_stroke_end_cap(&*self.0, value)
532 }
533
534 pub fn stroke_line_join(&self) -> CompositionStrokeLineJoin {
536 self.props().stroke_line_join()
537 }
538
539 pub fn set_stroke_line_join(&self, value: CompositionStrokeLineJoin) {
540 self.props().set_stroke_line_join(&*self.0, value)
541 }
542
543 pub fn stroke_miter_limit(&self) -> f32 {
546 self.props().stroke_miter_limit()
547 }
548
549 pub fn set_stroke_miter_limit(&self, value: f32) {
550 self.props().set_stroke_miter_limit(&*self.0, value)
551 }
552
553 pub fn stroke_start_cap(&self) -> CompositionStrokeCap {
556 self.props().stroke_start_cap()
557 }
558
559 pub fn set_stroke_start_cap(&self, value: CompositionStrokeCap) {
560 self.props().set_stroke_start_cap(&*self.0, value)
561 }
562
563 pub fn stroke_thickness(&self) -> f32 {
565 self.props().stroke_thickness()
566 }
567
568 pub fn set_stroke_thickness(&self, value: f32) {
569 self.props().set_stroke_thickness(&*self.0, value)
570 }
571}
572
573#[derive(Clone)]
577pub struct CompositionContainerShape(Rc<CompositionShape>);
578
579impl Deref for CompositionContainerShape {
580 type Target = Rc<CompositionShape>;
581
582 fn deref(&self) -> &Rc<CompositionShape> {
583 &self.0
584 }
585}
586
587impl CompositionContainerShape {
588 pub(crate) fn new(compositor: &Rc<Compositor>) -> CompositionContainerShape {
589 let shapes = CompositionShapeCollection::new(compositor);
590 CompositionContainerShape(CompositionShape::create(
591 compositor,
592 CompositionShapeKind::Container(CompositionContainerShapeProps::new()),
593 Some(shapes),
594 |c| ServerCompositionContainerShape::new(c),
595 ))
596 }
597
598 pub fn from_shape(shape: &Rc<CompositionShape>) -> Option<CompositionContainerShape> {
600 matches!(shape.kind, CompositionShapeKind::Container(_)).then(|| CompositionContainerShape(shape.clone()))
601 }
602
603 pub fn shape(&self) -> &Rc<CompositionShape> {
605 &self.0
606 }
607
608 pub fn shapes(&self) -> &Rc<CompositionShapeCollection> {
610 self.0.shapes.as_ref().expect("a container shape has a shape collection")
611 }
612}