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 virtual_offset: Vector,
18 position: Point,
19 node: &'a Node,
20}
21
22impl<'a> Layout<'a> {
23 pub fn new(node: &'a Node) -> Self {
25 Self::with_offset(Vector::new(0.0, 0.0), node)
26 }
27
28 pub fn with_offset(offset: Vector, node: &'a Node) -> Self {
31 let bounds = node.bounds();
32
33 Self {
34 virtual_offset: Vector::new(0., 0.),
35 position: Point::new(bounds.x, bounds.y) + offset,
36 node,
37 }
38 }
39
40 pub fn with_virtual_offset(mut self, virtual_offset: Vector) -> Self {
42 self.virtual_offset = virtual_offset;
43 self
44 }
45
46 pub fn position(&self) -> Point {
48 self.position
49 }
50
51 pub fn virtual_offset(&self) -> Vector {
54 self.virtual_offset
55 }
56
57 pub fn bounds(&self) -> Rectangle {
62 let bounds = self.node.bounds();
63
64 Rectangle {
65 x: self.position.x,
66 y: self.position.y,
67 width: bounds.width,
68 height: bounds.height,
69 }
70 }
71
72 pub fn children(self) -> impl DoubleEndedIterator<Item = Layout<'a>> {
74 self.node.children().iter().map(move |node| {
75 Layout::with_offset(
76 Vector::new(self.position.x, self.position.y),
77 node,
78 )
79 })
80 }
81}
82
83pub fn next_to_each_other(
85 limits: &Limits,
86 spacing: f32,
87 left: impl FnOnce(&Limits) -> Node,
88 right: impl FnOnce(&Limits) -> Node,
89) -> Node {
90 let left_node = left(limits);
91 let left_size = left_node.size();
92
93 let right_limits = limits.shrink(Size::new(left_size.width + spacing, 0.0));
94
95 let right_node = right(&right_limits);
96 let right_size = right_node.size();
97
98 let (left_y, right_y) = if left_size.height > right_size.height {
99 (0.0, (left_size.height - right_size.height) / 2.0)
100 } else {
101 ((right_size.height - left_size.height) / 2.0, 0.0)
102 };
103
104 Node::with_children(
105 Size::new(
106 left_size.width + spacing + right_size.width,
107 left_size.height.max(right_size.height),
108 ),
109 vec![
110 left_node.move_to(Point::new(0.0, left_y)),
111 right_node.move_to(Point::new(left_size.width + spacing, right_y)),
112 ],
113 )
114}
115
116pub fn atomic(
119 limits: &Limits,
120 width: impl Into<Length>,
121 height: impl Into<Length>,
122) -> Node {
123 let width = width.into();
124 let height = height.into();
125
126 Node::new(limits.resolve(width, height, Size::ZERO))
127}
128
129pub fn sized(
133 limits: &Limits,
134 width: impl Into<Length>,
135 height: impl Into<Length>,
136 f: impl FnOnce(&Limits) -> Size,
137) -> Node {
138 let width = width.into();
139 let height = height.into();
140
141 let limits = limits.width(width).height(height);
142 let intrinsic_size = f(&limits);
143
144 Node::new(limits.resolve(width, height, intrinsic_size))
145}
146
147pub fn contained(
151 limits: &Limits,
152 width: impl Into<Length>,
153 height: impl Into<Length>,
154 f: impl FnOnce(&Limits) -> Node,
155) -> Node {
156 let width = width.into();
157 let height = height.into();
158
159 let limits = limits.width(width).height(height);
160 let content = f(&limits);
161
162 Node::with_children(
163 limits.resolve(width, height, content.size()),
164 vec![content],
165 )
166}
167
168pub fn padded(
172 limits: &Limits,
173 width: impl Into<Length>,
174 height: impl Into<Length>,
175 padding: impl Into<Padding>,
176 layout: impl FnOnce(&Limits) -> Node,
177) -> Node {
178 positioned(limits, width, height, padding, layout, |content, _| content)
179}
180
181pub fn positioned(
183 limits: &Limits,
184 width: impl Into<Length>,
185 height: impl Into<Length>,
186 padding: impl Into<Padding>,
187 layout: impl FnOnce(&Limits) -> Node,
188 position: impl FnOnce(Node, Size) -> Node,
189) -> Node {
190 let width = width.into();
191 let height = height.into();
192 let padding = padding.into();
193
194 let limits = limits.width(width).height(height);
195 let content = layout(&limits.shrink(padding));
196 let padding = padding.fit(content.size(), limits.max());
197
198 let size = limits
199 .shrink(padding)
200 .resolve(width, height, content.size());
201
202 Node::with_children(
203 size.expand(padding),
204 vec![position(content.move_to((padding.left, padding.top)), size)],
205 )
206}