Skip to main content

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> {}