damascene_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 fill_width(mut self) -> Self {
44 self.width = Size::Fill(1.0);
45 self.explicit_width = true;
46 self
47 }
48
49 pub fn fill_height(mut self) -> Self {
53 self.height = Size::Fill(1.0);
54 self.explicit_height = true;
55 self
56 }
57
58 pub fn min_width(mut self, w: f32) -> Self {
63 self.min_width = Some(w);
64 self
65 }
66
67 pub fn max_width(mut self, w: f32) -> Self {
70 self.max_width = Some(w);
71 self
72 }
73
74 pub fn min_height(mut self, h: f32) -> Self {
77 self.min_height = Some(h);
78 self
79 }
80
81 pub fn max_height(mut self, h: f32) -> Self {
84 self.max_height = Some(h);
85 self
86 }
87
88 pub fn size(mut self, size: ComponentSize) -> Self {
90 self.component_size = Some(size);
91 self
92 }
93
94 pub fn medium(self) -> Self {
95 self.size(ComponentSize::Md)
96 }
97
98 pub fn large(self) -> Self {
99 self.size(ComponentSize::Lg)
100 }
101
102 pub fn metrics_role(mut self, role: MetricsRole) -> Self {
104 self.metrics_role = Some(role);
105 self
106 }
107
108 pub fn padding(mut self, p: impl Into<Sides>) -> Self {
110 self.padding = p.into();
111 self.explicit_padding = true;
112 self
113 }
114
115 pub fn pt(mut self, v: f32) -> Self {
121 self.padding.top = v;
122 self.explicit_padding = true;
123 self
124 }
125
126 pub fn pb(mut self, v: f32) -> Self {
129 self.padding.bottom = v;
130 self.explicit_padding = true;
131 self
132 }
133
134 pub fn pl(mut self, v: f32) -> Self {
137 self.padding.left = v;
138 self.explicit_padding = true;
139 self
140 }
141
142 pub fn pr(mut self, v: f32) -> Self {
145 self.padding.right = v;
146 self.explicit_padding = true;
147 self
148 }
149
150 pub fn px(mut self, v: f32) -> Self {
154 self.padding.left = v;
155 self.padding.right = v;
156 self.explicit_padding = true;
157 self
158 }
159
160 pub fn py(mut self, v: f32) -> Self {
164 self.padding.top = v;
165 self.padding.bottom = v;
166 self.explicit_padding = true;
167 self
168 }
169
170 pub fn gap(mut self, g: f32) -> Self {
171 self.gap = g;
172 self.explicit_gap = true;
173 self
174 }
175
176 pub fn align(mut self, a: Align) -> Self {
177 self.align = a;
178 self
179 }
180
181 pub fn justify(mut self, j: Justify) -> Self {
182 self.justify = j;
183 self
184 }
185
186 pub fn clip(mut self) -> Self {
187 self.clip = true;
188 self
189 }
190
191 pub fn scrollable(mut self) -> Self {
192 self.scrollable = true;
193 self
194 }
195
196 pub fn scrollbar(mut self) -> Self {
199 self.scrollbar = true;
200 self
201 }
202
203 pub fn no_scrollbar(mut self) -> Self {
205 self.scrollbar = false;
206 self
207 }
208
209 pub fn pin_end(mut self) -> Self {
222 self.pin_policy = crate::tree::PinPolicy::End;
223 self
224 }
225
226 pub fn pin_start(mut self) -> Self {
241 self.pin_policy = crate::tree::PinPolicy::Start;
242 self
243 }
244
245 pub fn virtual_anchor_policy(mut self, policy: VirtualAnchorPolicy) -> Self {
248 if let Some(items) = self.virtual_items.take() {
249 self.virtual_items = Some(items.anchor_policy(policy));
250 }
251 self
252 }
253
254 pub fn arrow_nav_siblings(mut self) -> Self {
257 self.arrow_nav_siblings = true;
258 self
259 }
260
261 pub fn layout<F>(mut self, f: F) -> Self
264 where
265 F: Fn(LayoutCtx) -> Vec<Rect> + Send + Sync + 'static,
266 {
267 self.layout_override = Some(LayoutFn::new(f));
268 self
269 }
270
271 pub fn child(mut self, c: impl Into<El>) -> Self {
273 self.children.push(c.into());
274 self
275 }
276
277 pub fn children<I, E>(mut self, cs: I) -> Self
278 where
279 I: IntoIterator<Item = E>,
280 E: Into<El>,
281 {
282 self.children.extend(cs.into_iter().map(Into::into));
283 self
284 }
285
286 pub fn axis(mut self, a: Axis) -> Self {
288 self.axis = a;
289 self
290 }
291
292 pub(crate) fn default_width(mut self, w: Size) -> Self {
294 self.width = w;
295 self.explicit_width = false;
296 self
297 }
298
299 pub(crate) fn default_height(mut self, h: Size) -> Self {
300 self.height = h;
301 self.explicit_height = false;
302 self
303 }
304
305 pub(crate) fn default_padding(mut self, p: impl Into<Sides>) -> Self {
306 self.padding = p.into();
307 self.explicit_padding = false;
308 self
309 }
310
311 pub(crate) fn default_gap(mut self, g: f32) -> Self {
312 self.gap = g;
313 self.explicit_gap = false;
314 self
315 }
316}
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321 use crate::tree::Kind;
322
323 fn fresh() -> El {
324 El::new(Kind::Group)
325 }
326
327 #[test]
328 fn pt_sets_only_top_and_marks_explicit() {
329 let el = fresh().pt(7.0);
330 assert_eq!(
331 el.padding,
332 Sides {
333 left: 0.0,
334 right: 0.0,
335 top: 7.0,
336 bottom: 0.0
337 }
338 );
339 assert!(el.explicit_padding);
340 }
341
342 #[test]
343 fn px_py_set_only_their_axis() {
344 let el = fresh().px(4.0).py(2.0);
345 assert_eq!(
346 el.padding,
347 Sides {
348 left: 4.0,
349 right: 4.0,
350 top: 2.0,
351 bottom: 2.0
352 }
353 );
354 assert!(el.explicit_padding);
355 }
356
357 #[test]
358 fn pt_overrides_only_top_when_following_padding() {
359 let el = fresh().padding(4.0).pt(0.0);
361 assert_eq!(
362 el.padding,
363 Sides {
364 left: 4.0,
365 right: 4.0,
366 top: 0.0,
367 bottom: 4.0
368 }
369 );
370 assert!(el.explicit_padding);
371 }
372
373 #[test]
374 fn pt_after_default_padding_preserves_other_sides_and_marks_explicit() {
375 let el = fresh().default_padding(4.0).pt(0.0);
379 assert_eq!(
380 el.padding,
381 Sides {
382 left: 4.0,
383 right: 4.0,
384 top: 0.0,
385 bottom: 4.0
386 }
387 );
388 assert!(el.explicit_padding);
389 }
390
391 #[test]
392 fn per_side_chainables_compose() {
393 let el = fresh().pl(1.0).pr(2.0).pt(3.0).pb(4.0);
394 assert_eq!(
395 el.padding,
396 Sides {
397 left: 1.0,
398 right: 2.0,
399 top: 3.0,
400 bottom: 4.0
401 }
402 );
403 assert!(el.explicit_padding);
404 }
405
406 #[test]
407 fn fill_width_sets_only_width_to_fill_one() {
408 let el = fresh().fill_width();
409 assert_eq!(el.width, Size::Fill(1.0));
410 assert!(el.explicit_width);
411 assert!(!el.explicit_height);
412 }
413
414 #[test]
415 fn fill_height_sets_only_height_to_fill_one() {
416 let el = fresh().fill_height();
417 assert_eq!(el.height, Size::Fill(1.0));
418 assert!(el.explicit_height);
419 assert!(!el.explicit_width);
420 }
421
422 #[test]
423 fn fill_width_and_fill_height_compose_to_fill_size() {
424 let combined = fresh().fill_width().fill_height();
425 let either = fresh().fill_size();
426 assert_eq!(combined.width, either.width);
427 assert_eq!(combined.height, either.height);
428 assert_eq!(combined.explicit_width, either.explicit_width);
429 assert_eq!(combined.explicit_height, either.explicit_height);
430 }
431
432 #[test]
433 fn sides_x_and_y_constructors_only_populate_one_axis() {
434 assert_eq!(
435 Sides::x(5.0),
436 Sides {
437 left: 5.0,
438 right: 5.0,
439 top: 0.0,
440 bottom: 0.0
441 }
442 );
443 assert_eq!(
444 Sides::y(5.0),
445 Sides {
446 left: 0.0,
447 right: 0.0,
448 top: 5.0,
449 bottom: 5.0
450 }
451 );
452 }
453}