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();
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, move |cx, v| {
182 let value = v.get_value(cx).into();
183 cx.style.width.insert(entity, value);
184 cx.style.height.insert(entity, 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 modifier!(
237 /// Set the text direction of the view.
238 direction,
239 Direction,
240 SystemFlags::RELAYOUT
241 );
242
243 modifier!(
244 /// Set the wrapping behavior of the view.
245 wrap,
246 LayoutWrap,
247 SystemFlags::RELAYOUT
248 );
249
250 /// Sets the space between the vew and its children.
251 ///
252 /// The child_space works by overriding the `Auto` space properties of its children.
253 fn padding<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
254 let entity = self.entity();
255 let current = self.current();
256 self.context().with_current(current, |cx| {
257 value.set_or_bind(cx, move |cx, v| {
258 let value = v.get_value(cx).into();
259 cx.style.padding_left.insert(entity, value);
260 cx.style.padding_right.insert(entity, value);
261 cx.style.padding_top.insert(entity, value);
262 cx.style.padding_bottom.insert(entity, value);
263
264 cx.style.needs_relayout();
265 });
266 });
267
268 self
269 }
270
271 modifier!(
272 /// Sets the space between the views children in the vertical direction.
273 vertical_gap,
274 Units,
275 SystemFlags::RELAYOUT
276 );
277
278 modifier!(
279 /// Sets the space between the views children in the horizontal direction.
280 horizontal_gap,
281 Units,
282 SystemFlags::RELAYOUT
283 );
284
285 /// Sets the space between the views children in both the horizontal and vertical directions.
286 fn gap<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
287 let entity = self.entity();
288 let current = self.current();
289 self.context().with_current(current, |cx| {
290 value.set_or_bind(cx, move |cx, v| {
291 let value = v.get_value(cx).into();
292 cx.style.horizontal_gap.insert(entity, value);
293 cx.style.vertical_gap.insert(entity, value);
294
295 cx.style.needs_relayout();
296 });
297 });
298
299 self
300 }
301
302 modifier!(
303 /// Set the vertical scroll position of the view.
304 vertical_scroll,
305 f32,
306 SystemFlags::RELAYOUT
307 );
308
309 modifier!(
310 /// Set the horizontal scroll position of the view.
311 horizontal_scroll,
312 f32,
313 SystemFlags::RELAYOUT
314 );
315
316 modifier!(
317 /// Sets the minimum width of the view.
318 min_width,
319 Units,
320 SystemFlags::RELAYOUT
321 );
322
323 modifier!(
324 /// Sets the minimum height of the view.
325 min_height,
326 Units,
327 SystemFlags::RELAYOUT
328 );
329
330 /// Sets the minimum width and minimum height of the view.
331 fn min_size<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
332 let entity = self.entity();
333 let current = self.current();
334 self.context().with_current(current, |cx| {
335 value.set_or_bind(cx, move |cx, v| {
336 let value = v.get_value(cx).into();
337 cx.style.min_width.insert(entity, value);
338 cx.style.min_height.insert(entity, value);
339
340 cx.needs_relayout();
341 });
342 });
343
344 self
345 }
346
347 modifier!(
348 /// Sets the maximum width of the view.
349 max_width,
350 Units,
351 SystemFlags::RELAYOUT
352 );
353
354 modifier!(
355 /// Sets the maximum height of the view.
356 max_height,
357 Units,
358 SystemFlags::RELAYOUT
359 );
360
361 /// Sets the maximum width and maximum height of the view.
362 fn max_size<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
363 let entity = self.entity();
364 let current = self.current();
365 self.context().with_current(current, |cx| {
366 value.set_or_bind(cx, move |cx, v| {
367 let value = v.get_value(cx).into();
368 cx.style.max_width.insert(entity, value);
369 cx.style.max_height.insert(entity, value);
370
371 cx.needs_relayout();
372 });
373 });
374
375 self
376 }
377
378 modifier!(
379 /// Sets the minimum horizontal space between the children of the view.
380 min_horizontal_gap,
381 Units,
382 SystemFlags::RELAYOUT
383 );
384
385 modifier!(
386 /// Sets the minimum vertical space between the children of the view.
387 min_vertical_gap,
388 Units,
389 SystemFlags::RELAYOUT
390 );
391
392 /// Sets the minimum horizontal and minimum vertical space between the children of the view.
393 fn min_gap<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
394 let entity = self.entity();
395 let current = self.current();
396 self.context().with_current(current, |cx| {
397 value.set_or_bind(cx, move |cx, v| {
398 let value = v.get_value(cx).into();
399 cx.style.min_horizontal_gap.insert(entity, value);
400 cx.style.min_vertical_gap.insert(entity, value);
401
402 cx.needs_relayout();
403 });
404 });
405
406 self
407 }
408
409 modifier!(
410 /// Sets the maximum horizontal space between the children of the view.
411 max_horizontal_gap,
412 Units,
413 SystemFlags::RELAYOUT
414 );
415
416 modifier!(
417 /// Sets the maximum vertical space between the children of the view.
418 max_vertical_gap,
419 Units,
420 SystemFlags::RELAYOUT
421 );
422
423 /// Sets the maximum horizontal and maximum vertical space between the children of the view.
424 fn max_gap<U: Into<Units>>(mut self, value: impl Res<U>) -> Self {
425 let entity = self.entity();
426 let current = self.current();
427 self.context().with_current(current, |cx| {
428 value.set_or_bind(cx, move |cx, v| {
429 let value = v.get_value(cx).into();
430 cx.style.max_horizontal_gap.insert(entity, value);
431 cx.style.max_vertical_gap.insert(entity, value);
432
433 cx.needs_relayout();
434 });
435 });
436
437 self
438 }
439
440 modifier!(
441 /// Sets the grid columns for a grid layout.
442 grid_columns,
443 Vec<Units>,
444 SystemFlags::RELAYOUT
445 );
446
447 modifier!(
448 /// Sets the grid rows for a grid layout.
449 grid_rows,
450 Vec<Units>,
451 SystemFlags::RELAYOUT
452 );
453
454 fn column_start(mut self, value: impl Res<usize>) -> Self {
455 let entity = self.entity();
456 let current = self.current();
457 self.context().with_current(current, |cx| {
458 value.set_or_bind(cx, move |cx, v| {
459 let value = v.get_value(cx);
460 cx.style.column_start.insert(entity, value);
461
462 cx.needs_relayout();
463 });
464 });
465
466 self
467 }
468
469 fn column_span(mut self, value: impl Res<usize>) -> Self {
470 let entity = self.entity();
471 let current = self.current();
472 self.context().with_current(current, |cx| {
473 value.set_or_bind(cx, move |cx, v| {
474 let value = v.get_value(cx);
475 cx.style.column_span.insert(entity, value);
476
477 cx.needs_relayout();
478 });
479 });
480
481 self
482 }
483
484 fn row_start(mut self, value: impl Res<usize>) -> Self {
485 let entity = self.entity();
486 let current = self.current();
487 self.context().with_current(current, |cx| {
488 value.set_or_bind(cx, move |cx, v| {
489 let value = v.get_value(cx);
490 cx.style.row_start.insert(entity, value);
491
492 cx.needs_relayout();
493 });
494 });
495
496 self
497 }
498
499 fn row_span(mut self, value: impl Res<usize>) -> Self {
500 let entity = self.entity();
501 let current = self.current();
502 self.context().with_current(current, |cx| {
503 value.set_or_bind(cx, move |cx, v| {
504 let value = v.get_value(cx);
505 cx.style.row_span.insert(entity, value);
506
507 cx.needs_relayout();
508 });
509 });
510
511 self
512 }
513}
514
515impl<V: View> LayoutModifiers for Handle<'_, V> {}