vizia_core/modifiers/layout.rs
1use super::internal;
2use crate::prelude::*;
3
4/// Modifiers for changing the layout properties of a view.
5pub trait LayoutModifiers: internal::Modifiable {
6 modifier!(
7 /// Sets the layout type of the view.
8 ///
9 /// The layout type controls how a parent will position any children which have `Position::Relative`.
10 /// Accepts any value or signal with a type which can be converted into `LayoutType`.
11 ///
12 /// There are three variants:
13 /// - `LayoutType::Row` - Parent will stack its children horizontally.
14 /// - `LayoutType::Column` - (default) Parent will stack its children vertically.
15 /// - `LayoutType::Grid` - The position of children is determine by the grid properties.
16 ///
17 /// # Example
18 /// ```
19 /// # use vizia_core::prelude::*;
20 /// # let cx = &mut Context::default();
21 /// #[derive(Model, Setter)]
22 /// pub struct AppData {
23 /// layout_type: LayoutType,
24 /// }
25 ///
26 /// # AppData {
27 /// # layout_type: LayoutType::Row,
28 /// # }.build(cx);
29 ///
30 /// Element::new(cx).layout_type(LayoutType::Row); // Value of type `LayoutType`.
31 /// Element::new(cx).layout_type(AppData::layout_type); // signal of type type `LayoutType`.
32 /// ```
33 layout_type,
34 LayoutType,
35 SystemFlags::RELAYOUT
36 );
37
38 modifier!(
39 /// Sets the position type of the view.
40 ///
41 /// The position type determines how a child will be positioned within a parent.
42 ///
43 /// - `Position::Relative` - The child will be positioned relative to its siblings in a stack
44 /// (if parent layout type is `Row` or `Column`), or relative to its grid position (if parent layout type is `Grid`).
45 /// - `Position::Absolute` - The child will be positioned relative to the top-left corner of its parents bounding box
46 /// and will ignore its siblings or grid position. This is approximately equivalent to absolute positioning.
47 ///
48 /// # Example
49 /// ```
50 /// # use vizia_core::prelude::*;
51 /// # let cx = &mut Context::default();
52 /// Element::new(cx).position_type(PositionType::Absolute);
53 /// ```
54 position_type,
55 PositionType,
56 SystemFlags::RELAYOUT
57 );
58
59 modifier!(
60 /// Sets the space on the left side of the view.
61 ///
62 /// The left space, along with the right space, determines the horizontal position of a view.
63 ///
64 /// - `Units::Pixels(...)` - The left space will be a fixed number of points. This will scale with the DPI of the target display.
65 /// - `Units::Percentage(...)` - The left space will be a proportion of the parent width.
66 /// - `Units::Stretch(...)` - The left space will be a ratio of the remaining free space, see [`Units`](crate::prelude::Units).
67 /// - `Units::Auto` - The left space will be determined by the parent `padding-left`, see [`padding_left`](crate::prelude::LayoutModifiers::left).
68 ///
69 /// # Example
70 /// ```
71 /// # use vizia_core::prelude::*;
72 /// # let cx = &mut Context::default();
73 /// Element::new(cx).left(Units::Pixels(100.0));
74 /// ```
75 left,
76 Units,
77 SystemFlags::RELAYOUT
78 );
79
80 modifier!(
81 /// Sets the space on the right side of the view.
82 ///
83 /// The right space, along with the left space, determines the horizontal position of a view.
84 ///
85 /// - `Units::Pixels(...)` - The right space will be a fixed number of points. This will scale with the DPI of the target display.
86 /// - `Units::Percentage(...)` - The right space will be a proportion of the parent width.
87 /// - `Units::Stretch(...)` - The right space will be a ratio of the remaining free space, see [`Units`](crate::prelude::Units).
88 /// - `Units::Auto` - The right space will be determined by the parent `padding-left`, see [`padding_left`](crate::prelude::LayoutModifiers::left).
89 ///
90 /// # Example
91 /// ```
92 /// # use vizia_core::prelude::*;
93 /// # let cx = &mut Context::default();
94 /// Element::new(cx).right(Units::Pixels(100.0));
95 /// ```
96 right,
97 Units,
98 SystemFlags::RELAYOUT
99 );
100
101 modifier!(
102 /// Sets the space on the top side of the view.
103 ///
104 /// The top space, along with the bottom space, determines the vertical position of a view.
105 ///
106 /// - `Units::Pixels(...)` - The top space will be a fixed number of points. This will scale with the DPI of the target display.
107 /// - `Units::Percentage(...)` - The top space will be a proportion of the parent width.
108 /// - `Units::Stretch(...)` - The top space will be a ratio of the remaining free space, see [`Units`](crate::prelude::Units).
109 /// - `Units::Auto` - The top space will be determined by the parent `padding-left`, see [`padding_left`](crate::prelude::LayoutModifiers::left).
110 ///
111 /// # Example
112 /// ```
113 /// # use vizia_core::prelude::*;
114 /// # let cx = &mut Context::default();
115 /// Element::new(cx).top(Units::Pixels(100.0));
116 /// ```
117 top,
118 Units,
119 SystemFlags::RELAYOUT
120 );
121
122 modifier!(
123 /// Sets the space on the bottom side of the view.
124 ///
125 /// The bottom space, along with the top space, determines the vertical position of a view.
126 ///
127 /// - `Units::Pixels(...)` - The bottom space will be a fixed number of points. This will scale with the DPI of the target display.
128 /// - `Units::Percentage(...)` - The bottom space will be a proportion of the parent width.
129 /// - `Units::Stretch(...)` - The bottom space will be a ratio of the remaining free space, see [`Units`](crate::prelude::Units).
130 /// - `Units::Auto` - The bottom space will be determined by the parent `padding-left`, see [`padding_left`](crate::prelude::LayoutModifiers::left).
131 ///
132 /// # Example
133 /// ```
134 /// # use vizia_core::prelude::*;
135 /// # let cx = &mut Context::default();
136 /// Element::new(cx).bottom(Units::Pixels(100.0));
137 /// ```
138 bottom,
139 Units,
140 SystemFlags::RELAYOUT
141 );
142
143 /// Sets the space for all sides of the view.
144 fn space<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
145 let entity = self.entity();
146 let current = self.current();
147 self.context().with_current(current, |cx| {
148 value.set_or_bind(cx, move |cx, v| {
149 let value = v.get_value(cx).into();
150 cx.style.left.insert(entity, value);
151 cx.style.right.insert(entity, value);
152 cx.style.top.insert(entity, value);
153 cx.style.bottom.insert(entity, value);
154
155 cx.style.needs_relayout(entity);
156 });
157 });
158
159 self
160 }
161
162 modifier!(
163 /// Sets the width of the view.
164 width,
165 Units,
166 SystemFlags::RELAYOUT
167 );
168
169 modifier!(
170 /// Sets the height of the view.
171 height,
172 Units,
173 SystemFlags::RELAYOUT
174 );
175
176 modifier!(
177 /// Sets the preferred aspect ratio of the view.
178 aspect_ratio,
179 AspectRatio,
180 SystemFlags::RELAYOUT
181 );
182
183 /// Sets the width and height of the view.
184 fn size<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
185 let entity = self.entity();
186 let current = self.current();
187 self.context().with_current(current, |cx| {
188 value.set_or_bind(cx, move |cx, v| {
189 let value = v.get_value(cx).into();
190 cx.style.width.insert(entity, value);
191 cx.style.height.insert(entity, value);
192
193 cx.style.needs_relayout(entity);
194 });
195 });
196
197 self
198 }
199
200 modifier!(
201 /// Sets the space between the left side of the view and the left side of its children.
202 ///
203 /// Applies only to child views which have a `left` property set to `Auto`.
204 padding_left,
205 Units,
206 SystemFlags::RELAYOUT
207 );
208
209 modifier!(
210 /// Sets the space between the right side of the view and the right side of its children.
211 ///
212 /// Applies only to child views which have a `right` property set to `Auto`.
213 padding_right,
214 Units,
215 SystemFlags::RELAYOUT
216 );
217
218 modifier!(
219 /// Sets the space between the top side of the view and the top side of its children.
220 ///
221 /// Applies only to child views which have a `top` property set to `Auto`.
222 padding_top,
223 Units,
224 SystemFlags::RELAYOUT
225 );
226
227 modifier!(
228 /// Sets the space between the bottom side of the view and the bottom side of its children.
229 ///
230 /// Applies only to child views which have a `bottom` property set to `Auto`.
231 padding_bottom,
232 Units,
233 SystemFlags::RELAYOUT
234 );
235
236 modifier!(
237 /// Set the alignment of the view.
238 alignment,
239 Alignment,
240 SystemFlags::RELAYOUT
241 );
242
243 modifier!(
244 /// Set the text direction of the view.
245 direction,
246 Direction,
247 SystemFlags::RELAYOUT
248 );
249
250 modifier!(
251 /// Set the wrapping behavior of the view.
252 wrap,
253 LayoutWrap,
254 SystemFlags::RELAYOUT
255 );
256
257 /// Sets the space between the vew and its children.
258 ///
259 /// The child_space works by overriding the `Auto` space properties of its children.
260 fn padding<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
261 let entity = self.entity();
262 let current = self.current();
263 self.context().with_current(current, |cx| {
264 value.set_or_bind(cx, move |cx, v| {
265 let value = v.get_value(cx).into();
266 cx.style.padding_left.insert(entity, value);
267 cx.style.padding_right.insert(entity, value);
268 cx.style.padding_top.insert(entity, value);
269 cx.style.padding_bottom.insert(entity, value);
270
271 cx.style.needs_relayout(entity);
272 });
273 });
274
275 self
276 }
277
278 modifier!(
279 /// Sets the space between the views children in the vertical direction.
280 vertical_gap,
281 Units,
282 SystemFlags::RELAYOUT
283 );
284
285 modifier!(
286 /// Sets the space between the views children in the horizontal direction.
287 horizontal_gap,
288 Units,
289 SystemFlags::RELAYOUT
290 );
291
292 /// Sets the space between the views children in both the horizontal and vertical directions.
293 fn gap<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
294 let entity = self.entity();
295 let current = self.current();
296 self.context().with_current(current, |cx| {
297 value.set_or_bind(cx, move |cx, v| {
298 let value = v.get_value(cx).into();
299 cx.style.horizontal_gap.insert(entity, value);
300 cx.style.vertical_gap.insert(entity, value);
301
302 cx.style.needs_relayout(entity);
303 });
304 });
305
306 self
307 }
308
309 modifier!(
310 /// Sets the minimum width of the view.
311 min_width,
312 Units,
313 SystemFlags::RELAYOUT
314 );
315
316 modifier!(
317 /// Sets the minimum height of the view.
318 min_height,
319 Units,
320 SystemFlags::RELAYOUT
321 );
322
323 /// Sets the minimum width and minimum height of the view.
324 fn min_size<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
325 let entity = self.entity();
326 let current = self.current();
327 self.context().with_current(current, |cx| {
328 value.set_or_bind(cx, move |cx, v| {
329 let value = v.get_value(cx).into();
330 cx.style.min_width.insert(entity, value);
331 cx.style.min_height.insert(entity, value);
332
333 cx.style.needs_relayout(entity);
334 });
335 });
336
337 self
338 }
339
340 modifier!(
341 /// Sets the maximum width of the view.
342 max_width,
343 Units,
344 SystemFlags::RELAYOUT
345 );
346
347 modifier!(
348 /// Sets the maximum height of the view.
349 max_height,
350 Units,
351 SystemFlags::RELAYOUT
352 );
353
354 /// Sets the maximum width and maximum height of the view.
355 fn max_size<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
356 let entity = self.entity();
357 let current = self.current();
358 self.context().with_current(current, |cx| {
359 value.set_or_bind(cx, move |cx, v| {
360 let value = v.get_value(cx).into();
361 cx.style.max_width.insert(entity, value);
362 cx.style.max_height.insert(entity, value);
363
364 cx.style.needs_relayout(entity);
365 });
366 });
367
368 self
369 }
370
371 modifier!(
372 /// Sets the minimum horizontal space between the children of the view.
373 min_horizontal_gap,
374 Units,
375 SystemFlags::RELAYOUT
376 );
377
378 modifier!(
379 /// Sets the minimum vertical space between the children of the view.
380 min_vertical_gap,
381 Units,
382 SystemFlags::RELAYOUT
383 );
384
385 /// Sets the minimum horizontal and minimum vertical space between the children of the view.
386 fn min_gap<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
387 let entity = self.entity();
388 let current = self.current();
389 self.context().with_current(current, |cx| {
390 value.set_or_bind(cx, move |cx, v| {
391 let value = v.get_value(cx).into();
392 cx.style.min_horizontal_gap.insert(entity, value);
393 cx.style.min_vertical_gap.insert(entity, value);
394
395 cx.style.needs_relayout(entity);
396 });
397 });
398
399 self
400 }
401
402 modifier!(
403 /// Sets the maximum horizontal space between the children of the view.
404 max_horizontal_gap,
405 Units,
406 SystemFlags::RELAYOUT
407 );
408
409 modifier!(
410 /// Sets the maximum vertical space between the children of the view.
411 max_vertical_gap,
412 Units,
413 SystemFlags::RELAYOUT
414 );
415
416 /// Sets the maximum horizontal and maximum vertical space between the children of the view.
417 fn max_gap<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
418 let entity = self.entity();
419 let current = self.current();
420 self.context().with_current(current, |cx| {
421 value.set_or_bind(cx, move |cx, v| {
422 let value = v.get_value(cx).into();
423 cx.style.max_horizontal_gap.insert(entity, value);
424 cx.style.max_vertical_gap.insert(entity, value);
425
426 cx.style.needs_relayout(entity);
427 });
428 });
429
430 self
431 }
432
433 modifier!(
434 /// Sets the grid columns for a grid layout.
435 grid_columns,
436 Vec<Units>,
437 SystemFlags::RELAYOUT
438 );
439
440 modifier!(
441 /// Sets the grid rows for a grid layout.
442 grid_rows,
443 Vec<Units>,
444 SystemFlags::RELAYOUT
445 );
446
447 fn column_start(mut self, value: impl Res<usize>) -> Self {
448 let entity = self.entity();
449 let current = self.current();
450 self.context().with_current(current, |cx| {
451 value.set_or_bind(cx, move |cx, v| {
452 let value = v.get_value(cx);
453 cx.style.column_start.insert(entity, value);
454
455 cx.style.needs_relayout(entity);
456 });
457 });
458
459 self
460 }
461
462 fn column_span(mut self, value: impl Res<usize>) -> Self {
463 let entity = self.entity();
464 let current = self.current();
465 self.context().with_current(current, |cx| {
466 value.set_or_bind(cx, move |cx, v| {
467 let value = v.get_value(cx);
468 cx.style.column_span.insert(entity, value);
469
470 cx.style.needs_relayout(entity);
471 });
472 });
473
474 self
475 }
476
477 fn row_start(mut self, value: impl Res<usize>) -> Self {
478 let entity = self.entity();
479 let current = self.current();
480 self.context().with_current(current, |cx| {
481 value.set_or_bind(cx, move |cx, v| {
482 let value = v.get_value(cx);
483 cx.style.row_start.insert(entity, value);
484
485 cx.style.needs_relayout(entity);
486 });
487 });
488
489 self
490 }
491
492 fn row_span(mut self, value: impl Res<usize>) -> Self {
493 let entity = self.entity();
494 let current = self.current();
495 self.context().with_current(current, |cx| {
496 value.set_or_bind(cx, move |cx, v| {
497 let value = v.get_value(cx);
498 cx.style.row_span.insert(entity, value);
499
500 cx.style.needs_relayout(entity);
501 });
502 });
503
504 self
505 }
506}
507
508impl<V: View> LayoutModifiers for Handle<'_, V> {}