1mod limits;
3mod node;
4
5pub mod flex;
6
7pub use limits::Limits;
8pub use node::Node;
9
10use crate::{Length, Padding, Point, Rectangle, Size, Vector};
11
12#[derive(Debug, Clone, Copy)]
14pub struct Layout<'a> {
15 position: Point,
16 node: &'a Node,
17}
18
19impl<'a> Layout<'a> {
20 pub fn new(node: &'a Node) -> Self {
22 Self::with_offset(Vector::new(0.0, 0.0), node)
23 }
24
25 pub fn with_offset(offset: Vector, node: &'a Node) -> Self {
28 let bounds = node.bounds();
29
30 Self {
31 position: Point::new(bounds.x, bounds.y) + offset,
32 node,
33 }
34 }
35
36 pub fn position(&self) -> Point {
38 self.position
39 }
40
41 pub fn bounds(&self) -> Rectangle {
46 let bounds = self.node.bounds();
47
48 Rectangle {
49 x: self.position.x,
50 y: self.position.y,
51 width: bounds.width,
52 height: bounds.height,
53 }
54 }
55
56 pub fn children(
58 self,
59 ) -> impl DoubleEndedIterator<Item = Layout<'a>> + ExactSizeIterator {
60 self.node.children().iter().map(move |node| {
61 Layout::with_offset(
62 Vector::new(self.position.x, self.position.y),
63 node,
64 )
65 })
66 }
67
68 pub fn child(self, index: usize) -> Layout<'a> {
76 let node = &self.node.children()[index];
77
78 Layout::with_offset(Vector::new(self.position.x, self.position.y), node)
79 }
80}
81
82pub fn next_to_each_other(
84 limits: &Limits,
85 spacing: f32,
86 left: impl FnOnce(&Limits) -> Node,
87 right: impl FnOnce(&Limits) -> Node,
88) -> Node {
89 let left_node = left(limits);
90 let left_size = left_node.size();
91
92 let right_limits = limits.shrink(Size::new(left_size.width + spacing, 0.0));
93
94 let right_node = right(&right_limits);
95 let right_size = right_node.size();
96
97 let (left_y, right_y) = if left_size.height > right_size.height {
98 (0.0, (left_size.height - right_size.height) / 2.0)
99 } else {
100 ((right_size.height - left_size.height) / 2.0, 0.0)
101 };
102
103 Node::with_children(
104 Size::new(
105 left_size.width + spacing + right_size.width,
106 left_size.height.max(right_size.height),
107 ),
108 vec![
109 left_node.move_to(Point::new(0.0, left_y)),
110 right_node.move_to(Point::new(left_size.width + spacing, right_y)),
111 ],
112 )
113}
114
115pub fn atomic(
118 limits: &Limits,
119 width: impl Into<Length>,
120 height: impl Into<Length>,
121) -> Node {
122 let width = width.into();
123 let height = height.into();
124
125 Node::new(limits.resolve(width, height, Size::ZERO))
126}
127
128pub fn sized(
132 limits: &Limits,
133 width: impl Into<Length>,
134 height: impl Into<Length>,
135 f: impl FnOnce(&Limits) -> Size,
136) -> Node {
137 let width = width.into();
138 let height = height.into();
139
140 let limits = limits.width(width).height(height);
141 let intrinsic_size = f(&limits);
142
143 Node::new(limits.resolve(width, height, intrinsic_size))
144}
145
146pub fn contained(
150 limits: &Limits,
151 width: impl Into<Length>,
152 height: impl Into<Length>,
153 f: impl FnOnce(&Limits) -> Node,
154) -> Node {
155 let width = width.into();
156 let height = height.into();
157
158 let limits = limits.width(width).height(height);
159 let content = f(&limits);
160
161 Node::with_children(
162 limits.resolve(width, height, content.size()),
163 vec![content],
164 )
165}
166
167pub fn padded(
171 limits: &Limits,
172 width: impl Into<Length>,
173 height: impl Into<Length>,
174 padding: impl Into<Padding>,
175 layout: impl FnOnce(&Limits) -> Node,
176) -> Node {
177 positioned(limits, width, height, padding, layout, |content, _| content)
178}
179
180pub fn positioned(
182 limits: &Limits,
183 width: impl Into<Length>,
184 height: impl Into<Length>,
185 padding: impl Into<Padding>,
186 layout: impl FnOnce(&Limits) -> Node,
187 position: impl FnOnce(Node, Size) -> Node,
188) -> Node {
189 let width = width.into();
190 let height = height.into();
191 let padding = padding.into();
192
193 let limits = limits.width(width).height(height);
194 let content = layout(&limits.shrink(padding));
195 let padding = padding.fit(content.size(), limits.max());
196
197 let size = limits
198 .shrink(padding)
199 .resolve(width, height, content.size());
200
201 Node::with_children(
202 size.expand(padding),
203 vec![position(content.move_to((padding.left, padding.top)), size)],
204 )
205}