Skip to main content

ferroui_base/
i_data_context_provider.rs

1use crate::{BoxedValue, FerroObject, StyledElement, TypeInfo};
2use std::cell::RefCell;
3
4crate::ferro_thread_local! {
5    static PROVIDER_TYPES: RefCell<Vec<&'static TypeInfo>> = const { RefCell::new(Vec::new()) };
6}
7
8/// Defines an element with a data context that can be used for binding.
9pub trait IDataContextProvider {
10    /// Gets the element's data context.
11    fn data_context(&self) -> Option<BoxedValue>;
12
13    /// Sets the element's data context.
14    fn set_data_context(&self, value: Option<BoxedValue>);
15}
16
17impl dyn IDataContextProvider {
18    /// Declares that the objects of a class that is not a styled element
19    /// (the application class) have a data context that can be used for
20    /// binding: the class is an owner of
21    /// [`StyledElement::data_context_property`]. Styled elements and the
22    /// classes deriving from a declared class are providers already.
23    pub fn register_type(type_: &'static TypeInfo) {
24        PROVIDER_TYPES.with_borrow_mut(|types| {
25            if !types.iter().any(|t| std::ptr::eq(*t, type_)) {
26                types.push(type_);
27            }
28        });
29    }
30
31    /// Whether `object` has a data context that can be used for binding.
32    pub fn is_implemented_by(object: &FerroObject) -> bool {
33        if object.is::<StyledElement>() {
34            return true;
35        }
36        let type_ = object.get_type();
37        PROVIDER_TYPES.with_borrow(|types| types.iter().any(|t| t.is_assignable_from(type_)))
38    }
39}
40
41impl IDataContextProvider for StyledElement {
42    fn data_context(&self) -> Option<BoxedValue> {
43        StyledElement::data_context(self)
44    }
45
46    fn set_data_context(&self, value: Option<BoxedValue>) {
47        StyledElement::set_data_context(self, value)
48    }
49}