Skip to main content

ferroui_base/styling/
style_children.rs

1use super::{IStyle, StyleBase};
2use crate::WeakRef;
3use std::cell::RefCell;
4use std::rc::Rc;
5
6/// The collection of child styles of a style.
7///
8/// The value is a shared handle: clones refer to the same collection, and
9/// handles compare by identity.
10#[derive(Clone)]
11pub struct StyleChildren(Rc<StyleChildrenData>);
12
13struct StyleChildrenData {
14    owner: WeakRef<StyleBase>,
15    items: RefCell<Rc<Vec<Rc<dyn IStyle>>>>,
16}
17
18fn as_style_base(item: &Rc<dyn IStyle>) -> Option<&StyleBase> {
19    item.as_object().and_then(|o| o.downcast_ref::<StyleBase>())
20}
21
22impl PartialEq for StyleChildren {
23    fn eq(&self, other: &Self) -> bool {
24        Rc::ptr_eq(&self.0, &other.0)
25    }
26}
27
28impl std::fmt::Debug for StyleChildren {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        write!(f, "StyleChildren({})", self.count())
31    }
32}
33
34impl StyleChildren {
35    pub(crate) fn new(owner: WeakRef<StyleBase>) -> Self {
36        Self(Rc::new(StyleChildrenData { owner, items: RefCell::new(Rc::new(Vec::new())) }))
37    }
38
39    /// The number of child styles.
40    #[inline]
41    pub fn count(&self) -> usize {
42        self.0.items.borrow().len()
43    }
44
45    #[inline]
46    pub fn is_empty(&self) -> bool {
47        self.0.items.borrow().is_empty()
48    }
49
50    /// The child style at `index`. Panics if out of range.
51    pub fn get(&self, index: usize) -> Rc<dyn IStyle> {
52        self.0.items.borrow()[index].clone()
53    }
54
55    /// A snapshot of the child styles.
56    #[inline]
57    pub fn snapshot(&self) -> Rc<Vec<Rc<dyn IStyle>>> {
58        self.0.items.borrow().clone()
59    }
60
61    /// Adds a child style.
62    pub fn add(&self, item: impl Into<Rc<dyn IStyle>>) {
63        self.insert(self.count(), item)
64    }
65
66    /// Inserts a child style.
67    pub fn insert(&self, index: usize, item: impl Into<Rc<dyn IStyle>>) {
68        let item = item.into();
69        let owner = self.0.owner.upgrade();
70        if let Some(style) = as_style_base(&item) {
71            style.set_parent(owner.as_ref());
72        }
73        Rc::make_mut(&mut *self.0.items.borrow_mut()).insert(index, item);
74    }
75
76    /// Removes the child style at `index`.
77    pub fn remove_at(&self, index: usize) {
78        let item = self.get(index);
79        if let Some(style) = as_style_base(&item) {
80            style.set_parent(None);
81        }
82        if let Some(host) = self.0.owner.upgrade().and_then(|o| o.owner()) {
83            if let Some(provider) = item.as_resource_provider() {
84                provider.remove_owner(&host);
85            }
86        }
87        Rc::make_mut(&mut *self.0.items.borrow_mut()).remove(index);
88    }
89
90    /// Removes a child style. Returns whether it was present.
91    pub fn remove(&self, item: impl Into<Rc<dyn IStyle>>) -> bool {
92        let item = item.into();
93        let index = self.0.items.borrow().iter().position(|i| super::style_ptr_eq(i, &item));
94        match index {
95            Some(index) => {
96                self.remove_at(index);
97                true
98            }
99            None => false,
100        }
101    }
102
103    /// Replaces the child style at `index`.
104    pub fn set(&self, index: usize, item: impl Into<Rc<dyn IStyle>>) {
105        let item = item.into();
106        let owner = self.0.owner.upgrade();
107        if let Some(style) = as_style_base(&item) {
108            style.set_parent(owner.as_ref());
109        }
110        Rc::make_mut(&mut *self.0.items.borrow_mut())[index] = item.clone();
111        if let Some(host) = owner.and_then(|o| o.owner()) {
112            if let Some(provider) = item.as_resource_provider() {
113                provider.add_owner(&host);
114            }
115        }
116    }
117
118    /// Removes all child styles.
119    pub fn clear(&self) {
120        *self.0.items.borrow_mut() = Rc::new(Vec::new());
121    }
122}