ferroui_diagnostics/diagnostics/view_models/
setter_view_model.rs1use super::{BindingSetterViewModel, ResourceSetterViewModel, ViewModelBase};
9use ferroui_base::data::core::ValueTypes;
10use ferroui_base::data::model::{Event, INotifyPropertyChanged};
11use ferroui_base::input::platform::{ClipboardExtensions, IClipboard};
12use ferroui_base::threading::Dispatcher;
13use ferroui_base::{ferro_markup_type, BoxedValue, FerroProperty};
14use std::cell::RefCell;
15use std::ops::Deref;
16use std::rc::Rc;
17
18pub struct SetterViewModel {
21 base: ViewModelBase,
22 is_active: RefCell<bool>,
23 is_visible: RefCell<bool>,
24 property: &'static FerroProperty,
25 name: String,
26 value: Option<BoxedValue>,
27 clipboard: Option<Rc<dyn IClipboard>>,
28}
29
30impl PartialEq for SetterViewModel {
31 fn eq(&self, other: &Self) -> bool {
32 std::ptr::eq(self, other)
33 }
34}
35
36impl INotifyPropertyChanged for SetterViewModel {
37 fn property_changed(&self) -> &Event<str> {
38 self.base.property_changed()
39 }
40}
41
42impl SetterViewModel {
43 pub fn new(
44 property: &'static FerroProperty,
45 value: Option<BoxedValue>,
46 clipboard: Option<Rc<dyn IClipboard>>,
47 ) -> Rc<Self> {
48 Rc::new(Self::construct(property, value, clipboard))
49 }
50
51 pub fn construct(
54 property: &'static FerroProperty,
55 value: Option<BoxedValue>,
56 clipboard: Option<Rc<dyn IClipboard>>,
57 ) -> Self {
58 let this = Self {
59 base: ViewModelBase::new(),
60 is_active: RefCell::new(false),
61 is_visible: RefCell::new(false),
62 property,
63 name: property.name().to_string(),
64 value,
65 clipboard,
66 };
67
68 this.set_is_active(true);
69 this.set_is_visible(true);
70
71 this
72 }
73
74 pub fn property(&self) -> &'static FerroProperty {
75 self.property
76 }
77
78 pub fn name(&self) -> String {
79 self.name.clone()
80 }
81
82 pub fn value(&self) -> Option<BoxedValue> {
83 self.value.clone()
84 }
85
86 pub fn is_active(&self) -> bool {
87 *self.is_active.borrow()
88 }
89
90 pub fn set_is_active(&self, value: bool) {
91 self.base.raise_and_set_if_changed(&self.is_active, value, "IsActive");
92 }
93
94 pub fn is_visible(&self) -> bool {
95 *self.is_visible.borrow()
96 }
97
98 pub fn set_is_visible(&self, value: bool) {
99 self.base.raise_and_set_if_changed(&self.is_visible, value, "IsVisible");
100 }
101
102 pub fn copy_value(&self) {
105 let Some(value) = self.value.as_ref() else {
107 return;
108 };
109 let text_to_copy = ValueTypes::to_display_string(Some(value));
110
111 self.copy_to_clipboard(&text_to_copy);
112 }
113
114 pub fn copy_property_name(&self) {
115 self.copy_to_clipboard(self.property.name());
116 }
117
118 pub fn copy_to_clipboard(&self, value: &str) {
121 let Some(clipboard) = self.clipboard.clone() else {
122 return;
123 };
124 let text = value.to_string();
125 let _ = Dispatcher::ui_thread().invoke_async_task_local(move || async move {
126 let _ = clipboard.set_text_async(Some(&text)).await;
127 });
128 }
129}
130
131#[derive(Clone)]
135pub enum SetterViewModelRef {
136 Setter(Rc<SetterViewModel>),
137 Binding(Rc<BindingSetterViewModel>),
138 Resource(Rc<ResourceSetterViewModel>),
139}
140
141impl PartialEq for SetterViewModelRef {
142 fn eq(&self, other: &Self) -> bool {
143 std::ptr::eq::<SetterViewModel>(&**self, &**other)
144 }
145}
146
147impl Deref for SetterViewModelRef {
148 type Target = SetterViewModel;
149
150 fn deref(&self) -> &SetterViewModel {
151 match self {
152 Self::Setter(setter) => setter,
153 Self::Binding(setter) => setter,
154 Self::Resource(setter) => setter,
155 }
156 }
157}
158
159impl SetterViewModelRef {
160 pub fn copy_value(&self) {
162 match self {
163 Self::Setter(setter) => setter.copy_value(),
164 Self::Binding(setter) => setter.copy_value(),
165 Self::Resource(setter) => setter.copy_value(),
166 }
167 }
168
169 pub fn boxed(&self) -> BoxedValue {
172 match self {
173 Self::Setter(setter) => setter.clone(),
174 Self::Binding(setter) => setter.clone(),
175 Self::Resource(setter) => setter.clone(),
176 }
177 }
178
179 pub fn from_boxed(value: &BoxedValue) -> Option<Self> {
181 if let Some(setter) = value.downcast_ref::<Rc<BindingSetterViewModel>>() {
182 return Some(Self::Binding(setter.clone()));
183 }
184 if let Some(setter) = value.downcast_ref::<Rc<ResourceSetterViewModel>>() {
185 return Some(Self::Resource(setter.clone()));
186 }
187 if let Some(setter) = value.downcast_ref::<Rc<SetterViewModel>>() {
188 return Some(Self::Setter(setter.clone()));
189 }
190 let any: Rc<dyn std::any::Any> = value.clone();
192 let any = match any.downcast::<BindingSetterViewModel>() {
193 Ok(setter) => return Some(Self::Binding(setter)),
194 Err(any) => any,
195 };
196 let any = match any.downcast::<ResourceSetterViewModel>() {
197 Ok(setter) => return Some(Self::Resource(setter)),
198 Err(any) => any,
199 };
200 any.downcast::<SetterViewModel>().ok().map(Self::Setter)
201 }
202}
203
204ferro_markup_type!(class SetterViewModel {
205 this: Rc<SetterViewModel>,
206 handles: [SetterViewModel, Rc<SetterViewModel>, Option<Rc<SetterViewModel>>],
207 properties: [
208 Property: &'static FerroProperty { get: SetterViewModel::property },
209 Name: String { get: SetterViewModel::name },
210 Value: Option<BoxedValue> { get: SetterViewModel::value },
211 IsActive: bool { get: SetterViewModel::is_active, set: SetterViewModel::set_is_active },
212 IsVisible: bool { get: SetterViewModel::is_visible, set: SetterViewModel::set_is_visible },
213 ],
214 methods: [
215 fn CopyValue() => SetterViewModel::copy_value,
216 fn CopyPropertyName() => SetterViewModel::copy_property_name,
217 ],
218 notify_property_changed: SetterViewModel,
219});