use crate::{Length, Size};
/// A set of size constraints for layouting.
#[derive(Debug, Clone, Copy)]
pub struct Limits {
min: Size,
max: Size,
fill: Size,
}
impl Limits {
/// No 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`].
///
/// [`Limits`]: struct.Limits.html
/// [`Size`]: ../struct.Size.html
pub const fn new(min: Size, max: Size) -> Limits {
Limits {
min,
max,
fill: Size::INFINITY,
}
}
/// Returns the minimum [`Size`] of the [`Limits`].
///
/// [`Limits`]: struct.Limits.html
/// [`Size`]: ../struct.Size.html
pub fn min(&self) -> Size {
self.min
}
/// Returns the maximum [`Size`] of the [`Limits`].
///
/// [`Limits`]: struct.Limits.html
/// [`Size`]: ../struct.Size.html
pub fn max(&self) -> Size {
self.max
}
/// Returns the fill [`Size`] of the [`Limits`].
///
/// [`Limits`]: struct.Limits.html
/// [`Size`]: ../struct.Size.html
pub fn fill(&self) -> Size {
self.fill
}
/// Applies a width constraint to the current [`Limits`].
///
/// [`Limits`]: struct.Limits.html
pub fn width(mut self, width: Length) -> Limits {
match width {
Length::Shrink => {
self.fill.width = self.min.width;
}
Length::Fill | Length::FillPortion(_) => {
self.fill.width = self.fill.width.min(self.max.width);
}
Length::Units(units) => {
let new_width =
(units as f32).min(self.max.width).max(self.min.width);
self.min.width = new_width;
self.max.width = new_width;
self.fill.width = new_width;
}
}
self
}
/// Applies a height constraint to the current [`Limits`].
///
/// [`Limits`]: struct.Limits.html
pub fn height(mut self, height: Length) -> Limits {
match height {
Length::Shrink => {
self.fill.height = self.min.height;
}
Length::Fill | Length::FillPortion(_) => {
self.fill.height = self.fill.height.min(self.max.height);
}
Length::Units(units) => {
let new_height =
(units as f32).min(self.max.height).max(self.min.height);
self.min.height = new_height;
self.max.height = new_height;
self.fill.height = new_height;
}
}
self
}
/// Applies a minimum width constraint to the current [`Limits`].
///
/// [`Limits`]: struct.Limits.html
pub fn min_width(mut self, min_width: u32) -> Limits {
self.min.width =
self.min.width.max(min_width as f32).min(self.max.width);
self
}
/// Applies a maximum width constraint to the current [`Limits`].
///
/// [`Limits`]: struct.Limits.html
pub fn max_width(mut self, max_width: u32) -> Limits {
self.max.width =
self.max.width.min(max_width as f32).max(self.min.width);
self
}
/// Applies a minimum height constraint to the current [`Limits`].
///
/// [`Limits`]: struct.Limits.html
pub fn min_height(mut self, min_height: u32) -> Limits {
self.min.height =
self.min.height.max(min_height as f32).min(self.max.height);
self
}
/// Applies a maximum height constraint to the current [`Limits`].
///
/// [`Limits`]: struct.Limits.html
pub fn max_height(mut self, max_height: u32) -> Limits {
self.max.height =
self.max.height.min(max_height as f32).max(self.min.height);
self
}
/// Shrinks the current [`Limits`] to account for the given padding.
///
/// [`Limits`]: struct.Limits.html
pub fn pad(&self, padding: f32) -> Limits {
self.shrink(Size::new(padding * 2.0, padding * 2.0))
}
/// Shrinks the current [`Limits`] by the given [`Size`].
///
/// [`Limits`]: struct.Limits.html
/// [`Size`]: ../struct.Size.html
pub fn shrink(&self, size: Size) -> Limits {
let min = Size::new(
(self.min().width - size.width).max(0.0),
(self.min().height - size.height).max(0.0),
);
let max = Size::new(
(self.max().width - size.width).max(0.0),
(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 }
}
/// Removes the minimum width constraint for the current [`Limits`].
///
/// [`Limits`]: struct.Limits.html
pub fn loose(&self) -> 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.
///
/// [`Limits`]: struct.Limits.html
pub fn resolve(&self, intrinsic_size: Size) -> Size {
Size::new(
intrinsic_size
.width
.min(self.max.width)
.max(self.fill.width),
intrinsic_size
.height
.min(self.max.height)
.max(self.fill.height),
)
}
}