ferroui_base/media/
transform.rs1use crate::animation::Animatable;
2use crate::media::immutable::ImmutableTransform;
3use crate::media::MatrixTransform;
4use crate::media::ref_adapter::RefAdapter;
5use crate::reactive::{Disposable, IDisposable};
6use crate::rendering::composition::drawing::{CompositorResourceHolder, ICompositionRenderResource};
7use crate::rendering::composition::generated::ServerCompositionSimpleTransformProps;
8use crate::rendering::composition::server::{IServerObject, ServerCompositionSimpleTransform, ServerObjectId};
9use crate::rendering::composition::transport::BatchStreamWriter;
10use crate::rendering::composition::{Compositor, ICompositorSerializable};
11use crate::utilities::{FormatError, HandlerList};
12use crate::{ferro_class, FerroObject, FerroObjectImpl, Matrix, Ref, Upcast};
13use std::fmt;
14use std::rc::Rc;
15
16#[repr(C)]
19pub struct Transform {
20 base: Animatable,
21 changed: HandlerList<dyn Fn()>,
22 resource: CompositorResourceHolder,
23}
24
25ferro_class! {
26 Transform: Animatable, virtuals TransformImpl: FerroObjectImpl {
27 fn value(this) -> Matrix;
29 }
30}
31crate::ferro_class_info!(Transform { interfaces: [std::rc::Rc<dyn crate::media::ITransform>] });
32
33crate::ferro_impl_classes!(Transform: FerroObjectImpl);
34
35impl TransformImpl for Transform {
36 fn value(_this: &Self) -> Matrix {
37 panic!("Transform is abstract: 'value' must be implemented by the deriving class")
38 }
39}
40
41impl Transform {
42 pub fn construct() -> Self {
44 Self { base: Animatable::construct(), changed: HandlerList::new(), resource: CompositorResourceHolder::new() }
45 }
46
47 pub fn parse(s: &str) -> Result<Ref<Transform>, FormatError> {
50 Ok(MatrixTransform::with_matrix(Matrix::parse(s)?).upcast())
51 }
52
53 pub fn changed(&self, handler: impl Fn() + 'static) -> Rc<dyn IDisposable> {
56 let token = self.changed.add(Rc::new(handler));
57 let object: &FerroObject = self.upcast();
58 let weak = object.to_weak();
59 Disposable::create(move || {
60 if let Some(this) = weak.upgrade() {
61 if let Some(this) = this.downcast_ref::<Transform>() {
62 this.changed.remove(token);
63 }
64 }
65 })
66 }
67
68 pub fn raise_changed(&self) {
70 if self.changed.is_empty() {
71 return;
72 }
73 for (_, handler) in self.changed.snapshot().iter() {
74 handler();
75 }
76 }
77
78 pub(crate) fn as_compositor_serializable(&self) -> Rc<dyn ICompositorSerializable> {
81 Rc::new(RefAdapter(self.to_ref()))
82 }
83
84 pub fn to_immutable(&self) -> ImmutableTransform {
86 ImmutableTransform::new(self.value())
87 }
88}
89
90impl ICompositionRenderResource for Transform {
91 fn add_ref_on_compositor(&self, c: &Rc<Compositor>) {
92 let owner = self.as_compositor_serializable();
93 self.resource.create_or_add_ref(c, Some(owner), |cc| {
94 cc.create_server_object(|server, _| ServerCompositionSimpleTransform::new(server) as Rc<dyn IServerObject>)
95 });
96 }
97
98 fn release_on_compositor(&self, c: &Rc<Compositor>) {
99 self.resource.release(c);
100 }
101
102 fn get_for_compositor(&self, c: &Compositor) -> ServerObjectId {
103 self.resource.get_for_compositor(c)
104 }
105}
106
107impl ICompositorSerializable for RefAdapter<Transform> {
108 fn try_get_server(&self, c: &Compositor) -> Option<ServerObjectId> {
109 self.0.resource.try_get_for_compositor(c)
110 }
111
112 fn serialization_key(&self) -> *const () {
113 RefAdapter::reference_id(self)
114 }
115
116 fn serialize_changes(&self, _c: &Compositor, writer: &mut BatchStreamWriter<'_>) {
117 ServerCompositionSimpleTransformProps::serialize_all_changes(writer, self.0.value());
118 }
119}
120
121impl fmt::Display for Transform {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 fmt::Display::fmt(&self.value(), f)
125 }
126}