From 36e007bd8cf69566dd597775224b40b38ef773fb Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 8 Apr 2025 12:36:43 +0300 Subject: [PATCH] Add overline option for Table rows (#5637) * Closes no issue, I just needed this for an app and figured it could be useful. * [x] I have followed the instructions in the PR template This PR adds an `overline` option for `egui_extras::TableRow`, which is useful for visually grouping rows. The overline consumes no layout space. A screenshot of the demo app, showing every 7th row getting an overline. Screenshot 2025-01-25 at 14 40 08 --------- Co-authored-by: Emil Ernerfeldt --- crates/egui_demo_lib/src/demo/table_demo.rs | 6 ++++++ .../egui_demo_lib/tests/snapshots/demos/Table.png | 4 ++-- crates/egui_extras/src/layout.rs | 9 +++++++++ crates/egui_extras/src/table.rs | 14 ++++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/crates/egui_demo_lib/src/demo/table_demo.rs b/crates/egui_demo_lib/src/demo/table_demo.rs index 5c6f42d9..17e19d01 100644 --- a/crates/egui_demo_lib/src/demo/table_demo.rs +++ b/crates/egui_demo_lib/src/demo/table_demo.rs @@ -13,6 +13,7 @@ enum DemoType { pub struct TableDemo { demo: DemoType, striped: bool, + overline: bool, resizable: bool, clickable: bool, num_rows: usize, @@ -28,6 +29,7 @@ impl Default for TableDemo { Self { demo: DemoType::Manual, striped: true, + overline: true, resizable: true, clickable: true, num_rows: 10_000, @@ -65,6 +67,7 @@ impl crate::View for TableDemo { ui.vertical(|ui| { ui.horizontal(|ui| { ui.checkbox(&mut self.striped, "Striped"); + ui.checkbox(&mut self.overline, "Overline some rows"); ui.checkbox(&mut self.resizable, "Resizable columns"); ui.checkbox(&mut self.clickable, "Clickable rows"); }); @@ -212,6 +215,7 @@ impl TableDemo { let row_height = if is_thick { 30.0 } else { 18.0 }; body.row(row_height, |mut row| { row.set_selected(self.selection.contains(&row_index)); + row.set_overline(self.overline && row_index % 7 == 3); row.col(|ui| { ui.label(row_index.to_string()); @@ -247,6 +251,7 @@ impl TableDemo { }; row.set_selected(self.selection.contains(&row_index)); + row.set_overline(self.overline && row_index % 7 == 3); row.col(|ui| { ui.label(row_index.to_string()); @@ -280,6 +285,7 @@ impl TableDemo { }; row.set_selected(self.selection.contains(&row_index)); + row.set_overline(self.overline && row_index % 7 == 3); row.col(|ui| { ui.label(row_index.to_string()); diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Table.png b/crates/egui_demo_lib/tests/snapshots/demos/Table.png index 6189f25c..c11788f4 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Table.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Table.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:13115759157beb57febcff4be6f1710340736108b520e9ad3efb04be3cedcf7b -size 68767 +oid sha256:9446da28768cae0b489e0f6243410a8b3acf0ca2a0b70690d65d2a6221bc25b9 +size 30517 diff --git a/crates/egui_extras/src/layout.rs b/crates/egui_extras/src/layout.rs index fb84169f..fb62cec4 100644 --- a/crates/egui_extras/src/layout.rs +++ b/crates/egui_extras/src/layout.rs @@ -33,6 +33,7 @@ pub(crate) struct StripLayoutFlags { pub(crate) striped: bool, pub(crate) hovered: bool, pub(crate) selected: bool, + pub(crate) overline: bool, /// Used when we want to accruately measure the size of this cell. pub(crate) sizing_pass: bool, @@ -232,6 +233,14 @@ impl<'l> StripLayout<'l> { child_ui.style_mut().visuals.override_text_color = Some(stroke_color); } + if flags.overline { + child_ui.painter().hline( + max_rect.x_range(), + max_rect.top(), + child_ui.visuals().widgets.noninteractive.bg_stroke, + ); + } + add_cell_contents(&mut child_ui); child_ui diff --git a/crates/egui_extras/src/table.rs b/crates/egui_extras/src/table.rs index 5fca1f9d..172f1bee 100644 --- a/crates/egui_extras/src/table.rs +++ b/crates/egui_extras/src/table.rs @@ -507,6 +507,7 @@ impl<'a> TableBuilder<'a> { striped: false, hovered: false, selected: false, + overline: false, response: &mut response, }); layout.allocate_rect(); @@ -990,6 +991,7 @@ impl<'a> TableBody<'a> { striped: self.striped && self.row_index % 2 == 0, hovered: self.hovered_row_index == Some(self.row_index), selected: false, + overline: false, response: &mut response, }); self.capture_hover_state(&response, self.row_index); @@ -1071,6 +1073,7 @@ impl<'a> TableBody<'a> { striped: self.striped && (row_index + self.row_index) % 2 == 0, hovered: self.hovered_row_index == Some(row_index), selected: false, + overline: false, response: &mut response, }); self.capture_hover_state(&response, row_index); @@ -1152,6 +1155,7 @@ impl<'a> TableBody<'a> { striped: self.striped && (row_index + self.row_index) % 2 == 0, hovered: self.hovered_row_index == Some(row_index), selected: false, + overline: false, response: &mut response, }); self.capture_hover_state(&response, row_index); @@ -1173,6 +1177,7 @@ impl<'a> TableBody<'a> { height: row_height, striped: self.striped && (row_index + self.row_index) % 2 == 0, hovered: self.hovered_row_index == Some(row_index), + overline: false, selected: false, response: &mut response, }); @@ -1260,6 +1265,7 @@ pub struct TableRow<'a, 'b> { striped: bool, hovered: bool, selected: bool, + overline: bool, response: &'b mut Option, } @@ -1297,6 +1303,7 @@ impl TableRow<'_, '_> { striped: self.striped, hovered: self.hovered, selected: self.selected, + overline: self.overline, sizing_pass: auto_size_this_frame || self.layout.ui.is_sizing_pass(), }; @@ -1333,6 +1340,13 @@ impl TableRow<'_, '_> { self.hovered = hovered; } + /// Set the overline state for this row. The overline is a line above the row, + /// usable for e.g. visually grouping rows. + #[inline] + pub fn set_overline(&mut self, overline: bool) { + self.overline = overline; + } + /// Returns a union of the [`Response`]s of the cells added to the row up to this point. /// /// You need to add at least one row to the table before calling this function.