egui_extras: fix bug when restoring persisted table widths

This commit is contained in:
Emil Ernerfeldt 2022-04-11 14:27:32 +02:00
parent e97241861e
commit efc0b992e0
3 changed files with 76 additions and 43 deletions

View file

@ -20,3 +20,31 @@ pub(crate) use crate::layout::StripLayout;
pub use crate::sizing::Size; pub use crate::sizing::Size;
pub use crate::strip::*; pub use crate::strip::*;
pub use crate::table::*; pub use crate::table::*;
/// Log an error with either `tracing` or `eprintln`
#[doc(hidden)]
#[macro_export]
macro_rules! log_err {
($fmt: literal, $($arg: tt)*) => {{
#[cfg(feature = "tracing")]
tracing::error!($fmt, $($arg)*);
#[cfg(not(feature = "tracing"))]
eprintln!(
concat!("egui_extras: ", $fmt), $($arg)*
);
}};
}
/// Panic in debug builds, log otherwise.
#[doc(hidden)]
#[macro_export]
macro_rules! log_or_panic {
($fmt: literal, $($arg: tt)*) => {{
if cfg!(debug_assertions) {
panic!($fmt, $($arg)*);
} else {
$crate::log_err!($fmt, $($arg)*);
}
}};
}

View file

@ -107,7 +107,8 @@ impl<'a> StripBuilder<'a> {
strip(Strip { strip(Strip {
layout: &mut layout, layout: &mut layout,
direction: CellDirection::Horizontal, direction: CellDirection::Horizontal,
sizes: &widths, sizes: widths,
size_index: 0,
}); });
layout.allocate_rect() layout.allocate_rect()
} }
@ -133,7 +134,8 @@ impl<'a> StripBuilder<'a> {
strip(Strip { strip(Strip {
layout: &mut layout, layout: &mut layout,
direction: CellDirection::Vertical, direction: CellDirection::Vertical,
sizes: &heights, sizes: heights,
size_index: 0,
}); });
layout.allocate_rect() layout.allocate_rect()
} }
@ -144,25 +146,21 @@ impl<'a> StripBuilder<'a> {
pub struct Strip<'a, 'b> { pub struct Strip<'a, 'b> {
layout: &'b mut StripLayout<'a>, layout: &'b mut StripLayout<'a>,
direction: CellDirection, direction: CellDirection,
sizes: &'b [f32], sizes: Vec<f32>,
size_index: usize,
} }
impl<'a, 'b> Strip<'a, 'b> { impl<'a, 'b> Strip<'a, 'b> {
fn next_cell_size(&mut self) -> (CellSize, CellSize) { fn next_cell_size(&mut self) -> (CellSize, CellSize) {
let size = if self.sizes.is_empty() { let size = if let Some(size) = self.sizes.get(self.size_index) {
if cfg!(debug_assertions) { self.size_index += 1;
panic!("Added more `Strip` cells than were allocated."); *size
} else {
#[cfg(feature = "tracing")]
tracing::error!("Added more `Strip` cells than were allocated");
#[cfg(not(feature = "tracing"))]
eprintln!("egui_extras: Added more `Strip` cells than were allocated");
8.0 // anything will look wrong, so pick something that is obviously wrong
}
} else { } else {
let size = self.sizes[0]; crate::log_or_panic!(
self.sizes = &self.sizes[1..]; "Added more `Strip` cells than were pre-allocated ({} pre-allocated)",
size self.sizes.len()
);
8.0 // anything will look wrong, so pick something that is obviously wrong
}; };
match self.direction { match self.direction {
@ -194,7 +192,7 @@ impl<'a, 'b> Strip<'a, 'b> {
impl<'a, 'b> Drop for Strip<'a, 'b> { impl<'a, 'b> Drop for Strip<'a, 'b> {
fn drop(&mut self) { fn drop(&mut self) {
while !self.sizes.is_empty() { while self.size_index < self.sizes.len() {
self.empty(); self.empty();
} }
} }

View file

@ -150,8 +150,8 @@ impl<'a> TableBuilder<'a> {
let resize_id = resizable.then(|| ui.id().with("__table_resize")); let resize_id = resizable.then(|| ui.id().with("__table_resize"));
let widths = read_table_widths(ui, resize_id) let default_widths = sizing.to_lengths(available_width, ui.spacing().item_spacing.x);
.unwrap_or_else(|| sizing.to_lengths(available_width, ui.spacing().item_spacing.x)); let widths = read_persisted_widths(ui, default_widths, resize_id);
let table_top = ui.cursor().top(); let table_top = ui.cursor().top();
@ -160,6 +160,7 @@ impl<'a> TableBuilder<'a> {
header(TableRow { header(TableRow {
layout: &mut layout, layout: &mut layout,
widths: &widths, widths: &widths,
width_index: 0,
striped: false, striped: false,
height, height,
}); });
@ -199,8 +200,8 @@ impl<'a> TableBuilder<'a> {
let resize_id = resizable.then(|| ui.id().with("__table_resize")); let resize_id = resizable.then(|| ui.id().with("__table_resize"));
let widths = read_table_widths(ui, resize_id) let default_widths = sizing.to_lengths(available_width, ui.spacing().item_spacing.x);
.unwrap_or_else(|| sizing.to_lengths(available_width, ui.spacing().item_spacing.x)); let widths = read_persisted_widths(ui, default_widths, resize_id);
let table_top = ui.cursor().top(); let table_top = ui.cursor().top();
@ -220,14 +221,23 @@ impl<'a> TableBuilder<'a> {
} }
} }
fn read_table_widths(ui: &egui::Ui, resize_id: Option<egui::Id>) -> Option<Vec<f32>> { fn read_persisted_widths(
ui: &egui::Ui,
default_widths: Vec<f32>,
resize_id: Option<egui::Id>,
) -> Vec<f32> {
if let Some(resize_id) = resize_id { if let Some(resize_id) = resize_id {
let rect = Rect::from_min_size(ui.available_rect_before_wrap().min, Vec2::ZERO); let rect = Rect::from_min_size(ui.available_rect_before_wrap().min, Vec2::ZERO);
ui.ctx().check_for_id_clash(resize_id, rect, "Table"); ui.ctx().check_for_id_clash(resize_id, rect, "Table");
ui.data().get_persisted(resize_id) if let Some(persisted) = ui.data().get_persisted::<Vec<f32>>(resize_id) {
} else { // make sure that the stored widths aren't out-dated
None if persisted.len() == default_widths.len() {
return persisted;
}
}
} }
default_widths
} }
/// Table struct which can construct a [`TableBody`]. /// Table struct which can construct a [`TableBody`].
@ -377,7 +387,7 @@ impl<'a> TableBody<'a> {
/// ///
/// This is primarily meant for use with [`TableBody::heterogeneous_rows`] in cases where row /// This is primarily meant for use with [`TableBody::heterogeneous_rows`] in cases where row
/// heights are expected to according to the width of one or more cells -- for example, if text /// heights are expected to according to the width of one or more cells -- for example, if text
/// is wrapped rather than clippped within the cell. /// is wrapped rather than clipped within the cell.
pub fn widths(&self) -> &[f32] { pub fn widths(&self) -> &[f32] {
&self.widths &self.widths
} }
@ -389,6 +399,7 @@ impl<'a> TableBody<'a> {
row(TableRow { row(TableRow {
layout: &mut self.layout, layout: &mut self.layout,
widths: &self.widths, widths: &self.widths,
width_index: 0,
striped: self.striped && self.row_nr % 2 == 0, striped: self.striped && self.row_nr % 2 == 0,
height, height,
}); });
@ -439,6 +450,7 @@ impl<'a> TableBody<'a> {
TableRow { TableRow {
layout: &mut self.layout, layout: &mut self.layout,
widths: &self.widths, widths: &self.widths,
width_index: 0,
striped: self.striped && idx % 2 == 0, striped: self.striped && idx % 2 == 0,
height, height,
}, },
@ -508,6 +520,7 @@ impl<'a> TableBody<'a> {
let tr = TableRow { let tr = TableRow {
layout: &mut self.layout, layout: &mut self.layout,
widths: &self.widths, widths: &self.widths,
width_index: 0,
striped: self.striped && striped, striped: self.striped && striped,
height, height,
}; };
@ -528,6 +541,7 @@ impl<'a> TableBody<'a> {
let tr = TableRow { let tr = TableRow {
layout: &mut self.layout, layout: &mut self.layout,
widths: &self.widths, widths: &self.widths,
width_index: 0,
striped: self.striped && striped, striped: self.striped && striped,
height, height,
}; };
@ -554,6 +568,7 @@ impl<'a> TableBody<'a> {
TableRow { TableRow {
layout: &mut self.layout, layout: &mut self.layout,
widths: &self.widths, widths: &self.widths,
width_index: 0,
striped: false, striped: false,
height, height,
} }
@ -572,6 +587,7 @@ impl<'a> Drop for TableBody<'a> {
pub struct TableRow<'a, 'b> { pub struct TableRow<'a, 'b> {
layout: &'b mut StripLayout<'a>, layout: &'b mut StripLayout<'a>,
widths: &'b [f32], widths: &'b [f32],
width_index: usize,
striped: bool, striped: bool,
height: f32, height: f32,
} }
@ -579,24 +595,15 @@ pub struct TableRow<'a, 'b> {
impl<'a, 'b> TableRow<'a, 'b> { impl<'a, 'b> TableRow<'a, 'b> {
/// Add the contents of a column. /// Add the contents of a column.
pub fn col(&mut self, add_contents: impl FnOnce(&mut Ui)) -> Response { pub fn col(&mut self, add_contents: impl FnOnce(&mut Ui)) -> Response {
assert!( let width = if let Some(width) = self.widths.get(self.width_index) {
!self.widths.is_empty(), self.width_index += 1;
"Tried using more table columns than available." *width
);
let width = if self.widths.is_empty() {
if cfg!(debug_assertions) {
panic!("Added more `Table` columns than were allocated.");
} else {
#[cfg(feature = "tracing")]
tracing::error!("Added more `Table` columns than were allocated");
#[cfg(not(feature = "tracing"))]
eprintln!("egui_extras: Added more `Table` columns than were allocated");
8.0 // anything will look wrong, so pick something that is obviously wrong
}
} else { } else {
let width = self.widths[0]; crate::log_or_panic!(
self.widths = &self.widths[1..]; "Added more `Table` columns than were pre-allocated ({} pre-allocated)",
width self.widths.len()
);
8.0 // anything will look wrong, so pick something that is obviously wrong
}; };
let width = CellSize::Absolute(width); let width = CellSize::Absolute(width);