ferroui_base/rendering/composition/
composition_property_set.rs1use super::animations::{PropertySetSnapshot, PropertySetSnapshotSource, PropertySetSnapshotSourceValue};
2use super::expressions::{ExpressionVariant, ExpressionVariantValue};
3use super::{AsCompositionObject, CompositionObject, Compositor};
4use crate::media::Color;
5use crate::numerics::{Matrix3x2, Matrix4x4, Quaternion, Vector2, Vector3, Vector4};
6use std::cell::RefCell;
7use std::collections::HashMap;
8use std::rc::Rc;
9
10pub struct CompositionPropertySet {
18 object: CompositionObject,
19 variants: RefCell<HashMap<String, ExpressionVariant>>,
20 objects: RefCell<HashMap<String, Rc<dyn AsCompositionObject>>>,
21}
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
25pub enum CompositionGetValueStatus {
26 Succeeded,
27 TypeMismatch,
28 NotFound,
29}
30
31impl CompositionPropertySet {
32 pub(crate) fn new(compositor: &Rc<Compositor>) -> Rc<CompositionPropertySet> {
33 Rc::new(CompositionPropertySet {
34 object: CompositionObject::new(compositor, None),
35 variants: RefCell::new(HashMap::new()),
36 objects: RefCell::new(HashMap::new()),
37 })
38 }
39
40 pub fn compositor(&self) -> &Rc<Compositor> {
41 self.object.compositor()
42 }
43
44 pub(crate) fn set(&self, key: &str, value: ExpressionVariant) {
45 self.objects.borrow_mut().remove(key);
46 self.variants.borrow_mut().insert(key.to_owned(), value);
47 }
48
49 pub(crate) fn set_object(&self, key: &str, obj: Rc<dyn AsCompositionObject>) {
52 self.objects.borrow_mut().insert(key.to_owned(), obj);
53 self.variants.borrow_mut().remove(key);
54 }
55
56 pub fn insert_color(&self, property_name: &str, value: Color) {
57 self.set(property_name, value.into())
58 }
59
60 pub fn insert_matrix3x2(&self, property_name: &str, value: Matrix3x2) {
61 self.set(property_name, value.into())
62 }
63
64 pub fn insert_matrix4x4(&self, property_name: &str, value: Matrix4x4) {
65 self.set(property_name, value.into())
66 }
67
68 pub fn insert_quaternion(&self, property_name: &str, value: Quaternion) {
69 self.set(property_name, value.into())
70 }
71
72 pub fn insert_scalar(&self, property_name: &str, value: f32) {
73 self.set(property_name, value.into())
74 }
75
76 pub fn insert_vector2(&self, property_name: &str, value: Vector2) {
77 self.set(property_name, value.into())
78 }
79
80 pub fn insert_vector3(&self, property_name: &str, value: Vector3) {
81 self.set(property_name, value.into())
82 }
83
84 pub fn insert_vector4(&self, property_name: &str, value: Vector4) {
85 self.set(property_name, value.into())
86 }
87
88 fn try_get_variant<T: ExpressionVariantValue>(&self, key: &str) -> (CompositionGetValueStatus, T) {
89 let Some(v) = self.variants.borrow().get(key).copied() else {
90 let status = if self.objects.borrow().contains_key(key) {
91 CompositionGetValueStatus::TypeMismatch
92 } else {
93 CompositionGetValueStatus::NotFound
94 };
95 return (status, T::default());
96 };
97
98 match v.try_cast::<T>() {
99 Some(value) => (CompositionGetValueStatus::Succeeded, value),
100 None => (CompositionGetValueStatus::TypeMismatch, T::default()),
101 }
102 }
103
104 pub fn try_get_color(&self, property_name: &str) -> (CompositionGetValueStatus, Color) {
105 self.try_get_variant(property_name)
106 }
107
108 pub fn try_get_matrix3x2(&self, property_name: &str) -> (CompositionGetValueStatus, Matrix3x2) {
109 self.try_get_variant(property_name)
110 }
111
112 pub fn try_get_matrix4x4(&self, property_name: &str) -> (CompositionGetValueStatus, Matrix4x4) {
113 self.try_get_variant(property_name)
114 }
115
116 pub fn try_get_quaternion(&self, property_name: &str) -> (CompositionGetValueStatus, Quaternion) {
117 self.try_get_variant(property_name)
118 }
119
120 pub fn try_get_scalar(&self, property_name: &str) -> (CompositionGetValueStatus, f32) {
121 self.try_get_variant(property_name)
122 }
123
124 pub fn try_get_vector2(&self, property_name: &str) -> (CompositionGetValueStatus, Vector2) {
125 self.try_get_variant(property_name)
126 }
127
128 pub fn try_get_vector3(&self, property_name: &str) -> (CompositionGetValueStatus, Vector3) {
129 self.try_get_variant(property_name)
130 }
131
132 pub fn try_get_vector4(&self, property_name: &str) -> (CompositionGetValueStatus, Vector4) {
133 self.try_get_variant(property_name)
134 }
135
136 pub fn insert_boolean(&self, property_name: &str, value: bool) {
137 self.set(property_name, value.into())
138 }
139
140 pub fn try_get_boolean(&self, property_name: &str) -> (CompositionGetValueStatus, bool) {
141 self.try_get_variant(property_name)
142 }
143
144 pub(crate) fn clear_all(&self) {
145 self.objects.borrow_mut().clear();
146 self.variants.borrow_mut().clear();
147 }
148
149 pub(crate) fn clear(&self, key: &str) {
150 self.objects.borrow_mut().remove(key);
151 self.variants.borrow_mut().remove(key);
152 }
153
154 pub(crate) fn snapshot(&self) -> PropertySetSnapshot {
155 self.snapshot_source().build()
156 }
157
158 pub(crate) fn snapshot_source(&self) -> PropertySetSnapshotSource {
161 self.snapshot_core(1)
162 }
163
164 fn snapshot_core(&self, allowed_nesting_level: i32) -> PropertySetSnapshotSource {
165 let objects: Vec<(String, Rc<dyn AsCompositionObject>)> =
166 self.objects.borrow().iter().map(|(k, v)| (k.clone(), v.clone())).collect();
167 let variants = self.variants.borrow();
168 let mut dic = HashMap::with_capacity(objects.len() + variants.len());
169 for (key, value) in objects {
170 let type_name = value.composition_type_name();
171 let server = value.as_composition_object().server();
172 if let Some(ps) = value.as_property_set() {
173 if allowed_nesting_level <= 0 {
174 panic!("PropertySet depth limit reached");
175 }
176 dic.insert(
177 key,
178 PropertySetSnapshotSourceValue::PropertySet(ps.snapshot_core(allowed_nesting_level - 1)),
179 );
180 } else if let Some(server) = server {
181 dic.insert(key, PropertySetSnapshotSourceValue::Server(server));
182 } else {
183 panic!("Object of type {type_name} is not allowed");
184 }
185 }
186
187 for (key, value) in variants.iter() {
188 dic.insert(key.clone(), PropertySetSnapshotSourceValue::Variant(*value));
189 }
190
191 PropertySetSnapshotSource::new(dic)
192 }
193}
194
195impl AsCompositionObject for CompositionPropertySet {
196 fn as_composition_object(&self) -> &CompositionObject {
197 &self.object
198 }
199
200 fn composition_type_name(&self) -> &'static str {
201 "CompositionPropertySet"
202 }
203
204 fn as_property_set(self: Rc<Self>) -> Option<Rc<CompositionPropertySet>> {
205 Some(self)
206 }
207}