Skip to main content

ferroui_diagnostics/diagnostics/view_models/
pseudo_class_view_model.rs

1//! Port of `Diagnostics/ViewModels/PseudoClassViewModel.cs`.
2
3use super::ViewModelBase;
4use ferroui_base::controls::{Classes, IPseudoClasses};
5use ferroui_base::data::model::{Event, INotifyPropertyChanged};
6use ferroui_base::{ferro_markup_type, Ref, StyledElement};
7use std::cell::{Cell, RefCell};
8use std::rc::Rc;
9
10/// A pseudo-class a control declares, with whether it is set on the control. Setting
11/// [`is_active`](Self::is_active) sets or clears the pseudo-class on the control.
12pub struct PseudoClassViewModel {
13    base: ViewModelBase,
14    pseudo_classes: Classes,
15    source: Ref<StyledElement>,
16    name: String,
17    is_active: RefCell<bool>,
18    is_updating: Cell<bool>,
19}
20
21impl PartialEq for PseudoClassViewModel {
22    fn eq(&self, other: &Self) -> bool {
23        std::ptr::eq(self, other)
24    }
25}
26
27impl INotifyPropertyChanged for PseudoClassViewModel {
28    fn property_changed(&self) -> &Event<str> {
29        self.base.property_changed()
30    }
31}
32
33impl PseudoClassViewModel {
34    pub fn new(name: &str, source: &StyledElement) -> Rc<Self> {
35        let this = Rc::new(Self {
36            base: ViewModelBase::new(),
37            // `_source.Classes`, as the pseudo-classes of the control.
38            pseudo_classes: source.classes(),
39            source: source.to_ref(),
40            name: name.to_string(),
41            is_active: RefCell::new(false),
42            is_updating: Cell::new(false),
43        });
44
45        this.update();
46
47        this
48    }
49
50    pub fn name(&self) -> String {
51        self.name.clone()
52    }
53
54    pub fn is_active(&self) -> bool {
55        *self.is_active.borrow()
56    }
57
58    pub fn set_is_active(&self, value: bool) {
59        self.base.raise_and_set_if_changed(&self.is_active, value, "IsActive");
60
61        if !self.is_updating.get() {
62            let pseudo_classes: &dyn IPseudoClasses = &self.pseudo_classes;
63            pseudo_classes.set(&self.name, value);
64        }
65    }
66
67    pub fn update(&self) {
68        // `try { .. } finally { _isUpdating = false; }`: nothing in between can fail.
69        self.is_updating.set(true);
70
71        self.set_is_active(self.source.classes().contains(&self.name));
72
73        self.is_updating.set(false);
74    }
75}
76
77ferro_markup_type!(class PseudoClassViewModel {
78    this: Rc<PseudoClassViewModel>,
79    handles: [PseudoClassViewModel, Rc<PseudoClassViewModel>, Option<Rc<PseudoClassViewModel>>],
80    properties: [
81        Name: String { get: PseudoClassViewModel::name },
82        IsActive: bool { get: PseudoClassViewModel::is_active, set: PseudoClassViewModel::set_is_active },
83    ],
84    methods: [
85        fn Update() => PseudoClassViewModel::update,
86    ],
87    notify_property_changed: PseudoClassViewModel,
88});