ferroui_base/controls/
resource_provider.rs1use super::{
2 IResourceNode, IResourceProvider, ResourceHostRef, ResourceKey, ResourceValue, ResourcesChangedEventArgs,
3 WeakResourceHost,
4};
5use crate::reactive::{Disposable, IDisposable};
6use crate::styling::ThemeVariant;
7use crate::utilities::HandlerList;
8use crate::{ferro_class, FerroObject, FerroObjectImpl, ObjectType, Ref, Upcast};
9use std::cell::RefCell;
10use std::rc::Rc;
11
12#[repr(C)]
14pub struct ResourceProvider {
15 base: FerroObject,
16 owner: RefCell<Option<WeakResourceHost>>,
17 owner_changed: HandlerList<dyn Fn()>,
18}
19
20ferro_class! {
21 ResourceProvider: FerroObject, virtuals ResourceProviderImpl: FerroObjectImpl {
22 fn has_resources(this) -> bool;
24 fn try_get_resource(this, key: &ResourceKey, theme: Option<&ThemeVariant>) -> Option<ResourceValue>;
26 fn on_add_owner(this, owner: &ResourceHostRef);
29 fn on_remove_owner(this, owner: &ResourceHostRef);
32 }
33}
34
35crate::ferro_class_info!(ResourceProvider { interfaces: [Rc<dyn IResourceProvider>] });
36
37impl FerroObjectImpl for ResourceProvider {}
38
39impl ResourceProviderImpl for ResourceProvider {
40 fn has_resources(_this: &Self) -> bool {
41 false
42 }
43
44 fn try_get_resource(_this: &Self, _key: &ResourceKey, _theme: Option<&ThemeVariant>) -> Option<ResourceValue> {
45 None
46 }
47
48 fn on_add_owner(this: &Self, owner: &ResourceHostRef) {
49 if this.has_resources() {
50 owner.notify_hosted_resources_changed(ResourcesChangedEventArgs::create());
51 }
52 }
53
54 fn on_remove_owner(this: &Self, owner: &ResourceHostRef) {
55 if this.has_resources() {
56 owner.notify_hosted_resources_changed(ResourcesChangedEventArgs::create());
57 }
58 }
59}
60
61impl ResourceProvider {
62 pub fn construct() -> Self {
64 Self { base: FerroObject::construct(), owner: RefCell::new(None), owner_changed: HandlerList::new() }
65 }
66
67 pub fn construct_with_owner(owner: &ResourceHostRef) -> Self {
69 Self {
70 base: FerroObject::construct(),
71 owner: RefCell::new(Some(owner.downgrade())),
72 owner_changed: HandlerList::new(),
73 }
74 }
75
76 pub fn owner(&self) -> Option<ResourceHostRef> {
78 let owner = self.owner.borrow().clone();
79 owner.and_then(|o| o.upgrade())
80 }
81
82 fn set_owner(&self, value: Option<&ResourceHostRef>) {
83 let old = self.owner();
84 if old.as_ref() != value {
85 *self.owner.borrow_mut() = value.map(ResourceHostRef::downgrade);
86 if !self.owner_changed.is_empty() {
87 for (_, handler) in self.owner_changed.snapshot().iter() {
88 handler();
89 }
90 }
91 }
92 }
93
94 pub fn owner_changed(&self, handler: impl Fn() + 'static) -> Rc<dyn IDisposable> {
96 self.subscribe_owner_changed(Rc::new(handler))
97 }
98
99 pub(crate) fn subscribe_owner_changed(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
100 let token = self.owner_changed.add(handler);
101 let weak = self.to_ref().downgrade();
102 Disposable::create(move || {
103 if let Some(this) = weak.upgrade() {
104 this.owner_changed.remove(token);
105 }
106 })
107 }
108
109 pub fn raise_resources_changed(&self) {
112 if let Some(owner) = self.owner() {
113 owner.notify_hosted_resources_changed(ResourcesChangedEventArgs::create());
114 }
115 }
116
117 pub fn add_owner(&self, owner: &ResourceHostRef) {
119 if self.owner().is_some() {
120 panic!("The ResourceDictionary already has a parent.");
121 }
122 self.set_owner(Some(owner));
123 self.on_add_owner(owner);
124 }
125
126 pub fn remove_owner(&self, owner: &ResourceHostRef) {
128 if self.owner().as_ref() == Some(owner) {
129 self.set_owner(None);
130 self.on_remove_owner(owner);
131 }
132 }
133}
134
135struct ResourceProviderHandle(Ref<ResourceProvider>);
137
138impl IResourceNode for ResourceProviderHandle {
139 fn reference_id(&self) -> *const () {
140 let object: &FerroObject = (*self.0).upcast();
141 object as *const FerroObject as *const ()
142 }
143
144 fn has_resources(&self) -> bool {
145 self.0.has_resources()
146 }
147
148 fn try_get_resource(&self, key: &ResourceKey, theme: Option<&ThemeVariant>) -> Option<ResourceValue> {
149 self.0.try_get_resource(key, theme)
150 }
151}
152
153impl IResourceProvider for ResourceProviderHandle {
154 fn owner(&self) -> Option<ResourceHostRef> {
155 self.0.owner()
156 }
157
158 fn owner_changed(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
159 self.0.subscribe_owner_changed(handler)
160 }
161
162 fn add_owner(&self, owner: &ResourceHostRef) {
163 self.0.add_owner(owner)
164 }
165
166 fn remove_owner(&self, owner: &ResourceHostRef) {
167 self.0.remove_owner(owner)
168 }
169
170 fn as_object(&self) -> Option<&FerroObject> {
171 Some((*self.0).upcast())
172 }
173}
174
175impl<T: ObjectType + Upcast<ResourceProvider>> From<Ref<T>> for Rc<dyn IResourceProvider> {
176 fn from(value: Ref<T>) -> Self {
177 Rc::new(ResourceProviderHandle(value.upcast()))
178 }
179}
180
181impl<T: ObjectType + Upcast<ResourceProvider>> From<&Ref<T>> for Rc<dyn IResourceProvider> {
182 fn from(value: &Ref<T>) -> Self {
183 Rc::new(ResourceProviderHandle(value.clone().upcast()))
184 }
185}