cloudmr-ux 4.6.3 → 4.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -186,7 +186,7 @@ export function CloudMrNiivuePanel(props) {
186
186
  left: 0,
187
187
  width: "100%",
188
188
  height: "100%"
189
- } }), props.shapeDraft && (_jsx(ShapeDraftOverlay, { nv: props.nv, draft: props.shapeDraft, onDraftChange: props.onShapeDraftChange, onApplyDraft: props.onApplyShapeDraft, overlayKey: props.mms })), props.penDraft && (_jsx(PenDraftOverlay, { nv: props.nv, draft: props.penDraft, onDraftChange: props.onPenDraftChange, onApplyDraft: props.onApplyPenDraft, overlayKey: props.mms }))] }))] })), _jsxs(Box, __assign({ sx: {
189
+ } }), props.shapeDraft && (_jsx(ShapeDraftOverlay, { nv: props.nv, draft: props.shapeDraft, onDraftChange: props.onShapeDraftChange, overlayKey: props.mms })), props.penDraft && (_jsx(PenDraftOverlay, { nv: props.nv, draft: props.penDraft, onDraftChange: props.onPenDraftChange, overlayKey: props.mms }))] }))] })), _jsxs(Box, __assign({ sx: {
190
190
  width: {
191
191
  xs: "100%",
192
192
  md: "35%"
@@ -586,6 +586,7 @@ export default function CloudMrNiivueViewer(props) {
586
586
  setPenDraft(null);
587
587
  penDraftRef.current = null;
588
588
  nv._cloudMrPenDraftActive = false;
589
+ clearActivePenDraftRef();
589
590
  setPolylineVertexCount(0);
590
591
  }
591
592
  if (shapeDraftRef.current) {
@@ -610,6 +611,7 @@ export default function CloudMrNiivueViewer(props) {
610
611
  setPenDraft(null);
611
612
  penDraftRef.current = null;
612
613
  nv._cloudMrPenDraftActive = false;
614
+ clearActivePenDraftRef();
613
615
  }
614
616
  setDrawShapeTool(null);
615
617
  nv.opts.penType = NI_PEN_TYPE.PEN;
@@ -641,6 +643,7 @@ export default function CloudMrNiivueViewer(props) {
641
643
  setPenDraft(null);
642
644
  penDraftRef.current = null;
643
645
  nv._cloudMrPenDraftActive = false;
646
+ clearActivePenDraftRef();
644
647
  }
645
648
  nvUpdateDrawPen({ target: { value: 8 } });
646
649
  nvSetDrawingEnabled(true);
@@ -838,6 +841,12 @@ export default function CloudMrNiivueViewer(props) {
838
841
  function clearActiveShapeDraftRef() {
839
842
  nv._cloudMrActiveShapeDraft = null;
840
843
  }
844
+ function syncActivePenDraftRef() {
845
+ nv._cloudMrActivePenDraft = penDraftRef.current;
846
+ }
847
+ function clearActivePenDraftRef() {
848
+ nv._cloudMrActivePenDraft = null;
849
+ }
841
850
  function cancelPenDraftHandler() {
842
851
  var _a;
843
852
  var draft = penDraftRef.current;
@@ -851,6 +860,7 @@ export default function CloudMrNiivueViewer(props) {
851
860
  setPenDraft(null);
852
861
  penDraftRef.current = null;
853
862
  nv._cloudMrPenDraftActive = false;
863
+ clearActivePenDraftRef();
854
864
  if (drawShapeToolRef.current === "pen") {
855
865
  nvSetDrawingEnabled(true);
856
866
  }
@@ -868,6 +878,7 @@ export default function CloudMrNiivueViewer(props) {
868
878
  setPenDraft(null);
869
879
  penDraftRef.current = null;
870
880
  nv._cloudMrPenDraftActive = false;
881
+ clearActivePenDraftRef();
871
882
  setDrawingChanged(true);
872
883
  if (drawShapeToolRef.current === "pen") {
873
884
  nvSetDrawingEnabled(true);
@@ -884,6 +895,7 @@ export default function CloudMrNiivueViewer(props) {
884
895
  function onPenDraftChange(draft) {
885
896
  setPenDraft(draft);
886
897
  penDraftRef.current = draft;
898
+ syncActivePenDraftRef();
887
899
  if (draft.kind === "polyline") {
888
900
  syncPolylineDraftToNv(nv, draft);
889
901
  }
@@ -895,6 +907,7 @@ export default function CloudMrNiivueViewer(props) {
895
907
  setPenDraft(draft);
896
908
  penDraftRef.current = draft;
897
909
  nv._cloudMrPenDraftActive = true;
910
+ syncActivePenDraftRef();
898
911
  nvSetDrawingEnabled(false);
899
912
  };
900
913
  nv.onPolylineChange = function (count) {
@@ -909,11 +922,13 @@ export default function CloudMrNiivueViewer(props) {
909
922
  if (draft) {
910
923
  setPenDraft(draft);
911
924
  penDraftRef.current = draft;
925
+ syncActivePenDraftRef();
912
926
  }
913
927
  }
914
928
  else if (((_b = penDraftRef.current) === null || _b === void 0 ? void 0 : _b.kind) === "polyline") {
915
929
  setPenDraft(null);
916
930
  penDraftRef.current = null;
931
+ clearActivePenDraftRef();
917
932
  }
918
933
  };
919
934
  function cancelShapeDraft() {
@@ -1481,6 +1481,23 @@ function isClickOnActiveShapeDraft(nv) {
1481
1481
  return isVoxelPartOfDraft(nv, draft, vox);
1482
1482
  }
1483
1483
 
1484
+ function isClickOnActivePenDraft(nv) {
1485
+ const draft = nv._cloudMrActivePenDraft;
1486
+ if (!draft || !nv._cloudMrPenDraftActive) return false;
1487
+ const vox = voxFromMouse(nv);
1488
+ if (!vox) return false;
1489
+ return isVoxelPartOfDraft(nv, draft, vox);
1490
+ }
1491
+
1492
+ function voxelLabelAt(nv, vox) {
1493
+ const dims = nv.back?.dims;
1494
+ if (!dims || !nv.drawBitmap || !vox) return 0;
1495
+ const dx = dims[1];
1496
+ const dy = dims[2];
1497
+ const idx = vox[0] + vox[1] * dx + vox[2] * dx * dy;
1498
+ return nv.drawBitmap[idx] || 0;
1499
+ }
1500
+
1484
1501
  function canReopenShapeDraftOnClick(nv) {
1485
1502
  const penType = nv.opts.penType;
1486
1503
  return (
@@ -1506,18 +1523,25 @@ function cloudMrOpenShapeDraftFromClick(nv) {
1506
1523
  /**
1507
1524
  * Re-enter rectangle/ellipse edit mode when clicking an existing shape ROI.
1508
1525
  */
1509
- function cloudMrTryReopenShapeDraftOnClick(nv) {
1510
- if (!isClickWithoutDrag(nv.uiData) || !canReopenShapeDraftOnClick(nv)) {
1526
+ function cloudMrTryOpenShapeDraftOnMouseDown(nv) {
1527
+ if (nv._cloudMrShapeDraftActive || nv._cloudMrPenDraftActive) {
1528
+ return false;
1529
+ }
1530
+ if (!canReopenShapeDraftOnClick(nv)) {
1531
+ return false;
1532
+ }
1533
+ const vox = voxFromMouse(nv);
1534
+ if (!vox || !voxelLabelAt(nv, vox)) {
1511
1535
  return false;
1512
1536
  }
1513
1537
  return cloudMrOpenShapeDraftFromClick(nv);
1514
1538
  }
1515
1539
 
1516
1540
  /**
1517
- * While editing one shape, mousedown on another shape applies the current
1518
- * draft immediately and opens the clicked shape for editing.
1541
+ * Click-away exits shape edit mode; clicking another shape selects it for editing.
1542
+ * Disconnected same-color shapes are distinguished by flood-fill from the click point.
1519
1543
  */
1520
- function cloudMrTrySwitchShapeDraftOnMouseDown(nv) {
1544
+ function cloudMrHandleShapeDraftClickOnMouseDown(nv) {
1521
1545
  if (!nv._cloudMrShapeDraftActive || nv._cloudMrPenDraftActive) {
1522
1546
  return false;
1523
1547
  }
@@ -1526,29 +1550,55 @@ function cloudMrTrySwitchShapeDraftOnMouseDown(nv) {
1526
1550
  }
1527
1551
 
1528
1552
  const vox = voxFromMouse(nv);
1529
- if (!vox || isClickOnActiveShapeDraft(nv)) {
1553
+ if (!vox) {
1554
+ return false;
1555
+ }
1556
+ if (isClickOnActiveShapeDraft(nv)) {
1530
1557
  return false;
1531
1558
  }
1532
1559
 
1533
- const dims = nv.back?.dims;
1534
- if (!dims || !nv.drawBitmap) return false;
1535
- const dx = dims[1];
1536
- const dy = dims[2];
1537
- const idx = vox[0] + vox[1] * dx + vox[2] * dx * dy;
1538
- if (!nv.drawBitmap[idx]) {
1560
+ if (typeof nv.onApplyActiveDraft === "function") {
1561
+ nv.onApplyActiveDraft();
1562
+ }
1563
+
1564
+ if (voxelLabelAt(nv, vox) > 0) {
1565
+ cloudMrOpenShapeDraftFromClick(nv);
1566
+ }
1567
+ return true;
1568
+ }
1569
+
1570
+ /** Click-away applies a pen draft without starting a new stroke. */
1571
+ function cloudMrHandlePenDraftClickOnMouseDown(nv) {
1572
+ if (!nv._cloudMrPenDraftActive) {
1573
+ return false;
1574
+ }
1575
+
1576
+ const vox = voxFromMouse(nv);
1577
+ if (!vox) {
1578
+ return false;
1579
+ }
1580
+ if (isClickOnActivePenDraft(nv)) {
1539
1581
  return false;
1540
1582
  }
1541
1583
 
1542
1584
  if (typeof nv.onApplyActiveDraft === "function") {
1543
1585
  nv.onApplyActiveDraft();
1544
1586
  }
1545
- return cloudMrOpenShapeDraftFromClick(nv);
1587
+ return true;
1546
1588
  }
1547
1589
 
1548
1590
  const _mouseDownListener = Niivue.prototype.mouseDownListener;
1549
1591
  Niivue.prototype.mouseDownListener = function cloudMrMouseDownListener(e) {
1550
- if (e.button === 0 && cloudMrTrySwitchShapeDraftOnMouseDown(this)) {
1551
- return;
1592
+ if (e.button === 0) {
1593
+ if (cloudMrHandleShapeDraftClickOnMouseDown(this)) {
1594
+ return;
1595
+ }
1596
+ if (cloudMrHandlePenDraftClickOnMouseDown(this)) {
1597
+ return;
1598
+ }
1599
+ if (cloudMrTryOpenShapeDraftOnMouseDown(this)) {
1600
+ return;
1601
+ }
1552
1602
  }
1553
1603
  if (shouldDeferFreehandCommit(this) && this.drawBitmap) {
1554
1604
  this._cloudMrFreehandSessionStartBitmap = this.drawBitmap.slice();
@@ -1618,14 +1668,12 @@ Niivue.prototype.mouseUpListener = function cloudMrMouseUpListener() {
1618
1668
  }
1619
1669
 
1620
1670
  if (!pendingDraft?.baseBitmap) {
1621
- cloudMrTryReopenShapeDraftOnClick(this);
1622
1671
  return;
1623
1672
  }
1624
1673
  if (isDraftTooSmall(pendingDraft.ptA, pendingDraft.ptB)) {
1625
1674
  this.drawBitmap.set(pendingDraft.baseBitmap);
1626
1675
  this.refreshDrawing(true, false);
1627
1676
  this.drawScene();
1628
- cloudMrTryReopenShapeDraftOnClick(this);
1629
1677
  return;
1630
1678
  }
1631
1679
  this._cloudMrSuppressDrawingChangedMouseUp = true;
@@ -1,12 +1,11 @@
1
1
  /**
2
2
  * Adjust handles for polyline (vertex drag) or freehand (move only) drafts.
3
- * @param {{ nv: any, draft: any, onDraftChange: (d: any) => void, onApplyDraft?: () => void, overlayKey?: unknown }} props
3
+ * @param {{ nv: any, draft: any, onDraftChange: (d: any) => void, overlayKey?: unknown }} props
4
4
  */
5
- export function PenDraftOverlay({ nv, draft, onDraftChange, onApplyDraft, overlayKey }: {
5
+ export function PenDraftOverlay({ nv, draft, onDraftChange, overlayKey }: {
6
6
  nv: any;
7
7
  draft: any;
8
8
  onDraftChange: (d: any) => void;
9
- onApplyDraft?: (() => void) | undefined;
10
9
  overlayKey?: unknown;
11
10
  }): import("react/jsx-runtime").JSX.Element | null;
12
11
  export default PenDraftOverlay;
@@ -29,10 +29,10 @@ function cloneFreehandDraft(draft) {
29
29
  }
30
30
  /**
31
31
  * Adjust handles for polyline (vertex drag) or freehand (move only) drafts.
32
- * @param {{ nv: any, draft: any, onDraftChange: (d: any) => void, onApplyDraft?: () => void, overlayKey?: unknown }} props
32
+ * @param {{ nv: any, draft: any, onDraftChange: (d: any) => void, overlayKey?: unknown }} props
33
33
  */
34
34
  export function PenDraftOverlay(_a) {
35
- var nv = _a.nv, draft = _a.draft, onDraftChange = _a.onDraftChange, onApplyDraft = _a.onApplyDraft, overlayKey = _a.overlayKey;
35
+ var nv = _a.nv, draft = _a.draft, onDraftChange = _a.onDraftChange, overlayKey = _a.overlayKey;
36
36
  var dragRef = useRef(null);
37
37
  var draftRef = useRef(draft);
38
38
  draftRef.current = draft;
@@ -110,7 +110,6 @@ export function PenDraftOverlay(_a) {
110
110
  onDraftChange(nextDraft);
111
111
  }, [nv, onDraftChange]);
112
112
  finishDragRef.current = function () {
113
- var hadDrag = dragRef.current != null;
114
113
  dragRef.current = null;
115
114
  if (onPointerMoveRef.current) {
116
115
  window.removeEventListener("pointermove", onPointerMoveRef.current);
@@ -118,10 +117,6 @@ export function PenDraftOverlay(_a) {
118
117
  if (finishDragRef.current) {
119
118
  window.removeEventListener("pointerup", finishDragRef.current);
120
119
  }
121
- // Auto-apply as soon as the user releases the handle after a move/resize
122
- if (hadDrag && onApplyDraft) {
123
- onApplyDraft();
124
- }
125
120
  };
126
121
  onPointerMoveRef.current = function (event) {
127
122
  var drag = dragRef.current;
@@ -1,12 +1,11 @@
1
1
  /**
2
2
  * Overlay handles for adjusting a rectangle/ellipse draft before commit.
3
- * @param {{ nv: any, draft: import('./shapeDraftUtils').ShapeDraft, onDraftChange: (d: any) => void, onApplyDraft?: () => void, overlayKey?: unknown }} props
3
+ * @param {{ nv: any, draft: import('./shapeDraftUtils').ShapeDraft, onDraftChange: (d: any) => void, overlayKey?: unknown }} props
4
4
  */
5
- export function ShapeDraftOverlay({ nv, draft, onDraftChange, onApplyDraft, overlayKey }: {
5
+ export function ShapeDraftOverlay({ nv, draft, onDraftChange, overlayKey }: {
6
6
  nv: any;
7
7
  draft: import('./shapeDraftUtils').ShapeDraft;
8
8
  onDraftChange: (d: any) => void;
9
- onApplyDraft?: (() => void) | undefined;
10
9
  overlayKey?: unknown;
11
10
  }): import("react/jsx-runtime").JSX.Element | null;
12
11
  export default ShapeDraftOverlay;
@@ -25,11 +25,11 @@ var HANDLE_SIZE = 10;
25
25
  var ACCENT = "#580f8b";
26
26
  /**
27
27
  * Overlay handles for adjusting a rectangle/ellipse draft before commit.
28
- * @param {{ nv: any, draft: import('./shapeDraftUtils').ShapeDraft, onDraftChange: (d: any) => void, onApplyDraft?: () => void, overlayKey?: unknown }} props
28
+ * @param {{ nv: any, draft: import('./shapeDraftUtils').ShapeDraft, onDraftChange: (d: any) => void, overlayKey?: unknown }} props
29
29
  */
30
30
  export function ShapeDraftOverlay(_a) {
31
31
  var _b;
32
- var nv = _a.nv, draft = _a.draft, onDraftChange = _a.onDraftChange, onApplyDraft = _a.onApplyDraft, overlayKey = _a.overlayKey;
32
+ var nv = _a.nv, draft = _a.draft, onDraftChange = _a.onDraftChange, overlayKey = _a.overlayKey;
33
33
  var dragRef = useRef(null);
34
34
  var draftRef = useRef(draft);
35
35
  draftRef.current = draft;
@@ -84,7 +84,6 @@ export function ShapeDraftOverlay(_a) {
84
84
  onDraftChange(nextDraft);
85
85
  }, [nv, onDraftChange]);
86
86
  finishDragRef.current = function () {
87
- var hadDrag = dragRef.current != null;
88
87
  dragRef.current = null;
89
88
  if (onPointerMoveRef.current) {
90
89
  window.removeEventListener("pointermove", onPointerMoveRef.current);
@@ -92,10 +91,6 @@ export function ShapeDraftOverlay(_a) {
92
91
  if (finishDragRef.current) {
93
92
  window.removeEventListener("pointerup", finishDragRef.current);
94
93
  }
95
- // Auto-apply as soon as the user releases the handle after a move/resize
96
- if (hadDrag && onApplyDraft) {
97
- onApplyDraft();
98
- }
99
94
  };
100
95
  onPointerMoveRef.current = function (event) {
101
96
  var drag = dragRef.current;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudmr-ux",
3
- "version": "4.6.3",
3
+ "version": "4.6.5",
4
4
  "author": "erosmontin@gmail.com",
5
5
  "license": "MIT",
6
6
  "repository": "erosmontin/cloudmr-ux",