Skip to content

Fix/annotation ribbon and mesh regressions - #202

Merged
harleensachdev merged 8 commits into
mainfrom
fix/annotation-ribbon-and-mesh-regressions
Aug 26, 2026
Merged

Fix/annotation ribbon and mesh regressions#202
harleensachdev merged 8 commits into
mainfrom
fix/annotation-ribbon-and-mesh-regressions

Conversation

@harleensachdev

Copy link
Copy Markdown
Collaborator

Summary

A cluster of fixes and reverts addresses issues with the annotation ribbon and 3D mesh viewer.

The Applying…/Deleting… busy indicators have been removed end-to-end. The related UI and logic in AnnotationToolbar.tsx and VisualizationPage.tsx were dead code that added complexity without providing meaningful value.

The annotation ribbon has been redesigned. It is now a small, centered popout with a pointer arrow back to the pencil button instead of a full-width bar. The mask-visibility toggle and masking-scope selector have also been moved out of the ribbon and into SegmentsPopup.

The first-brush-stroke lag in the 3D pane has been fixed. Static organs no longer switch to a live marching-cubes mesh on their first edit; they always render the pre-baked GLB. Custom classes still build a live mesh, but they now build it from a pre-edit snapshot captured when setActiveEditSegment is called, before the triggering stroke lands. The snapshot is cached per segment rather than rebuilt on every edit.

The Annotate button now triggers its own HD upgrade. When HD is not yet loaded, clicking Annotate displays a full-screen loading overlay instead of simply leaving the button disabled. Once the upgrade resolves, the annotation ribbon opens.

SegmentsPopup now docks directly under the main topbar. This is possible because the redesigned ribbon no longer reserves space as a full-width bar.

Testing

  • Click around the 2D panes and confirm the crosshair moves again.
  • Open the annotation ribbon and confirm there is no residual "Applying…" or "Deleting…" text anywhere.
  • Edit an existing catalog organ and confirm the 3D pane does not lag or stutter on the first stroke and continues showing the original mesh.
  • Create a new custom class, paint into it, and confirm a 3D mesh appears after the first stroke and does not rebuild on every subsequent stroke.
  • Click Annotate while HD is not loaded yet and confirm the loading overlay appears and the ribbon opens once the upgrade resolves.
  • Open SegmentsPopup and confirm it now docks closer to the topbar.

The 'single owner for the primary mouse button' effect had grown two
branches meant to fix edge cases (lasso/level-tracing forcing the
crosshair off instead of falling through to crosshairToolActive, and
smartfill/point/box-segment calling releasePrimaryMouseTools() instead
of a plain toggleCrosshairTool(false)). Neither fix actually worked in
practice, and the box-segment/pointSegment change in particular left
the crosshair tool not registering as a controllable interaction
target, so clicking anywhere in the 2D panes stopped moving the
crosshair at all.

Reverts both branches back to the simpler pre-fix behavior:
- lasso/levelTracing now falls through to the plain else branch again
- smartfill/pointSegment/boxSegment now just does toggleCrosshairTool(false)
…per-viewport checks

These were hardcoded to always return false to suppress a redundant
rotate-handle icon on the crosshair, but CrosshairsTool apparently
uses these same callbacks to decide which viewports are interactive
navigation targets — hardcoding false broke click-to-move crosshair
navigation entirely. Reverted to the original per-viewport
[viewportId1, viewportId2, viewportId3].indexOf(viewportId) !== -1
checks. handleRadius left at its original value/formatting.
Strips the isRendering/isDeletingSegment plumbing end-to-end:
- AnnotationToolbar: removed RenderingIndicator component, the
  renderingDot*/deletingDot* state + effects, and their props
- VisualizationPage: removed isEditRendering/isDeletingSegment state,
  every onBusyChange={setIsEditRendering} call site (Margin, Islands,
  LogicalOperators, GrowFromSeeds, FillBetweenSlices, Smoothing), the
  setIsEditRendering(true/false) calls in the pointer-guard effect
  (kept beginBrushMaskGuard/endBrushMaskGuard, which are functional,
  not just indicator), and onDeletingChange from SegmentsPopup.

promptToolBusy is left alone — it still gates re-entrant point/box
segment calls, it just no longer feeds a visual indicator.
…le to SegmentsPopup

- AnnotationToolbar now renders as a small centered popout
  (.atb-shell, no more clip-path 'branch off the button' reveal) with
  a small square pointer notch (.atb--horizontal__pointer) tracked via
  getBoundingClientRect() against the pencil button, instead of the
  old dark rotated-square connector capped at the shell's z-index.
- Removed the ribbon's own 'Show only target class' checkbox and the
  global MaskingSelect scope control — showOnlyTargetMask/
  onShowOnlyTargetMaskChange/hasActiveTarget now passed to
  SegmentsPopup instead, and maskingArea/onMaskingAreaChange/
  hasAnySegments/scopeLocked props dropped entirely.
- Removed pointSegment/boxSegment from TOOL_DEFS and their related
  IconPointer/IconFrame imports.
- CSS: .atb--horizontal is now position:relative/width:auto/centered
  instead of a full-width static bar; brightened border opacity
  0.28 -> 0.55; new .atb--horizontal__pointer rules; removed the old
  .atb-shell__connector/.atb-shell__pointer rules.
…gering stroke

markSegmentEdited only fires AFTER Cornerstone's
SEGMENTATION_DATA_MODIFIED event, i.e. after the first stroke has
already mutated the labelmap — so the mesh that used to get built the
moment a segment 'became edited' already included that first stroke.

- CornerstoneNifti2: new _preEditMaskSnapshots map, captured in
  setActiveEditSegment (before any stroke can land) via
  _capturePreEditSnapshotIfAbsent; consumePreEditSegmentSnapshot is a
  one-shot getter/clear; clearPreEditSegmentSnapshot for manual
  invalidation; extractSegmentSurface takes an optional
  precomputedMask to build from a frozen snapshot instead of the live
  volume; clearEditedSegments now also clears snapshots.
- LiveSegmentMesh: rewritten to extract once (cached per
  segmentIndex, keyed only on segmentIndex/manifestCenter — never on
  paint activity) using the pre-edit snapshot when available, instead
  of the old debounced rebuild-on-every-edit (subscribeToSegmentationEdits)
  which caused visible 2D-pane stutter.
The 3D pane switched a static catalog organ from its baked GLB to a
live marching-cubes mesh (LiveSegmentMesh) the instant it picked up
its first edit. That switch — not painting itself — was the source of
a lag spike on the first brush stroke, and the 3D pane is only meant
to show the original mesh anyway, never a live reconstruction of
in-progress annotations. Static organs now always render via
OrganMesh regardless of edit state. Removed the now-unused
editVersion state, its subscribeToSegmentationEdits subscription, and
getEditedSegments()/editedSegments.has() branch. Custom classes (no
baked GLB) still go through LiveSegmentMesh — that's unavoidable and
unrelated to this bug.
Previously the Annotate button was simply disabled until the HD
upgrade finished elsewhere. Now clicking it always does something: if
HD is already ready it just toggles the ribbon as before; if not, it
kicks off runEnhance() (reusing an in-flight one) and shows a
full-screen blurred loading overlay (.vp-annotate-hd-overlay) until
the upgrade resolves, only then opening the annotation
toolbar/SegmentsPopup — so there's never a window where the ribbon is
up but painting would hit the still-low-res segmentation grid.

Adds annotateHdLoading state + the watcher effect, handleAnnotateClick,
and the overlay CSS/keyframes in VisualizationPage.css.
…th ribbon

DOCK_CLEARANCE was still reserving --atb-ribbon-h/--atb-panel-h as if
the ribbon were a full-width bar in-flow under the topbar. Now that
it's a small centered floating popout, that space is no longer
occupied, so the panel can dock right under --vp-topbar-h.
@harleensachdev
harleensachdev merged commit 1218c5d into main Aug 26, 2026
8 checks passed
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