Make Shrink have priority over Fill in layout

This commit is contained in:
Héctor Ramón Jiménez 2023-03-16 20:23:25 +01:00 committed by Héctor Ramón Jiménez
parent 68c0484b5c
commit 0655a20ad1
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
46 changed files with 264 additions and 273 deletions

View file

@ -71,12 +71,12 @@ pub fn next_to_each_other(
left: impl FnOnce(&Limits) -> Node,
right: impl FnOnce(&Limits) -> Node,
) -> Node {
let mut left_node = left(limits);
let left_node = left(limits);
let left_size = left_node.size();
let right_limits = limits.shrink(Size::new(left_size.width + spacing, 0.0));
let mut right_node = right(&right_limits);
let right_node = right(&right_limits);
let right_size = right_node.size();
let (left_y, right_y) = if left_size.height > right_size.height {
@ -85,14 +85,14 @@ pub fn next_to_each_other(
((right_size.height - left_size.height) / 2.0, 0.0)
};
left_node.move_to(Point::new(0.0, left_y));
right_node.move_to(Point::new(left_size.width + spacing, right_y));
Node::with_children(
Size::new(
left_size.width + spacing + right_size.width,
left_size.height.max(right_size.height),
),
vec![left_node, right_node],
vec![
left_node.move_to(Point::new(0.0, left_y)),
right_node.move_to(Point::new(left_size.width + spacing, right_y)),
],
)
}

View file

@ -20,7 +20,7 @@ use crate::Element;
use crate::layout::{Limits, Node};
use crate::widget;
use crate::{Alignment, Padding, Point, Size};
use crate::{Alignment, Length, Padding, Point, Size};
/// The main axis of a flex layout.
#[derive(Debug)]
@ -63,6 +63,8 @@ pub fn resolve<Message, Renderer>(
axis: Axis,
renderer: &Renderer,
limits: &Limits,
width: Length,
height: Length,
padding: Padding,
spacing: f32,
align_items: Alignment,
@ -72,12 +74,12 @@ pub fn resolve<Message, Renderer>(
where
Renderer: crate::Renderer,
{
let limits = limits.pad(padding);
let limits = limits.width(width).height(height).shrink(padding);
let total_spacing = spacing * items.len().saturating_sub(1) as f32;
let max_cross = axis.cross(limits.max());
let mut fill_sum = 0;
let mut cross = axis.cross(limits.min()).max(axis.cross(limits.fill()));
let mut cross = 0.0f32;
let mut available = axis.main(limits.max()) - total_spacing;
let mut nodes: Vec<Node> = Vec::with_capacity(items.len());
@ -109,7 +111,16 @@ where
}
}
let remaining = available.max(0.0);
let remaining = match axis {
Axis::Horizontal => match width {
Length::Shrink => 0.0,
_ => available.max(0.0),
},
Axis::Vertical => match height {
Length::Shrink => 0.0,
_ => available.max(0.0),
},
};
for (i, (child, tree)) in items.iter().zip(trees).enumerate() {
let fill_factor = match axis {
@ -154,18 +165,18 @@ where
let (x, y) = axis.pack(main, pad.1);
node.move_to(Point::new(x, y));
node.move_to_mut(Point::new(x, y));
match axis {
Axis::Horizontal => {
node.align(
node.align_mut(
Alignment::Start,
align_items,
Size::new(0.0, cross),
);
}
Axis::Vertical => {
node.align(
node.align_mut(
align_items,
Alignment::Start,
Size::new(cross, 0.0),
@ -179,7 +190,7 @@ where
}
let (width, height) = axis.pack(main - pad.0, cross);
let size = limits.resolve(Size::new(width, height));
let size = limits.resolve(Size::new(width, height), width, height);
Node::with_children(size.pad(padding), nodes)
Node::with_children(size.expand(padding), nodes)
}

View file

@ -1,12 +1,11 @@
#![allow(clippy::manual_clamp)]
use crate::{Length, Padding, Size};
use crate::{Length, Size};
/// A set of size constraints for layouting.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Limits {
min: Size,
max: Size,
fill: Size,
}
impl Limits {
@ -14,16 +13,11 @@ impl Limits {
pub const NONE: Limits = Limits {
min: Size::ZERO,
max: Size::INFINITY,
fill: Size::INFINITY,
};
/// Creates new [`Limits`] with the given minimum and maximum [`Size`].
pub const fn new(min: Size, max: Size) -> Limits {
Limits {
min,
max,
fill: Size::INFINITY,
}
Limits { min, max }
}
/// Returns the minimum [`Size`] of the [`Limits`].
@ -36,26 +30,15 @@ impl Limits {
self.max
}
/// Returns the fill [`Size`] of the [`Limits`].
pub fn fill(&self) -> Size {
self.fill
}
/// Applies a width constraint to the current [`Limits`].
pub fn width(mut self, width: impl Into<Length>) -> Limits {
match width.into() {
Length::Shrink => {
self.fill.width = self.min.width;
}
Length::Fill | Length::FillPortion(_) => {
self.fill.width = self.fill.width.min(self.max.width);
}
Length::Shrink | Length::Fill | Length::FillPortion(_) => {}
Length::Fixed(amount) => {
let new_width = amount.min(self.max.width).max(self.min.width);
self.min.width = new_width;
self.max.width = new_width;
self.fill.width = new_width;
}
}
@ -65,19 +48,13 @@ impl Limits {
/// Applies a height constraint to the current [`Limits`].
pub fn height(mut self, height: impl Into<Length>) -> Limits {
match height.into() {
Length::Shrink => {
self.fill.height = self.min.height;
}
Length::Fill | Length::FillPortion(_) => {
self.fill.height = self.fill.height.min(self.max.height);
}
Length::Shrink | Length::Fill | Length::FillPortion(_) => {}
Length::Fixed(amount) => {
let new_height =
amount.min(self.max.height).max(self.min.height);
self.min.height = new_height;
self.max.height = new_height;
self.fill.height = new_height;
}
}
@ -112,13 +89,10 @@ impl Limits {
self
}
/// Shrinks the current [`Limits`] to account for the given padding.
pub fn pad(&self, padding: Padding) -> Limits {
self.shrink(Size::new(padding.horizontal(), padding.vertical()))
}
/// Shrinks the current [`Limits`] by the given [`Size`].
pub fn shrink(&self, size: Size) -> Limits {
pub fn shrink(&self, size: impl Into<Size>) -> Limits {
let size = size.into();
let min = Size::new(
(self.min().width - size.width).max(0.0),
(self.min().height - size.height).max(0.0),
@ -129,12 +103,7 @@ impl Limits {
(self.max().height - size.height).max(0.0),
);
let fill = Size::new(
(self.fill.width - size.width).max(0.0),
(self.fill.height - size.height).max(0.0),
);
Limits { min, max, fill }
Limits { min, max }
}
/// Removes the minimum width constraint for the current [`Limits`].
@ -142,22 +111,38 @@ impl Limits {
Limits {
min: Size::ZERO,
max: self.max,
fill: self.fill,
}
}
/// Computes the resulting [`Size`] that fits the [`Limits`] given the
/// intrinsic size of some content.
pub fn resolve(&self, intrinsic_size: Size) -> Size {
Size::new(
intrinsic_size
.width
.min(self.max.width)
.max(self.fill.width),
intrinsic_size
pub fn resolve(
&self,
intrinsic_size: Size,
width: impl Into<Length>,
height: impl Into<Length>,
) -> Size {
let width = match width.into() {
Length::Fill | Length::FillPortion(_) => self.max.width,
Length::Fixed(amount) => {
amount.min(self.max.width).max(self.min.width)
}
Length::Shrink => {
intrinsic_size.width.min(self.max.width).max(self.min.width)
}
};
let height = match height.into() {
Length::Fill | Length::FillPortion(_) => self.max.height,
Length::Fixed(amount) => {
amount.min(self.max.height).max(self.min.height)
}
Length::Shrink => intrinsic_size
.height
.min(self.max.height)
.max(self.fill.height),
)
.max(self.min.height),
};
Size::new(width, height)
}
}

View file

@ -1,4 +1,4 @@
use crate::{Alignment, Point, Rectangle, Size, Vector};
use crate::{Alignment, Padding, Point, Rectangle, Size, Vector};
/// The bounds of an element and its children.
#[derive(Debug, Clone, Default)]
@ -26,6 +26,14 @@ impl Node {
}
}
/// Creates a new [`Node`] that wraps a single child with some [`Padding`].
pub fn container(child: Self, padding: Padding) -> Self {
Self::with_children(
child.bounds.size().expand(padding),
vec![child.move_to(Point::new(padding.left, padding.top))],
)
}
/// Returns the [`Size`] of the [`Node`].
pub fn size(&self) -> Size {
Size::new(self.bounds.width, self.bounds.height)
@ -43,6 +51,17 @@ impl Node {
/// Aligns the [`Node`] in the given space.
pub fn align(
mut self,
horizontal_alignment: Alignment,
vertical_alignment: Alignment,
space: Size,
) -> Self {
self.align_mut(horizontal_alignment, vertical_alignment, space);
self
}
/// Mutable reference version of [`align`].
pub fn align_mut(
&mut self,
horizontal_alignment: Alignment,
vertical_alignment: Alignment,
@ -70,7 +89,13 @@ impl Node {
}
/// Moves the [`Node`] to the given position.
pub fn move_to(&mut self, position: Point) {
pub fn move_to(mut self, position: Point) -> Self {
self.move_to_mut(position);
self
}
/// Mutable reference version of [`move_to`].
pub fn move_to_mut(&mut self, position: Point) {
self.bounds.x = position.x;
self.bounds.y = position.y;
}

View file

@ -154,3 +154,9 @@ impl From<[f32; 4]> for Padding {
}
}
}
impl From<Padding> for Size {
fn from(padding: Padding) -> Self {
Self::new(padding.horizontal(), padding.vertical())
}
}

View file

@ -1,4 +1,4 @@
use crate::{Padding, Vector};
use crate::Vector;
/// An amount of space in 2 dimensions.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -26,15 +26,7 @@ impl Size {
/// A [`Size`] with infinite width and height.
pub const INFINITY: Size = Size::new(f32::INFINITY, f32::INFINITY);
/// Increments the [`Size`] to account for the given padding.
pub fn pad(&self, padding: Padding) -> Self {
Size {
width: self.width + padding.horizontal(),
height: self.height + padding.vertical(),
}
}
/// Returns the minimum of each component of this size and another
/// Returns the minimum of each component of this size and another.
pub fn min(self, other: Self) -> Self {
Size {
width: self.width.min(other.width),
@ -42,13 +34,23 @@ impl Size {
}
}
/// Returns the maximum of each component of this size and another
/// Returns the maximum of each component of this size and another.
pub fn max(self, other: Self) -> Self {
Size {
width: self.width.max(other.width),
height: self.height.max(other.height),
}
}
/// Expands this [`Size`] by the given amount.
pub fn expand(self, other: impl Into<Size>) -> Self {
let other = other.into();
Size {
width: self.width + other.width,
height: self.height + other.height,
}
}
}
impl From<[f32; 2]> for Size {

View file

@ -224,7 +224,7 @@ where
shaping,
});
let size = limits.resolve(paragraph.min_bounds());
let size = limits.resolve(paragraph.min_bounds(), width, height);
layout::Node::new(size)
}