emilk / emilk/egui

warn_if_rect_changes_id false positive with virtualized egui_extras::Table

Open
#8,092 2 comments 7 reactions 0 assignees View on GitHub

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:

  1. "at least one id stayed the same" — No, the row changed, so the cell container id changed too
  2. "all previous ids still exist" — No, the old row's cell is no longer laid out (virtualized away)
  3. "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: WidgetRect could carry an Option<UiKind> so the check can skip TableCell ↔ TableCell transitions. Cost: 0 bytes (fits in existing padding on 64-bit). Downside: threads UiKind through all WidgetRect construction 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 child Uis 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.