use super::composition_object_impls::composition_object_impls;
use super::generated::{
CompositionContainerShapeHooks, CompositionContainerShapeProps, CompositionShapeCollectionHooks,
CompositionShapeCollectionProps, CompositionShapeHooks, CompositionShapeProps, CompositionSpriteShapeHooks,
CompositionSpriteShapeProps, ServerCompositionContainerShapeProps, ServerCompositionSpriteShapeProps,
};
use super::server::{
IServerObject, ServerCompositionContainerShape, ServerCompositionShapeCollection, ServerCompositionSpriteShape,
ServerCompositor, ServerObjectId, ServerPropertyValue,
};
use super::transport::{BatchValue, BatchValueReader};
use super::{CompositionBrush, CompositionGeometry, CompositionObject, Compositor, ICompositionObject};
use crate::media::{PenLineCap, PenLineJoin};
use crate::{Matrix, Vector};
use std::ops::Deref;
use std::rc::{Rc, Weak};
use std::sync::Arc;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum CompositionStrokeCap {
#[default]
Flat = 0,
Square = 1,
Round = 2,
Triangle = 3,
}
impl CompositionStrokeCap {
pub fn to_pen_line_cap(self) -> PenLineCap {
match self {
CompositionStrokeCap::Flat => PenLineCap::Flat,
CompositionStrokeCap::Square => PenLineCap::Square,
CompositionStrokeCap::Round | CompositionStrokeCap::Triangle => PenLineCap::Round,
}
}
}
impl BatchValue for CompositionStrokeCap {
fn write_to(&self, out: &mut Vec<u8>) {
(*self as i32).write_to(out);
}
fn read_from(input: &mut BatchValueReader<'_>) -> Self {
match i32::read_from(input) {
0 => Self::Flat,
1 => Self::Square,
2 => Self::Round,
3 => Self::Triangle,
value => panic!("the batch value stream holds {value}, which is not a CompositionStrokeCap"),
}
}
}
impl ServerPropertyValue for CompositionStrokeCap {
fn differs(&self, other: &Self) -> bool {
self != other
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum CompositionStrokeLineJoin {
#[default]
Miter = 0,
Bevel = 1,
Round = 2,
MiterOrBevel = 3,
}
impl CompositionStrokeLineJoin {
pub fn to_pen_line_join(self) -> PenLineJoin {
match self {
CompositionStrokeLineJoin::Miter | CompositionStrokeLineJoin::MiterOrBevel => PenLineJoin::Miter,
CompositionStrokeLineJoin::Bevel => PenLineJoin::Bevel,
CompositionStrokeLineJoin::Round => PenLineJoin::Round,
}
}
}
impl BatchValue for CompositionStrokeLineJoin {
fn write_to(&self, out: &mut Vec<u8>) {
(*self as i32).write_to(out);
}
fn read_from(input: &mut BatchValueReader<'_>) -> Self {
match i32::read_from(input) {
0 => Self::Miter,
1 => Self::Bevel,
2 => Self::Round,
3 => Self::MiterOrBevel,
value => panic!("the batch value stream holds {value}, which is not a CompositionStrokeLineJoin"),
}
}
}
impl ServerPropertyValue for CompositionStrokeLineJoin {
fn differs(&self, other: &Self) -> bool {
self != other
}
}
pub struct CompositionShapeCollection {
this: Weak<CompositionShapeCollection>,
object: CompositionObject,
props: CompositionShapeCollectionProps<CompositionShape>,
}
impl CompositionShapeCollection {
pub(crate) fn new(compositor: &Rc<Compositor>) -> Rc<CompositionShapeCollection> {
let server = compositor.create_server_object(|compositor, _| ServerCompositionShapeCollection::new(compositor));
let collection = Rc::new_cyclic(|this: &Weak<CompositionShapeCollection>| CompositionShapeCollection {
this: this.clone(),
object: CompositionObject::new(compositor, Some(server)),
props: CompositionShapeCollectionProps::new(),
});
collection.props.initialize_defaults(&*collection);
collection
}
pub fn server(&self) -> ServerObjectId {
self.object.required_server()
}
pub fn items(&self) -> Vec<Rc<CompositionShape>> {
self.props.items()
}
pub fn append(&self, item: Rc<CompositionShape>) {
self.add(item);
}
pub fn add(&self, item: Rc<CompositionShape>) {
self.props.add(self, item);
}
pub fn clear(&self) {
self.props.clear(self);
}
pub fn contains(&self, item: &Rc<CompositionShape>) -> bool {
self.props.contains(item)
}
pub fn remove(&self, item: &Rc<CompositionShape>) -> bool {
self.props.remove(self, item)
}
pub fn count(&self) -> usize {
self.props.count()
}
pub fn index_of(&self, item: &Rc<CompositionShape>) -> Option<usize> {
self.props.index_of(item)
}
pub fn insert(&self, index: usize, item: Rc<CompositionShape>) {
self.props.insert(self, index, item);
}
pub fn remove_at(&self, index: usize) {
self.props.remove_at(self, index);
}
pub fn get(&self, index: usize) -> Rc<CompositionShape> {
self.props.get(index)
}
pub fn set(&self, index: usize, value: Rc<CompositionShape>) {
self.props.set(self, index, value);
}
}
impl CompositionShapeCollectionHooks<CompositionShape> for CompositionShapeCollection {}
composition_object_impls!(
CompositionShapeCollection, "CompositionShapeCollection",
serialize: |this, writer| this.props.serialize_changes_core(this, writer),
start_animation: |_this, _name, _animation, _final_value| false,
composition_property: |_this, _name| None,
);
pub(crate) enum CompositionShapeKind {
Sprite(CompositionSpriteShapeProps),
Container(CompositionContainerShapeProps),
}
pub struct CompositionShape {
this: Weak<CompositionShape>,
object: CompositionObject,
kind: CompositionShapeKind,
shapes: Option<Rc<CompositionShapeCollection>>,
}
impl CompositionShape {
fn create(
compositor: &Rc<Compositor>,
kind: CompositionShapeKind,
shapes: Option<Rc<CompositionShapeCollection>>,
server: impl FnOnce(&Rc<ServerCompositor>) -> Rc<dyn IServerObject> + Send + 'static,
) -> Rc<CompositionShape> {
let server = compositor.create_server_object(move |compositor, _| server(compositor));
let shape = Rc::new_cyclic(|this: &Weak<CompositionShape>| CompositionShape {
this: this.clone(),
object: CompositionObject::new(compositor, Some(server)),
kind,
shapes,
});
match &shape.kind {
CompositionShapeKind::Sprite(props) => props.initialize_defaults(&*shape),
CompositionShapeKind::Container(props) => {
props.initialize_defaults(&*shape);
let shapes = shape.shapes.clone().map(|shapes| shapes as Rc<dyn ICompositionObject>);
props.set_shapes(&*shape, shapes);
}
}
shape
}
pub fn shape_props(&self) -> &CompositionShapeProps {
match &self.kind {
CompositionShapeKind::Sprite(props) => props.base(),
CompositionShapeKind::Container(props) => props.base(),
}
}
pub fn compositor(&self) -> &Rc<Compositor> {
self.object.compositor()
}
pub fn object(&self) -> &CompositionObject {
&self.object
}
pub fn server(&self) -> ServerObjectId {
self.object.required_server()
}
pub fn is_disposed(&self) -> bool {
self.object.is_disposed()
}
pub fn dispose(&self) {
self.object.dispose();
}
pub fn type_name(&self) -> &'static str {
match &self.kind {
CompositionShapeKind::Sprite(_) => "CompositionSpriteShape",
CompositionShapeKind::Container(_) => "CompositionContainerShape",
}
}
pub fn center_point(&self) -> Vector {
self.shape_props().center_point()
}
pub fn set_center_point(&self, value: Vector) {
self.shape_props().set_center_point(self, value)
}
pub fn offset(&self) -> Vector {
self.shape_props().offset()
}
pub fn set_offset(&self, value: Vector) {
self.shape_props().set_offset(self, value)
}
pub fn rotation_angle(&self) -> f32 {
self.shape_props().rotation_angle()
}
pub fn set_rotation_angle(&self, value: f32) {
self.shape_props().set_rotation_angle(self, value)
}
pub fn rotation_angle_in_degrees(&self) -> f32 {
self.rotation_angle().to_degrees()
}
pub fn set_rotation_angle_in_degrees(&self, value: f32) {
self.set_rotation_angle(value.to_radians())
}
pub fn scale(&self) -> Vector {
self.shape_props().scale()
}
pub fn set_scale(&self, value: Vector) {
self.shape_props().set_scale(self, value)
}
pub fn transform_matrix(&self) -> Matrix {
self.shape_props().transform_matrix()
}
pub fn set_transform_matrix(&self, value: Matrix) {
self.shape_props().set_transform_matrix(self, value)
}
}
impl CompositionShapeHooks for CompositionShape {}
impl CompositionSpriteShapeHooks for CompositionShape {}
impl CompositionContainerShapeHooks for CompositionShape {}
composition_object_impls!(
CompositionShape, "CompositionShape",
serialize: |this, writer| match &this.kind {
CompositionShapeKind::Sprite(props) => props.serialize_changes_core(this, writer),
CompositionShapeKind::Container(props) => props.serialize_changes_core(this, writer),
},
start_animation: |this, name, animation, final_value| match &this.kind {
CompositionShapeKind::Sprite(props) => props.start_animation(this, name, animation, final_value),
CompositionShapeKind::Container(props) => props.start_animation(this, name, animation, final_value),
},
composition_property: |this, name| match &this.kind {
CompositionShapeKind::Sprite(_) => ServerCompositionSpriteShapeProps::get_composition_property(name),
CompositionShapeKind::Container(_) => ServerCompositionContainerShapeProps::get_composition_property(name),
},
);
#[derive(Clone)]
pub struct CompositionSpriteShape(Rc<CompositionShape>);
impl Deref for CompositionSpriteShape {
type Target = Rc<CompositionShape>;
fn deref(&self) -> &Rc<CompositionShape> {
&self.0
}
}
impl CompositionSpriteShape {
pub(crate) fn new(compositor: &Rc<Compositor>) -> CompositionSpriteShape {
CompositionSpriteShape(CompositionShape::create(
compositor,
CompositionShapeKind::Sprite(CompositionSpriteShapeProps::new()),
None,
|c| ServerCompositionSpriteShape::new(c),
))
}
pub(crate) fn with_geometry(
compositor: &Rc<Compositor>,
geometry: Option<Rc<CompositionGeometry>>,
) -> CompositionSpriteShape {
let shape = Self::new(compositor);
shape.set_geometry(geometry);
shape
}
pub fn from_shape(shape: &Rc<CompositionShape>) -> Option<CompositionSpriteShape> {
matches!(shape.kind, CompositionShapeKind::Sprite(_)).then(|| CompositionSpriteShape(shape.clone()))
}
pub fn shape(&self) -> &Rc<CompositionShape> {
&self.0
}
fn props(&self) -> &CompositionSpriteShapeProps {
match &self.0.kind {
CompositionShapeKind::Sprite(props) => props,
_ => unreachable!("a sprite shape handle wraps a sprite shape"),
}
}
pub fn fill_brush(&self) -> Option<Rc<CompositionBrush>> {
self.props().fill_brush().and_then(|brush| brush.into_any_rc().downcast::<CompositionBrush>().ok())
}
pub fn set_fill_brush(&self, value: Option<Rc<CompositionBrush>>) {
self.props().set_fill_brush(&*self.0, value.map(|brush| brush as Rc<dyn ICompositionObject>))
}
pub fn geometry(&self) -> Option<Rc<CompositionGeometry>> {
self.props().geometry().and_then(|geometry| geometry.into_any_rc().downcast::<CompositionGeometry>().ok())
}
pub fn set_geometry(&self, value: Option<Rc<CompositionGeometry>>) {
self.props().set_geometry(&*self.0, value.map(|geometry| geometry as Rc<dyn ICompositionObject>))
}
pub fn is_stroke_non_scaling(&self) -> bool {
self.props().is_stroke_non_scaling()
}
pub fn set_is_stroke_non_scaling(&self, value: bool) {
self.props().set_is_stroke_non_scaling(&*self.0, value)
}
pub fn stroke_brush(&self) -> Option<Rc<CompositionBrush>> {
self.props().stroke_brush().and_then(|brush| brush.into_any_rc().downcast::<CompositionBrush>().ok())
}
pub fn set_stroke_brush(&self, value: Option<Rc<CompositionBrush>>) {
self.props().set_stroke_brush(&*self.0, value.map(|brush| brush as Rc<dyn ICompositionObject>))
}
pub fn stroke_dash_array(&self) -> Vec<f32> {
self.props().stroke_dash_array().map(|dashes| (*dashes).clone()).unwrap_or_default()
}
pub fn set_stroke_dash_array(&self, value: Vec<f32>) {
let value = if value.is_empty() { None } else { Some(Arc::new(value)) };
self.props().set_stroke_dash_array(&*self.0, value)
}
pub fn stroke_dash_cap(&self) -> CompositionStrokeCap {
self.props().stroke_dash_cap()
}
pub fn set_stroke_dash_cap(&self, value: CompositionStrokeCap) {
self.props().set_stroke_dash_cap(&*self.0, value)
}
pub fn stroke_dash_offset(&self) -> f32 {
self.props().stroke_dash_offset()
}
pub fn set_stroke_dash_offset(&self, value: f32) {
self.props().set_stroke_dash_offset(&*self.0, value)
}
pub fn stroke_end_cap(&self) -> CompositionStrokeCap {
self.props().stroke_end_cap()
}
pub fn set_stroke_end_cap(&self, value: CompositionStrokeCap) {
self.props().set_stroke_end_cap(&*self.0, value)
}
pub fn stroke_line_join(&self) -> CompositionStrokeLineJoin {
self.props().stroke_line_join()
}
pub fn set_stroke_line_join(&self, value: CompositionStrokeLineJoin) {
self.props().set_stroke_line_join(&*self.0, value)
}
pub fn stroke_miter_limit(&self) -> f32 {
self.props().stroke_miter_limit()
}
pub fn set_stroke_miter_limit(&self, value: f32) {
self.props().set_stroke_miter_limit(&*self.0, value)
}
pub fn stroke_start_cap(&self) -> CompositionStrokeCap {
self.props().stroke_start_cap()
}
pub fn set_stroke_start_cap(&self, value: CompositionStrokeCap) {
self.props().set_stroke_start_cap(&*self.0, value)
}
pub fn stroke_thickness(&self) -> f32 {
self.props().stroke_thickness()
}
pub fn set_stroke_thickness(&self, value: f32) {
self.props().set_stroke_thickness(&*self.0, value)
}
}
#[derive(Clone)]
pub struct CompositionContainerShape(Rc<CompositionShape>);
impl Deref for CompositionContainerShape {
type Target = Rc<CompositionShape>;
fn deref(&self) -> &Rc<CompositionShape> {
&self.0
}
}
impl CompositionContainerShape {
pub(crate) fn new(compositor: &Rc<Compositor>) -> CompositionContainerShape {
let shapes = CompositionShapeCollection::new(compositor);
CompositionContainerShape(CompositionShape::create(
compositor,
CompositionShapeKind::Container(CompositionContainerShapeProps::new()),
Some(shapes),
|c| ServerCompositionContainerShape::new(c),
))
}
pub fn from_shape(shape: &Rc<CompositionShape>) -> Option<CompositionContainerShape> {
matches!(shape.kind, CompositionShapeKind::Container(_)).then(|| CompositionContainerShape(shape.clone()))
}
pub fn shape(&self) -> &Rc<CompositionShape> {
&self.0
}
pub fn shapes(&self) -> &Rc<CompositionShapeCollection> {
self.0.shapes.as_ref().expect("a container shape has a shape collection")
}
}