ferroui_reactiveui_controls/
reactive_user_control_base.rs1use crate::reactive_view::{IReactiveViewClass, ITypedReactiveViewClass, ReactiveViewFor, ViewModelFilter};
5use crate::view_model_property_sync::ViewModelPropertySync;
6use ferroui_base::input::InputElementImpl;
7use ferroui_base::interactivity::InteractiveImpl;
8use ferroui_base::layout::LayoutableImpl;
9use ferroui_base::{
10 ferro_class, ferro_class_info, ferro_impl_classes, ferro_properties, instantiate, BoxedValue, FerroObjectImpl,
11 FerroObjectImplExt, FerroProperty, FerroPropertyChangedEventArgs, Ref, StyledElementImpl, StyledProperty, VisualImpl,
12};
13use ferroui_controls::primitives::TemplatedControlImpl;
14use ferroui_controls::{ContentControlImpl, ControlImpl, UserControl};
15use ferroui_reactiveui::IViewFor;
16use std::cell::Cell;
17use std::rc::Rc;
18
19#[repr(C)]
29pub struct ReactiveUserControlBase {
30 base: UserControl,
31 view_model_filter: Cell<Option<ViewModelFilter>>,
34}
35
36ferro_class!(ReactiveUserControlBase: UserControl);
37ferro_class_info!(ReactiveUserControlBase { new: ReactiveUserControlBase::new });
38ferro_impl_classes!(
39 ReactiveUserControlBase: StyledElementImpl,
40 VisualImpl,
41 LayoutableImpl,
42 InteractiveImpl,
43 InputElementImpl,
44 ControlImpl,
45 TemplatedControlImpl,
46 ContentControlImpl
47);
48
49impl FerroObjectImpl for ReactiveUserControlBase {
50 fn constructed(this: &Self) {
53 Self::parent_constructed(this);
54 ViewModelPropertySync::forward_activation(&this.to_ref());
55 }
56
57 fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
58 Self::parent_on_property_changed(this, change);
59
60 ViewModelPropertySync::apply(this, change, Self::view_model_property(), |value| {
61 IReactiveViewClass::is_valid_view_model_value(this, value)
62 });
63 }
64}
65
66ferro_properties! {
67 impl ReactiveUserControlBase {
68 pub fn view_model_property() -> StyledProperty<Option<BoxedValue>> {
70 FerroProperty::register::<ReactiveUserControlBase, _>("ViewModel", None)
71 }
72 }
73}
74
75impl ReactiveUserControlBase {
76 pub fn construct() -> Self {
78 Self { base: UserControl::construct(), view_model_filter: Cell::new(None) }
79 }
80
81 pub fn new() -> Ref<Self> {
83 instantiate(Self::construct())
84 }
85
86 pub fn view_model_value(&self) -> Option<BoxedValue> {
88 self.get_value(Self::view_model_property())
89 }
90
91 pub fn set_view_model_value(&self, value: Option<BoxedValue>) {
93 self.set_value(Self::view_model_property(), value)
94 }
95
96 pub fn view_for(this: &Ref<Self>) -> Rc<dyn IViewFor> {
98 ReactiveViewFor::new(this.clone())
99 }
100}
101
102impl IReactiveViewClass for ReactiveUserControlBase {
103 fn view_model_property() -> &'static StyledProperty<Option<BoxedValue>> {
104 ReactiveUserControlBase::view_model_property()
105 }
106
107 fn is_valid_view_model_value(&self, value: Option<&BoxedValue>) -> bool {
109 match (value, self.view_model_filter.get()) {
110 (Some(value), Some(filter)) => filter(value),
111 _ => true,
112 }
113 }
114}
115
116impl ITypedReactiveViewClass for ReactiveUserControlBase {
117 fn create() -> Ref<Self> {
118 Self::new()
119 }
120
121 fn set_view_model_filter(&self, filter: Option<ViewModelFilter>) {
122 self.view_model_filter.set(filter);
123 }
124}