Skip to main content

ferroui_controls/notifications/
reversible_stack_panel.rs

1use crate::{ControlImpl, PanelImpl, StackPanel, StackPanelImpl};
2use ferroui_base::input::InputElementImpl;
3use ferroui_base::interactivity::InteractiveImpl;
4use ferroui_base::layout::{
5    HorizontalAlignment, LayoutExtensions, Layoutable, LayoutableImpl, Orientation, VerticalAlignment,
6};
7use ferroui_base::{
8    ferro_class, ferro_impl_classes, ferro_property, instantiate, FerroObjectImpl, FerroProperty,
9    Rect, Ref, Size, StyledElementImpl, StyledProperty, VisualImpl,
10};
11
12/// Implements a panel which lays out its children horizontally or vertically
13/// and can reverse the order of its children.
14#[repr(C)]
15pub struct ReversibleStackPanel {
16    base: StackPanel,
17}
18
19ferro_class!(ReversibleStackPanel: StackPanel);
20ferroui_base::ferro_class_info!(ReversibleStackPanel { new: ReversibleStackPanel::new });
21ferro_impl_classes!(
22    ReversibleStackPanel: StyledElementImpl,
23    VisualImpl,
24    InteractiveImpl,
25    InputElementImpl,
26    ControlImpl,
27    PanelImpl,
28    StackPanelImpl
29);
30
31ferroui_base::ferro_impl_classes!(ReversibleStackPanel: FerroObjectImpl);
32
33impl LayoutableImpl for ReversibleStackPanel {
34    fn arrange_override(this: &Self, final_size: Size) -> Size {
35        let orientation = this.orientation();
36        let spacing = this.spacing();
37        let final_rect = Rect::from_size(final_size);
38        let mut pos = 0.0;
39
40        let children = this.children().snapshot();
41        let reverse_order = this.reverse_order();
42
43        for index in 0..children.len() {
44            let child = &children[if reverse_order { children.len() - 1 - index } else { index }];
45
46            if !child.is_visible() {
47                continue;
48            }
49
50            let child_width = child.desired_size().width;
51            let child_height = child.desired_size().height;
52
53            if orientation == Orientation::Vertical {
54                let rect = LayoutExtensions::align(
55                    Rect::new(0.0, pos, child_width, child_height),
56                    final_rect,
57                    child.horizontal_alignment(),
58                    VerticalAlignment::Top,
59                );
60                this.arrange_child(child, rect, final_size, orientation);
61                pos += child_height + spacing;
62            } else {
63                let rect = LayoutExtensions::align(
64                    Rect::new(pos, 0.0, child_width, child_height),
65                    final_rect,
66                    HorizontalAlignment::Left,
67                    child.vertical_alignment(),
68                );
69                this.arrange_child(child, rect, final_size, orientation);
70                pos += child_width + spacing;
71            }
72        }
73
74        final_size
75    }
76}
77
78ferroui_base::ferro_properties! { impl ReversibleStackPanel {
79    ferro_property!(
80        /// Defines the `ReverseOrder` property.
81        pub fn reverse_order_property() -> StyledProperty<bool> {
82            FerroProperty::register::<ReversibleStackPanel, _>("ReverseOrder", false)
83        }
84    );
85} }
86
87impl ReversibleStackPanel {
88    fn static_constructor() {
89        Layoutable::affects_arrange::<ReversibleStackPanel>(&[Self::reverse_order_property().as_property()]);
90    }
91
92    /// Creates the class data; see [`ferroui_base::FerroObject::construct`].
93    pub fn construct() -> Self {
94        Self { base: StackPanel::construct() }
95    }
96
97    pub fn new() -> Ref<Self> {
98        instantiate(Self::construct())
99    }
100
101    /// Whether the order of the children is reversed when they are arranged.
102    pub fn reverse_order(&self) -> bool {
103        self.get_value(Self::reverse_order_property())
104    }
105
106    pub fn set_reverse_order(&self, value: bool) {
107        self.set_value(Self::reverse_order_property(), value)
108    }
109}