Use row-major order for cells in table widget
This commit is contained in:
parent
a3d42e2d37
commit
291e615c0b
1 changed files with 76 additions and 69 deletions
|
|
@ -10,13 +10,12 @@ use crate::core::{
|
||||||
Widget,
|
Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn table<'a, R, T, Message, Theme, Renderer>(
|
pub fn table<'a, T, Message, Theme, Renderer>(
|
||||||
columns: impl IntoIterator<Item = Column<'a, T, Message, Theme, Renderer>>,
|
columns: impl IntoIterator<Item = Column<'a, T, Message, Theme, Renderer>>,
|
||||||
rows: R,
|
rows: impl IntoIterator<Item = T>,
|
||||||
) -> Table<'a, Message, Theme, Renderer>
|
) -> Table<'a, Message, Theme, Renderer>
|
||||||
where
|
where
|
||||||
R: IntoIterator<Item = T>,
|
T: Clone,
|
||||||
R::IntoIter: Clone,
|
|
||||||
Theme: Catalog,
|
Theme: Catalog,
|
||||||
Renderer: core::Renderer,
|
Renderer: core::Renderer,
|
||||||
{
|
{
|
||||||
|
|
@ -66,46 +65,51 @@ where
|
||||||
Theme: Catalog,
|
Theme: Catalog,
|
||||||
Renderer: core::Renderer,
|
Renderer: core::Renderer,
|
||||||
{
|
{
|
||||||
pub fn new<R, T>(
|
pub fn new<T>(
|
||||||
columns: impl IntoIterator<Item = Column<'a, T, Message, Theme, Renderer>>,
|
columns: impl IntoIterator<Item = Column<'a, T, Message, Theme, Renderer>>,
|
||||||
rows: R,
|
rows: impl IntoIterator<Item = T>,
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
R: IntoIterator<Item = T>,
|
T: Clone,
|
||||||
R::IntoIter: Clone,
|
|
||||||
{
|
{
|
||||||
let columns = columns.into_iter();
|
let columns = columns.into_iter();
|
||||||
let rows = rows.into_iter();
|
let rows = rows.into_iter();
|
||||||
|
|
||||||
let mut width = Length::Shrink;
|
let mut width = Length::Shrink;
|
||||||
let mut height = Length::Shrink;
|
let mut height = Length::Shrink;
|
||||||
|
|
||||||
let mut cells = Vec::with_capacity(
|
let mut cells = Vec::with_capacity(
|
||||||
columns.size_hint().0 * (1 + rows.size_hint().0),
|
columns.size_hint().0 * (1 + rows.size_hint().0),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut columns: Vec<_> = columns
|
let (mut columns, views): (Vec<_>, Vec<_>) = columns
|
||||||
.into_iter()
|
|
||||||
.map(|column| {
|
.map(|column| {
|
||||||
cells.push(column.header);
|
|
||||||
cells.extend(rows.clone().map(|row| {
|
|
||||||
let cell = (column.view)(row);
|
|
||||||
let size_hint = cell.as_widget().size_hint();
|
|
||||||
|
|
||||||
height = height.enclose(size_hint.height);
|
|
||||||
|
|
||||||
cell
|
|
||||||
}));
|
|
||||||
|
|
||||||
width = width.enclose(column.width);
|
width = width.enclose(column.width);
|
||||||
|
|
||||||
Column_ {
|
cells.push(column.header);
|
||||||
width: column.width,
|
|
||||||
align_x: column.align_x,
|
(
|
||||||
align_y: column.align_y,
|
Column_ {
|
||||||
}
|
width: column.width,
|
||||||
|
align_x: column.align_x,
|
||||||
|
align_y: column.align_y,
|
||||||
|
},
|
||||||
|
column.view,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
for row in rows {
|
||||||
|
for view in &views {
|
||||||
|
let cell = view(row.clone());
|
||||||
|
let size_hint = cell.as_widget().size_hint();
|
||||||
|
|
||||||
|
height = height.enclose(size_hint.height);
|
||||||
|
|
||||||
|
cells.push(cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if width == Length::Shrink {
|
if width == Length::Shrink {
|
||||||
if let Some(first) = columns.first_mut() {
|
if let Some(first) = columns.first_mut() {
|
||||||
first.width = Length::Fill;
|
first.width = Length::Fill;
|
||||||
|
|
@ -163,7 +167,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Metrics {
|
struct Metrics {
|
||||||
columns: Vec<f32>,
|
columns: Vec<f32>,
|
||||||
rows: Vec<f32>,
|
rows: Vec<f32>,
|
||||||
}
|
}
|
||||||
|
|
@ -210,7 +214,8 @@ where
|
||||||
limits: &layout::Limits,
|
limits: &layout::Limits,
|
||||||
) -> layout::Node {
|
) -> layout::Node {
|
||||||
let metrics = tree.state.downcast_mut::<Metrics>();
|
let metrics = tree.state.downcast_mut::<Metrics>();
|
||||||
let rows = self.cells.len() / self.columns.len();
|
let columns = self.columns.len();
|
||||||
|
let rows = self.cells.len() / columns;
|
||||||
|
|
||||||
let limits = limits.width(self.width).height(self.height);
|
let limits = limits.width(self.width).height(self.height);
|
||||||
let available = limits.max();
|
let available = limits.max();
|
||||||
|
|
@ -223,7 +228,9 @@ where
|
||||||
metrics.rows = vec![0.0; rows];
|
metrics.rows = vec![0.0; rows];
|
||||||
|
|
||||||
let mut column_factors = vec![0; self.columns.len()];
|
let mut column_factors = vec![0; self.columns.len()];
|
||||||
let mut row_factors = vec![0; rows];
|
let mut total_row_factors = 0;
|
||||||
|
let mut total_fluid_height = 0.0;
|
||||||
|
let mut row_factor = 0;
|
||||||
|
|
||||||
let spacing_x = self.padding_x * 2.0 + self.separator_x;
|
let spacing_x = self.padding_x * 2.0 + self.separator_x;
|
||||||
let spacing_y = self.padding_y * 2.0 + self.separator_y;
|
let spacing_y = self.padding_y * 2.0 + self.separator_y;
|
||||||
|
|
@ -236,17 +243,24 @@ where
|
||||||
for (i, (cell, state)) in
|
for (i, (cell, state)) in
|
||||||
self.cells.iter().zip(&mut tree.children).enumerate()
|
self.cells.iter().zip(&mut tree.children).enumerate()
|
||||||
{
|
{
|
||||||
let column = i / rows;
|
let row = i / columns;
|
||||||
let row = i % rows;
|
let column = i % columns;
|
||||||
|
|
||||||
let width = self.columns[column].width;
|
let width = self.columns[column].width;
|
||||||
let size = cell.as_widget().size();
|
let size = cell.as_widget().size();
|
||||||
|
|
||||||
if row == 0 {
|
if column == 0 {
|
||||||
y = self.padding_y;
|
x = self.padding_x;
|
||||||
|
|
||||||
if column > 0 {
|
if row > 0 {
|
||||||
x += metrics.columns[column - 1] + spacing_x;
|
y += metrics.rows[row - 1] + spacing_y;
|
||||||
|
|
||||||
|
if row_factor != 0 {
|
||||||
|
total_fluid_height += metrics.rows[row - 1];
|
||||||
|
total_row_factors += row_factor;
|
||||||
|
|
||||||
|
row_factor = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,7 +271,7 @@ where
|
||||||
column_factors[column] =
|
column_factors[column] =
|
||||||
column_factors[column].max(width_factor);
|
column_factors[column].max(width_factor);
|
||||||
|
|
||||||
row_factors[row] = row_factors[row].max(height_factor);
|
row_factor = row_factor.max(height_factor);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -275,7 +289,7 @@ where
|
||||||
metrics.rows[row] = metrics.rows[row].max(size.height);
|
metrics.rows[row] = metrics.rows[row].max(size.height);
|
||||||
cells[i] = layout;
|
cells[i] = layout;
|
||||||
|
|
||||||
y += size.height + spacing_y;
|
x += size.width + spacing_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SECOND PASS
|
// SECOND PASS
|
||||||
|
|
@ -289,14 +303,7 @@ where
|
||||||
.filter(|(i, _)| column_factors[*i] == 0)
|
.filter(|(i, _)| column_factors[*i] == 0)
|
||||||
.map(|(_, width)| width)
|
.map(|(_, width)| width)
|
||||||
.sum::<f32>(),
|
.sum::<f32>(),
|
||||||
available.height
|
available.height - total_fluid_height,
|
||||||
- metrics
|
|
||||||
.rows
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter(|(i, _)| row_factors[*i] == 0)
|
|
||||||
.map(|(_, height)| height)
|
|
||||||
.sum::<f32>(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let width_unit = (left.width
|
let width_unit = (left.width
|
||||||
|
|
@ -307,7 +314,7 @@ where
|
||||||
let height_unit = (left.height
|
let height_unit = (left.height
|
||||||
- spacing_y * rows.saturating_sub(1) as f32
|
- spacing_y * rows.saturating_sub(1) as f32
|
||||||
- self.padding_y * 2.0)
|
- self.padding_y * 2.0)
|
||||||
/ row_factors.iter().sum::<u16>() as f32;
|
/ total_row_factors as f32;
|
||||||
|
|
||||||
let mut x = self.padding_x;
|
let mut x = self.padding_x;
|
||||||
let mut y = self.padding_y;
|
let mut y = self.padding_y;
|
||||||
|
|
@ -315,19 +322,20 @@ where
|
||||||
for (i, (cell, state)) in
|
for (i, (cell, state)) in
|
||||||
self.cells.iter().zip(&mut tree.children).enumerate()
|
self.cells.iter().zip(&mut tree.children).enumerate()
|
||||||
{
|
{
|
||||||
let column = i / rows;
|
let row = i / columns;
|
||||||
let row = i % rows;
|
let column = i % columns;
|
||||||
|
|
||||||
let size = cell.as_widget().size();
|
let size = cell.as_widget().size();
|
||||||
|
|
||||||
let width = self.columns[column].width;
|
let width = self.columns[column].width;
|
||||||
let width_factor = width.fill_factor();
|
let width_factor = width.fill_factor();
|
||||||
|
let height_factor = size.height.fill_factor();
|
||||||
|
|
||||||
if row == 0 {
|
if column == 0 {
|
||||||
y = self.padding_y;
|
x = self.padding_x;
|
||||||
|
|
||||||
if column > 0 {
|
if row > 0 {
|
||||||
x += metrics.columns[column - 1] + spacing_x;
|
y += metrics.rows[row - 1] + spacing_y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -338,8 +346,6 @@ where
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let row_factor = row_factors[row];
|
|
||||||
|
|
||||||
let max_width = if width_factor == 0 {
|
let max_width = if width_factor == 0 {
|
||||||
if size.width.is_fill() {
|
if size.width.is_fill() {
|
||||||
metrics.columns[column]
|
metrics.columns[column]
|
||||||
|
|
@ -350,14 +356,14 @@ where
|
||||||
width_unit * width_factor as f32
|
width_unit * width_factor as f32
|
||||||
};
|
};
|
||||||
|
|
||||||
let max_height = if row_factor == 0 {
|
let max_height = if height_factor == 0 {
|
||||||
if size.height.is_fill() {
|
if size.height.is_fill() {
|
||||||
metrics.rows[row]
|
metrics.rows[row]
|
||||||
} else {
|
} else {
|
||||||
(available.height - y).max(0.0)
|
(available.height - y).max(0.0)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
height_unit * row_factor as f32
|
height_unit * height_factor as f32
|
||||||
};
|
};
|
||||||
|
|
||||||
let limits = layout::Limits::new(
|
let limits = layout::Limits::new(
|
||||||
|
|
@ -381,7 +387,7 @@ where
|
||||||
metrics.rows[row] = metrics.rows[row].max(size.height);
|
metrics.rows[row] = metrics.rows[row].max(size.height);
|
||||||
cells[i] = layout;
|
cells[i] = layout;
|
||||||
|
|
||||||
y += size.height + spacing_y;
|
x += size.width + spacing_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// THIRD PASS
|
// THIRD PASS
|
||||||
|
|
@ -390,14 +396,14 @@ where
|
||||||
let mut y = self.padding_y;
|
let mut y = self.padding_y;
|
||||||
|
|
||||||
for (i, cell) in cells.iter_mut().enumerate() {
|
for (i, cell) in cells.iter_mut().enumerate() {
|
||||||
let column = i / rows;
|
let row = i / columns;
|
||||||
let row = i % rows;
|
let column = i % columns;
|
||||||
|
|
||||||
if row == 0 {
|
if column == 0 {
|
||||||
y = self.padding_y;
|
x = self.padding_x;
|
||||||
|
|
||||||
if column > 0 {
|
if row > 0 {
|
||||||
x += metrics.columns[column - 1] + spacing_x;
|
y += metrics.rows[row - 1] + spacing_y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -412,20 +418,20 @@ where
|
||||||
Size::new(metrics.columns[column], metrics.rows[row]),
|
Size::new(metrics.columns[column], metrics.rows[row]),
|
||||||
);
|
);
|
||||||
|
|
||||||
y += metrics.rows[row] + spacing_y;
|
x += metrics.columns[column] + spacing_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
let intrinsic = limits.resolve(
|
let intrinsic = limits.resolve(
|
||||||
self.width,
|
self.width,
|
||||||
self.height,
|
self.height,
|
||||||
Size::new(
|
Size::new(
|
||||||
x + metrics
|
x - spacing_x + self.padding_x,
|
||||||
.columns
|
y + metrics
|
||||||
|
.rows
|
||||||
.last()
|
.last()
|
||||||
.copied()
|
.copied()
|
||||||
.map(|width| width + self.padding_x)
|
.map(|height| height + self.padding_y)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
y - spacing_y + self.padding_y,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -599,9 +605,10 @@ impl Catalog for crate::Theme {
|
||||||
/// The default style of a [`Table`].
|
/// The default style of a [`Table`].
|
||||||
pub fn default(theme: &crate::Theme) -> Style {
|
pub fn default(theme: &crate::Theme) -> Style {
|
||||||
let palette = theme.extended_palette();
|
let palette = theme.extended_palette();
|
||||||
|
let separator = palette.background.strong.color.into();
|
||||||
|
|
||||||
Style {
|
Style {
|
||||||
separator_x: palette.background.strong.color.into(),
|
separator_x: separator,
|
||||||
separator_y: palette.background.strong.color.into(),
|
separator_y: separator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue