diff --git a/examples/gallery/src/main.rs b/examples/gallery/src/main.rs index 73958ad4..0d52483b 100644 --- a/examples/gallery/src/main.rs +++ b/examples/gallery/src/main.rs @@ -22,6 +22,10 @@ use std::collections::HashMap; fn main() -> iced::Result { iced::application(Gallery::new, Gallery::update, Gallery::view) + .window_size(( + Preview::WIDTH as f32 * 4.0, + Preview::HEIGHT as f32 * 2.5, + )) .subscription(Gallery::subscription) .theme(Gallery::theme) .run() @@ -183,7 +187,7 @@ impl Gallery { let gallery = grid(images) .fluid(Preview::WIDTH) - .ratio(Preview::WIDTH as f32 / Preview::HEIGHT as f32) + .height(grid::aspect_ratio(Preview::WIDTH, Preview::HEIGHT)) .spacing(10); let content = container(scrollable(gallery).spacing(10)).padding(10); @@ -225,7 +229,7 @@ fn card<'a>( horizontal_space().into() }; - let card = mouse_area(container(image).height(Fill).style(container::dark)) + let card = mouse_area(container(image).style(container::dark)) .on_enter(Message::ThumbnailHovered(metadata.id, true)) .on_exit(Message::ThumbnailHovered(metadata.id, false)); @@ -245,10 +249,7 @@ fn card<'a>( } fn placeholder<'a>() -> Element<'a, Message> { - container(horizontal_space()) - .height(Fill) - .style(container::dark) - .into() + container(horizontal_space()).style(container::dark).into() } enum Preview { diff --git a/widget/src/grid.rs b/widget/src/grid.rs index e0486856..26e741db 100644 --- a/widget/src/grid.rs +++ b/widget/src/grid.rs @@ -15,7 +15,7 @@ pub struct Grid<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> { spacing: f32, columns: Constraint, width: Option, - ratio: Option, + height: Sizing, children: Vec>, } @@ -55,7 +55,7 @@ where spacing: 0.0, columns: Constraint::Amount(3), width: None, - ratio: None, + height: Sizing::AspectRatio(1.0), children, } } @@ -76,6 +76,14 @@ where self } + /// Sets the height of the [`Grid`]. + /// + /// By default, a [`Grid`] uses a cell aspect ratio of `1.0` (i.e. squares). + pub fn height(mut self, height: impl Into) -> Self { + self.height = height.into(); + self + } + /// Sets the amount of columns in the [`Grid`]. pub fn columns(mut self, column: usize) -> Self { self.columns = Constraint::Amount(column); @@ -89,12 +97,6 @@ where self } - /// Sets the amount of horizontal pixels per each vertical pixel of a cell in the [`Grid`]. - pub fn ratio(mut self, ratio: impl Into) -> Self { - self.ratio = Some(ratio.into()); - self - } - /// Adds an [`Element`] to the [`Grid`]. pub fn push( mut self, @@ -166,7 +168,10 @@ where .width .map(|pixels| Length::Fixed(pixels.0)) .unwrap_or(Length::Fill), - height: Length::Shrink, + height: match self.height { + Sizing::AspectRatio(_) => Length::Shrink, + Sizing::EvenlyDistribute(length) => length, + }, } } @@ -194,22 +199,23 @@ where - self.spacing * (cells_per_row - 1) as f32) / cells_per_row as f32; - let cell_height = if let Some(ratio) = self.ratio { - cell_width / ratio.0 - } else if available.height.is_finite() { - available.height / total_rows as f32 - } else { - f32::INFINITY + let cell_height = match self.height { + Sizing::AspectRatio(ratio) => Some(cell_width / ratio), + Sizing::EvenlyDistribute(Length::Shrink) => None, + Sizing::EvenlyDistribute(_) => { + Some(available.height / total_rows as f32) + } }; let cell_limits = layout::Limits::new( - Size::new(cell_width, 0.0), - Size::new(cell_width, cell_height), + Size::new(cell_width, cell_height.unwrap_or(0.0)), + Size::new(cell_width, cell_height.unwrap_or(available.height)), ); let mut nodes = Vec::new(); let mut x = 0.0; let mut y = 0.0; + let mut row_height = 0.0f32; for (i, (child, tree)) in self.children.iter().zip(&mut tree.children).enumerate() @@ -219,11 +225,15 @@ where .layout(tree, renderer, &cell_limits) .move_to((x, y)); - x += node.size().width + self.spacing; + let size = node.size(); + + x += size.width + self.spacing; + row_height = row_height.max(size.height); if (i + 1) % cells_per_row == 0 { - y += cell_height + self.spacing; + y += cell_height.unwrap_or(row_height) + self.spacing; x = 0.0; + row_height = 0.0; } nodes.push(node); @@ -232,7 +242,7 @@ where if x == 0.0 { y -= self.spacing; } else { - y += cell_height; + y += cell_height.unwrap_or(row_height); } layout::Node::with_children(Size::new(available.width, y), nodes) @@ -356,3 +366,38 @@ where Self::new(row) } } + +/// The sizing strategy of a [`Grid`]. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Sizing { + /// The [`Grid`] will ensure each cell follows the given aspect ratio and the + /// total size will be the sum of the cells and the spacing between them. + /// + /// The ratio is the amount of horizontal pixels per each vertical pixel of a cell + /// in the [`Grid`]. + AspectRatio(f32), + + /// The [`Grid`] will evenly distribute the space available in the given [`Length`] + /// for each cell. + EvenlyDistribute(Length), +} + +impl From for Sizing { + fn from(height: f32) -> Self { + Self::EvenlyDistribute(Length::from(height)) + } +} + +impl From for Sizing { + fn from(height: Length) -> Self { + Self::EvenlyDistribute(height) + } +} + +/// Creates a new [`Sizing`] strategy that maintains the given aspect ratio. +pub fn aspect_ratio( + width: impl Into, + height: impl Into, +) -> Sizing { + Sizing::AspectRatio(width.into().0 / height.into().0) +} diff --git a/widget/src/lib.rs b/widget/src/lib.rs index 96692c85..dcaea007 100644 --- a/widget/src/lib.rs +++ b/widget/src/lib.rs @@ -10,7 +10,6 @@ pub use iced_runtime::core; mod action; mod column; -mod grid; mod mouse_area; mod pin; mod space; @@ -21,6 +20,7 @@ pub mod button; pub mod checkbox; pub mod combo_box; pub mod container; +pub mod grid; pub mod keyed; pub mod overlay; pub mod pane_grid; diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 0c876036..d50591a1 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -461,7 +461,7 @@ where limits.max().width }, if self.direction.vertical().is_some() { - f32::MAX + f32::INFINITY } else { limits.max().height },