Grid::num_columns: allow the last column to take up the rest of the space

This allows for resizaeable grids, where the last column will be given the remainder of the width.
To demonstrate, the widget gallery window is now resizeable.
This commit is contained in:
Emil Ernerfeldt 2021-07-02 09:55:57 +02:00
parent 9603bb4f85
commit faf104220b
3 changed files with 37 additions and 13 deletions

View file

@ -6,7 +6,10 @@ NOTE: [`eframe`](eframe/CHANGELOG.md), [`egui_web`](egui_web/CHANGELOG.md) and [
## Unreleased ## Unreleased
### Added ⭐
* [Progress bar](https://github.com/emilk/egui/pull/519) * [Progress bar](https://github.com/emilk/egui/pull/519)
* `Grid::num_columns`: allow the last column to take up the rest of the space of the parent `Ui`.
## 0.13.1 - 2021-06-28 - Plot fixes ## 0.13.1 - 2021-06-28 - Plot fixes

View file

@ -46,13 +46,16 @@ pub(crate) struct GridLayout {
prev_state: State, prev_state: State,
/// State accumulated during the current frame. /// State accumulated during the current frame.
curr_state: State, curr_state: State,
initial_available: Rect,
// Options:
num_columns: Option<usize>,
spacing: Vec2, spacing: Vec2,
striped: bool,
initial_x: f32,
min_cell_size: Vec2, min_cell_size: Vec2,
max_cell_size: Vec2, max_cell_size: Vec2,
striped: bool,
// Cursor:
col: usize, col: usize,
row: usize, row: usize,
} }
@ -63,10 +66,9 @@ impl GridLayout {
// TODO: respect current layout // TODO: respect current layout
let available = ui.placer().max_rect().intersect(ui.cursor()); let initial_available = ui.placer().max_rect().intersect(ui.cursor());
let initial_x = available.min.x;
assert!( assert!(
initial_x.is_finite(), initial_available.min.x.is_finite(),
"Grid not yet available for right-to-left layouts" "Grid not yet available for right-to-left layouts"
); );
@ -76,11 +78,14 @@ impl GridLayout {
id, id,
prev_state, prev_state,
curr_state: State::default(), curr_state: State::default(),
initial_available,
num_columns: None,
spacing: ui.spacing().item_spacing, spacing: ui.spacing().item_spacing,
striped: false,
initial_x,
min_cell_size: ui.spacing().interact_size, min_cell_size: ui.spacing().interact_size,
max_cell_size: Vec2::INFINITY, max_cell_size: Vec2::INFINITY,
striped: false,
col: 0, col: 0,
row: 0, row: 0,
} }
@ -109,7 +114,11 @@ impl GridLayout {
} }
pub(crate) fn available_rect_finite(&self, region: &Region) -> Rect { pub(crate) fn available_rect_finite(&self, region: &Region) -> Rect {
let width = if self.max_cell_size.x.is_finite() { let is_last_column = Some(self.col + 1) == self.num_columns;
let width = if is_last_column {
(self.initial_available.right() - region.cursor.left()).at_most(self.max_cell_size.x)
} else if self.max_cell_size.x.is_finite() {
// TODO: should probably heed `prev_state` here too // TODO: should probably heed `prev_state` here too
self.max_cell_size.x self.max_cell_size.x
} else { } else {
@ -183,7 +192,7 @@ impl GridLayout {
} }
pub(crate) fn end_row(&mut self, cursor: &mut Rect, painter: &Painter) { pub(crate) fn end_row(&mut self, cursor: &mut Rect, painter: &Painter) {
cursor.min.x = self.initial_x; cursor.min.x = self.initial_available.min.x;
cursor.min.y += self.spacing.y; cursor.min.y += self.spacing.y;
cursor.min.y += self cursor.min.y += self
.curr_state .curr_state
@ -247,6 +256,7 @@ impl GridLayout {
#[must_use = "You should call .show()"] #[must_use = "You should call .show()"]
pub struct Grid { pub struct Grid {
id_source: Id, id_source: Id,
num_columns: Option<usize>,
striped: bool, striped: bool,
min_col_width: Option<f32>, min_col_width: Option<f32>,
min_row_height: Option<f32>, min_row_height: Option<f32>,
@ -260,6 +270,7 @@ impl Grid {
pub fn new(id_source: impl std::hash::Hash) -> Self { pub fn new(id_source: impl std::hash::Hash) -> Self {
Self { Self {
id_source: Id::new(id_source), id_source: Id::new(id_source),
num_columns: None,
striped: false, striped: false,
min_col_width: None, min_col_width: None,
min_row_height: None, min_row_height: None,
@ -269,6 +280,12 @@ impl Grid {
} }
} }
/// Setting this will allow the last column to expand to take up the rest of the space of the parent [`Ui`].
pub fn num_columns(mut self, num_columns: usize) -> Self {
self.num_columns = Some(num_columns);
self
}
/// If `true`, add a subtle background color to every other row. /// If `true`, add a subtle background color to every other row.
/// ///
/// This can make a table easier to read. /// This can make a table easier to read.
@ -317,6 +334,7 @@ impl Grid {
pub fn show<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> { pub fn show<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
let Self { let Self {
id_source, id_source,
num_columns,
striped, striped,
min_col_width, min_col_width,
min_row_height, min_row_height,
@ -336,10 +354,11 @@ impl Grid {
ui.horizontal(|ui| { ui.horizontal(|ui| {
let id = ui.make_persistent_id(id_source); let id = ui.make_persistent_id(id_source);
let grid = GridLayout { let grid = GridLayout {
num_columns,
striped, striped,
spacing,
min_cell_size: vec2(min_col_width, min_row_height), min_cell_size: vec2(min_col_width, min_row_height),
max_cell_size, max_cell_size,
spacing,
row: start_row, row: start_row,
..GridLayout::new(ui, id) ..GridLayout::new(ui, id)
}; };

View file

@ -42,7 +42,8 @@ impl super::Demo for WidgetGallery {
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) { fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
egui::Window::new(self.name()) egui::Window::new(self.name())
.open(open) .open(open)
.resizable(false) .resizable(true)
.default_width(300.0)
.show(ctx, |ui| { .show(ctx, |ui| {
use super::View; use super::View;
self.ui(ui); self.ui(ui);
@ -57,8 +58,9 @@ impl super::View for WidgetGallery {
ui.set_enabled(self.enabled); ui.set_enabled(self.enabled);
egui::Grid::new("my_grid") egui::Grid::new("my_grid")
.striped(true) .num_columns(2)
.spacing([40.0, 4.0]) .spacing([40.0, 4.0])
.striped(true)
.show(ui, |ui| { .show(ui, |ui| {
self.gallery_grid_contents(ui); self.gallery_grid_contents(ui);
}); });