Skip to content

Commit 5533c50

Browse files
adityaapteclaude
andcommitted
Contouring: close the discard dialog on Yes; live erase boundary
(1) The "Discard unsaved edits?" confirm did not dismiss on Yes: self.close() ran synchronously inside the message box's button-click handler, deleting the box (a child of the panel) before it dismissed. Defer the panel close with QTimer.singleShot. (2) Erasing left the old boundary on screen until the drag ended. The full render drew the working-mask overlay (and the edited structure's committed contour) statically, and _live_update_axial stacked a live overlay on top. Now skip the edited structure's committed contour, and hand the axial working overlay to the live updater so each brush/erase step removes and redraws it - the dashed boundary shrinks in real time while erasing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 1f8619e commit 5533c50

1 file changed

Lines changed: 23 additions & 9 deletions

File tree

cerr/viewer/pycerr_gui.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2608,7 +2608,12 @@ def refresh_views(self, only=None):
26082608
aspect="equal")
26092609

26102610
# ---- structure contours ----
2611+
ctl = self.contourCtl
2612+
editStrNum = (ctl.structNum if ctl is not None and ctl.isVisible()
2613+
else None)
26112614
for strNum in self._axis_structs(orient):
2615+
if strNum == editStrNum:
2616+
continue # being edited: shown via the live overlay below
26122617
mask = self._struct_mask(strNum)
26132618
if mask is None or mask.shape != self.scan3M.shape:
26142619
continue
@@ -2623,18 +2628,24 @@ def refresh_views(self, only=None):
26232628
self._draw_contour_dots(ax, cs, color)
26242629

26252630
# ---- live contouring overlay (working mask being edited) ----
2626-
ctl = self.contourCtl
26272631
if ctl is not None and ctl.isVisible() and ctl.mask3M is not None \
26282632
and ctl.mask3M.shape == self.scan3M.shape:
26292633
cslc = slicer(ctl.mask3M)
2634+
im = cs = None
26302635
if np.any(cslc):
2631-
ax.imshow(np.ma.masked_where(~cslc, cslc.astype(float)),
2632-
cmap=ListedColormap([ctl.color]), extent=extent,
2633-
alpha=0.35, vmin=0, vmax=1,
2634-
interpolation="nearest", aspect="equal")
2635-
ax.contour(hV, vV, cslc.astype(float), levels=[0.5],
2636-
colors=[ctl.color], linewidths=1.6,
2637-
linestyles="--")
2636+
im = ax.imshow(
2637+
np.ma.masked_where(~cslc, cslc.astype(float)),
2638+
cmap=ListedColormap([ctl.color]), extent=extent,
2639+
alpha=0.35, vmin=0, vmax=1,
2640+
interpolation="nearest", aspect="equal")
2641+
cs = ax.contour(hV, vV, cslc.astype(float), levels=[0.5],
2642+
colors=[ctl.color], linewidths=1.6,
2643+
linestyles="--")
2644+
if view is ctl.axView:
2645+
# the live updater owns the axial overlay, so each brush
2646+
# step removes and redraws it (no stale boundary on erase)
2647+
ctl._liveIm = im
2648+
ctl._liveContour = cs
26382649

26392650
# ---- registration QA split/lens guides ----
26402651
if regComp is not None:
@@ -3890,7 +3901,10 @@ def closeEvent(self, event):
38903901
def _on_done(btn):
38913902
if box.standardButton(btn) == QtWidgets.QMessageBox.Yes:
38923903
self._force_close = True
3893-
self.close()
3904+
# defer: let the message box finish closing itself first,
3905+
# then close the panel (closing it now, mid button-click,
3906+
# deletes the box before it dismisses).
3907+
QtCore.QTimer.singleShot(0, self.close)
38943908
box.buttonClicked.connect(_on_done)
38953909
box.show()
38963910
box.raise_()

0 commit comments

Comments
 (0)