ferroui_controls/
canvas.rs1use crate::{Control, ControlImpl, Panel, PanelImpl};
2use ferroui_base::input::{INavigableContainer, InputElement, InputElementImpl, NavigationDirection};
3use ferroui_base::interactivity::InteractiveImpl;
4use ferroui_base::layout::LayoutableImpl;
5use ferroui_base::{
6 ferro_class, ferro_impl_classes, ferro_property, instantiate, AttachedProperty, FerroObject, FerroObjectImpl, FerroProperty, Point, Rect, Ref, Size, StyledElementImpl, Visual, VisualImpl,
7};
8
9#[repr(C)]
16pub struct Canvas {
17 base: Panel,
18}
19
20ferro_class! {
21 Canvas: Panel, virtuals CanvasImpl: PanelImpl {
22 fn arrange_child(this, child: &Ref<Control>, final_size: Size);
24 }
25}
26ferroui_base::ferro_class_info!(Canvas { new: Canvas::new });
27
28ferro_impl_classes!(Canvas: StyledElementImpl, VisualImpl, InteractiveImpl, InputElementImpl, ControlImpl, PanelImpl);
29
30ferroui_base::ferro_impl_classes!(Canvas: FerroObjectImpl);
31
32impl LayoutableImpl for Canvas {
33 fn measure_override(this: &Self, _available_size: Size) -> Size {
34 let available_size = Size::new(f64::INFINITY, f64::INFINITY);
35
36 for child in this.children().snapshot().iter() {
37 child.measure(available_size);
38 }
39
40 Size::default()
41 }
42
43 fn arrange_override(this: &Self, final_size: Size) -> Size {
44 for child in this.children().snapshot().iter() {
45 this.arrange_child(child, final_size);
46 }
47
48 final_size
49 }
50}
51
52impl CanvasImpl for Canvas {
53 fn arrange_child(_this: &Self, child: &Ref<Control>, final_size: Size) {
54 let mut x = 0.0;
55 let mut y = 0.0;
56 let element_left = Self::get_left(child);
57
58 if !element_left.is_nan() {
59 x = element_left;
60 } else {
61 let element_right = Self::get_right(child);
63 if !element_right.is_nan() {
64 x = final_size.width - child.desired_size().width - element_right;
65 }
66 }
67
68 let element_top = Self::get_top(child);
69 if !element_top.is_nan() {
70 y = element_top;
71 } else {
72 let element_bottom = Self::get_bottom(child);
73 if !element_bottom.is_nan() {
74 y = final_size.height - child.desired_size().height - element_bottom;
75 }
76 }
77
78 child.arrange(Rect::from_position_size(Point::new(x, y), child.desired_size()));
79 }
80}
81
82ferroui_base::ferro_properties! { impl Canvas {
83 ferro_property!(
84 pub fn left_property() -> AttachedProperty<f64> {
86 FerroProperty::register_attached::<Canvas, Control, _>("Left", f64::NAN)
87 }
88 );
89
90 ferro_property!(
91 pub fn top_property() -> AttachedProperty<f64> {
93 FerroProperty::register_attached::<Canvas, Control, _>("Top", f64::NAN)
94 }
95 );
96
97 ferro_property!(
98 pub fn right_property() -> AttachedProperty<f64> {
100 FerroProperty::register_attached::<Canvas, Control, _>("Right", f64::NAN)
101 }
102 );
103
104 ferro_property!(
105 pub fn bottom_property() -> AttachedProperty<f64> {
107 FerroProperty::register_attached::<Canvas, Control, _>("Bottom", f64::NAN)
108 }
109 );
110} }
111
112impl Canvas {
113 fn static_constructor() {
114 Visual::clip_to_bounds_property().override_default_value::<Canvas>(false);
115 Panel::affects_parent_arrange::<Canvas>(&[
116 Self::left_property().as_property(),
117 Self::top_property().as_property(),
118 Self::right_property().as_property(),
119 Self::bottom_property().as_property(),
120 ]);
121 }
122
123 pub fn construct() -> Self {
125 Self { base: Panel::construct() }
126 }
127
128 pub fn new() -> Ref<Self> {
129 instantiate(Self::construct())
130 }
131
132 pub fn get_left(element: &FerroObject) -> f64 {
134 element.get_value(Self::left_property())
135 }
136
137 pub fn set_left(element: &FerroObject, value: f64) {
139 element.set_value(Self::left_property(), value)
140 }
141
142 pub fn get_top(element: &FerroObject) -> f64 {
144 element.get_value(Self::top_property())
145 }
146
147 pub fn set_top(element: &FerroObject, value: f64) {
149 element.set_value(Self::top_property(), value)
150 }
151
152 pub fn get_right(element: &FerroObject) -> f64 {
154 element.get_value(Self::right_property())
155 }
156
157 pub fn set_right(element: &FerroObject, value: f64) {
159 element.set_value(Self::right_property(), value)
160 }
161
162 pub fn get_bottom(element: &FerroObject) -> f64 {
164 element.get_value(Self::bottom_property())
165 }
166
167 pub fn set_bottom(element: &FerroObject, value: f64) {
169 element.set_value(Self::bottom_property(), value)
170 }
171}
172
173impl INavigableContainer for Canvas {
174 fn get_control(
176 &self,
177 _direction: NavigationDirection,
178 _from: Option<&Ref<InputElement>>,
179 _wrap: bool,
180 ) -> Option<Ref<InputElement>> {
181 None
183 }
184}