1use super::{
2 DirectPropertySetterBindingInstance, DirectPropertySetterInstance, IStyleInstance, ISetterInstance,
3 ISetterValue, ITemplate, PropertySetterTemplateInstance, SetterBase, SetterInstance, SetterInstanceKind,
4 StyleInstance, TargetPropertyPath,
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 target: RefCell<Option<Rc<TargetPropertyPath>>>,
49}
50
51
52impl PartialEq for Setter {
55 #[inline]
56 fn eq(&self, other: &Self) -> bool {
57 std::ptr::eq(self, other)
58 }
59}
60
61impl Default for Setter {
62 fn default() -> Self {
63 Self {
64 property: Cell::new(None),
65 value: RefCell::new(None),
66 direct: OnceCell::new(),
67 target: RefCell::new(None),
68 }
69 }
70}
71
72impl Setter {
73 pub fn empty() -> Rc<Self> {
75 Rc::new(Self::default())
76 }
77
78 pub fn new<T: PropertyValue>(property: &'static StyledProperty<T>, value: T) -> Rc<Self> {
80 Self::with_value(property, SetterValue::Value(Rc::new(value)))
81 }
82
83 pub fn new_untyped(property: &'static FerroProperty, value: BoxedValue) -> Rc<Self> {
86 Self::with_value(property, SetterValue::Value(value))
87 }
88
89 pub fn new_binding(property: &'static FerroProperty, source: Rc<dyn IObservable<BoxedValue>>) -> Rc<Self> {
91 Self::with_value(property, SetterValue::Binding(source))
92 }
93
94 pub fn new_binding_base(property: &'static FerroProperty, binding: Rc<dyn BindingBase>) -> Rc<Self> {
97 Self::with_value(property, SetterValue::BindingBase(binding))
98 }
99
100 pub fn new_template(property: &'static FerroProperty, template: Rc<dyn ITemplate>) -> Rc<Self> {
103 Self::with_value(property, SetterValue::Template(template))
104 }
105
106 pub fn with_value(property: &'static FerroProperty, value: SetterValue) -> Rc<Self> {
108 let setter = Self::default();
109 setter.property.set(Some(property));
110 *setter.value.borrow_mut() = Some(value);
111 Rc::new(setter)
112 }
113
114 pub fn property(&self) -> Option<&'static FerroProperty> {
116 self.property.get()
117 }
118
119 pub fn set_property(&self, value: Option<&'static FerroProperty>) {
120 self.property.set(value)
121 }
122
123 pub fn target(&self) -> Option<Rc<TargetPropertyPath>> {
130 self.target.borrow().clone()
131 }
132
133 pub fn set_target(&self, value: Option<Rc<TargetPropertyPath>>) {
134 *self.target.borrow_mut() = value;
135 }
136
137 pub fn value(&self) -> Option<SetterValue> {
139 self.value.borrow().clone()
140 }
141
142 pub fn set_value(&self, value: Option<SetterValue>) {
143 *self.value.borrow_mut() = value;
144 }
145
146 pub fn set_setter_value(&self, value: &dyn ISetterValue, boxed: BoxedValue) {
149 value.initialize(self);
150 *self.value.borrow_mut() = Some(SetterValue::Value(boxed));
151 }
152
153 fn ensure_property(&self) -> &'static FerroProperty {
154 match self.property.get() {
155 Some(property) => property,
156 None => panic!("Setter.Property must be set."),
157 }
158 }
159
160 fn plain_value(&self) -> Option<BoxedValue> {
161 match &*self.value.borrow() {
162 Some(SetterValue::Value(value)) => Some(value.clone()),
163 None => self.property.get().and_then(Self::null_value),
165 _ => None,
166 }
167 }
168
169 fn null_value(property: &'static FerroProperty) -> Option<BoxedValue> {
172 crate::data::core::ValueTypes::null_value(crate::data::core::ValueType::new(
173 property.property_type(),
174 property.property_type_name(),
175 ))
176 }
177
178 fn set_binding(
179 &self,
180 property: &'static FerroProperty,
181 instance: &Rc<StyleInstance>,
182 target: &StyledElement,
183 source: Rc<dyn IObservable<BoxedValue>>,
184 ) -> SetterInstance {
185 if !property.is_direct() {
186 let frame: Rc<dyn ValueFrame> = instance.clone();
187 let entry = property.routes().route_create_binding_entry(target, Rc::downgrade(&frame), source);
188 SetterInstance { kind: SetterInstanceKind::Entry(entry), is_setter: false }
189 } else {
190 target.bind_property_untyped(property, source, BindingPriority::LocalValue);
191 SetterInstance {
192 kind: SetterInstanceKind::Other(Rc::new(DirectPropertySetterBindingInstance)),
193 is_setter: false,
194 }
195 }
196 }
197
198 fn set_binding_base(
199 &self,
200 property: &'static FerroProperty,
201 instance: &Rc<StyleInstance>,
202 target: &StyledElement,
203 binding: Rc<dyn BindingBase>,
204 ) -> SetterInstance {
205 if !property.is_direct() {
206 let expression = binding.create_instance(target, Some(property), None);
210 let owner: &crate::FerroObject = target;
211 let frame: &dyn ValueFrame = &**instance;
212 expression.attach(SinkRef::Store(owner.to_weak()), None, owner, property, frame.base().priority());
213 let entry: Rc<dyn IValueEntry> = expression;
214 SetterInstance { kind: SetterInstanceKind::Entry(entry), is_setter: false }
215 } else {
216 target.bind_binding(property, &*binding);
217 SetterInstance {
218 kind: SetterInstanceKind::Other(Rc::new(DirectPropertySetterBindingInstance)),
219 is_setter: false,
220 }
221 }
222 }
223
224 fn set_direct_value(&self, property: &'static FerroProperty, target: &StyledElement, value: &BoxedValue) -> SetterInstance {
225 let value: &dyn AnyValue = &**value;
226 target.set_value_untyped(property, value.as_any(), BindingPriority::LocalValue);
227 let direct: Rc<dyn ISetterInstance> =
228 self.direct.get_or_init(|| Rc::new(DirectPropertySetterInstance)).clone();
229 SetterInstance { kind: SetterInstanceKind::Other(direct), is_setter: false }
232 }
233}
234
235impl ISetterInstance for Setter {}
236
237impl SetterBase for Setter {
238 fn as_any(&self) -> Option<&dyn Any> {
239 Some(self)
240 }
241
242 fn instance(self: Rc<Self>, instance: &Rc<StyleInstance>, target: &StyledElement) -> SetterInstance {
243 let Some(property) = self.property.get() else {
244 panic!("Setter.Property must be set.");
245 };
246
247 if self.target.borrow().is_some() {
248 panic!(
249 "Setter.Target is only valid in a visual state, not in '{}'.",
250 instance.source_display()
251 );
252 }
253
254 if property.is_direct() && instance.has_activator() {
255 panic!(
256 "Cannot set direct property '{}' in '{}' because the style has an activator.",
257 property,
258 instance.source_display()
259 );
260 }
261
262 if instance.has_activator() {
263 if let Some(class_property_name) = crate::ClassBindingManager::is_classes_binding_property(property) {
264 panic!(
265 "Cannot set Class Binding property '(Classes.{})' in '{}' because the style has an activator.",
266 class_property_name,
267 instance.source_display()
268 );
269 }
270 }
271
272 let value = self.value.borrow().clone();
273 match value {
274 Some(SetterValue::Binding(source)) => self.set_binding(property, instance, target, source),
275 Some(SetterValue::BindingBase(binding)) => self.set_binding_base(property, instance, target, binding),
276 Some(SetterValue::Template(template)) => SetterInstance {
277 kind: SetterInstanceKind::Entry(Rc::new(PropertySetterTemplateInstance::new(property, template))),
278 is_setter: false,
279 },
280 Some(SetterValue::Value(value)) => {
281 let inner: &dyn AnyValue = &*value;
282 if !property.is_valid_value(inner.as_any()) {
283 panic!("Setter value '{:?}' is not a valid value for property '{}'.", inner, property);
284 }
285 if property.is_direct() {
286 self.set_direct_value(property, target, &value)
287 } else {
288 SetterInstance { kind: SetterInstanceKind::Entry(self), is_setter: true }
289 }
290 }
291 None => match Self::null_value(property) {
294 Some(null) if property.is_direct() => self.set_direct_value(property, target, &null),
295 Some(_) => SetterInstance { kind: SetterInstanceKind::Entry(self), is_setter: true },
296 None => panic!("Setter value '(null)' is not a valid value for property '{}'.", property),
297 },
298 }
299 }
300}
301
302impl IValueEntry for Setter {
303 fn property(&self) -> &'static FerroProperty {
304 self.ensure_property()
305 }
306
307 fn has_value(&self) -> bool {
308 true
309 }
310
311 fn try_get_value(&self, out: &mut dyn Any) -> bool {
312 match self.plain_value() {
313 Some(value) => {
314 let value: &dyn AnyValue = &*value;
315 self.ensure_property().routes().route_copy_value(value.as_any(), out)
316 }
317 None => false,
318 }
319 }
320
321 fn get_value_boxed(&self) -> Option<BoxedValue> {
322 self.plain_value()
323 }
324
325 fn unsubscribe(&self) {}
326}
327
328impl fmt::Display for Setter {
329 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
330 let property = self.property.get().map(|p| p.name().to_string()).unwrap_or_default();
331 match &*self.value.borrow() {
332 Some(SetterValue::Value(value)) => write!(f, "Setter: {property} = {:?}", &**value),
333 Some(SetterValue::Binding(_)) | Some(SetterValue::BindingBase(_)) => {
334 write!(f, "Setter: {property} = (binding)")
335 }
336 Some(SetterValue::Template(_)) => write!(f, "Setter: {property} = (template)"),
337 None => write!(f, "Setter: {property} = "),
338 }
339 }
340}