warn_if_rect_changes_id false positive with virtualized egui_extras::Table
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 30.6k
- Forks
- 2.1k
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 72
Description
Summary
warn_if_rect_changes_id produces false positives (red debug outlines) when scrolling a virtualized egui_extras::TableBuilder table.
What happens
egui_extras::TableBuilder virtualizes rows: only visible rows are laid out each frame. When the user scrolls, a screen Rect that previously belonged to row N now belongs to row M. The inner Ui container for each cell (UiKind::TableCell) gets a different Id because it's a different logical row.
warn_if_rect_changes_id sees:
- Same
Rect - Different
Id - Same
parent_id(the table body)
…and draws a red debug outline, treating it as widget id-instability.
For TableCell containers this is a false positive: no user widget state is being confused. The id change is expected — it's just a different row occupying the same screen slot after scroll.
Reproduction
Any egui_extras::TableBuilder with enough rows to scroll will show red debug outlines on cells during/after scrolling in debug builds.
egui_extras::TableBuilder::new(ui)
.id_salt("my_table")
.column(Column::auto())
.body(|body| {
body.rows(20.0, 200, |mut row| {
row.col(|ui| {
ui.label(format!("Row {}", row.index()));
});
});
});
Scroll the table → red outlines appear on cells.
Analysis
The existing filters in warn_if_rect_changes_id don't cover this case:
- "at least one id stayed the same" — No, the row changed, so the cell container id changed too
- "all previous ids still exist" — No, the old row's cell is no longer laid out (virtualized away)
- "all parent_ids changed" — No, parent is the same table body
Ui
All three filters pass, so the warning fires. But it's semantically wrong — this is normal virtualization behavior, not a bug.
Possible fix directions
The root cause is that warn_if_rect_changes_id has no way to distinguish "widget whose id is unstable (bug)" from "virtual container that legitimately maps different logical content to the same screen rect (normal)".
Some ideas (not prescriptive):
- Tag approach:
WidgetRectcould carry anOption<UiKind>so the check can skipTableCell ↔ TableCelltransitions. Cost: 0 bytes (fits in existing padding on 64-bit). Downside: threadsUiKindthrough allWidgetRectconstruction sites. - Sense-based heuristic: skip the warning when all conflicting widgets have
Sense::hover()(Ui containers, not interactive widgets). Less precise. - Opt-out flag: let
TableBuilder(or any virtualizing container) mark its childUis as "expect rect reuse", suppressing the check for those rects.
Workaround
We currently vendor egui 0.34.1 and patch warn_if_rect_changes_id with the tag approach (adding ui_kind: Option<UiKind> to WidgetRect). It works but feels heavy for a debug-only check — would prefer an upstream solution.
Version
egui 0.34.1
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with warn_if_rect_changes_id and the WidgetRect construction sites, then reproduce the issue with the provided egui_extras::TableBuilder example on egui 0.34.1. Done means scrolling virtualized TableCell rows no longer produces red debug outlines for expected rectangle reuse, while genuine widget ID instability is still reported.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100