ferroui_base/rendering/composition/server/
server_object.rs1use super::{
2 CompositionProperty, IServerAnimatedPropertyHost, IServerRenderResource, ServerCompositor, ServerObjectAnimations,
3 ServerValueChange,
4};
5use crate::rendering::composition::animations::IAnimationInstance;
6use crate::rendering::composition::expressions::{ExpressionObjectKey, ExpressionVariant, IExpressionObject};
7use crate::media::{IBrush, IGradientStop, IPen, ITransform};
8use crate::rendering::composition::drawing::IRenderDataGeometry;
9use crate::rendering::composition::transport::BatchStreamReader;
10use std::any::{Any, TypeId};
11use std::cell::{Cell, RefCell};
12use std::rc::{Rc, Weak};
13use std::time::Duration;
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
21pub struct ServerObjectId(pub(crate) u32);
22
23impl ServerObjectId {
24 #[inline]
26 pub fn index(self) -> usize {
27 self.0 as usize
28 }
29}
30
31pub trait IServerObject: 'static {
34 fn deserialize_changes_core(&self, _reader: &mut BatchStreamReader<'_>, _committed_at: Duration) {}
36
37 fn values_invalidated(&self) {}
39
40 fn deserialize_changes(&self, reader: &mut BatchStreamReader<'_>, committed_at: Duration) {
42 self.deserialize_changes_core(reader, committed_at);
43 self.values_invalidated();
44 }
45
46 fn dispose(&self) {}
48
49 fn as_render_resource(self: Rc<Self>) -> Option<Rc<dyn IServerRenderResource>> {
51 None
52 }
53
54 fn as_brush(self: Rc<Self>) -> Option<Rc<dyn IBrush>> {
56 None
57 }
58
59 fn as_pen(self: Rc<Self>) -> Option<Rc<dyn IPen>> {
61 None
62 }
63
64 fn as_render_data_geometry(self: Rc<Self>) -> Option<Rc<dyn IRenderDataGeometry>> {
67 None
68 }
69
70 fn as_transform(self: Rc<Self>) -> Option<Rc<dyn ITransform>> {
72 None
73 }
74
75 fn as_gradient_stop(self: Rc<Self>) -> Option<Rc<dyn IGradientStop>> {
77 None
78 }
79
80 fn as_surface(self: Rc<Self>) -> Option<Rc<dyn super::IServerCompositionSurface>> {
82 None
83 }
84
85 fn as_animated(self: Rc<Self>) -> Option<Rc<dyn IAnimatedServerObject>> {
87 None
88 }
89
90 fn get_props(&self, _type_id: TypeId) -> Option<&dyn Any> {
95 None
96 }
97
98 fn as_any(&self) -> &dyn Any;
99
100 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any>;
101}
102
103pub trait IAnimatedServerObject: IServerObject + IServerAnimatedPropertyHost {
110 fn server_object(&self) -> &ServerObject;
112
113 fn get_composition_property(&self, _field_name: &str) -> Option<&'static CompositionProperty> {
115 None
116 }
117
118 fn as_server_object_dyn(&self) -> &dyn IServerObject;
120
121 fn read_property_variant(&self, property: &'static CompositionProperty) -> ExpressionVariant {
125 property.get_variant().map(|get| get(self.as_server_object_dyn())).unwrap_or_default()
126 }
127
128 fn write_property_variant(&self, property: &'static CompositionProperty, value: ExpressionVariant) {
133 if let Some(set) = property.set_variant() {
134 set(self.as_server_object_dyn(), value);
135 }
136 }
137}
138
139#[derive(Clone)]
144pub struct ServerExpressionObject(pub Rc<dyn IAnimatedServerObject>);
145
146impl IExpressionObject for ServerExpressionObject {
147 fn get_property(&self, name: &str) -> ExpressionVariant {
148 self.0.server_object().get_property(name)
149 }
150
151 fn key(&self) -> ExpressionObjectKey {
152 ExpressionObjectKey(Rc::as_ptr(&self.0) as *const () as usize)
153 }
154}
155
156pub struct ServerObject {
159 compositor: Weak<ServerCompositor>,
160 owner: Weak<dyn IAnimatedServerObject>,
161 activation_count: Cell<u32>,
162 animations: RefCell<Option<Rc<ServerObjectAnimations>>>,
163}
164
165impl ServerObject {
166 pub fn new(compositor: &Rc<ServerCompositor>, owner: Weak<dyn IAnimatedServerObject>) -> Self {
168 Self {
169 compositor: Rc::downgrade(compositor),
170 owner,
171 activation_count: Cell::new(0),
172 animations: RefCell::new(None),
173 }
174 }
175
176 pub fn compositor(&self) -> Option<Rc<ServerCompositor>> {
178 self.compositor.upgrade()
179 }
180
181 pub fn animations(&self) -> Option<Rc<ServerObjectAnimations>> {
182 self.animations.borrow().clone()
183 }
184
185 pub fn get_or_create_animations(&self) -> Rc<ServerObjectAnimations> {
186 self.animations
187 .borrow_mut()
188 .get_or_insert_with(|| Rc::new(ServerObjectAnimations::new(self.owner.clone(), self.compositor.clone())))
189 .clone()
190 }
191
192 pub fn is_active(&self) -> bool {
193 self.activation_count.get() != 0
194 }
195
196 pub fn activate(&self) {
197 self.activation_count.set(self.activation_count.get() + 1);
198 if self.activation_count.get() == 1 {
199 self.activated();
200 }
201 }
202
203 pub fn deactivate(&self) {
204 if cfg!(debug_assertions) && self.activation_count.get() == 0 {
205 panic!("the server object is not active");
206 }
207 self.activation_count.set(self.activation_count.get().saturating_sub(1));
208 if self.activation_count.get() == 0 {
209 self.deactivated();
210 }
211 }
212
213 fn activated(&self) {
214 if let Some(animations) = self.animations() {
215 animations.activated();
216 }
217 }
218
219 fn deactivated(&self) {
220 if let Some(animations) = self.animations() {
221 animations.deactivated();
222 }
223 }
224
225 pub fn set_value(&self, property: &'static CompositionProperty, change: ServerValueChange<'_>) {
228 (change.assign)();
229 if let Some(animations) = self.animations() {
230 animations.on_set_direct_value(property);
231 }
232 }
233
234 pub fn set_animated_value(
236 &self,
237 property: &'static CompositionProperty,
238 current_value: ExpressionVariant,
239 committed_at: Duration,
240 animation: Rc<dyn IAnimationInstance>,
241 ) {
242 self.get_or_create_animations().on_set_animated_value(property, current_value, committed_at, animation);
243 }
244
245 pub fn remove_animation_for_property(&self, property: &'static CompositionProperty) {
247 if let Some(animations) = self.animations() {
248 animations.remove_animation_for_property(property);
249 }
250 }
251
252 pub fn get_property(&self, name: &str) -> ExpressionVariant {
254 match self.animations() {
255 None => {
256 let Some(owner) = self.owner.upgrade() else { return ExpressionVariant::default() };
257 owner
258 .get_composition_property(name)
259 .map(|property| owner.read_property_variant(property))
260 .unwrap_or_default()
261 }
262 Some(animations) => animations.get_property_for_animation(name),
263 }
264 }
265}
266
267#[doc(hidden)]
272#[macro_export]
273macro_rules! __impl_animated_server_object {
274 ($ty:ty, $object:ident $(, composition_property: $get:expr)?) => {
275 impl $crate::rendering::composition::server::IServerPropertyHost for $ty {
276 fn server_compositor(
277 &self,
278 ) -> Option<::std::rc::Rc<$crate::rendering::composition::server::ServerCompositor>> {
279 self.$object.compositor()
280 }
281
282 fn set_value(
283 &self,
284 property: &'static $crate::rendering::composition::server::CompositionProperty,
285 change: $crate::rendering::composition::server::ServerValueChange<'_>,
286 ) {
287 self.$object.set_value(property, change);
288 }
289 }
290
291 impl $crate::rendering::composition::server::IServerAnimatedPropertyHost for $ty {
292 fn set_animated_value(
293 &self,
294 property: &'static $crate::rendering::composition::server::CompositionProperty,
295 current_value: $crate::rendering::composition::expressions::ExpressionVariant,
296 committed_at: ::std::time::Duration,
297 animation: ::std::rc::Rc<dyn $crate::rendering::composition::animations::IAnimationInstance>,
298 ) {
299 self.$object.set_animated_value(property, current_value, committed_at, animation);
300 }
301
302 fn remove_animation_for_property(
303 &self,
304 property: &'static $crate::rendering::composition::server::CompositionProperty,
305 ) {
306 self.$object.remove_animation_for_property(property);
307 }
308
309 fn notify_animated_value_changed(
310 &self,
311 _property: &'static $crate::rendering::composition::server::CompositionProperty,
312 ) {
313 $crate::rendering::composition::server::IServerObject::values_invalidated(self);
314 }
315 }
316
317 impl $crate::rendering::composition::server::IAnimatedServerObject for $ty {
318 fn server_object(&self) -> &$crate::rendering::composition::server::ServerObject {
319 &self.$object
320 }
321
322 $(fn get_composition_property(
323 &self,
324 field_name: &str,
325 ) -> Option<&'static $crate::rendering::composition::server::CompositionProperty> {
326 ($get)(field_name)
327 })?
328
329 fn as_server_object_dyn(&self) -> &dyn $crate::rendering::composition::server::IServerObject {
330 self
331 }
332 }
333 };
334}
335
336pub use crate::__impl_animated_server_object as impl_animated_server_object;