Skip to content

fix(canvas): paint the committed shape before the label dialog opens - #2429

Merged
wkentaro merged 1 commit into
mainfrom
fix/canvas-paint-shape-before-label-dialog
Jul 29, 2026
Merged

fix(canvas): paint the committed shape before the label dialog opens#2429
wkentaro merged 1 commit into
mainfrom
fix/canvas-paint-shape-before-label-dialog

Conversation

@wkentaro

@wkentaro wkentaro commented Jul 29, 2026

Copy link
Copy Markdown
Owner

An AI-Box annotation opens the label dialog over a canvas that still shows the
drag bbox, not the segmentation it is asking you to name.

_reset_after_shape_creation emits new_shape, whose handler blocks in
_label_dialog.popup() -> exec(), before invalidating the canvas, so the
committed shape is only scheduled for repaint after the dialog closes.

Three non-obvious bits:

  1. It presents as intermittent rather than always broken. If a paint request
    from the drag is still pending when the second click lands, the dialog's own
    nested event loop flushes it, and because self.shapes was already extended
    it happens to render the new shape. When nothing is pending, which is the
    normal case once the drag repaints have drained, the dialog opens over the
    previous frame. Stack traces confirmed both paths, and this is why the
    existing GUI tests never caught it.

  2. AI-Box is where this is most visible. Its last painted frame is the drag bbox
    because _build_preview_shape returns None, so the segmentation result is
    missing entirely. Point mode can also finalize before any matching preview is
    painted. Other create modes leave a preview that already matches the
    committed geometry.

  3. repaint() is required rather than hoisting the existing update() above
    the emit. update() only posts an event, so it would still depend on the
    modal loop delivering it, which is the same mechanism that masks the bug
    today. The trailing update() stays because the handler mutates shapes
    afterwards by applying labels on accept or calling undo_last_line() on
    cancel.

Test plan

  • tests/unit/widgets/canvas_test.py::test_finalize_paints_new_shape_before_notifying
    asserts that the shape is painted by the time new_shape fires; verified
    for point mode and both AI create modes
  • Screenshotted the running app while the dialog was open, before and after:
    bbox only before, segmentation polygon after
  • make lint
  • Full suite: 913 tests passed

@wkentaro wkentaro self-assigned this Jul 29, 2026
_reset_after_shape_creation emitted new_shape, whose handler blocks on the modal label dialog, before invalidating the canvas, so the canvas was only repainted once the dialog closed. Whether the new shape was visible behind the dialog came down to whether a paint request happened to still be pending when the shape was committed: if one was, the dialog's own event loop flushed it and the shape appeared; if not, the dialog opened over the previous frame.

AI-Box is where this is most visible because its last painted frame is the drag bbox rather than the segmentation result. Point mode can also finalize before any matching preview is painted. Other create modes leave a preview that already matches the committed geometry.

Repaint synchronously before emitting so the shape is on screen regardless of the pending-paint state.
@wkentaro
wkentaro force-pushed the fix/canvas-paint-shape-before-label-dialog branch from 881ee7b to 3155734 Compare July 29, 2026 22:56
@wkentaro wkentaro added this to the next milestone Jul 29, 2026
@wkentaro

Copy link
Copy Markdown
Owner Author

confirmed this only happens on linux (not on macOS)

@wkentaro
wkentaro merged commit d74d703 into main Jul 29, 2026
12 checks passed
@wkentaro
wkentaro deleted the fix/canvas-paint-shape-before-label-dialog branch July 29, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant