1use super::{
2 DirectPropertySetterBindingInstance, DirectPropertySetterInstance, IStyleInstance, ISetterInstance,
3 ISetterValue, ITemplate, PropertySetterTemplateInstance, SetterBase, SetterInstance, SetterInstanceKind,
4 StyleInstance,
5};
6use crate::data::core::SinkRef;
7use crate::data::{BindingBase, BindingPriority};
8use crate::property_store::{IValueEntry, ValueFrame};
9use crate::reactive::IObservable;
10use crate::{AnyValue, BoxedValue, FerroProperty, PropertyValue, StyledElement, StyledProperty};
11use std::any::Any;
12use std::cell::{Cell, OnceCell, RefCell};
13use std::fmt;
14use std::rc::Rc;
15
16#[derive(Clone)]
18pub enum SetterValue {
19 Value(BoxedValue),
22 Binding(Rc<dyn IObservable<BoxedValue>>),
29 BindingBase(Rc<dyn BindingBase>),
32 Template(Rc<dyn ITemplate>),
35}
36
37pub struct Setter {
43 property: Cell<Option<&'static FerroProperty>>,
44 value: RefCell<Option<SetterValue>>,
45 direct: OnceCell<Rc<DirectPropertySetterInstance>>,
46}
47
48
49impl PartialEq for Setter {
52 #[inline]
53 fn eq(&self, other: &Self) -> bool {
54 std::ptr::eq(self, other)
55 }
56}
57
58impl Default for Setter {
59 fn default() -> Self {
60 Self { property: Cell::new(None), value: RefCell::new(None), direct: OnceCell::new() }
61 }
62}
63
64impl Setter {
65 pub fn empty() -> Rc<Self> {
67 Rc::new(Self::default())
68 }
69
70 pub fn new<T: PropertyValue>(property: &'static StyledProperty<T>, value: T) -> Rc<Self> {
72 Self::with_value(property, SetterValue::Value(Rc::new(value)))
73 }
74
75 pub fn new_untyped(property: &'static FerroProperty, value: BoxedValue) -> Rc<Self> {
78 Self::with_value(property, SetterValue::Value(value))
79 }
80
81 pub fn new_binding(property: &'static FerroProperty, source: Rc<dyn IObservable<BoxedValue>>) -> Rc<Self> {
83 Self::with_value(property, SetterValue::Binding(source))
84 }
85
86 pub fn new_binding_base(property: &'static FerroProperty, binding: Rc<dyn BindingBase>) -> Rc<Self> {
89 Self::with_value(property, SetterValue::BindingBase(binding))
90 }
91
92 pub fn new_template(property: &'static FerroProperty, template: Rc<dyn ITemplate>) -> Rc<Self> {
95 Self::with_value(property, SetterValue::Template(template))
96 }
97
98 pub fn with_value(property: &'static FerroProperty, value: SetterValue) -> Rc<Self> {
100 let setter = Self::default();
101 setter.property.set(Some(property));
102 *setter.value.borrow_mut() = Some(value);
103 Rc::new(setter)
104 }
105
106 pub fn property(&self) -> Option<&'static FerroProperty> {
108 self.property.get()
109 }
110
111 pub fn set_property(&self, value: Option<&'static FerroProperty>) {
112 self.property.set(value)
113 }
114
115 pub fn value(&self) -> Option<SetterValue> {
117 self.value.borrow().clone()
118 }
119
120 pub fn set_value(&self, value: Option<SetterValue>) {
121 *self.value.borrow_mut() = value;
122 }
123
124 pub fn set_setter_value(&self, value: &dyn ISetterValue, boxed: BoxedValue) {
127 value.initialize(self);
128 *self.value.borrow_mut() = Some(SetterValue::Value(boxed));
129 }
130
131 fn ensure_property(&self) -> &'static FerroProperty {
132 match self.property.get() {
133 Some(property) => property,
134 None => panic!("Setter.Property must be set."),
135 }
136 }
137
138 fn plain_value(&self) -> Option<BoxedValue> {
139 match &*self.value.borrow() {
140 Some(SetterValue::Value(value)) => Some(value.clone()),
141 None => self.property.get().and_then(Self::null_value),
143 _ => None,
144 }
145 }
146
147 fn null_value(property: &'static FerroProperty) -> Option<BoxedValue> {
150 crate::data::core::ValueTypes::null_value(crate::data::core::ValueType::new(
151 property.property_type(),
152 property.property_type_name(),
153 ))
154 }
155
156 fn set_binding(
157 &self,
158 property: &'static FerroProperty,
159 instance: &Rc<StyleInstance>,
160 target: &StyledElement,
161 source: Rc<dyn IObservable<BoxedValue>>,
162 ) -> SetterInstance {
163 if !property.is_direct() {
164 let frame: Rc<dyn ValueFrame> = instance.clone();
165 let entry = property.routes().route_create_binding_entry(target, Rc::downgrade(&frame), source);
166 SetterInstance { kind: SetterInstanceKind::Entry(entry), is_setter: false }
167 } else {
168 target.bind_property_untyped(property, source, BindingPriority::LocalValue);
169 SetterInstance {
170 kind: SetterInstanceKind::Other(Rc::new(DirectPropertySetterBindingInstance)),
171 is_setter: false,
172 }
173 }
174 }
175
176 fn set_binding_base(
177 &self,
178 property: &'static FerroProperty,
179 instance: &Rc<StyleInstance>,
180 target: &StyledElement,
181 binding: Rc<dyn BindingBase>,
182 ) -> SetterInstance {
183 if !property.is_direct() {
184 let expression = binding.create_instance(target, Some(property), None);
188 let owner: &crate::FerroObject = target;
189 let frame: &dyn ValueFrame = &**instance;
190 expression.attach(SinkRef::Store(owner.to_weak()), None, owner, property, frame.base().priority());
191 let entry: Rc<dyn IValueEntry> = expression;
192 SetterInstance { kind: SetterInstanceKind::Entry(entry), is_setter: false }
193 } else {
194 target.bind_binding(property, &*binding);
195 SetterInstance {
196 kind: SetterInstanceKind::Other(Rc::new(DirectPropertySetterBindingInstance)),
197 is_setter: false,
198 }
199 }
200 }
201
202 fn set_direct_value(&self, property: &'static FerroProperty, target: &StyledElement, value: &BoxedValue) -> SetterInstance {
203 let value: &dyn AnyValue = &**value;
204 target.set_value_untyped(property, value.as_any(), BindingPriority::LocalValue);
205 let direct: Rc<dyn ISetterInstance> =
206 self.direct.get_or_init(|| Rc::new(DirectPropertySetterInstance)).clone();
207 SetterInstance { kind: SetterInstanceKind::Other(direct), is_setter: false }
210 }
211}
212
213impl ISetterInstance for Setter {}
214
215impl SetterBase for Setter {
216 fn as_any(&self) -> Option<&dyn Any> {
217 Some(self)
218 }
219
220 fn instance(self: Rc<Self>, instance: &Rc<StyleInstance>, target: &StyledElement) -> SetterInstance {
221 let Some(property) = self.property.get() else {
222 panic!("Setter.Property must be set.");
223 };
224
225 if property.is_direct() && instance.has_activator() {
226 panic!(
227 "Cannot set direct property '{}' in '{}' because the style has an activator.",
228 property,
229 instance.source_display()
230 );
231 }
232
233 if instance.has_activator() {
234 if let Some(class_property_name) = crate::ClassBindingManager::is_classes_binding_property(property) {
235 panic!(
236 "Cannot set Class Binding property '(Classes.{})' in '{}' because the style has an activator.",
237 class_property_name,
238 instance.source_display()
239 );
240 }
241 }
242
243 let value = self.value.borrow().clone();
244 match value {
245 Some(SetterValue::Binding(source)) => self.set_binding(property, instance, target, source),
246 Some(SetterValue::BindingBase(binding)) => self.set_binding_base(property, instance, target, binding),
247 Some(SetterValue::Template(template)) => SetterInstance {
248 kind: SetterInstanceKind::Entry(Rc::new(PropertySetterTemplateInstance::new(property, template))),
249 is_setter: false,
250 },
251 Some(SetterValue::Value(value)) => {
252 let inner: &dyn AnyValue = &*value;
253 if !property.is_valid_value(inner.as_any()) {
254 panic!("Setter value '{:?}' is not a valid value for property '{}'.", inner, property);
255 }
256 if property.is_direct() {
257 self.set_direct_value(property, target, &value)
258 } else {
259 SetterInstance { kind: SetterInstanceKind::Entry(self), is_setter: true }
260 }
261 }
262 None => match Self::null_value(property) {
265 Some(null) if property.is_direct() => self.set_direct_value(property, target, &null),
266 Some(_) => SetterInstance { kind: SetterInstanceKind::Entry(self), is_setter: true },
267 None => panic!("Setter value '(null)' is not a valid value for property '{}'.", property),
268 },
269 }
270 }
271}
272
273impl IValueEntry for Setter {
274 fn property(&self) -> &'static FerroProperty {
275 self.ensure_property()
276 }
277
278 fn has_value(&self) -> bool {
279 true
280 }
281
282 fn try_get_value(&self, out: &mut dyn Any) -> bool {
283 match self.plain_value() {
284 Some(value) => {
285 let value: &dyn AnyValue = &*value;
286 self.ensure_property().routes().route_copy_value(value.as_any(), out)
287 }
288 None => false,
289 }
290 }
291
292 fn get_value_boxed(&self) -> Option<BoxedValue> {
293 self.plain_value()
294 }
295
296 fn unsubscribe(&self) {}
297}
298
299impl fmt::Display for Setter {
300 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301 let property = self.property.get().map(|p| p.name().to_string()).unwrap_or_default();
302 match &*self.value.borrow() {
303 Some(SetterValue::Value(value)) => write!(f, "Setter: {property} = {:?}", &**value),
304 Some(SetterValue::Binding(_)) | Some(SetterValue::BindingBase(_)) => {
305 write!(f, "Setter: {property} = (binding)")
306 }
307 Some(SetterValue::Template(_)) => write!(f, "Setter: {property} = (template)"),
308 None => write!(f, "Setter: {property} = "),
309 }
310 }
311}