summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-01-09 06:35:33 +0100
committerLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-01-10 10:01:49 +0100
commitd62bb8193c1c43f565fcc5c52293d564c91e215d (patch)
tree7f2d33d2f18a3dfb4e4e8e46b4e968523ca43bc6
parentd24e50c1a61eee7bca887224ad583eca60e14d32 (diff)
downloadiced-d62bb8193c1c43f565fcc5c52293d564c91e215d.tar.gz
iced-d62bb8193c1c43f565fcc5c52293d564c91e215d.tar.bz2
iced-d62bb8193c1c43f565fcc5c52293d564c91e215d.zip
Introduce useful helpers in `layout` module
-rw-r--r--core/src/layout.rs94
-rw-r--r--core/src/layout/flex.rs2
-rw-r--r--core/src/layout/limits.rs7
-rw-r--r--core/src/layout/node.rs10
-rw-r--r--core/src/point.rs20
-rw-r--r--core/src/widget/text.rs43
-rw-r--r--examples/geometry/src/main.rs4
-rw-r--r--examples/loading_spinners/src/circular.rs5
-rw-r--r--examples/loading_spinners/src/linear.rs5
-rw-r--r--widget/src/button.rs19
-rw-r--r--widget/src/canvas.rs4
-rw-r--r--widget/src/container.rs28
-rw-r--r--widget/src/image.rs2
-rw-r--r--widget/src/image/viewer.rs2
-rw-r--r--widget/src/overlay/menu.rs2
-rw-r--r--widget/src/pane_grid.rs2
-rw-r--r--widget/src/pick_list.rs5
-rw-r--r--widget/src/progress_bar.rs8
-rw-r--r--widget/src/rule.rs2
-rw-r--r--widget/src/scrollable.rs39
-rw-r--r--widget/src/shader.rs5
-rw-r--r--widget/src/slider.rs4
-rw-r--r--widget/src/space.rs2
-rw-r--r--widget/src/svg.rs2
-rw-r--r--widget/src/text_input.rs4
-rw-r--r--widget/src/vertical_slider.rs4
26 files changed, 193 insertions, 131 deletions
diff --git a/core/src/layout.rs b/core/src/layout.rs
index 277473fe..95720aba 100644
--- a/core/src/layout.rs
+++ b/core/src/layout.rs
@@ -7,7 +7,7 @@ pub mod flex;
pub use limits::Limits;
pub use node::Node;
-use crate::{Point, Rectangle, Size, Vector};
+use crate::{Length, Padding, Point, Rectangle, Size, Vector};
/// The bounds of a [`Node`] and its children, using absolute coordinates.
#[derive(Debug, Clone, Copy)]
@@ -96,3 +96,95 @@ pub fn next_to_each_other(
],
)
}
+
+/// Computes the resulting [`Node`] that fits the [`Limits`] given
+/// some width and height requirements and no intrinsic size.
+pub fn atomic(
+ limits: &Limits,
+ width: impl Into<Length>,
+ height: impl Into<Length>,
+) -> Node {
+ let width = width.into();
+ let height = height.into();
+
+ Node::new(limits.resolve(width, height, Size::ZERO))
+}
+
+/// Computes the resulting [`Node`] that fits the [`Limits`] given
+/// some width and height requirements and a closure that produces
+/// the intrinsic [`Size`] inside the given [`Limits`].
+pub fn sized(
+ limits: &Limits,
+ width: impl Into<Length>,
+ height: impl Into<Length>,
+ f: impl FnOnce(&Limits) -> Size,
+) -> Node {
+ let width = width.into();
+ let height = height.into();
+
+ let limits = limits.width(width).height(height);
+ let intrinsic_size = f(&limits);
+
+ Node::new(limits.resolve(width, height, intrinsic_size))
+}
+
+/// Computes the resulting [`Node`] that fits the [`Limits`] given
+/// some width and height requirements and a closure that produces
+/// the content [`Node`] inside the given [`Limits`].
+pub fn contained(
+ limits: &Limits,
+ width: impl Into<Length>,
+ height: impl Into<Length>,
+ f: impl FnOnce(&Limits) -> Node,
+) -> Node {
+ let width = width.into();
+ let height = height.into();
+
+ let limits = limits.width(width).height(height);
+ let content = f(&limits);
+
+ Node::with_children(
+ limits.resolve(width, height, content.size()),
+ vec![content],
+ )
+}
+
+/// Computes the [`Node`] that fits the [`Limits`] given some width, height, and
+/// [`Padding`] requirements and a closure that produces the content [`Node`]
+/// inside the given [`Limits`].
+pub fn padded(
+ limits: &Limits,
+ width: impl Into<Length>,
+ height: impl Into<Length>,
+ padding: impl Into<Padding>,
+ layout: impl FnOnce(&Limits) -> Node,
+) -> Node {
+ positioned(limits, width, height, padding, layout, |content, _| content)
+}
+
+/// Computes a [`padded`] [`Node`] with a positioning step.
+pub fn positioned(
+ limits: &Limits,
+ width: impl Into<Length>,
+ height: impl Into<Length>,
+ padding: impl Into<Padding>,
+ layout: impl FnOnce(&Limits) -> Node,
+ position: impl FnOnce(Node, Size) -> Node,
+) -> Node {
+ let width = width.into();
+ let height = height.into();
+ let padding = padding.into();
+
+ let limits = limits.width(width).height(height);
+ let content = layout(&limits.shrink(padding));
+ let padding = padding.fit(content.size(), limits.max());
+
+ let size = limits
+ .shrink(padding)
+ .resolve(width, height, content.size());
+
+ Node::with_children(
+ size.expand(padding),
+ vec![position(content.move_to((padding.left, padding.top)), size)],
+ )
+}
diff --git a/core/src/layout/flex.rs b/core/src/layout/flex.rs
index 2a12d57f..cf3e1340 100644
--- a/core/src/layout/flex.rs
+++ b/core/src/layout/flex.rs
@@ -239,9 +239,9 @@ where
let (intrinsic_width, intrinsic_height) = axis.pack(main - pad.0, cross);
let size = limits.resolve(
- Size::new(intrinsic_width, intrinsic_height),
width,
height,
+ Size::new(intrinsic_width, intrinsic_height),
);
Node::with_children(size.expand(padding), nodes)
diff --git a/core/src/layout/limits.rs b/core/src/layout/limits.rs
index eef4c4c9..7fbc7b9d 100644
--- a/core/src/layout/limits.rs
+++ b/core/src/layout/limits.rs
@@ -114,13 +114,14 @@ impl Limits {
}
}
- /// Computes the resulting [`Size`] that fits the [`Limits`] given the
- /// intrinsic size of some content.
+ /// Computes the resulting [`Size`] that fits the [`Limits`] given
+ /// some width and height requirements and the intrinsic size of
+ /// some content.
pub fn resolve(
&self,
- intrinsic_size: Size,
width: impl Into<Length>,
height: impl Into<Length>,
+ intrinsic_size: Size,
) -> Size {
let width = match width.into() {
Length::Fill | Length::FillPortion(_) => self.max.width,
diff --git a/core/src/layout/node.rs b/core/src/layout/node.rs
index 00087431..40c71436 100644
--- a/core/src/layout/node.rs
+++ b/core/src/layout/node.rs
@@ -89,19 +89,23 @@ impl Node {
}
/// Moves the [`Node`] to the given position.
- pub fn move_to(mut self, position: Point) -> Self {
+ pub fn move_to(mut self, position: impl Into<Point>) -> Self {
self.move_to_mut(position);
self
}
/// Mutable reference version of [`move_to`].
- pub fn move_to_mut(&mut self, position: Point) {
+ pub fn move_to_mut(&mut self, position: impl Into<Point>) {
+ let position = position.into();
+
self.bounds.x = position.x;
self.bounds.y = position.y;
}
/// Translates the [`Node`] by the given translation.
- pub fn translate(self, translation: Vector) -> Self {
+ pub fn translate(self, translation: impl Into<Vector>) -> Self {
+ let translation = translation.into();
+
Self {
bounds: self.bounds + translation,
..self
diff --git a/core/src/point.rs b/core/src/point.rs
index ef42852f..cea57518 100644
--- a/core/src/point.rs
+++ b/core/src/point.rs
@@ -36,20 +36,26 @@ impl<T: Num> Point<T> {
}
}
-impl From<[f32; 2]> for Point {
- fn from([x, y]: [f32; 2]) -> Self {
+impl<T> From<[T; 2]> for Point<T>
+where
+ T: Num,
+{
+ fn from([x, y]: [T; 2]) -> Self {
Point { x, y }
}
}
-impl From<[u16; 2]> for Point<u16> {
- fn from([x, y]: [u16; 2]) -> Self {
- Point::new(x, y)
+impl<T> From<(T, T)> for Point<T>
+where
+ T: Num,
+{
+ fn from((x, y): (T, T)) -> Self {
+ Self { x, y }
}
}
-impl From<Point> for [f32; 2] {
- fn from(point: Point) -> [f32; 2] {
+impl<T> From<Point<T>> for [T; 2] {
+ fn from(point: Point<T>) -> [T; 2] {
[point.x, point.y]
}
}
diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs
index fe3b77d3..4cabc7ce 100644
--- a/core/src/widget/text.rs
+++ b/core/src/widget/text.rs
@@ -206,28 +206,27 @@ pub fn layout<Renderer>(
where
Renderer: text::Renderer,
{
- let limits = limits.width(width).height(height);
- let bounds = limits.max();
-
- let size = size.unwrap_or_else(|| renderer.default_size());
- let font = font.unwrap_or_else(|| renderer.default_font());
-
- let State(ref mut paragraph) = state;
-
- paragraph.update(text::Text {
- content,
- bounds,
- size,
- line_height,
- font,
- horizontal_alignment,
- vertical_alignment,
- shaping,
- });
-
- let size = limits.resolve(paragraph.min_bounds(), width, height);
-
- layout::Node::new(size)
+ layout::sized(limits, width, height, |limits| {
+ let bounds = limits.max();
+
+ let size = size.unwrap_or_else(|| renderer.default_size());
+ let font = font.unwrap_or_else(|| renderer.default_font());
+
+ let State(ref mut paragraph) = state;
+
+ paragraph.update(text::Text {
+ content,
+ bounds,
+ size,
+ line_height,
+ font,
+ horizontal_alignment,
+ vertical_alignment,
+ shaping,
+ });
+
+ paragraph.min_bounds()
+ })
}
/// Draws text using the same logic as the [`Text`] widget.
diff --git a/examples/geometry/src/main.rs b/examples/geometry/src/main.rs
index d6a4c702..5cf9963d 100644
--- a/examples/geometry/src/main.rs
+++ b/examples/geometry/src/main.rs
@@ -29,9 +29,9 @@ mod rainbow {
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
- let size = limits.resolve(Size::ZERO, Length::Fill, Length::Shrink);
+ let width = limits.max().width;
- layout::Node::new(Size::new(size.width, size.width))
+ layout::Node::new(Size::new(width, width))
}
fn draw(
diff --git a/examples/loading_spinners/src/circular.rs b/examples/loading_spinners/src/circular.rs
index e80617d0..1b163585 100644
--- a/examples/loading_spinners/src/circular.rs
+++ b/examples/loading_spinners/src/circular.rs
@@ -257,10 +257,7 @@ where
_renderer: &iced::Renderer<Theme>,
limits: &layout::Limits,
) -> layout::Node {
- let limits = limits.width(self.size).height(self.size);
- let size = limits.resolve(Size::ZERO, self.size, self.size);
-
- layout::Node::new(size)
+ layout::atomic(limits, self.size, self.size)
}
fn on_event(
diff --git a/examples/loading_spinners/src/linear.rs b/examples/loading_spinners/src/linear.rs
index d205d3f1..d245575c 100644
--- a/examples/loading_spinners/src/linear.rs
+++ b/examples/loading_spinners/src/linear.rs
@@ -178,10 +178,7 @@ where
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
- let limits = limits.width(self.width).height(self.height);
- let size = limits.resolve(Size::ZERO, self.width, self.height);
-
- layout::Node::new(size)
+ layout::atomic(limits, self.width, self.height)
}
fn on_event(
diff --git a/widget/src/button.rs b/widget/src/button.rs
index 1ce4f662..86abee77 100644
--- a/widget/src/button.rs
+++ b/widget/src/button.rs
@@ -10,8 +10,8 @@ use crate::core::touch;
use crate::core::widget::tree::{self, Tree};
use crate::core::widget::Operation;
use crate::core::{
- Background, Clipboard, Color, Element, Layout, Length, Padding, Point,
- Rectangle, Shell, Size, Vector, Widget,
+ Background, Clipboard, Color, Element, Layout, Length, Padding, Rectangle,
+ Shell, Size, Vector, Widget,
};
pub use iced_style::button::{Appearance, StyleSheet};
@@ -430,20 +430,7 @@ pub fn layout(
padding: Padding,
layout_content: impl FnOnce(&layout::Limits) -> layout::Node,
) -> layout::Node {
- let limits = limits.width(width).height(height);
-
- let content = layout_content(&limits.shrink(padding));
- let padding = padding.fit(content.size(), limits.max());
-
- let size = limits
- .shrink(padding)
- .resolve(content.size(), width, height)
- .expand(padding);
-
- layout::Node::with_children(
- size,
- vec![content.move_to(Point::new(padding.left, padding.top))],
- )
+ layout::padded(limits, width, height, padding, layout_content)
}
/// Returns the [`mouse::Interaction`] of a [`Button`].
diff --git a/widget/src/canvas.rs b/widget/src/canvas.rs
index 2bf09eec..4e42a671 100644
--- a/widget/src/canvas.rs
+++ b/widget/src/canvas.rs
@@ -133,9 +133,7 @@ where
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
- let size = limits.resolve(Size::ZERO, self.width, self.height);
-
- layout::Node::new(size)
+ layout::atomic(limits, self.width, self.height)
}
fn on_event(
diff --git a/widget/src/container.rs b/widget/src/container.rs
index 93d8daba..c98de41c 100644
--- a/widget/src/container.rs
+++ b/widget/src/container.rs
@@ -321,27 +321,19 @@ pub fn layout(
vertical_alignment: alignment::Vertical,
layout_content: impl FnOnce(&layout::Limits) -> layout::Node,
) -> layout::Node {
- let limits = limits
- .width(width)
- .height(height)
- .max_width(max_width)
- .max_height(max_height);
-
- let content = layout_content(&limits.shrink(padding).loose());
- let padding = padding.fit(content.size(), limits.max());
- let size = limits
- .shrink(padding)
- .resolve(content.size(), width, height);
-
- layout::Node::with_children(
- size.expand(padding),
- vec![content
- .move_to(Point::new(padding.left, padding.top))
- .align(
+ layout::positioned(
+ &limits.max_width(max_width).max_height(max_height),
+ width,
+ height,
+ padding,
+ |limits| layout_content(&limits.loose()),
+ |content, size| {
+ content.align(
Alignment::from(horizontal_alignment),
Alignment::from(vertical_alignment),
size,
- )],
+ )
+ },
)
}
diff --git a/widget/src/image.rs b/widget/src/image.rs
index 6750c1b3..e906ac13 100644
--- a/widget/src/image.rs
+++ b/widget/src/image.rs
@@ -99,7 +99,7 @@ where
};
// The size to be available to the widget prior to `Shrink`ing
- let raw_size = limits.resolve(image_size, width, height);
+ let raw_size = limits.resolve(width, height, image_size);
// The uncropped size of the image when fit to the bounds above
let full_size = content_fit.fit(image_size, raw_size);
diff --git a/widget/src/image/viewer.rs b/widget/src/image/viewer.rs
index dc910f1f..98080577 100644
--- a/widget/src/image/viewer.rs
+++ b/widget/src/image/viewer.rs
@@ -113,9 +113,9 @@ where
let Size { width, height } = renderer.dimensions(&self.handle);
let mut size = limits.resolve(
- Size::new(width as f32, height as f32),
self.width,
self.height,
+ Size::new(width as f32, height as f32),
);
let expansion_size = if height > width {
diff --git a/widget/src/overlay/menu.rs b/widget/src/overlay/menu.rs
index b9e06de8..f83eebea 100644
--- a/widget/src/overlay/menu.rs
+++ b/widget/src/overlay/menu.rs
@@ -369,7 +369,7 @@ where
* self.options.len() as f32,
);
- limits.resolve(intrinsic, Length::Fill, Length::Shrink)
+ limits.resolve(Length::Fill, Length::Shrink, intrinsic)
};
layout::Node::new(size)
diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs
index 36c785b7..cf1f0455 100644
--- a/widget/src/pane_grid.rs
+++ b/widget/src/pane_grid.rs
@@ -489,7 +489,7 @@ pub fn layout<Renderer, T>(
&layout::Limits,
) -> layout::Node,
) -> layout::Node {
- let size = limits.resolve(Size::ZERO, width, height);
+ let size = limits.resolve(width, height, Size::ZERO);
let regions = node.pane_regions(spacing, size);
let children = contents
diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs
index d83b0624..2576a1e8 100644
--- a/widget/src/pick_list.rs
+++ b/widget/src/pick_list.rs
@@ -392,7 +392,6 @@ where
{
use std::f32;
- let limits = limits.width(width).height(Length::Shrink);
let font = font.unwrap_or_else(|| renderer.default_font());
let text_size = text_size.unwrap_or_else(|| renderer.default_size());
@@ -451,8 +450,10 @@ where
);
limits
+ .width(width)
+ .height(Length::Shrink)
.shrink(padding)
- .resolve(intrinsic, width, Length::Shrink)
+ .resolve(width, Length::Shrink, intrinsic)
.expand(padding)
};
diff --git a/widget/src/progress_bar.rs b/widget/src/progress_bar.rs
index a05923a2..15f1277b 100644
--- a/widget/src/progress_bar.rs
+++ b/widget/src/progress_bar.rs
@@ -98,13 +98,11 @@ where
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
- let size = limits.resolve(
- Size::ZERO,
+ layout::atomic(
+ limits,
self.width,
self.height.unwrap_or(Length::Fixed(Self::DEFAULT_HEIGHT)),
- );
-
- layout::Node::new(size)
+ )
}
fn draw(
diff --git a/widget/src/rule.rs b/widget/src/rule.rs
index 4ab16c40..cded9cb1 100644
--- a/widget/src/rule.rs
+++ b/widget/src/rule.rs
@@ -75,7 +75,7 @@ where
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
- layout::Node::new(limits.resolve(Size::ZERO, self.width, self.height))
+ layout::atomic(limits, self.width, self.height)
}
fn draw(
diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs
index 5197afde..70db490a 100644
--- a/widget/src/scrollable.rs
+++ b/widget/src/scrollable.rs
@@ -469,28 +469,25 @@ pub fn layout<Renderer>(
direction: &Direction,
layout_content: impl FnOnce(&Renderer, &layout::Limits) -> layout::Node,
) -> layout::Node {
- let limits = limits.width(width).height(height);
-
- let child_limits = layout::Limits::new(
- Size::new(limits.min().width, limits.min().height),
- Size::new(
- if direction.horizontal().is_some() {
- f32::INFINITY
- } else {
- limits.max().width
- },
- if direction.vertical().is_some() {
- f32::MAX
- } else {
- limits.max().height
- },
- ),
- );
-
- let content = layout_content(renderer, &child_limits);
- let size = limits.resolve(content.size(), width, height);
+ layout::contained(limits, width, height, |limits| {
+ let child_limits = layout::Limits::new(
+ Size::new(limits.min().width, limits.min().height),
+ Size::new(
+ if direction.horizontal().is_some() {
+ f32::INFINITY
+ } else {
+ limits.max().width
+ },
+ if direction.vertical().is_some() {
+ f32::MAX
+ } else {
+ limits.max().height
+ },
+ ),
+ );
- layout::Node::with_children(size, vec![content])
+ layout_content(renderer, &child_limits)
+ })
}
/// Processes an [`Event`] and updates the [`State`] of a [`Scrollable`]
diff --git a/widget/src/shader.rs b/widget/src/shader.rs
index 82432c6c..16b68c55 100644
--- a/widget/src/shader.rs
+++ b/widget/src/shader.rs
@@ -83,10 +83,7 @@ where
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
- let limits = limits.width(self.width).height(self.height);
- let size = limits.resolve(Size::ZERO, self.width, self.height);
-
- layout::Node::new(size)
+ layout::atomic(limits, self.width, self.height)
}
fn on_event(
diff --git a/widget/src/slider.rs b/widget/src/slider.rs
index 27588852..1bc94661 100644
--- a/widget/src/slider.rs
+++ b/widget/src/slider.rs
@@ -172,9 +172,7 @@ where
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
- let size = limits.resolve(Size::ZERO, self.width, self.height);
-
- layout::Node::new(size)
+ layout::atomic(limits, self.width, self.height)
}
fn on_event(
diff --git a/widget/src/space.rs b/widget/src/space.rs
index 9fd4dcb9..eef990d1 100644
--- a/widget/src/space.rs
+++ b/widget/src/space.rs
@@ -58,7 +58,7 @@ where
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
- layout::Node::new(limits.resolve(Size::ZERO, self.width, self.height))
+ layout::atomic(limits, self.width, self.height)
}
fn draw(
diff --git a/widget/src/svg.rs b/widget/src/svg.rs
index 75ab238a..830abb0f 100644
--- a/widget/src/svg.rs
+++ b/widget/src/svg.rs
@@ -114,7 +114,7 @@ where
let image_size = Size::new(width as f32, height as f32);
// The size to be available to the widget prior to `Shrink`ing
- let raw_size = limits.resolve(image_size, self.width, self.height);
+ let raw_size = limits.resolve(self.width, self.height, image_size);
// The uncropped size of the image when fit to the bounds above
let full_size = self.content_fit.fit(image_size, raw_size);
diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs
index 7e91105c..d8540658 100644
--- a/widget/src/text_input.rs
+++ b/widget/src/text_input.rs
@@ -508,8 +508,8 @@ where
let padding = padding.fit(Size::ZERO, limits.max());
let height = line_height.to_absolute(text_size);
- let limits = limits.width(width).shrink(padding).height(height);
- let text_bounds = limits.resolve(Size::ZERO, width, height);
+ let limits = limits.width(width).shrink(padding);
+ let text_bounds = limits.resolve(width, height, Size::ZERO);
let placeholder_text = Text {
font,
diff --git a/widget/src/vertical_slider.rs b/widget/src/vertical_slider.rs
index 35bc2fe2..a3029d76 100644
--- a/widget/src/vertical_slider.rs
+++ b/widget/src/vertical_slider.rs
@@ -169,9 +169,7 @@ where
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
- let size = limits.resolve(Size::ZERO, self.width, self.height);
-
- layout::Node::new(size)
+ layout::atomic(limits, self.width, self.height)
}
fn on_event(