aetna_core/tree/
layout_modifiers.rs1use crate::layout::{LayoutCtx, LayoutFn, VirtualAnchorPolicy};
4use crate::metrics::{ComponentSize, MetricsRole};
5
6use super::geometry::{Rect, Sides};
7use super::layout_types::{Align, Axis, Justify, Size};
8use super::node::El;
9
10impl El {
11 pub fn width(mut self, w: Size) -> Self {
13 self.width = w;
14 self.explicit_width = true;
15 self
16 }
17
18 pub fn height(mut self, h: Size) -> Self {
19 self.height = h;
20 self.explicit_height = true;
21 self
22 }
23
24 pub fn hug(mut self) -> Self {
25 self.width = Size::Hug;
26 self.height = Size::Hug;
27 self.explicit_width = true;
28 self.explicit_height = true;
29 self
30 }
31
32 pub fn fill_size(mut self) -> Self {
33 self.width = Size::Fill(1.0);
34 self.height = Size::Fill(1.0);
35 self.explicit_width = true;
36 self.explicit_height = true;
37 self
38 }
39
40 pub fn size(mut self, size: ComponentSize) -> Self {
42 self.component_size = Some(size);
43 self
44 }
45
46 pub fn medium(self) -> Self {
47 self.size(ComponentSize::Md)
48 }
49
50 pub fn large(self) -> Self {
51 self.size(ComponentSize::Lg)
52 }
53
54 pub fn metrics_role(mut self, role: MetricsRole) -> Self {
56 self.metrics_role = Some(role);
57 self
58 }
59
60 pub fn padding(mut self, p: impl Into<Sides>) -> Self {
62 self.padding = p.into();
63 self.explicit_padding = true;
64 self
65 }
66
67 pub fn pt(mut self, v: f32) -> Self {
73 self.padding.top = v;
74 self.explicit_padding = true;
75 self
76 }
77
78 pub fn pb(mut self, v: f32) -> Self {
81 self.padding.bottom = v;
82 self.explicit_padding = true;
83 self
84 }
85
86 pub fn pl(mut self, v: f32) -> Self {
89 self.padding.left = v;
90 self.explicit_padding = true;
91 self
92 }
93
94 pub fn pr(mut self, v: f32) -> Self {
97 self.padding.right = v;
98 self.explicit_padding = true;
99 self
100 }
101
102 pub fn px(mut self, v: f32) -> Self {
106 self.padding.left = v;
107 self.padding.right = v;
108 self.explicit_padding = true;
109 self
110 }
111
112 pub fn py(mut self, v: f32) -> Self {
116 self.padding.top = v;
117 self.padding.bottom = v;
118 self.explicit_padding = true;
119 self
120 }
121
122 pub fn gap(mut self, g: f32) -> Self {
123 self.gap = g;
124 self.explicit_gap = true;
125 self
126 }
127
128 pub fn align(mut self, a: Align) -> Self {
129 self.align = a;
130 self
131 }
132
133 pub fn justify(mut self, j: Justify) -> Self {
134 self.justify = j;
135 self
136 }
137
138 pub fn clip(mut self) -> Self {
139 self.clip = true;
140 self
141 }
142
143 pub fn scrollable(mut self) -> Self {
144 self.scrollable = true;
145 self
146 }
147
148 pub fn scrollbar(mut self) -> Self {
151 self.scrollbar = true;
152 self
153 }
154
155 pub fn no_scrollbar(mut self) -> Self {
157 self.scrollbar = false;
158 self
159 }
160
161 pub fn pin_end(mut self) -> Self {
174 self.pin_end = true;
175 self
176 }
177
178 pub fn virtual_anchor_policy(mut self, policy: VirtualAnchorPolicy) -> Self {
181 if let Some(items) = self.virtual_items.take() {
182 self.virtual_items = Some(items.anchor_policy(policy));
183 }
184 self
185 }
186
187 pub fn arrow_nav_siblings(mut self) -> Self {
190 self.arrow_nav_siblings = true;
191 self
192 }
193
194 pub fn layout<F>(mut self, f: F) -> Self
197 where
198 F: Fn(LayoutCtx) -> Vec<Rect> + Send + Sync + 'static,
199 {
200 self.layout_override = Some(LayoutFn::new(f));
201 self
202 }
203
204 pub fn child(mut self, c: impl Into<El>) -> Self {
206 self.children.push(c.into());
207 self
208 }
209
210 pub fn children<I, E>(mut self, cs: I) -> Self
211 where
212 I: IntoIterator<Item = E>,
213 E: Into<El>,
214 {
215 self.children.extend(cs.into_iter().map(Into::into));
216 self
217 }
218
219 pub fn axis(mut self, a: Axis) -> Self {
221 self.axis = a;
222 self
223 }
224
225 pub(crate) fn default_width(mut self, w: Size) -> Self {
227 self.width = w;
228 self.explicit_width = false;
229 self
230 }
231
232 pub(crate) fn default_height(mut self, h: Size) -> Self {
233 self.height = h;
234 self.explicit_height = false;
235 self
236 }
237
238 pub(crate) fn default_padding(mut self, p: impl Into<Sides>) -> Self {
239 self.padding = p.into();
240 self.explicit_padding = false;
241 self
242 }
243
244 pub(crate) fn default_gap(mut self, g: f32) -> Self {
245 self.gap = g;
246 self.explicit_gap = false;
247 self
248 }
249}
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254 use crate::tree::Kind;
255
256 fn fresh() -> El {
257 El::new(Kind::Group)
258 }
259
260 #[test]
261 fn pt_sets_only_top_and_marks_explicit() {
262 let el = fresh().pt(7.0);
263 assert_eq!(
264 el.padding,
265 Sides {
266 left: 0.0,
267 right: 0.0,
268 top: 7.0,
269 bottom: 0.0
270 }
271 );
272 assert!(el.explicit_padding);
273 }
274
275 #[test]
276 fn px_py_set_only_their_axis() {
277 let el = fresh().px(4.0).py(2.0);
278 assert_eq!(
279 el.padding,
280 Sides {
281 left: 4.0,
282 right: 4.0,
283 top: 2.0,
284 bottom: 2.0
285 }
286 );
287 assert!(el.explicit_padding);
288 }
289
290 #[test]
291 fn pt_overrides_only_top_when_following_padding() {
292 let el = fresh().padding(4.0).pt(0.0);
294 assert_eq!(
295 el.padding,
296 Sides {
297 left: 4.0,
298 right: 4.0,
299 top: 0.0,
300 bottom: 4.0
301 }
302 );
303 assert!(el.explicit_padding);
304 }
305
306 #[test]
307 fn pt_after_default_padding_preserves_other_sides_and_marks_explicit() {
308 let el = fresh().default_padding(4.0).pt(0.0);
312 assert_eq!(
313 el.padding,
314 Sides {
315 left: 4.0,
316 right: 4.0,
317 top: 0.0,
318 bottom: 4.0
319 }
320 );
321 assert!(el.explicit_padding);
322 }
323
324 #[test]
325 fn per_side_chainables_compose() {
326 let el = fresh().pl(1.0).pr(2.0).pt(3.0).pb(4.0);
327 assert_eq!(
328 el.padding,
329 Sides {
330 left: 1.0,
331 right: 2.0,
332 top: 3.0,
333 bottom: 4.0
334 }
335 );
336 assert!(el.explicit_padding);
337 }
338
339 #[test]
340 fn sides_x_and_y_constructors_only_populate_one_axis() {
341 assert_eq!(
342 Sides::x(5.0),
343 Sides {
344 left: 5.0,
345 right: 5.0,
346 top: 0.0,
347 bottom: 0.0
348 }
349 );
350 assert_eq!(
351 Sides::y(5.0),
352 Sides {
353 left: 0.0,
354 right: 0.0,
355 top: 5.0,
356 bottom: 5.0
357 }
358 );
359 }
360}