Skip to main content

ferroui_base/styling/
i_style_host.rs

1use super::{IStyle, Styles};
2use crate::controls::{IResourceHost, ResourceHostRef};
3use crate::{ObjectType, Ref, StyledElement, Upcast};
4use std::ops::Deref;
5use std::rc::Rc;
6
7/// Defines an element that has a [`Styles`] collection.
8///
9/// Implemented by [`StyledElement`] and by the application object, which
10/// holds the global styles and is the root of the styling-parent chain. Every
11/// style host is also a resource host.
12pub trait IStyleHost: IResourceHost {
13    /// Whether the styles collection has been created.
14    ///
15    /// The styles collection is created lazily; this lets a style lookup
16    /// skip hosts without styles without creating the collection.
17    fn is_styles_initialized(&self) -> bool;
18
19    /// The styles for the element.
20    fn styles(&self) -> Ref<Styles>;
21
22    /// The parent style host element.
23    fn styling_parent(&self) -> Option<StyleHostRef>;
24
25    /// Called when styles are added to the styles collection of the host or
26    /// a nested styles collection.
27    fn styles_added(&self, styles: &[Rc<dyn IStyle>]);
28
29    /// Called when styles are removed from the styles collection of the host
30    /// or a nested styles collection.
31    fn styles_removed(&self, styles: &[Rc<dyn IStyle>]);
32}
33
34/// A strong reference to a style host: a styled element, or another host
35/// such as the application object.
36#[derive(Clone)]
37pub enum StyleHostRef {
38    Element(Ref<StyledElement>),
39    Other(Rc<dyn IStyleHost>),
40}
41
42impl StyleHostRef {
43    /// The host as a styled element, if it is one.
44    #[inline]
45    pub fn as_element(&self) -> Option<&Ref<StyledElement>> {
46        match self {
47            StyleHostRef::Element(e) => Some(e),
48            StyleHostRef::Other(_) => None,
49        }
50    }
51
52    /// The host as a resource host.
53    pub fn to_resource_host(&self) -> ResourceHostRef {
54        match self {
55            StyleHostRef::Element(e) => ResourceHostRef::Element(e.clone()),
56            StyleHostRef::Other(h) => ResourceHostRef::Other(h.clone()),
57        }
58    }
59}
60
61impl Deref for StyleHostRef {
62    type Target = dyn IStyleHost;
63
64    #[inline]
65    fn deref(&self) -> &(dyn IStyleHost + 'static) {
66        match self {
67            StyleHostRef::Element(e) => {
68                let element: &StyledElement = e;
69                element
70            }
71            StyleHostRef::Other(h) => &**h,
72        }
73    }
74}
75
76impl PartialEq for StyleHostRef {
77    fn eq(&self, other: &Self) -> bool {
78        match (self, other) {
79            (StyleHostRef::Element(a), StyleHostRef::Element(b)) => a.ptr_eq(b),
80            (StyleHostRef::Other(a), StyleHostRef::Other(b)) => std::ptr::addr_eq(Rc::as_ptr(a), Rc::as_ptr(b)),
81            _ => false,
82        }
83    }
84}
85
86impl<T: ObjectType + Upcast<StyledElement>> From<Ref<T>> for StyleHostRef {
87    fn from(value: Ref<T>) -> Self {
88        StyleHostRef::Element(value.upcast())
89    }
90}
91
92impl<T: ObjectType + Upcast<StyledElement>> From<&Ref<T>> for StyleHostRef {
93    fn from(value: &Ref<T>) -> Self {
94        StyleHostRef::Element(value.clone().upcast())
95    }
96}
97
98impl From<Rc<dyn IStyleHost>> for StyleHostRef {
99    fn from(value: Rc<dyn IStyleHost>) -> Self {
100        StyleHostRef::Other(value)
101    }
102}
103
104impl<T: IStyleHost + 'static> From<Rc<T>> for StyleHostRef {
105    fn from(value: Rc<T>) -> Self {
106        StyleHostRef::Other(value)
107    }
108}
109
110/// Handles compare by identity (reference equality): two handles are equal
111/// when they refer to the same host.
112impl PartialEq for dyn IStyleHost {
113    #[inline]
114    fn eq(&self, other: &Self) -> bool {
115        self.reference_id() == other.reference_id()
116    }
117}