pushrod/layouts/
vertical_layout.rs

1// Pushrod Rendering Library
2// Vertical Layout Manager
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::render::layout::{Layout, LayoutPosition};
17use crate::render::widget_cache::WidgetContainer;
18use crate::render::widget_config::{PaddingConstraint, CONFIG_ORIGIN, CONFIG_SIZE};
19use crate::render::{Points, Size, SIZE_HEIGHT, SIZE_WIDTH};
20
21/// This is the `VerticalLayout` storage structure for the `VerticalLayout` implementation.
22pub struct VerticalLayout {
23    widget_ids: Vec<i32>,
24    widget_positions: Vec<LayoutPosition>,
25    origin: Points,
26    size: Size,
27    padding: PaddingConstraint,
28    invalidated: bool,
29}
30
31/// Creates a new `VerticalLayout` manager.
32impl VerticalLayout {
33    pub fn new(x: i32, y: i32, w: u32, h: u32, padding: PaddingConstraint) -> Self {
34        Self {
35            widget_ids: Vec::new(),
36            widget_positions: Vec::new(),
37            origin: vec![x, y],
38            size: vec![w, h],
39            padding,
40            invalidated: false,
41        }
42    }
43}
44
45/// This is the `Layout` implementation for the `VerticalLayout` manager.  This `Layout` manager will
46/// not reposition any objects within the bounds of the `Layout` until at least 2 objects have been
47/// added to the bounds of the `Layout`.
48impl Layout for VerticalLayout {
49    /// Adds a widget to the `VerticalLayout` managed stack.
50    fn insert_widget(&mut self, widget_id: i32, widget_position: LayoutPosition) {
51        self.widget_ids.push(widget_id);
52        self.widget_positions.push(widget_position);
53        self.invalidated = true;
54    }
55
56    /// Appends a widget to the `VerticalLayout` managed stack.
57    fn append_widget(&mut self, widget_id: i32) {
58        let positions = self.widget_positions.len();
59        let widget_position = if self.widget_positions.is_empty() {
60            LayoutPosition::new(0, 0)
61        } else {
62            LayoutPosition::new(self.widget_positions[positions - 1].x + 1, 0)
63        };
64
65        self.insert_widget(widget_id, widget_position);
66    }
67
68    fn set_padding(&mut self, padding: PaddingConstraint) {
69        self.padding = padding;
70        self.invalidated = true;
71    }
72
73    fn get_padding(&self) -> PaddingConstraint {
74        self.padding
75    }
76
77    /// Adjusts the layout of the `Widget`s managed by this `Layout` manager.  Currently only obeys
78    /// the spacing in the object.  The rest of the padding is not (yet) honored.
79    fn do_layout(&mut self, _widgets: &[WidgetContainer]) {
80        if self.widget_ids.len() <= 1 {
81            return;
82        }
83
84        let offset_x: i32 = self.origin[0];
85        let offset_y: i32 = self.origin[1];
86        let num_widgets = self.widget_ids.len() as u32;
87        let widget_height = self.size[SIZE_HEIGHT] / num_widgets as u32;
88        let subtractor_bottom = ((self.padding.spacing as f64 / 2.0).ceil()) as u32;
89        let subtractor_top = ((self.padding.spacing as f64 / 2.0).floor()) as u32;
90
91        for i in 0..num_widgets {
92            let set_y: i32;
93            let mut set_height: u32 = widget_height;
94            let widget_id = self.widget_ids[i as usize];
95
96            if i == 0 {
97                set_y = (i * set_height) as i32 + self.padding.top;
98                set_height = widget_height - subtractor_bottom - self.padding.top as u32;
99            } else if i == num_widgets - 1 {
100                set_y = (i * set_height) as i32 + subtractor_top as i32;
101                set_height = widget_height - subtractor_top - self.padding.bottom as u32;
102            } else {
103                set_y = (i * set_height) as i32 + subtractor_top as i32;
104                set_height = widget_height - subtractor_top - subtractor_bottom;
105            }
106
107            _widgets[widget_id as usize]
108                .widget
109                .borrow_mut()
110                .get_config()
111                .set_point(
112                    CONFIG_ORIGIN,
113                    offset_x + self.padding.left,
114                    offset_y + set_y,
115                );
116
117            _widgets[widget_id as usize]
118                .widget
119                .borrow_mut()
120                .get_config()
121                .set_size(
122                    CONFIG_SIZE,
123                    self.size[SIZE_WIDTH] - self.padding.right as u32 - self.padding.left as u32,
124                    set_height,
125                );
126
127            _widgets[widget_id as usize]
128                .widget
129                .borrow_mut()
130                .get_config()
131                .set_invalidated(true);
132        }
133
134        self.invalidated = false;
135    }
136
137    fn needs_layout(&self) -> bool {
138        self.invalidated
139    }
140}