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();
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> {}