Make grid sizing strategy explicit and more intuitive
This commit is contained in:
parent
504d9c2959
commit
687750e026
4 changed files with 74 additions and 28 deletions
|
|
@ -22,6 +22,10 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
fn main() -> iced::Result {
|
fn main() -> iced::Result {
|
||||||
iced::application(Gallery::new, Gallery::update, Gallery::view)
|
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)
|
.subscription(Gallery::subscription)
|
||||||
.theme(Gallery::theme)
|
.theme(Gallery::theme)
|
||||||
.run()
|
.run()
|
||||||
|
|
@ -183,7 +187,7 @@ impl Gallery {
|
||||||
|
|
||||||
let gallery = grid(images)
|
let gallery = grid(images)
|
||||||
.fluid(Preview::WIDTH)
|
.fluid(Preview::WIDTH)
|
||||||
.ratio(Preview::WIDTH as f32 / Preview::HEIGHT as f32)
|
.height(grid::aspect_ratio(Preview::WIDTH, Preview::HEIGHT))
|
||||||
.spacing(10);
|
.spacing(10);
|
||||||
|
|
||||||
let content = container(scrollable(gallery).spacing(10)).padding(10);
|
let content = container(scrollable(gallery).spacing(10)).padding(10);
|
||||||
|
|
@ -225,7 +229,7 @@ fn card<'a>(
|
||||||
horizontal_space().into()
|
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_enter(Message::ThumbnailHovered(metadata.id, true))
|
||||||
.on_exit(Message::ThumbnailHovered(metadata.id, false));
|
.on_exit(Message::ThumbnailHovered(metadata.id, false));
|
||||||
|
|
||||||
|
|
@ -245,10 +249,7 @@ fn card<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn placeholder<'a>() -> Element<'a, Message> {
|
fn placeholder<'a>() -> Element<'a, Message> {
|
||||||
container(horizontal_space())
|
container(horizontal_space()).style(container::dark).into()
|
||||||
.height(Fill)
|
|
||||||
.style(container::dark)
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Preview {
|
enum Preview {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ pub struct Grid<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {
|
||||||
spacing: f32,
|
spacing: f32,
|
||||||
columns: Constraint,
|
columns: Constraint,
|
||||||
width: Option<Pixels>,
|
width: Option<Pixels>,
|
||||||
ratio: Option<Pixels>,
|
height: Sizing,
|
||||||
children: Vec<Element<'a, Message, Theme, Renderer>>,
|
children: Vec<Element<'a, Message, Theme, Renderer>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ where
|
||||||
spacing: 0.0,
|
spacing: 0.0,
|
||||||
columns: Constraint::Amount(3),
|
columns: Constraint::Amount(3),
|
||||||
width: None,
|
width: None,
|
||||||
ratio: None,
|
height: Sizing::AspectRatio(1.0),
|
||||||
children,
|
children,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -76,6 +76,14 @@ where
|
||||||
self
|
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<Sizing>) -> Self {
|
||||||
|
self.height = height.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the amount of columns in the [`Grid`].
|
/// Sets the amount of columns in the [`Grid`].
|
||||||
pub fn columns(mut self, column: usize) -> Self {
|
pub fn columns(mut self, column: usize) -> Self {
|
||||||
self.columns = Constraint::Amount(column);
|
self.columns = Constraint::Amount(column);
|
||||||
|
|
@ -89,12 +97,6 @@ where
|
||||||
self
|
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<Pixels>) -> Self {
|
|
||||||
self.ratio = Some(ratio.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds an [`Element`] to the [`Grid`].
|
/// Adds an [`Element`] to the [`Grid`].
|
||||||
pub fn push(
|
pub fn push(
|
||||||
mut self,
|
mut self,
|
||||||
|
|
@ -166,7 +168,10 @@ where
|
||||||
.width
|
.width
|
||||||
.map(|pixels| Length::Fixed(pixels.0))
|
.map(|pixels| Length::Fixed(pixels.0))
|
||||||
.unwrap_or(Length::Fill),
|
.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)
|
- self.spacing * (cells_per_row - 1) as f32)
|
||||||
/ cells_per_row as f32;
|
/ cells_per_row as f32;
|
||||||
|
|
||||||
let cell_height = if let Some(ratio) = self.ratio {
|
let cell_height = match self.height {
|
||||||
cell_width / ratio.0
|
Sizing::AspectRatio(ratio) => Some(cell_width / ratio),
|
||||||
} else if available.height.is_finite() {
|
Sizing::EvenlyDistribute(Length::Shrink) => None,
|
||||||
available.height / total_rows as f32
|
Sizing::EvenlyDistribute(_) => {
|
||||||
} else {
|
Some(available.height / total_rows as f32)
|
||||||
f32::INFINITY
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let cell_limits = layout::Limits::new(
|
let cell_limits = layout::Limits::new(
|
||||||
Size::new(cell_width, 0.0),
|
Size::new(cell_width, cell_height.unwrap_or(0.0)),
|
||||||
Size::new(cell_width, cell_height),
|
Size::new(cell_width, cell_height.unwrap_or(available.height)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut nodes = Vec::new();
|
let mut nodes = Vec::new();
|
||||||
let mut x = 0.0;
|
let mut x = 0.0;
|
||||||
let mut y = 0.0;
|
let mut y = 0.0;
|
||||||
|
let mut row_height = 0.0f32;
|
||||||
|
|
||||||
for (i, (child, tree)) in
|
for (i, (child, tree)) in
|
||||||
self.children.iter().zip(&mut tree.children).enumerate()
|
self.children.iter().zip(&mut tree.children).enumerate()
|
||||||
|
|
@ -219,11 +225,15 @@ where
|
||||||
.layout(tree, renderer, &cell_limits)
|
.layout(tree, renderer, &cell_limits)
|
||||||
.move_to((x, y));
|
.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 {
|
if (i + 1) % cells_per_row == 0 {
|
||||||
y += cell_height + self.spacing;
|
y += cell_height.unwrap_or(row_height) + self.spacing;
|
||||||
x = 0.0;
|
x = 0.0;
|
||||||
|
row_height = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
|
|
@ -232,7 +242,7 @@ where
|
||||||
if x == 0.0 {
|
if x == 0.0 {
|
||||||
y -= self.spacing;
|
y -= self.spacing;
|
||||||
} else {
|
} else {
|
||||||
y += cell_height;
|
y += cell_height.unwrap_or(row_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
layout::Node::with_children(Size::new(available.width, y), nodes)
|
layout::Node::with_children(Size::new(available.width, y), nodes)
|
||||||
|
|
@ -356,3 +366,38 @@ where
|
||||||
Self::new(row)
|
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<f32> for Sizing {
|
||||||
|
fn from(height: f32) -> Self {
|
||||||
|
Self::EvenlyDistribute(Length::from(height))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Length> 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<Pixels>,
|
||||||
|
height: impl Into<Pixels>,
|
||||||
|
) -> Sizing {
|
||||||
|
Sizing::AspectRatio(width.into().0 / height.into().0)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ pub use iced_runtime::core;
|
||||||
|
|
||||||
mod action;
|
mod action;
|
||||||
mod column;
|
mod column;
|
||||||
mod grid;
|
|
||||||
mod mouse_area;
|
mod mouse_area;
|
||||||
mod pin;
|
mod pin;
|
||||||
mod space;
|
mod space;
|
||||||
|
|
@ -21,6 +20,7 @@ pub mod button;
|
||||||
pub mod checkbox;
|
pub mod checkbox;
|
||||||
pub mod combo_box;
|
pub mod combo_box;
|
||||||
pub mod container;
|
pub mod container;
|
||||||
|
pub mod grid;
|
||||||
pub mod keyed;
|
pub mod keyed;
|
||||||
pub mod overlay;
|
pub mod overlay;
|
||||||
pub mod pane_grid;
|
pub mod pane_grid;
|
||||||
|
|
|
||||||
|
|
@ -461,7 +461,7 @@ where
|
||||||
limits.max().width
|
limits.max().width
|
||||||
},
|
},
|
||||||
if self.direction.vertical().is_some() {
|
if self.direction.vertical().is_some() {
|
||||||
f32::MAX
|
f32::INFINITY
|
||||||
} else {
|
} else {
|
||||||
limits.max().height
|
limits.max().height
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue