cloudmr-ux 4.6.5 → 4.6.6

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.
@@ -586,7 +586,6 @@ export default function CloudMrNiivueViewer(props) {
586
586
  setPenDraft(null);
587
587
  penDraftRef.current = null;
588
588
  nv._cloudMrPenDraftActive = false;
589
- clearActivePenDraftRef();
590
589
  setPolylineVertexCount(0);
591
590
  }
592
591
  if (shapeDraftRef.current) {
@@ -611,7 +610,6 @@ export default function CloudMrNiivueViewer(props) {
611
610
  setPenDraft(null);
612
611
  penDraftRef.current = null;
613
612
  nv._cloudMrPenDraftActive = false;
614
- clearActivePenDraftRef();
615
613
  }
616
614
  setDrawShapeTool(null);
617
615
  nv.opts.penType = NI_PEN_TYPE.PEN;
@@ -643,7 +641,6 @@ export default function CloudMrNiivueViewer(props) {
643
641
  setPenDraft(null);
644
642
  penDraftRef.current = null;
645
643
  nv._cloudMrPenDraftActive = false;
646
- clearActivePenDraftRef();
647
644
  }
648
645
  nvUpdateDrawPen({ target: { value: 8 } });
649
646
  nvSetDrawingEnabled(true);
@@ -835,18 +832,6 @@ export default function CloudMrNiivueViewer(props) {
835
832
  (_a = nv.cloudMrCancelPolyline) === null || _a === void 0 ? void 0 : _a.call(nv);
836
833
  }
837
834
  }
838
- function syncActiveShapeDraftRef() {
839
- nv._cloudMrActiveShapeDraft = shapeDraftRef.current;
840
- }
841
- function clearActiveShapeDraftRef() {
842
- nv._cloudMrActiveShapeDraft = null;
843
- }
844
- function syncActivePenDraftRef() {
845
- nv._cloudMrActivePenDraft = penDraftRef.current;
846
- }
847
- function clearActivePenDraftRef() {
848
- nv._cloudMrActivePenDraft = null;
849
- }
850
835
  function cancelPenDraftHandler() {
851
836
  var _a;
852
837
  var draft = penDraftRef.current;
@@ -860,7 +845,6 @@ export default function CloudMrNiivueViewer(props) {
860
845
  setPenDraft(null);
861
846
  penDraftRef.current = null;
862
847
  nv._cloudMrPenDraftActive = false;
863
- clearActivePenDraftRef();
864
848
  if (drawShapeToolRef.current === "pen") {
865
849
  nvSetDrawingEnabled(true);
866
850
  }
@@ -878,7 +862,6 @@ export default function CloudMrNiivueViewer(props) {
878
862
  setPenDraft(null);
879
863
  penDraftRef.current = null;
880
864
  nv._cloudMrPenDraftActive = false;
881
- clearActivePenDraftRef();
882
865
  setDrawingChanged(true);
883
866
  if (drawShapeToolRef.current === "pen") {
884
867
  nvSetDrawingEnabled(true);
@@ -895,7 +878,6 @@ export default function CloudMrNiivueViewer(props) {
895
878
  function onPenDraftChange(draft) {
896
879
  setPenDraft(draft);
897
880
  penDraftRef.current = draft;
898
- syncActivePenDraftRef();
899
881
  if (draft.kind === "polyline") {
900
882
  syncPolylineDraftToNv(nv, draft);
901
883
  }
@@ -907,7 +889,6 @@ export default function CloudMrNiivueViewer(props) {
907
889
  setPenDraft(draft);
908
890
  penDraftRef.current = draft;
909
891
  nv._cloudMrPenDraftActive = true;
910
- syncActivePenDraftRef();
911
892
  nvSetDrawingEnabled(false);
912
893
  };
913
894
  nv.onPolylineChange = function (count) {
@@ -922,13 +903,11 @@ export default function CloudMrNiivueViewer(props) {
922
903
  if (draft) {
923
904
  setPenDraft(draft);
924
905
  penDraftRef.current = draft;
925
- syncActivePenDraftRef();
926
906
  }
927
907
  }
928
908
  else if (((_b = penDraftRef.current) === null || _b === void 0 ? void 0 : _b.kind) === "polyline") {
929
909
  setPenDraft(null);
930
910
  penDraftRef.current = null;
931
- clearActivePenDraftRef();
932
911
  }
933
912
  };
934
913
  function cancelShapeDraft() {
@@ -941,7 +920,6 @@ export default function CloudMrNiivueViewer(props) {
941
920
  setShapeDraft(null);
942
921
  shapeDraftRef.current = null;
943
922
  nv._cloudMrShapeDraftActive = false;
944
- clearActiveShapeDraftRef();
945
923
  if (drawShapeToolRef.current) {
946
924
  nvSetDrawingEnabled(true);
947
925
  }
@@ -954,7 +932,6 @@ export default function CloudMrNiivueViewer(props) {
954
932
  setShapeDraft(null);
955
933
  shapeDraftRef.current = null;
956
934
  nv._cloudMrShapeDraftActive = false;
957
- clearActiveShapeDraftRef();
958
935
  if (drawShapeToolRef.current) {
959
936
  nvSetDrawingEnabled(true);
960
937
  }
@@ -963,13 +940,11 @@ export default function CloudMrNiivueViewer(props) {
963
940
  function onShapeDraftChange(draft) {
964
941
  setShapeDraft(draft);
965
942
  shapeDraftRef.current = draft;
966
- syncActiveShapeDraftRef();
967
943
  }
968
944
  nv.onShapeDraftReady = function (draft) {
969
945
  setShapeDraft(draft);
970
946
  shapeDraftRef.current = draft;
971
947
  nv._cloudMrShapeDraftActive = true;
972
- syncActiveShapeDraftRef();
973
948
  nvSetDrawingEnabled(false);
974
949
  };
975
950
  nv.onApplyActiveDraft = function () {
@@ -986,6 +961,32 @@ export default function CloudMrNiivueViewer(props) {
986
961
  React.useEffect(function () {
987
962
  nv._cloudMrShapeDraftActive = shapeDraft != null;
988
963
  }, [shapeDraft]);
964
+ React.useEffect(function () {
965
+ if (!shapeDraft && !penDraft) {
966
+ return undefined;
967
+ }
968
+ var canvas = document.getElementById("niiCanvas");
969
+ if (!canvas) {
970
+ return undefined;
971
+ }
972
+ var applyOnRightClick = function (event) {
973
+ var _a;
974
+ event.preventDefault();
975
+ event.stopPropagation();
976
+ (_a = nv.onApplyActiveDraft) === null || _a === void 0 ? void 0 : _a.call(nv);
977
+ };
978
+ var onMouseDown = function (event) {
979
+ if (event.button === 2) {
980
+ applyOnRightClick(event);
981
+ }
982
+ };
983
+ canvas.addEventListener("mousedown", onMouseDown, true);
984
+ canvas.addEventListener("contextmenu", applyOnRightClick, true);
985
+ return function () {
986
+ canvas.removeEventListener("mousedown", onMouseDown, true);
987
+ canvas.removeEventListener("contextmenu", applyOnRightClick, true);
988
+ };
989
+ }, [shapeDraft, penDraft]);
989
990
  React.useEffect(function () {
990
991
  if (!shapeDraft && !penDraft) {
991
992
  return undefined;
@@ -999,6 +1000,16 @@ export default function CloudMrNiivueViewer(props) {
999
1000
  else if (penDraft) {
1000
1001
  cancelPenDraftHandler();
1001
1002
  }
1003
+ return;
1004
+ }
1005
+ if (event.key === "Enter") {
1006
+ event.preventDefault();
1007
+ if (shapeDraft) {
1008
+ applyShapeDraft();
1009
+ }
1010
+ else if (penDraft) {
1011
+ applyPenDraftHandler();
1012
+ }
1002
1013
  }
1003
1014
  };
1004
1015
  window.addEventListener("keydown", onKeyDown);
@@ -6,7 +6,6 @@ import {
6
6
  captureDeferredShapeDraft,
7
7
  captureShapeDraftFromClick,
8
8
  isDraftTooSmall,
9
- isVoxelPartOfDraft,
10
9
  redrawDraftShape,
11
10
  shouldDeferShapeCommit,
12
11
  } from "./shapeDraftUtils.js";
@@ -1469,136 +1468,55 @@ Niivue.prototype.cloudMrResetPolyline = function cloudMrResetPolyline() {
1469
1468
  resetPolylineState(this);
1470
1469
  };
1471
1470
 
1471
+ const RIGHT_MOUSE_BUTTON = 2;
1472
+
1472
1473
  function cloudMrHasApplyableDraft(nv) {
1473
1474
  return !!(nv._cloudMrShapeDraftActive || nv._cloudMrPenDraftActive);
1474
1475
  }
1475
1476
 
1476
- function isClickOnActiveShapeDraft(nv) {
1477
- const draft = nv._cloudMrActiveShapeDraft;
1478
- if (!draft || !nv._cloudMrShapeDraftActive) return false;
1479
- const vox = voxFromMouse(nv);
1480
- if (!vox) return false;
1481
- return isVoxelPartOfDraft(nv, draft, vox);
1482
- }
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
-
1501
- function canReopenShapeDraftOnClick(nv) {
1502
- const penType = nv.opts.penType;
1503
- return (
1504
- nv.opts.deferShapeCommit &&
1505
- nv.opts.drawingEnabled &&
1506
- !nv._cloudMrShapeDraftActive &&
1507
- !nv._cloudMrPenDraftActive &&
1508
- (penType === NI_PEN_TYPE.RECTANGLE || penType === NI_PEN_TYPE.ELLIPSE)
1509
- );
1510
- }
1511
-
1512
- function cloudMrOpenShapeDraftFromClick(nv) {
1513
- const reopenDraft = captureShapeDraftFromClick(nv);
1514
- if (!reopenDraft) return false;
1515
- redrawDraftShape(nv, reopenDraft);
1516
- nv._cloudMrSuppressDrawingChangedMouseUp = true;
1517
- if (typeof nv.onShapeDraftReady === "function") {
1518
- nv.onShapeDraftReady(reopenDraft);
1519
- }
1520
- return true;
1521
- }
1522
-
1523
- /**
1524
- * Re-enter rectangle/ellipse edit mode when clicking an existing shape ROI.
1525
- */
1526
- function cloudMrTryOpenShapeDraftOnMouseDown(nv) {
1527
- if (nv._cloudMrShapeDraftActive || nv._cloudMrPenDraftActive) {
1528
- return false;
1529
- }
1530
- if (!canReopenShapeDraftOnClick(nv)) {
1477
+ function cloudMrTryApplyDraftOnRightClick(nv, event) {
1478
+ if (!cloudMrHasApplyableDraft(nv)) {
1531
1479
  return false;
1532
1480
  }
1533
- const vox = voxFromMouse(nv);
1534
- if (!vox || !voxelLabelAt(nv, vox)) {
1535
- return false;
1536
- }
1537
- return cloudMrOpenShapeDraftFromClick(nv);
1538
- }
1539
-
1540
- /**
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.
1543
- */
1544
- function cloudMrHandleShapeDraftClickOnMouseDown(nv) {
1545
- if (!nv._cloudMrShapeDraftActive || nv._cloudMrPenDraftActive) {
1546
- return false;
1547
- }
1548
- if (!nv.opts.deferShapeCommit || !nv.opts.drawingEnabled) {
1549
- return false;
1550
- }
1551
-
1552
- const vox = voxFromMouse(nv);
1553
- if (!vox) {
1554
- return false;
1555
- }
1556
- if (isClickOnActiveShapeDraft(nv)) {
1557
- return false;
1558
- }
1559
-
1481
+ event.preventDefault();
1482
+ event.stopPropagation();
1560
1483
  if (typeof nv.onApplyActiveDraft === "function") {
1561
1484
  nv.onApplyActiveDraft();
1562
1485
  }
1563
-
1564
- if (voxelLabelAt(nv, vox) > 0) {
1565
- cloudMrOpenShapeDraftFromClick(nv);
1566
- }
1567
1486
  return true;
1568
1487
  }
1569
1488
 
1570
- /** Click-away applies a pen draft without starting a new stroke. */
1571
- function cloudMrHandlePenDraftClickOnMouseDown(nv) {
1572
- if (!nv._cloudMrPenDraftActive) {
1489
+ /**
1490
+ * Re-enter rectangle/ellipse edit mode when clicking an existing applied ROI.
1491
+ */
1492
+ function cloudMrTryReopenShapeDraftOnClick(nv) {
1493
+ const penType = nv.opts.penType;
1494
+ if (
1495
+ !nv.opts.deferShapeCommit ||
1496
+ !nv.opts.drawingEnabled ||
1497
+ nv._cloudMrShapeDraftActive ||
1498
+ nv._cloudMrPenDraftActive ||
1499
+ !isClickWithoutDrag(nv.uiData) ||
1500
+ (penType !== NI_PEN_TYPE.RECTANGLE && penType !== NI_PEN_TYPE.ELLIPSE)
1501
+ ) {
1573
1502
  return false;
1574
1503
  }
1575
1504
 
1576
- const vox = voxFromMouse(nv);
1577
- if (!vox) {
1578
- return false;
1579
- }
1580
- if (isClickOnActivePenDraft(nv)) {
1581
- return false;
1582
- }
1505
+ const reopenDraft = captureShapeDraftFromClick(nv);
1506
+ if (!reopenDraft) return false;
1583
1507
 
1584
- if (typeof nv.onApplyActiveDraft === "function") {
1585
- nv.onApplyActiveDraft();
1508
+ redrawDraftShape(nv, reopenDraft);
1509
+ nv._cloudMrSuppressDrawingChangedMouseUp = true;
1510
+ if (typeof nv.onShapeDraftReady === "function") {
1511
+ nv.onShapeDraftReady(reopenDraft);
1586
1512
  }
1587
1513
  return true;
1588
1514
  }
1589
1515
 
1590
1516
  const _mouseDownListener = Niivue.prototype.mouseDownListener;
1591
1517
  Niivue.prototype.mouseDownListener = function cloudMrMouseDownListener(e) {
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
- }
1518
+ if (e.button === RIGHT_MOUSE_BUTTON && cloudMrTryApplyDraftOnRightClick(this, e)) {
1519
+ return;
1602
1520
  }
1603
1521
  if (shouldDeferFreehandCommit(this) && this.drawBitmap) {
1604
1522
  this._cloudMrFreehandSessionStartBitmap = this.drawBitmap.slice();
@@ -1668,12 +1586,14 @@ Niivue.prototype.mouseUpListener = function cloudMrMouseUpListener() {
1668
1586
  }
1669
1587
 
1670
1588
  if (!pendingDraft?.baseBitmap) {
1589
+ cloudMrTryReopenShapeDraftOnClick(this);
1671
1590
  return;
1672
1591
  }
1673
1592
  if (isDraftTooSmall(pendingDraft.ptA, pendingDraft.ptB)) {
1674
1593
  this.drawBitmap.set(pendingDraft.baseBitmap);
1675
1594
  this.refreshDrawing(true, false);
1676
1595
  this.drawScene();
1596
+ cloudMrTryReopenShapeDraftOnClick(this);
1677
1597
  return;
1678
1598
  }
1679
1599
  this._cloudMrSuppressDrawingChangedMouseUp = true;
@@ -1,11 +1,10 @@
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, overlayKey?: unknown }} props
4
3
  */
5
4
  export function PenDraftOverlay({ nv, draft, onDraftChange, overlayKey }: {
6
5
  nv: any;
7
6
  draft: any;
8
- onDraftChange: (d: any) => void;
9
- overlayKey?: unknown;
7
+ onDraftChange: any;
8
+ overlayKey: any;
10
9
  }): import("react/jsx-runtime").JSX.Element | null;
11
10
  export default PenDraftOverlay;
@@ -29,7 +29,6 @@ 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, overlayKey?: unknown }} props
33
32
  */
34
33
  export function PenDraftOverlay(_a) {
35
34
  var nv = _a.nv, draft = _a.draft, onDraftChange = _a.onDraftChange, overlayKey = _a.overlayKey;
@@ -1,4 +1,4 @@
1
- export default function DrawColorPlatte({ expanded, updateDrawPen, setDrawingEnabled, showPenModes, penDrawMode, onPenDrawModeChange, polylineVertexCount, penDraftActive, onCancelPenDraft, onFillPenDraft, brushSize, updateBrushSize, shapeDraftActive, onCancelShapeDraft, }: {
1
+ export default function DrawColorPlatte({ expanded, updateDrawPen, setDrawingEnabled, showPenModes, penDrawMode, onPenDrawModeChange, polylineVertexCount, penDraftActive, onApplyPenDraft, onCancelPenDraft, onFillPenDraft, brushSize, updateBrushSize, shapeDraftActive, onApplyShapeDraft, onCancelShapeDraft, }: {
2
2
  expanded: any;
3
3
  updateDrawPen: any;
4
4
  setDrawingEnabled: any;
@@ -7,10 +7,12 @@ export default function DrawColorPlatte({ expanded, updateDrawPen, setDrawingEna
7
7
  onPenDrawModeChange: any;
8
8
  polylineVertexCount?: number | undefined;
9
9
  penDraftActive?: boolean | undefined;
10
+ onApplyPenDraft: any;
10
11
  onCancelPenDraft: any;
11
12
  onFillPenDraft: any;
12
13
  brushSize?: number | undefined;
13
14
  updateBrushSize: any;
14
15
  shapeDraftActive?: boolean | undefined;
16
+ onApplyShapeDraft: any;
15
17
  onCancelShapeDraft: any;
16
18
  }): import("react/jsx-runtime").JSX.Element;
@@ -11,13 +11,12 @@ var __assign = (this && this.__assign) || function () {
11
11
  };
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  /**
14
- * Pen palette adds freehand vs polyline mode; pen/shape drafts show Cancel while adjusting.
15
- * Shapes are applied automatically on mouse release.
14
+ * Pen palette adds freehand vs polyline mode; pen/shape drafts show Apply/Cancel while adjusting.
16
15
  */
17
16
  import { Stack, IconButton, Button, Tooltip, Typography } from "@mui/material";
18
17
  import FiberManualRecordIcon from "@mui/icons-material/FiberManualRecord";
18
+ import CheckIcon from "@mui/icons-material/Check";
19
19
  import CloseIcon from "@mui/icons-material/Close";
20
- import FormatColorFillIcon from "@mui/icons-material/FormatColorFill";
21
20
  import { BrushSizeSlider } from "./BrushSizeSlider";
22
21
  var FILLED_COLORS = [
23
22
  { sx: { color: "red" } },
@@ -38,7 +37,7 @@ var modeBtnSx = function (active) { return ({
38
37
  px: 0.75
39
38
  }); };
40
39
  export default function DrawColorPlatte(_a) {
41
- var expanded = _a.expanded, updateDrawPen = _a.updateDrawPen, setDrawingEnabled = _a.setDrawingEnabled, _b = _a.showPenModes, showPenModes = _b === void 0 ? false : _b, _c = _a.penDrawMode, penDrawMode = _c === void 0 ? "freehand" : _c, onPenDrawModeChange = _a.onPenDrawModeChange, _d = _a.polylineVertexCount, polylineVertexCount = _d === void 0 ? 0 : _d, _e = _a.penDraftActive, penDraftActive = _e === void 0 ? false : _e, onCancelPenDraft = _a.onCancelPenDraft, onFillPenDraft = _a.onFillPenDraft, _f = _a.brushSize, brushSize = _f === void 0 ? 1 : _f, updateBrushSize = _a.updateBrushSize, _g = _a.shapeDraftActive, shapeDraftActive = _g === void 0 ? false : _g, onCancelShapeDraft = _a.onCancelShapeDraft;
40
+ var expanded = _a.expanded, updateDrawPen = _a.updateDrawPen, setDrawingEnabled = _a.setDrawingEnabled, _b = _a.showPenModes, showPenModes = _b === void 0 ? false : _b, _c = _a.penDrawMode, penDrawMode = _c === void 0 ? "freehand" : _c, onPenDrawModeChange = _a.onPenDrawModeChange, _d = _a.polylineVertexCount, polylineVertexCount = _d === void 0 ? 0 : _d, _e = _a.penDraftActive, penDraftActive = _e === void 0 ? false : _e, onApplyPenDraft = _a.onApplyPenDraft, onCancelPenDraft = _a.onCancelPenDraft, onFillPenDraft = _a.onFillPenDraft, _f = _a.brushSize, brushSize = _f === void 0 ? 1 : _f, updateBrushSize = _a.updateBrushSize, _g = _a.shapeDraftActive, shapeDraftActive = _g === void 0 ? false : _g, onApplyShapeDraft = _a.onApplyShapeDraft, onCancelShapeDraft = _a.onCancelShapeDraft;
42
41
  return (_jsxs(Stack, __assign({ style: {
43
42
  position: "absolute",
44
43
  top: "100%",
@@ -63,22 +62,36 @@ export default function DrawColorPlatte(_a) {
63
62
  py: 0.25,
64
63
  px: 0.75,
65
64
  "& .MuiButton-startIcon": { mr: 0.5, ml: 0 }
66
- } }, { children: "Cancel" })) })), penDrawMode === "polyline" && polylineVertexCount >= 3 && (_jsx(Tooltip, __assign({ title: "Fill interior (keeps outline editable until release)" }, { children: _jsx(Button, __assign({ size: "small", "aria-label": "fill polyline", onClick: function () { return onFillPenDraft === null || onFillPenDraft === void 0 ? void 0 : onFillPenDraft(); }, startIcon: _jsx(FormatColorFillIcon, { sx: { fontSize: ACTION_ICON_SIZE } }), sx: {
65
+ } }, { children: "Cancel" })) })), _jsxs(Stack, __assign({ direction: "row", alignItems: "center", spacing: 1 }, { children: [penDrawMode === "polyline" && polylineVertexCount >= 3 && (_jsx(Tooltip, __assign({ title: "Fill interior (keeps outline editable until Apply)" }, { children: _jsx(Button, __assign({ size: "small", "aria-label": "fill polyline", onClick: function () { return onFillPenDraft === null || onFillPenDraft === void 0 ? void 0 : onFillPenDraft(); }, sx: {
66
+ color: "#c9a0e8",
67
+ fontSize: ACTION_FONT_SIZE,
68
+ textTransform: "none",
69
+ minWidth: 0,
70
+ py: 0.25,
71
+ px: 0.75
72
+ } }, { children: "Fill" })) }))), _jsx(Tooltip, __assign({ title: "Apply shape (enter or right-click)" }, { children: _jsx(Button, __assign({ size: "small", "aria-label": "apply pen draft", onClick: function () { return onApplyPenDraft === null || onApplyPenDraft === void 0 ? void 0 : onApplyPenDraft(); }, startIcon: _jsx(CheckIcon, { sx: { fontSize: ACTION_ICON_SIZE } }), sx: {
73
+ color: "#c9a0e8",
74
+ fontSize: ACTION_FONT_SIZE,
75
+ textTransform: "none",
76
+ minWidth: 0,
77
+ py: 0.25,
78
+ px: 0.75,
79
+ "& .MuiButton-startIcon": { mr: 0.5, ml: 0 }
80
+ } }, { children: "Apply" })) }))] }))] }))), shapeDraftActive && expanded && (_jsxs(Stack, __assign({ direction: "row", alignItems: "center", justifyContent: "space-between", sx: { px: 1, py: 0.5, borderTop: "1px solid #555", width: "100%" } }, { children: [_jsx(Tooltip, __assign({ title: "Cancel shape (Esc)" }, { children: _jsx(Button, __assign({ size: "small", "aria-label": "cancel shape", onClick: function () { return onCancelShapeDraft === null || onCancelShapeDraft === void 0 ? void 0 : onCancelShapeDraft(); }, startIcon: _jsx(CloseIcon, { sx: { fontSize: ACTION_ICON_SIZE } }), sx: {
81
+ color: "#ccc",
82
+ fontSize: ACTION_FONT_SIZE,
83
+ textTransform: "none",
84
+ minWidth: 0,
85
+ py: 0.25,
86
+ px: 0.75,
87
+ "& .MuiButton-startIcon": { mr: 0.5, ml: 0 }
88
+ } }, { children: "Cancel" })) })), _jsx(Tooltip, __assign({ title: "Apply shape (enter or right-click)" }, { children: _jsx(Button, __assign({ size: "small", "aria-label": "apply shape", onClick: function () { return onApplyShapeDraft === null || onApplyShapeDraft === void 0 ? void 0 : onApplyShapeDraft(); }, startIcon: _jsx(CheckIcon, { sx: { fontSize: ACTION_ICON_SIZE } }), sx: {
67
89
  color: "#c9a0e8",
68
90
  fontSize: ACTION_FONT_SIZE,
69
91
  textTransform: "none",
70
92
  minWidth: 0,
71
93
  py: 0.25,
72
94
  px: 0.75,
73
- ml: "auto",
74
95
  "& .MuiButton-startIcon": { mr: 0.5, ml: 0 }
75
- } }, { children: "Fill" })) })))] }))), shapeDraftActive && expanded && (_jsx(Stack, __assign({ direction: "row", alignItems: "center", sx: { px: 1, py: 0.5, borderTop: "1px solid #555", width: "100%" } }, { children: _jsx(Tooltip, __assign({ title: "Cancel shape (Esc)" }, { children: _jsx(Button, __assign({ size: "small", "aria-label": "cancel shape", onClick: function () { return onCancelShapeDraft === null || onCancelShapeDraft === void 0 ? void 0 : onCancelShapeDraft(); }, startIcon: _jsx(CloseIcon, { sx: { fontSize: ACTION_ICON_SIZE } }), sx: {
76
- color: "#ccc",
77
- fontSize: ACTION_FONT_SIZE,
78
- textTransform: "none",
79
- minWidth: 0,
80
- py: 0.25,
81
- px: 0.75,
82
- "& .MuiButton-startIcon": { mr: 0.5, ml: 0 }
83
- } }, { children: "Cancel" })) })) })))] })));
96
+ } }, { children: "Apply" })) }))] })))] })));
84
97
  }
@@ -49,27 +49,10 @@ export function captureDeferredShapeDraft(nv: any): {
49
49
  baseBitmap: Uint8Array | null;
50
50
  };
51
51
  export function shouldDeferShapeCommit(nv: any): any;
52
- /**
53
- * Flood-fill a connected voxel cluster from a seed.
54
- * @returns {{ label: number, visited: Set<number>, voxels: [number,number,number][], bounds: object } | null}
55
- */
56
- export function floodFillClusterFromVox(nv: any, seedVox: any): {
57
- label: number;
58
- visited: Set<number>;
59
- voxels: [number, number, number][];
60
- bounds: object;
61
- } | null;
62
- /** True when a voxel belongs to the live draft overlay (drawn on top of baseBitmap). */
63
- export function isVoxelPartOfDraft(nv: any, draft: any, seedVox: any): boolean;
64
- export function eraseClusterFromBitmap(bitmap: any, visited: any): Uint8Array;
65
- /** Guess rectangle vs ellipse from the filled voxel pattern, not the active tool. */
66
- export function inferShapePenTypeFromCluster(cluster: any, axCorSag: any): 1 | 2;
67
52
  /**
68
53
  * When the user clicks on an existing filled ROI while the rectangle/ellipse tool
69
54
  * is active (but no draft is currently open), flood-fill the clicked cluster to
70
55
  * reconstruct a ShapeDraft so the bounding-box overlay reappears for re-editing.
71
- *
72
- * Returns null if the click didn't land on a labeled voxel.
73
56
  */
74
57
  export function captureShapeDraftFromClick(nv: any): {
75
58
  ptA: any[];
@@ -210,11 +210,18 @@ function inferAxCorSagFromBounds(x1, y1, z1, x2, y2, z2, fallback) {
210
210
  return 2;
211
211
  return fallback;
212
212
  }
213
+ function sliceKey(axCorSag, x, y, z) {
214
+ if (axCorSag === 0)
215
+ return "".concat(x, ",").concat(y);
216
+ if (axCorSag === 1)
217
+ return "".concat(x, ",").concat(z);
218
+ return "".concat(y, ",").concat(z);
219
+ }
213
220
  /**
214
221
  * Flood-fill a connected voxel cluster from a seed.
215
222
  * @returns {{ label: number, visited: Set<number>, voxels: [number,number,number][], bounds: object } | null}
216
223
  */
217
- export function floodFillClusterFromVox(nv, seedVox) {
224
+ function floodFillClusterFromVox(nv, seedVox) {
218
225
  var _a;
219
226
  var dims = (_a = nv.back) === null || _a === void 0 ? void 0 : _a.dims;
220
227
  if (!dims || !nv.drawBitmap || !seedVox)
@@ -274,36 +281,15 @@ export function floodFillClusterFromVox(nv, seedVox) {
274
281
  bounds: { x1: x1, y1: y1, z1: z1, x2: x2, y2: y2, z2: z2 }
275
282
  };
276
283
  }
277
- /** True when a voxel belongs to the live draft overlay (drawn on top of baseBitmap). */
278
- export function isVoxelPartOfDraft(nv, draft, seedVox) {
279
- var _a;
280
- if (!(draft === null || draft === void 0 ? void 0 : draft.baseBitmap) || !(nv === null || nv === void 0 ? void 0 : nv.drawBitmap) || !seedVox)
281
- return false;
282
- var dims = (_a = nv.back) === null || _a === void 0 ? void 0 : _a.dims;
283
- if (!dims)
284
- return false;
285
- var dx = dims[1];
286
- var dy = dims[2];
287
- var idx = voxelIndex(seedVox[0], seedVox[1], seedVox[2], dx, dy);
288
- return (nv.drawBitmap[idx] === draft.penValue &&
289
- draft.baseBitmap[idx] !== draft.penValue);
290
- }
291
- export function eraseClusterFromBitmap(bitmap, visited) {
284
+ function eraseClusterFromBitmap(bitmap, visited) {
292
285
  var next = new Uint8Array(bitmap);
293
286
  visited.forEach(function (idx) {
294
287
  next[idx] = 0;
295
288
  });
296
289
  return next;
297
290
  }
298
- function sliceKey(axCorSag, x, y, z) {
299
- if (axCorSag === 0)
300
- return "".concat(x, ",").concat(y);
301
- if (axCorSag === 1)
302
- return "".concat(x, ",").concat(z);
303
- return "".concat(y, ",").concat(z);
304
- }
305
291
  /** Guess rectangle vs ellipse from the filled voxel pattern, not the active tool. */
306
- export function inferShapePenTypeFromCluster(cluster, axCorSag) {
292
+ function inferShapePenTypeFromCluster(cluster, axCorSag) {
307
293
  var bounds = cluster.bounds, voxels = cluster.voxels;
308
294
  var x1 = bounds.x1, y1 = bounds.y1, z1 = bounds.z1, x2 = bounds.x2, y2 = bounds.y2, z2 = bounds.z2;
309
295
  var filled = new Set();
@@ -358,8 +344,6 @@ export function inferShapePenTypeFromCluster(cluster, axCorSag) {
358
344
  * When the user clicks on an existing filled ROI while the rectangle/ellipse tool
359
345
  * is active (but no draft is currently open), flood-fill the clicked cluster to
360
346
  * reconstruct a ShapeDraft so the bounding-box overlay reappears for re-editing.
361
- *
362
- * Returns null if the click didn't land on a labeled voxel.
363
347
  */
364
348
  export function captureShapeDraftFromClick(nv) {
365
349
  var seedVox = voxFromMouse(nv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudmr-ux",
3
- "version": "4.6.5",
3
+ "version": "4.6.6",
4
4
  "author": "erosmontin@gmail.com",
5
5
  "license": "MIT",
6
6
  "repository": "erosmontin/cloudmr-ux",