use super::animations::{PropertySetSnapshot, PropertySetSnapshotSource, PropertySetSnapshotSourceValue};
use super::expressions::{ExpressionVariant, ExpressionVariantValue};
use super::{AsCompositionObject, CompositionObject, Compositor};
use crate::media::Color;
use crate::numerics::{Matrix3x2, Matrix4x4, Quaternion, Vector2, Vector3, Vector4};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
pub struct CompositionPropertySet {
object: CompositionObject,
variants: RefCell<HashMap<String, ExpressionVariant>>,
objects: RefCell<HashMap<String, Rc<dyn AsCompositionObject>>>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum CompositionGetValueStatus {
Succeeded,
TypeMismatch,
NotFound,
}
impl CompositionPropertySet {
pub(crate) fn new(compositor: &Rc<Compositor>) -> Rc<CompositionPropertySet> {
Rc::new(CompositionPropertySet {
object: CompositionObject::new(compositor, None),
variants: RefCell::new(HashMap::new()),
objects: RefCell::new(HashMap::new()),
})
}
pub fn compositor(&self) -> &Rc<Compositor> {
self.object.compositor()
}
pub(crate) fn set(&self, key: &str, value: ExpressionVariant) {
self.objects.borrow_mut().remove(key);
self.variants.borrow_mut().insert(key.to_owned(), value);
}
pub(crate) fn set_object(&self, key: &str, obj: Rc<dyn AsCompositionObject>) {
self.objects.borrow_mut().insert(key.to_owned(), obj);
self.variants.borrow_mut().remove(key);
}
pub fn insert_color(&self, property_name: &str, value: Color) {
self.set(property_name, value.into())
}
pub fn insert_matrix3x2(&self, property_name: &str, value: Matrix3x2) {
self.set(property_name, value.into())
}
pub fn insert_matrix4x4(&self, property_name: &str, value: Matrix4x4) {
self.set(property_name, value.into())
}
pub fn insert_quaternion(&self, property_name: &str, value: Quaternion) {
self.set(property_name, value.into())
}
pub fn insert_scalar(&self, property_name: &str, value: f32) {
self.set(property_name, value.into())
}
pub fn insert_vector2(&self, property_name: &str, value: Vector2) {
self.set(property_name, value.into())
}
pub fn insert_vector3(&self, property_name: &str, value: Vector3) {
self.set(property_name, value.into())
}
pub fn insert_vector4(&self, property_name: &str, value: Vector4) {
self.set(property_name, value.into())
}
fn try_get_variant<T: ExpressionVariantValue>(&self, key: &str) -> (CompositionGetValueStatus, T) {
let Some(v) = self.variants.borrow().get(key).copied() else {
let status = if self.objects.borrow().contains_key(key) {
CompositionGetValueStatus::TypeMismatch
} else {
CompositionGetValueStatus::NotFound
};
return (status, T::default());
};
match v.try_cast::<T>() {
Some(value) => (CompositionGetValueStatus::Succeeded, value),
None => (CompositionGetValueStatus::TypeMismatch, T::default()),
}
}
pub fn try_get_color(&self, property_name: &str) -> (CompositionGetValueStatus, Color) {
self.try_get_variant(property_name)
}
pub fn try_get_matrix3x2(&self, property_name: &str) -> (CompositionGetValueStatus, Matrix3x2) {
self.try_get_variant(property_name)
}
pub fn try_get_matrix4x4(&self, property_name: &str) -> (CompositionGetValueStatus, Matrix4x4) {
self.try_get_variant(property_name)
}
pub fn try_get_quaternion(&self, property_name: &str) -> (CompositionGetValueStatus, Quaternion) {
self.try_get_variant(property_name)
}
pub fn try_get_scalar(&self, property_name: &str) -> (CompositionGetValueStatus, f32) {
self.try_get_variant(property_name)
}
pub fn try_get_vector2(&self, property_name: &str) -> (CompositionGetValueStatus, Vector2) {
self.try_get_variant(property_name)
}
pub fn try_get_vector3(&self, property_name: &str) -> (CompositionGetValueStatus, Vector3) {
self.try_get_variant(property_name)
}
pub fn try_get_vector4(&self, property_name: &str) -> (CompositionGetValueStatus, Vector4) {
self.try_get_variant(property_name)
}
pub fn insert_boolean(&self, property_name: &str, value: bool) {
self.set(property_name, value.into())
}
pub fn try_get_boolean(&self, property_name: &str) -> (CompositionGetValueStatus, bool) {
self.try_get_variant(property_name)
}
pub(crate) fn clear_all(&self) {
self.objects.borrow_mut().clear();
self.variants.borrow_mut().clear();
}
pub(crate) fn clear(&self, key: &str) {
self.objects.borrow_mut().remove(key);
self.variants.borrow_mut().remove(key);
}
pub(crate) fn snapshot(&self) -> PropertySetSnapshot {
self.snapshot_source().build()
}
pub(crate) fn snapshot_source(&self) -> PropertySetSnapshotSource {
self.snapshot_core(1)
}
fn snapshot_core(&self, allowed_nesting_level: i32) -> PropertySetSnapshotSource {
let objects: Vec<(String, Rc<dyn AsCompositionObject>)> =
self.objects.borrow().iter().map(|(k, v)| (k.clone(), v.clone())).collect();
let variants = self.variants.borrow();
let mut dic = HashMap::with_capacity(objects.len() + variants.len());
for (key, value) in objects {
let type_name = value.composition_type_name();
let server = value.as_composition_object().server();
if let Some(ps) = value.as_property_set() {
if allowed_nesting_level <= 0 {
panic!("PropertySet depth limit reached");
}
dic.insert(
key,
PropertySetSnapshotSourceValue::PropertySet(ps.snapshot_core(allowed_nesting_level - 1)),
);
} else if let Some(server) = server {
dic.insert(key, PropertySetSnapshotSourceValue::Server(server));
} else {
panic!("Object of type {type_name} is not allowed");
}
}
for (key, value) in variants.iter() {
dic.insert(key.clone(), PropertySetSnapshotSourceValue::Variant(*value));
}
PropertySetSnapshotSource::new(dic)
}
}
impl AsCompositionObject for CompositionPropertySet {
fn as_composition_object(&self) -> &CompositionObject {
&self.object
}
fn composition_type_name(&self) -> &'static str {
"CompositionPropertySet"
}
fn as_property_set(self: Rc<Self>) -> Option<Rc<CompositionPropertySet>> {
Some(self)
}
}