ferroui_base/media/
transform_group.rs1use crate::media::media_collection::media_collection_type;
2use crate::media::{MediaCollection, ResetBehavior, Transform, TransformImpl};
3use crate::reactive::IDisposable;
4use crate::{
5 ferro_class, ferro_property, instantiate, FerroObjectImpl, FerroObjectImplExt, FerroProperty,
6 FerroPropertyChangedEventArgs, Matrix,
7 Ref, StyledProperty,
8};
9use std::cell::{Cell, RefCell};
10use std::rc::Rc;
11
12media_collection_type!(
13 Transforms, Ref<Transform>
15);
16
17impl Transforms {
18 pub fn new() -> Self {
20 Self(MediaCollection::new())
21 }
22
23 pub fn from_items(items: impl IntoIterator<Item = Ref<Transform>>) -> Self {
25 Self(MediaCollection::from_items(items))
26 }
27}
28
29type ChildSubscriptions = Rc<RefCell<Vec<(Ref<Transform>, Rc<dyn IDisposable>)>>>;
30
31#[repr(C)]
33pub struct TransformGroup {
34 base: Transform,
35 children_notification_subscription: RefCell<Option<Rc<dyn IDisposable>>>,
36 child_subscriptions: ChildSubscriptions,
37 last_matrix: Cell<Option<Matrix>>,
38}
39
40ferro_class!(TransformGroup: Transform);
41crate::ferro_class_info!(TransformGroup { new: TransformGroup::new });
42
43impl FerroObjectImpl for TransformGroup {
44 fn constructed(this: &Self) {
45 Self::parent_constructed(this);
46 this.set_children(Transforms::new());
47 }
48
49 fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
50 Self::parent_on_property_changed(this, change);
51
52 if change.property() == Self::children_property().as_property() {
53 if let Some(subscription) = this.children_notification_subscription.take() {
54 subscription.dispose();
55 }
56
57 let old = std::mem::take(&mut *this.child_subscriptions.borrow_mut());
59 for (_, subscription) in old {
60 subscription.dispose();
61 }
62
63 if let Some(new_transforms) = change.get_new_value::<Option<Transforms>>() {
64 new_transforms.set_reset_behavior(ResetBehavior::Remove);
66
67 let weak = this.to_ref().downgrade();
68 let subscriptions = this.child_subscriptions.clone();
69 let weak_added = weak.clone();
70 let subscriptions_added = subscriptions.clone();
71 let subscription = new_transforms.for_each_item(
72 move |_, tr: &Ref<Transform>| {
73 let weak_child = weak_added.clone();
74 let handle = tr.changed(move || {
75 if let Some(this) = weak_child.upgrade() {
76 this.on_transform_invalidated();
77 }
78 });
79 subscriptions_added.borrow_mut().push((tr.clone(), handle));
80 if let Some(this) = weak_added.upgrade() {
81 this.on_transform_invalidated();
82 }
83 },
84 move |_, tr: &Ref<Transform>| {
85 let position = subscriptions.borrow().iter().position(|(t, _)| t.ptr_eq(tr));
86 if let Some(position) = position {
87 let (_, handle) = subscriptions.borrow_mut().remove(position);
88 handle.dispose();
89 }
90 if let Some(this) = weak.upgrade() {
91 this.on_transform_invalidated();
92 }
93 },
94 || {},
95 );
96 *this.children_notification_subscription.borrow_mut() = Some(subscription);
97 }
98
99 this.on_transform_invalidated();
100 }
101 }
102}
103
104impl TransformImpl for TransformGroup {
105 fn value(this: &Self) -> Matrix {
106 if let Some(matrix) = this.last_matrix.get() {
107 return matrix;
108 }
109
110 let mut matrix = Matrix::IDENTITY;
111 if let Some(children) = this.get_value(Self::children_property()) {
112 for t in children.iter() {
113 matrix *= t.value();
114 }
115 }
116 this.last_matrix.set(Some(matrix));
117 matrix
118 }
119}
120
121crate::ferro_properties! { impl TransformGroup {
122 ferro_property!(pub fn children_property() -> StyledProperty<Option<Transforms>> {
123 FerroProperty::register::<TransformGroup, _>("Children", None)
124 });
125} }
126
127impl TransformGroup {
128 pub fn construct() -> Self {
130 Self {
131 base: Transform::construct(),
132 children_notification_subscription: RefCell::new(None),
133 child_subscriptions: Rc::new(RefCell::new(Vec::new())),
134 last_matrix: Cell::new(None),
135 }
136 }
137
138 pub fn new() -> Ref<Self> {
139 instantiate(Self::construct())
140 }
141
142 fn on_transform_invalidated(&self) {
143 self.last_matrix.set(None);
144 self.raise_changed();
145 }
146
147 pub fn children(&self) -> Transforms {
149 self.get_value(Self::children_property()).expect("Children is not set")
150 }
151
152 pub fn set_children(&self, value: Transforms) {
153 self.set_value(Self::children_property(), Some(value))
154 }
155}