ferroui_controls/
decorator.rs1use crate::{Control, ControlImpl};
2use ferroui_base::input::InputElementImpl;
3use ferroui_base::interactivity::InteractiveImpl;
4use ferroui_base::layout::{LayoutHelper, Layoutable, LayoutableImpl};
5use ferroui_base::{
6 ferro_class, ferro_impl_classes, ferro_property, instantiate, FerroObjectImpl,
7 FerroProperty, FerroPropertyChangedEventArgs, Nullable, Ref, Size, StyledElementImpl, StyledProperty,
8 StyledPropertyOptions, Thickness, VisualImpl,
9};
10
11#[repr(C)]
13pub struct Decorator {
14 base: Control,
15}
16
17ferro_class!(Decorator: Control);
18ferroui_base::ferro_class_info!(Decorator { new: Decorator::new });
19ferro_impl_classes!(Decorator: StyledElementImpl, VisualImpl, InteractiveImpl, InputElementImpl, ControlImpl);
20
21ferroui_base::ferro_impl_classes!(Decorator: FerroObjectImpl);
22
23impl LayoutableImpl for Decorator {
24 fn measure_override(this: &Self, available_size: Size) -> Size {
25 let child = this.child();
26 LayoutHelper::measure_child(child.as_deref().map(|c| -> &Layoutable { c }), available_size, this.padding())
27 }
28
29 fn arrange_override(this: &Self, final_size: Size) -> Size {
30 let child = this.child();
31 LayoutHelper::arrange_child(child.as_deref().map(|c| -> &Layoutable { c }), final_size, this.padding())
32 }
33}
34
35ferroui_base::ferro_properties! { impl Decorator {
36 ferro_property!(
37 pub fn child_property() -> StyledProperty<Option<Ref<Control>>> {
39 FerroProperty::register::<Decorator, _>("Child", None)
40 }
41 );
42
43 ferro_property!(
44 pub fn padding_property() -> StyledProperty<Thickness> {
46 FerroProperty::register_with::<Decorator, _>(
47 "Padding",
48 StyledPropertyOptions::new(Thickness::default())
49 .validate(|value| Layoutable::margin_property().validate_value().is_none_or(|validate| validate(value))),
50 )
51 }
52 );
53} }
54
55impl Decorator {
56 fn static_constructor() {
57 Layoutable::affects_measure::<Decorator>(&[
58 Self::child_property().as_property(),
59 Self::padding_property().as_property(),
60 ]);
61 Self::child_property().changed().add_class_handler::<Decorator>(|x, e| x.child_changed(e));
62 }
63
64 pub fn construct() -> Self {
66 Self { base: Control::construct() }
67 }
68
69 pub fn new() -> Ref<Self> {
70 instantiate(Self::construct())
71 }
72
73 pub fn child(&self) -> Option<Ref<Control>> {
75 self.get_value(Self::child_property())
76 }
77
78 pub fn set_child(&self, value: impl Into<Nullable<Control>>) {
79 self.set_value(Self::child_property(), value.into().0)
80 }
81
82 pub fn padding(&self) -> Thickness {
84 self.get_value(Self::padding_property())
85 }
86
87 pub fn set_padding(&self, value: Thickness) {
88 self.set_value(Self::padding_property(), value)
89 }
90
91 fn child_changed(&self, e: &FerroPropertyChangedEventArgs<'_>) {
93 let (old_child, new_child) = e.get_old_and_new_value::<Option<Ref<Control>>>();
94
95 if let Some(old_child) = old_child {
96 old_child.set_parent(None);
97 self.logical_children().clear();
98 self.visual_children().remove(&old_child.upcast());
99 }
100
101 if let Some(new_child) = new_child {
102 new_child.set_parent(self.to_ref());
103 self.visual_children().add(new_child.clone().upcast());
104 self.logical_children().add(new_child.upcast());
105 }
106 }
107}