Skip to main content

ferroui_base/rendering/composition/
visual_collection.rs

1use super::generated::{CompositionVisualCollectionHooks, CompositionVisualCollectionProps};
2use super::server::{CompositionProperty, ServerObjectId};
3use super::transport::{BatchStreamWriter, IRegisterForSerialization};
4use super::{
5    AsCompositionObject, CompositionObject, ICompositionObjectAnimations, CompositionVisual, Compositor, ICompositionObject, ICompositionObjectHost,
6    ICompositorSerializable, PendingAnimations,
7};
8use crate::rendering::composition::animations::{ICompositionAnimation, ICompositionAnimationBase};
9use crate::rendering::composition::expressions::ExpressionVariant;
10use std::any::Any;
11use std::rc::{Rc, Weak};
12
13/// The children of a composition visual.
14pub struct CompositionVisualCollection {
15    this: Weak<CompositionVisualCollection>,
16    object: CompositionObject,
17    owner: Weak<CompositionVisual>,
18    props: CompositionVisualCollectionProps<CompositionVisual>,
19}
20
21impl CompositionVisualCollection {
22    pub(crate) fn new(
23        compositor: &Rc<Compositor>,
24        parent: Weak<CompositionVisual>,
25        server: ServerObjectId,
26    ) -> Rc<CompositionVisualCollection> {
27        let collection = Rc::new_cyclic(|this: &Weak<CompositionVisualCollection>| CompositionVisualCollection {
28            this: this.clone(),
29            object: CompositionObject::new(compositor, Some(server)),
30            owner: parent,
31            props: CompositionVisualCollectionProps::new(),
32        });
33        collection.props.initialize_defaults(&*collection);
34        collection
35    }
36
37    fn owner(&self) -> Option<Rc<CompositionVisual>> {
38        self.owner.upgrade()
39    }
40
41    pub fn insert_above(&self, new_child: Rc<CompositionVisual>, sibling: &Rc<CompositionVisual>) {
42        let Some(idx) = self.props.index_of(sibling) else { panic!("the sibling is not in the collection") };
43        self.insert(idx + 1, new_child);
44    }
45
46    pub fn insert_below(&self, new_child: Rc<CompositionVisual>, sibling: &Rc<CompositionVisual>) {
47        let Some(idx) = self.props.index_of(sibling) else { panic!("the sibling is not in the collection") };
48        self.insert(idx, new_child);
49    }
50
51    pub fn insert_at_top(&self, new_child: Rc<CompositionVisual>) {
52        self.insert(self.props.count(), new_child);
53    }
54
55    pub fn insert_at_bottom(&self, new_child: Rc<CompositionVisual>) {
56        self.insert(0, new_child);
57    }
58
59    pub fn remove_all(&self) {
60        self.clear();
61    }
62
63    // --- the list ----------------------------------------------------------------
64
65    /// A snapshot of the items, for enumeration.
66    pub fn items(&self) -> Vec<Rc<CompositionVisual>> {
67        self.props.items()
68    }
69
70    pub fn add(&self, item: Rc<CompositionVisual>) {
71        self.props.add(self, item);
72    }
73
74    pub fn clear(&self) {
75        self.props.clear(self);
76    }
77
78    pub fn contains(&self, item: &Rc<CompositionVisual>) -> bool {
79        self.props.contains(item)
80    }
81
82    pub fn remove(&self, item: &Rc<CompositionVisual>) -> bool {
83        self.props.remove(self, item)
84    }
85
86    pub fn count(&self) -> usize {
87        self.props.count()
88    }
89
90    pub fn is_read_only(&self) -> bool {
91        self.props.is_read_only()
92    }
93
94    pub fn index_of(&self, item: &Rc<CompositionVisual>) -> Option<usize> {
95        self.props.index_of(item)
96    }
97
98    pub fn insert(&self, index: usize, item: Rc<CompositionVisual>) {
99        self.props.insert(self, index, item);
100    }
101
102    pub fn remove_at(&self, index: usize) {
103        self.props.remove_at(self, index);
104    }
105
106    pub fn get(&self, index: usize) -> Rc<CompositionVisual> {
107        self.props.get(index)
108    }
109
110    pub fn set(&self, index: usize, value: Rc<CompositionVisual>) {
111        self.props.set(self, index, value);
112    }
113}
114
115impl CompositionVisualCollectionHooks<CompositionVisual> for CompositionVisualCollection {
116    fn on_added(&self, item: &Rc<CompositionVisual>) {
117        let owner = self.owner();
118        item.set_parent(owner.clone());
119        if let Some(owner) = owner {
120            owner.add_hit_test_child(item);
121        }
122    }
123
124    fn on_before_replace(&self, old_item: &Rc<CompositionVisual>, new_item: &Rc<CompositionVisual>) {
125        if !Rc::ptr_eq(old_item, new_item) {
126            self.on_before_added(new_item);
127        }
128    }
129
130    fn on_replace(&self, old_item: &Rc<CompositionVisual>, new_item: &Rc<CompositionVisual>) {
131        if !Rc::ptr_eq(old_item, new_item) {
132            self.on_removed(old_item);
133            self.on_added(new_item);
134        }
135    }
136
137    fn on_removed(&self, item: &Rc<CompositionVisual>) {
138        item.set_parent(None);
139        if let Some(owner) = self.owner() {
140            owner.remove_hit_test_child(item);
141        }
142    }
143
144    fn on_before_clear(&self) {
145        for item in self.items() {
146            item.set_parent(None);
147        }
148    }
149
150    fn on_clear(&self) {
151        if let Some(owner) = self.owner() {
152            owner.clear_hit_test_children();
153        }
154    }
155
156    fn on_before_added(&self, item: &Rc<CompositionVisual>) {
157        if item.parent().is_some() {
158            panic!("Visual already has a parent");
159        }
160        item.set_parent(self.owner());
161    }
162}
163
164impl IRegisterForSerialization for CompositionVisualCollection {
165    fn register_for_serialization(&self) {
166        self.object
167            .register_for_serialization(|| self.this.upgrade().map(|this| this as Rc<dyn ICompositorSerializable>));
168    }
169}
170
171impl ICompositionObjectHost for CompositionVisualCollection {
172    fn server(&self) -> ServerObjectId {
173        self.object.required_server()
174    }
175
176    fn pending_animations(&self) -> &PendingAnimations {
177        self.object.pending_animations()
178    }
179
180    fn implicit_animation(&self, property_name: &str) -> Option<Rc<dyn ICompositionAnimationBase>> {
181        self.object.implicit_animation(property_name)
182    }
183
184    fn start_animation_group(
185        &self,
186        grp: &Rc<dyn ICompositionAnimationBase>,
187        target: &str,
188        final_value: ExpressionVariant,
189    ) -> bool {
190        self.start_animation_group_for(&**grp, target, final_value)
191    }
192}
193
194/// The class has no animated property: upstream does not override
195/// `StartAnimation`, whose base implementation rejects every property.
196impl ICompositionObjectAnimations for CompositionVisualCollection {
197    fn try_start_animation(
198        &self,
199        _property_name: &str,
200        _animation: &dyn ICompositionAnimation,
201        _final_value: Option<ExpressionVariant>,
202    ) -> bool {
203        false
204    }
205
206    fn get_composition_property(&self, property_name: &str) -> Option<&'static CompositionProperty> {
207        let _ = property_name;
208        None
209    }
210
211    fn composition_object(&self) -> &CompositionObject {
212        &self.object
213    }
214}
215
216impl AsCompositionObject for CompositionVisualCollection {
217    fn as_composition_object(&self) -> &CompositionObject {
218        &self.object
219    }
220
221    fn composition_type_name(&self) -> &'static str {
222        "CompositionVisualCollection"
223    }
224}
225
226impl ICompositionObject for CompositionVisualCollection {
227    fn server(&self) -> ServerObjectId {
228        self.object.required_server()
229    }
230
231    fn as_any(&self) -> &dyn Any {
232        self
233    }
234
235    fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
236        self
237    }
238}
239
240impl ICompositorSerializable for CompositionVisualCollection {
241    fn try_get_server(&self, c: &Compositor) -> Option<ServerObjectId> {
242        self.object.try_get_server(c)
243    }
244
245    fn serialize_changes(&self, c: &Compositor, writer: &mut BatchStreamWriter<'_>) {
246        self.object.begin_serialize_changes(c);
247        self.props.serialize_changes_core(self, writer);
248    }
249}