Skip to main content

iced_core/
layout.rs

1//! Position your widgets properly.
2mod limits;
3
4pub mod flex;
5
6pub use limits::Limits;
7
8use crate::widget;
9use crate::{Length, Padding, Point, Rectangle, Size, Vector};
10
11/// The bounds of a widget and its children, using absolute coordinates.
12#[derive(Debug, Clone, Copy, PartialEq)]
13pub struct Layout {
14    position: Point,
15    size: Size,
16    parent: Option<Rectangle>,
17}
18
19impl Layout {
20    /// Creates a new [`Layout`] for the given [`Size`] at the origin.
21    pub fn new(size: Size) -> Self {
22        Self {
23            position: Point::ORIGIN,
24            size,
25            parent: None,
26        }
27    }
28
29    /// Returns the position of the [`Layout`].
30    pub fn position(&self) -> Point {
31        self.position
32    }
33
34    /// Moves the [`Layout`] to the given position.
35    pub fn move_to(self, position: impl Into<Point>) -> Self {
36        Self {
37            position: position.into(),
38            size: self.size,
39            parent: self.parent,
40        }
41    }
42
43    /// Returns the bounds of the [`Layout`].
44    ///
45    /// The returned [`Rectangle`] describes the position and size of the
46    /// laid out widget.
47    pub fn bounds(&self) -> Rectangle {
48        Rectangle::new(self.position, self.size)
49    }
50
51    /// Returns the size of the [`Layout`].
52    pub fn size(&self) -> Size {
53        self.size
54    }
55
56    /// Returns the bounds of the parent of this [`Layout`], if any.
57    pub fn parent(&self) -> Option<Rectangle> {
58        self.parent
59    }
60
61    /// Returns an iterator over the children of this [`Layout`].
62    pub fn iter(
63        self,
64        children: &[widget::Tree],
65    ) -> impl DoubleEndedIterator<Item = (Self, &widget::Tree)> + ExactSizeIterator {
66        children.iter().map(move |child| (self.child(child), child))
67    }
68
69    /// Returns a mutable iterator over the children of this [`Layout`].
70    pub fn iter_mut(
71        self,
72        children: &mut [widget::Tree],
73    ) -> impl DoubleEndedIterator<Item = (Self, &mut widget::Tree)> + ExactSizeIterator {
74        children
75            .iter_mut()
76            .map(move |child| (self.child(child), child))
77    }
78
79    fn child(&self, child: &widget::Tree) -> Self {
80        Self {
81            position: self.position + child.translation,
82            size: child.size,
83            parent: Some(self.bounds()),
84        }
85    }
86}
87
88/// Lays out two children side by side in the provided [`widget::Tree`].
89///
90/// The tree must have exactly two children. The first is placed at the left
91/// edge, and the second to its right after `spacing`, both vertically
92/// centered with respect to each other.
93///
94/// The resulting size is stored in the tree, along with the children's
95/// sizes and translations.
96pub fn next_to_each_other(tree: &mut widget::Tree, left: Size, right: Size, spacing: f32) {
97    let (left_y, right_y) = if left.height > right.height {
98        (0.0, (left.height - right.height) / 2.0)
99    } else {
100        ((right.height - left.height) / 2.0, 0.0)
101    };
102
103    tree.size = Size::new(
104        left.width + spacing + right.width,
105        left.height.max(right.height),
106    );
107
108    tree.children[0].size = left;
109    tree.children[0].translation = Vector::new(0.0, left_y);
110
111    tree.children[1].size = right;
112    tree.children[1].translation = Vector::new(left.width + spacing, right_y);
113}
114
115/// Computes the resulting [`Size`] that fits the [`Limits`] given
116/// some width and height requirements and no intrinsic size.
117pub fn atomic(limits: &Limits, width: impl Into<Length>, height: impl Into<Length>) -> Size {
118    let width = width.into();
119    let height = height.into();
120
121    limits
122        .width(width)
123        .height(height)
124        .resolve(width, height, Size::ZERO)
125}
126
127/// Computes the resulting [`Size`] that fits the [`Limits`] given
128/// some width and height requirements and a closure that produces
129/// the intrinsic [`Size`] inside the given [`Limits`].
130pub fn sized(
131    limits: &Limits,
132    width: impl Into<Length>,
133    height: impl Into<Length>,
134    f: impl FnOnce(&Limits) -> Size,
135) -> Size {
136    let width = width.into();
137    let height = height.into();
138
139    let limits = limits.width(width).height(height);
140    let intrinsic_size = f(&limits);
141
142    limits.resolve(width, height, intrinsic_size)
143}
144
145/// Computes the resulting [`Size`] that fits the [`Limits`] given
146/// some width and height requirements and a closure that produces
147/// the content inside the given [`Limits`].
148pub fn contained(
149    tree: &mut widget::Tree,
150    limits: &Limits,
151    width: impl Into<Length>,
152    height: impl Into<Length>,
153    f: impl FnOnce(&mut widget::Tree, &Limits) -> Size,
154) {
155    let width = width.into();
156    let height = height.into();
157    let limits = limits.width(width).height(height);
158
159    let child = &mut tree.children[0];
160    let content = f(child, &limits);
161
162    tree.size = limits.resolve(width, height, content);
163    child.translation = Vector::ZERO;
164}
165
166/// Computes the [`Size`] that fits the [`Limits`] given some width, height, and
167/// [`Padding`] requirements and a closure that produces the content
168/// inside the given [`Limits`].
169pub fn padded(
170    tree: &mut widget::Tree,
171    limits: &Limits,
172    width: impl Into<Length>,
173    height: impl Into<Length>,
174    padding: impl Into<Padding>,
175    layout: impl FnOnce(&mut widget::Tree, &Limits) -> Size,
176) {
177    positioned(tree, limits, width, height, padding, layout, |_, _| {
178        Vector::ZERO
179    });
180}
181
182/// Computes a [`padded`] [`Size`] with a positioning step.
183pub fn positioned(
184    tree: &mut widget::Tree,
185    limits: &Limits,
186    width: impl Into<Length>,
187    height: impl Into<Length>,
188    padding: impl Into<Padding>,
189    layout: impl FnOnce(&mut widget::Tree, &Limits) -> Size,
190    translate: impl FnOnce(Size, Size) -> Vector,
191) {
192    let width = width.into();
193    let height = height.into();
194    let padding = padding.into();
195    let limits = limits.width(width).height(height);
196
197    let child = &mut tree.children[0];
198    let content = layout(child, &limits.shrink(padding));
199    let padding = padding.fit(content, limits.bounds());
200
201    let container = limits.shrink(padding).resolve(width, height, content);
202
203    tree.size = container.expand(padding);
204    child.translation = Vector::new(padding.left, padding.top) + translate(content, container);
205}