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 lens to a target, 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(Lens, 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); // Lens to target of 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, entity, |cx, v| {
149 let value = v.get(cx).into();
150 cx.style.left.insert(cx.current, value);
151 cx.style.right.insert(cx.current, value);
152 cx.style.top.insert(cx.current, value);
153 cx.style.bottom.insert(cx.current, value);
154
155 cx.style.needs_relayout();
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 /// Sets the width and height of the view.
177 fn size<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
178 let entity = self.entity();
179 let current = self.current();
180 self.context().with_current(current, |cx| {
181 value.set_or_bind(cx, entity, move |cx, v| {
182 let value = v.get(cx).into();
183 cx.style.width.insert(cx.current, value);
184 cx.style.height.insert(cx.current, value);
185
186 cx.style.needs_relayout();
187 });
188 });
189
190 self
191 }
192
193 modifier!(
194 /// Sets the space between the left side of the view and the left side of its children.
195 ///
196 /// Applies only to child views which have a `left` property set to `Auto`.
197 padding_left,
198 Units,
199 SystemFlags::RELAYOUT
200 );
201
202 modifier!(
203 /// Sets the space between the right side of the view and the right side of its children.
204 ///
205 /// Applies only to child views which have a `right` property set to `Auto`.
206 padding_right,
207 Units,
208 SystemFlags::RELAYOUT
209 );
210
211 modifier!(
212 /// Sets the space between the top side of the view and the top side of its children.
213 ///
214 /// Applies only to child views which have a `top` property set to `Auto`.
215 padding_top,
216 Units,
217 SystemFlags::RELAYOUT
218 );
219
220 modifier!(
221 /// Sets the space between the bottom side of the view and the bottom side of its children.
222 ///
223 /// Applies only to child views which have a `bottom` property set to `Auto`.
224 padding_bottom,
225 Units,
226 SystemFlags::RELAYOUT
227 );
228
229 modifier!(
230 /// Set the alignment of the view.
231 alignment,
232 Alignment,
233 SystemFlags::RELAYOUT
234 );
235
236 /// Sets the space between the vew and its children.
237 ///
238 /// The child_space works by overriding the `Auto` space properties of its children.
239 fn padding<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
240 let entity = self.entity();
241 let current = self.current();
242 self.context().with_current(current, |cx| {
243 value.set_or_bind(cx, entity, move |cx, v| {
244 let value = v.get(cx).into();
245 cx.style.padding_left.insert(cx.current, value);
246 cx.style.padding_right.insert(cx.current, value);
247 cx.style.padding_top.insert(cx.current, value);
248 cx.style.padding_bottom.insert(cx.current, value);
249
250 cx.style.needs_relayout();
251 });
252 });
253
254 self
255 }
256
257 modifier!(
258 /// Sets the space between the views children in the vertical direction.
259 vertical_gap,
260 Units,
261 SystemFlags::RELAYOUT
262 );
263
264 modifier!(
265 /// Sets the space between the views children in the horizontal direction.
266 horizontal_gap,
267 Units,
268 SystemFlags::RELAYOUT
269 );
270
271 /// Sets the space between the views children in both the horizontal and vertical directions.
272 fn gap<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
273 let entity = self.entity();
274 let current = self.current();
275 self.context().with_current(current, |cx| {
276 value.set_or_bind(cx, entity, move |cx, v| {
277 let value = v.get(cx).into();
278 cx.style.horizontal_gap.insert(cx.current, value);
279 cx.style.vertical_gap.insert(cx.current, value);
280
281 cx.style.needs_relayout();
282 });
283 });
284
285 self
286 }
287
288 modifier!(
289 /// Set the vertical scroll position of the view.
290 vertical_scroll,
291 f32,
292 SystemFlags::RELAYOUT
293 );
294
295 modifier!(
296 /// Set the horizontal scroll position of the view.
297 horizontal_scroll,
298 f32,
299 SystemFlags::RELAYOUT
300 );
301
302 modifier!(
303 /// Sets the minimum width of the view.
304 min_width,
305 Units,
306 SystemFlags::RELAYOUT
307 );
308
309 modifier!(
310 /// Sets the minimum height of the view.
311 min_height,
312 Units,
313 SystemFlags::RELAYOUT
314 );
315
316 /// Sets the minimum width and minimum height of the view.
317 fn min_size<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
318 let entity = self.entity();
319 let current = self.current();
320 self.context().with_current(current, |cx| {
321 value.set_or_bind(cx, entity, move |cx, v| {
322 let value = v.get(cx).into();
323 cx.style.min_width.insert(cx.current, value);
324 cx.style.min_height.insert(cx.current, value);
325
326 cx.needs_relayout();
327 });
328 });
329
330 self
331 }
332
333 modifier!(
334 /// Sets the maximum width of the view.
335 max_width,
336 Units,
337 SystemFlags::RELAYOUT
338 );
339
340 modifier!(
341 /// Sets the maximum height of the view.
342 max_height,
343 Units,
344 SystemFlags::RELAYOUT
345 );
346
347 /// Sets the maximum width and maximum height of the view.
348 fn max_size<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
349 let entity = self.entity();
350 let current = self.current();
351 self.context().with_current(entity, |cx| {
352 value.set_or_bind(cx, current, move |cx, v| {
353 let value = v.get(cx).into();
354 cx.style.max_width.insert(cx.current, value);
355 cx.style.max_height.insert(cx.current, value);
356
357 cx.needs_relayout();
358 });
359 });
360
361 self
362 }
363
364 modifier!(
365 /// Sets the minimum horizontal space between the children of the view.
366 min_horizontal_gap,
367 Units,
368 SystemFlags::RELAYOUT
369 );
370
371 modifier!(
372 /// Sets the minimum vertical space between the children of the view.
373 min_vertical_gap,
374 Units,
375 SystemFlags::RELAYOUT
376 );
377
378 /// Sets the minimum horizontal and minimum vertical space between the children of the view.
379 fn min_gap<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
380 let entity = self.entity();
381 let current = self.current();
382 self.context().with_current(current, |cx| {
383 value.set_or_bind(cx, entity, move |cx, v| {
384 let value = v.get(cx).into();
385 cx.style.min_horizontal_gap.insert(cx.current, value);
386 cx.style.min_vertical_gap.insert(cx.current, value);
387
388 cx.needs_relayout();
389 });
390 });
391
392 self
393 }
394
395 modifier!(
396 /// Sets the maximum horizontal space between the children of the view.
397 max_horizontal_gap,
398 Units,
399 SystemFlags::RELAYOUT
400 );
401
402 modifier!(
403 /// Sets the maximum vertical space between the children of the view.
404 max_vertical_gap,
405 Units,
406 SystemFlags::RELAYOUT
407 );
408
409 /// Sets the maximum horizontal and maximum vertical space between the children of the view.
410 fn max_gap<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
411 let entity = self.entity();
412 let current = self.current();
413 self.context().with_current(current, |cx| {
414 value.set_or_bind(cx, entity, move |cx, v| {
415 let value = v.get(cx).into();
416 cx.style.max_horizontal_gap.insert(cx.current, value);
417 cx.style.max_vertical_gap.insert(cx.current, value);
418
419 cx.needs_relayout();
420 });
421 });
422
423 self
424 }
425
426 modifier!(
427 /// Sets the grid columns for a grid layout.
428 grid_columns,
429 Vec<Units>,
430 SystemFlags::RELAYOUT
431 );
432
433 modifier!(
434 /// Sets the grid rows for a grid layout.
435 grid_rows,
436 Vec<Units>,
437 SystemFlags::RELAYOUT
438 );
439
440 fn column_start(mut self, value: impl Res<usize>) -> Self {
441 let entity = self.entity();
442 let current = self.current();
443 self.context().with_current(current, |cx| {
444 value.set_or_bind(cx, entity, move |cx, v| {
445 let value = v.get(cx);
446 cx.style.column_start.insert(cx.current, value);
447
448 cx.needs_relayout();
449 });
450 });
451
452 self
453 }
454
455 fn column_span(mut self, value: impl Res<usize>) -> Self {
456 let entity = self.entity();
457 let current = self.current();
458 self.context().with_current(current, |cx| {
459 value.set_or_bind(cx, entity, move |cx, v| {
460 let value = v.get(cx);
461 cx.style.column_span.insert(cx.current, value);
462
463 cx.needs_relayout();
464 });
465 });
466
467 self
468 }
469
470 fn row_start(mut self, value: impl Res<usize>) -> Self {
471 let entity = self.entity();
472 let current = self.current();
473 self.context().with_current(current, |cx| {
474 value.set_or_bind(cx, entity, move |cx, v| {
475 let value = v.get(cx);
476 cx.style.row_start.insert(cx.current, value);
477
478 cx.needs_relayout();
479 });
480 });
481
482 self
483 }
484
485 fn row_span(mut self, value: impl Res<usize>) -> Self {
486 let entity = self.entity();
487 let current = self.current();
488 self.context().with_current(current, |cx| {
489 value.set_or_bind(cx, entity, move |cx, v| {
490 let value = v.get(cx);
491 cx.style.row_span.insert(cx.current, value);
492
493 cx.needs_relayout();
494 });
495 });
496
497 self
498 }
499}
500
501impl<V: View> LayoutModifiers for Handle<'_, V> {}