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 parent: Option<Rectangle>,
18}
19
20impl<'a> Layout<'a> {
21 pub fn new(node: &'a Node) -> Self {
23 Self::with_offset(Vector::new(0.0, 0.0), node)
24 }
25
26 pub fn with_offset(offset: Vector, node: &'a Node) -> Self {
29 Self {
30 position: node.position() + offset,
31 node,
32 parent: None,
33 }
34 }
35
36 pub fn position(&self) -> Point {
38 self.position
39 }
40
41 pub fn move_to(self, position: impl Into<Point>) -> Self {
43 Self {
44 position: position.into(),
45 node: self.node,
46 parent: self.parent,
47 }
48 }
49
50 pub fn bounds(&self) -> Rectangle {
55 Rectangle::new(self.position, self.node.size())
56 }
57
58 pub fn parent(&self) -> Option<Rectangle> {
60 self.parent
61 }
62
63 pub fn children(self) -> impl DoubleEndedIterator<Item = Layout<'a>> + ExactSizeIterator {
65 let parent = self.bounds();
66 let offset = Vector::new(self.position.x, self.position.y);
67
68 self.node.children().iter().map(move |node| Layout {
69 position: node.position() + offset,
70 node,
71 parent: Some(parent),
72 })
73 }
74
75 pub fn child(self, index: usize) -> Layout<'a> {
83 let node = &self.node.children()[index];
84 let offset = Vector::new(self.position.x, self.position.y);
85
86 Layout {
87 position: node.position() + offset,
88 node,
89 parent: Some(self.bounds()),
90 }
91 }
92}
93
94pub fn next_to_each_other(
96 limits: &Limits,
97 spacing: f32,
98 left: impl FnOnce(&Limits) -> Node,
99 right: impl FnOnce(&Limits) -> Node,
100) -> Node {
101 let left_node = left(limits);
102 let left_size = left_node.size();
103
104 let right_limits = limits.shrink(Size::new(left_size.width + spacing, 0.0));
105
106 let right_node = right(&right_limits);
107 let right_size = right_node.size();
108
109 let (left_y, right_y) = if left_size.height > right_size.height {
110 (0.0, (left_size.height - right_size.height) / 2.0)
111 } else {
112 ((right_size.height - left_size.height) / 2.0, 0.0)
113 };
114
115 Node::with_children(
116 Size::new(
117 left_size.width + spacing + right_size.width,
118 left_size.height.max(right_size.height),
119 ),
120 vec![
121 left_node.move_to(Point::new(0.0, left_y)),
122 right_node.move_to(Point::new(left_size.width + spacing, right_y)),
123 ],
124 )
125}
126
127pub fn atomic(limits: &Limits, width: impl Into<Length>, height: impl Into<Length>) -> Node {
130 let width = width.into();
131 let height = height.into();
132
133 Node::new(
134 limits
135 .width(width)
136 .height(height)
137 .resolve(width, height, Size::ZERO),
138 )
139}
140
141pub fn sized(
145 limits: &Limits,
146 width: impl Into<Length>,
147 height: impl Into<Length>,
148 f: impl FnOnce(&Limits) -> Size,
149) -> Node {
150 let width = width.into();
151 let height = height.into();
152
153 let limits = limits.width(width).height(height);
154 let intrinsic_size = f(&limits);
155
156 Node::new(limits.resolve(width, height, intrinsic_size))
157}
158
159pub fn contained(
163 limits: &Limits,
164 width: impl Into<Length>,
165 height: impl Into<Length>,
166 f: impl FnOnce(&Limits) -> Node,
167) -> Node {
168 let width = width.into();
169 let height = height.into();
170
171 let limits = limits.width(width).height(height);
172 let content = f(&limits);
173
174 Node::with_children(limits.resolve(width, height, content.size()), vec![content])
175}
176
177pub fn padded(
181 limits: &Limits,
182 width: impl Into<Length>,
183 height: impl Into<Length>,
184 padding: impl Into<Padding>,
185 layout: impl FnOnce(&Limits) -> Node,
186) -> Node {
187 positioned(limits, width, height, padding, layout, |content, _| content)
188}
189
190pub fn positioned(
192 limits: &Limits,
193 width: impl Into<Length>,
194 height: impl Into<Length>,
195 padding: impl Into<Padding>,
196 layout: impl FnOnce(&Limits) -> Node,
197 position: impl FnOnce(Node, Size) -> Node,
198) -> Node {
199 let width = width.into();
200 let height = height.into();
201 let padding = padding.into();
202
203 let limits = limits.width(width).height(height);
204 let content = layout(&limits.shrink(padding));
205 let padding = padding.fit(content.size(), limits.max());
206
207 let size = limits
208 .shrink(padding)
209 .resolve(width, height, content.size());
210
211 Node::with_children(
212 size.expand(padding),
213 vec![position(content.move_to((padding.left, padding.top)), size)],
214 )
215}