@ohif/app 3.13.0-beta.7 → 3.13.0-beta.70

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.
Files changed (72) hide show
  1. package/dist/{1459.bundle.0b4384c95c63e0d5245b.js → 1459.bundle.8df5bb7808389c8dcaa0.js} +5 -6
  2. package/dist/{1608.bundle.0687c661f1c9edfb3b8a.js → 1608.bundle.26306ea38618db59eff7.js} +12 -12
  3. package/dist/{1927.bundle.3050588e95f43cf57cdd.js → 1927.bundle.be67b3aafe238ca9f191.js} +27 -38
  4. package/dist/{1933.bundle.052fd9ab23c1236f788d.js → 1933.bundle.87b41a716353fed2610d.js} +32 -27
  5. package/dist/{2018.bundle.8d5580bd4dcea3ebaa23.js → 2018.bundle.e7a25ccc24941c9039e8.js} +18 -19
  6. package/dist/{6409.bundle.b36048896cb11c8571fb.js → 2075.bundle.23265b8e7597c398db4f.js} +327 -256
  7. package/dist/{2108.bundle.e84aa8d858d8c4f2413e.js → 2108.bundle.aea8d3b39486dd5ab39e.js} +569 -558
  8. package/dist/{213.bundle.9974b55ea267a38098f2.js → 213.bundle.ddafd3a6cc133357f03e.js} +3 -5
  9. package/dist/{2424.bundle.f62de9c66b85446b577b.js → 2424.bundle.daf0c3e78529e8aee79e.js} +3 -5
  10. package/dist/{2516.bundle.1ea0988d309a757bb6da.js → 2516.bundle.f62228e9a800de8d4b31.js} +6 -6
  11. package/dist/{2701.bundle.12bd01a80a9f8ea4cd94.js → 2701.bundle.6873805ddfdccc7a8b1e.js} +10 -10
  12. package/dist/{9195.bundle.ebe8a2e0ed02f4b5ffb6.js → 2851.bundle.51e26e3a79a24f508a03.js} +482 -177
  13. package/dist/{1730.bundle.82fdc899ec54ab6c18a0.js → 3138.bundle.1359814ebef04d7b2f2b.js} +16 -310
  14. package/dist/{3461.bundle.acbbc488820719343d48.js → 3461.bundle.522c6009f47a1a01ce47.js} +131 -107
  15. package/dist/{147.bundle.37d627289453cb6c3937.js → 3754.bundle.fd4b67c2a29c4bc4a840.js} +486 -49
  16. package/dist/{4202.bundle.5a0f8e4004c5d8a68548.js → 4202.bundle.4fcd0de412907efd5b53.js} +6 -6
  17. package/dist/{4019.bundle.83a604779f7da0101ced.js → 4287.bundle.b7840e7b94cbbc102236.js} +348 -237
  18. package/dist/{5462.bundle.21beddaca145b7465c72.js → 4406.bundle.573d234b4641d23cf8db.js} +1083 -1308
  19. package/dist/{1403.bundle.2fc4502e0990b048a4bb.js → 4507.bundle.929c147b8f17517e7769.js} +10 -305
  20. package/dist/{6347.bundle.784c48912700f281de1d.js → 4579.bundle.0a6b2f49a7e136a79e37.js} +561 -649
  21. package/dist/{4819.bundle.9fc6f913afc5f53fe33d.js → 4819.bundle.38df45ea36b450c9c236.js} +39 -39
  22. package/dist/{4775.bundle.7c0cead4a44ddc0b06d7.js → 5015.bundle.e907b7e60824e9b21863.js} +29 -333
  23. package/dist/{5028.bundle.6e48cc78ac80a3860418.js → 5028.bundle.807858e82e7c652139d9.js} +11 -13
  24. package/dist/{5261.bundle.6e1a017f8f1027557f5b.js → 5261.bundle.2655560097e9250eac44.js} +412 -345
  25. package/dist/{5457.bundle.716478f2792f83daa2bc.js → 5457.bundle.361d8d5426840a12b668.js} +16 -23
  26. package/dist/{5485.bundle.782d3f49f1020dc1f730.js → 5485.bundle.82495f29805a950f9172.js} +30 -36
  27. package/dist/{5491.bundle.2e01dd7ad29e4cc01bc1.js → 5491.bundle.4866d2ecb20dd089e071.js} +54 -51
  28. package/dist/{5802.bundle.3bf5e6b3ab330a594a47.js → 5802.bundle.26f84db0ff8851532c36.js} +79 -20
  29. package/dist/5802.css +1 -1
  30. package/dist/{5830.bundle.b073c265c4fcea1afff3.js → 5830.bundle.791019deddd536980a11.js} +3 -3
  31. package/dist/{5858.bundle.ff6b340cf7457db76a1a.js → 5858.bundle.466e58128de344ab53f3.js} +90 -86
  32. package/dist/{6027.bundle.5f39b6eb697906760a97.js → 6027.bundle.2f64fca578d9f2636144.js} +3 -5
  33. package/dist/{6354.bundle.c387737dc09c9cab4ff2.js → 6354.bundle.929febcf6d326e582e00.js} +151 -140
  34. package/dist/{6376.bundle.9cb74d7bc08476e2f1a7.js → 6376.bundle.527820a5cb1eece2a8d2.js} +6 -6
  35. package/dist/{2842.bundle.860b9f10fcdd9656947a.js → 6386.bundle.5d82d1f41d1c37a0358d.js} +904 -2298
  36. package/dist/6939.bundle.41fbdef87597b5172ec6.js +3 -3
  37. package/dist/{7159.bundle.a5991a5d4f0dd8f1c95f.js → 7159.bundle.fb9df255868960f69765.js} +7 -5
  38. package/dist/{3081.bundle.a91d88fbfb53b4f77ee4.js → 7166.bundle.5ac3827d0b367fe6bd6e.js} +1232 -470
  39. package/dist/{7190.bundle.e8f0193e0e06472f795c.js → 7190.bundle.479332d662ffe08d1f92.js} +1228 -855
  40. package/dist/{732.bundle.6978ac30a1e36abf06db.js → 732.bundle.ea6f9d8504e37e01a208.js} +5 -13
  41. package/dist/{7431.bundle.b01791d10e6cf9f503b0.js → 7431.bundle.5e14641f2c71e852abe7.js} +28 -28
  42. package/dist/{4410.bundle.c5224cd7d6238a7d4660.js → 7537.bundle.889ba5f2707418c6fd88.js} +5216 -2238
  43. package/dist/{7639.bundle.a6b187c87374ce1508bb.js → 7639.bundle.7e3a1383fb92172e8079.js} +3 -5
  44. package/dist/7758.bundle.c8d106364298e7d288f0.js +3 -3
  45. package/dist/{8094.bundle.5c44190a325ac23e3e5c.js → 8094.bundle.148a66619607e37cbf19.js} +3 -4
  46. package/dist/{8305.bundle.4e40a6d83d548535b0a4.js → 8305.bundle.1790ebf371ba9caf3a24.js} +71 -66
  47. package/dist/{6163.bundle.ad576a38d517b0031edb.js → 8499.bundle.2386efbfe1210c92d384.js} +7 -302
  48. package/dist/8499.css +2 -0
  49. package/dist/{85.bundle.29e6f5b4d8068a50e5ca.js → 85.bundle.3ebecb20682a1798dc77.js} +3 -5
  50. package/dist/{8558.bundle.0e8b808e19293cdd69a4.js → 8558.bundle.0cf331cc257bb5a04f21.js} +15 -309
  51. package/dist/{8583.bundle.9b62be9d8431e17782c8.js → 8583.bundle.1cb20f6f1e7ec1ca549c.js} +24 -27
  52. package/dist/{997.bundle.822b33e561263084e18c.js → 9039.bundle.f72736f47fedeff521e2.js} +4049 -2992
  53. package/dist/{7412.bundle.fab1742191b7fe937330.js → 9205.bundle.ed7bce8436a7a431955e.js} +6154 -3313
  54. package/dist/{3584.bundle.8cc0750425513433e9cc.js → 9567.bundle.ff782480a4c66e306027.js} +3751 -2856
  55. package/dist/{9845.bundle.255e7c7f7a88193b4e47.js → 9845.bundle.8c450e8d65a78a5afcd3.js} +10 -10
  56. package/dist/{9862.bundle.3a8958a82c572015d25d.js → 9862.bundle.a5f7925840868fa4ecdb.js} +8 -6
  57. package/dist/{9927.bundle.e0f2262ef305795ce7b1.js → 9927.bundle.e21480928d7062501426.js} +8 -6
  58. package/dist/app-config.js +12 -0
  59. package/dist/{app.bundle.4d14ef92d206bcd77aa6.js → app.bundle.3c03c873a65adf3826e0.js} +67399 -64373
  60. package/dist/app.bundle.css +3 -3
  61. package/dist/{polySeg.bundle.a5aa9130b4191253c410.js → compute.bundle.b7c2ea55f1a69f4a736b.js} +8 -20
  62. package/dist/{histogram-worker.bundle.d4e40a8018d2698b072e.js → histogram-worker.bundle.a2a50c4674d99c619ca7.js} +11 -23
  63. package/dist/index.html +1 -1
  64. package/dist/{interpolation.bundle.c70cb95d164dc494e6dc.js → interpolation.bundle.829844ff3f72f5645f29.js} +14 -26
  65. package/dist/{compute.bundle.64280c7af19ff567465f.js → polySeg.bundle.e1f6f05d81ea1352bef3.js} +10 -22
  66. package/dist/sw.js +1 -1
  67. package/package.json +23 -22
  68. package/dist/3343.bundle.d7578ce8f75d158c0bab.js +0 -297
  69. /package/dist/{1730.css → 3138.css} +0 -0
  70. /package/dist/{147.css → 3754.css} +0 -0
  71. /package/dist/{3343.css → 4972.css} +0 -0
  72. /package/dist/{6163.css → 7829.css} +0 -0
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
- (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[3081],{
2
+ (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[7166],{
3
3
 
4
- /***/ 38007:
5
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
4
+ /***/ 38007
5
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
6
6
 
7
7
 
8
8
  // EXPORTS
@@ -25,8 +25,8 @@ var useSegmentations = __webpack_require__(73421);
25
25
  var useViewportSegmentations = __webpack_require__(79063);
26
26
  // EXTERNAL MODULE: ../../../node_modules/react/index.js
27
27
  var react = __webpack_require__(86326);
28
- // EXTERNAL MODULE: ../../ui-next/src/index.ts + 3075 modules
29
- var src = __webpack_require__(12517);
28
+ // EXTERNAL MODULE: ../../ui-next/src/index.ts + 3085 modules
29
+ var src = __webpack_require__(564);
30
30
  ;// ../../../extensions/cornerstone/src/hooks/useViewportHover.ts
31
31
 
32
32
 
@@ -109,15 +109,15 @@ var useViewportRendering = __webpack_require__(47488);
109
109
 
110
110
 
111
111
 
112
- /***/ }),
112
+ /***/ },
113
113
 
114
- /***/ 9234:
115
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
114
+ /***/ 9234
115
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
116
116
 
117
117
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
118
118
  /* harmony export */ c: () => (/* binding */ useActiveViewportSegmentationRepresentations)
119
119
  /* harmony export */ });
120
- /* harmony import */ var _ohif_ui_next__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12517);
120
+ /* harmony import */ var _ohif_ui_next__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(564);
121
121
  /* harmony import */ var _useViewportSegmentations__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(79063);
122
122
 
123
123
 
@@ -131,10 +131,10 @@ function useActiveViewportSegmentationRepresentations() {
131
131
  }
132
132
 
133
133
 
134
- /***/ }),
134
+ /***/ },
135
135
 
136
- /***/ 84535:
137
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
136
+ /***/ 84535
137
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
138
138
 
139
139
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
140
140
  /* harmony export */ R: () => (/* binding */ useMeasurementTracking)
@@ -238,10 +238,10 @@ function useMeasurementTracking({
238
238
  }
239
239
  /* unused harmony default export */ var __WEBPACK_DEFAULT_EXPORT__ = ((/* unused pure expression or super */ null && (useMeasurementTracking)));
240
240
 
241
- /***/ }),
241
+ /***/ },
242
242
 
243
- /***/ 19214:
244
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
243
+ /***/ 19214
244
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
245
245
 
246
246
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
247
247
  /* harmony export */ d: () => (/* binding */ useMeasurements)
@@ -348,10 +348,10 @@ function useMeasurements({
348
348
  return displayMeasurements;
349
349
  }
350
350
 
351
- /***/ }),
351
+ /***/ },
352
352
 
353
- /***/ 73421:
354
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
353
+ /***/ 73421
354
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
355
355
 
356
356
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
357
357
  /* harmony export */ j: () => (/* binding */ useSegmentations)
@@ -483,10 +483,10 @@ function useSegmentations(options) {
483
483
  return segmentations;
484
484
  }
485
485
 
486
- /***/ }),
486
+ /***/ },
487
487
 
488
- /***/ 10225:
489
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
488
+ /***/ 10225
489
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
490
490
 
491
491
 
492
492
  // EXPORTS
@@ -498,8 +498,8 @@ __webpack_require__.d(__webpack_exports__, {
498
498
  var react = __webpack_require__(86326);
499
499
  // EXTERNAL MODULE: ../../core/src/index.ts + 69 modules
500
500
  var src = __webpack_require__(42356);
501
- // EXTERNAL MODULE: ../../ui-next/src/index.ts + 3075 modules
502
- var ui_next_src = __webpack_require__(12517);
501
+ // EXTERNAL MODULE: ../../ui-next/src/index.ts + 3085 modules
502
+ var ui_next_src = __webpack_require__(564);
503
503
  // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 1 modules
504
504
  var esm = __webpack_require__(15327);
505
505
  ;// ../../../extensions/cornerstone/src/components/ViewportDataOverlaySettingMenu/utils.ts
@@ -805,10 +805,10 @@ function useViewportDisplaySets(viewportId, options) {
805
805
  return result;
806
806
  }
807
807
 
808
- /***/ }),
808
+ /***/ },
809
809
 
810
- /***/ 47488:
811
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
810
+ /***/ 47488
811
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
812
812
 
813
813
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
814
814
  /* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__),
@@ -818,7 +818,9 @@ function useViewportDisplaySets(viewportId, options) {
818
818
  /* harmony import */ var _ohif_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(42356);
819
819
  /* harmony import */ var _useViewportDisplaySets__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(10225);
820
820
  /* harmony import */ var _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(15327);
821
- /* harmony import */ var _ohif_core_src_services_ToolBarService_ToolbarService__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(93813);
821
+ /* harmony import */ var _utils_getDataIdForViewport__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(67142);
822
+ /* harmony import */ var _ohif_core_src_services_ToolBarService_ToolbarService__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(93813);
823
+
822
824
 
823
825
 
824
826
 
@@ -826,13 +828,13 @@ function useViewportDisplaySets(viewportId, options) {
826
828
 
827
829
  const getPosition = location => {
828
830
  switch (location) {
829
- case _ohif_core_src_services_ToolBarService_ToolbarService__WEBPACK_IMPORTED_MODULE_4__/* .ButtonLocation */ .ij.LeftMiddle:
831
+ case _ohif_core_src_services_ToolBarService_ToolbarService__WEBPACK_IMPORTED_MODULE_5__/* .ButtonLocation */ .ij.LeftMiddle:
830
832
  return 'left';
831
- case _ohif_core_src_services_ToolBarService_ToolbarService__WEBPACK_IMPORTED_MODULE_4__/* .ButtonLocation */ .ij.RightMiddle:
833
+ case _ohif_core_src_services_ToolBarService_ToolbarService__WEBPACK_IMPORTED_MODULE_5__/* .ButtonLocation */ .ij.RightMiddle:
832
834
  return 'right';
833
- case _ohif_core_src_services_ToolBarService_ToolbarService__WEBPACK_IMPORTED_MODULE_4__/* .ButtonLocation */ .ij.BottomMiddle:
835
+ case _ohif_core_src_services_ToolBarService_ToolbarService__WEBPACK_IMPORTED_MODULE_5__/* .ButtonLocation */ .ij.BottomMiddle:
834
836
  return 'bottom';
835
- case _ohif_core_src_services_ToolBarService_ToolbarService__WEBPACK_IMPORTED_MODULE_4__/* .ButtonLocation */ .ij.TopMiddle:
837
+ case _ohif_core_src_services_ToolBarService_ToolbarService__WEBPACK_IMPORTED_MODULE_5__/* .ButtonLocation */ .ij.TopMiddle:
836
838
  return 'top';
837
839
  default:
838
840
  return 'bottom';
@@ -846,13 +848,6 @@ const linearToOpacity = linearValue => {
846
848
  const opacityToLinear = opacityValue => {
847
849
  return Math.pow(opacityValue, 1.0 / GAMMA);
848
850
  };
849
- const is3DViewport = ({
850
- viewportId,
851
- cornerstoneViewportService
852
- }) => {
853
- const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
854
- return viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.VolumeViewport3D;
855
- };
856
851
 
857
852
  /**
858
853
  * Hook to access window level functionality for a specific viewport
@@ -871,14 +866,13 @@ function useViewportRendering(viewportId, options) {
871
866
  colorbarService,
872
867
  customizationService
873
868
  } = servicesManager.services;
874
- const [is3DVolume, setIs3DVolume] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(is3DViewport({
875
- viewportId,
876
- cornerstoneViewportService
877
- }));
878
869
  const [hasColorbar, setHasColorbar] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(colorbarService.hasColorbar(viewportId));
879
870
  const [colorbarPosition, setColorbarPosition] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(options?.location ? getPosition(options.location) : 'bottom');
880
871
  const [voiRange, setVoiRange] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)();
881
872
  const voiRangeRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef();
873
+ // Viewport from service; kept in state so we can subscribe to VIEWPORT_DATA_CHANGED when null and re-run effects when it becomes available
874
+ const [viewport, setViewport] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(() => viewportId ? cornerstoneViewportService.getCornerstoneViewport(viewportId) ?? null : null);
875
+ const [is3DVolume, setIs3DVolume] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.VolumeViewport3D);
882
876
  const [opacity, setOpacityState] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)();
883
877
  const [opacityLinear, setOpacityLinearState] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)();
884
878
  const [threshold, setThresholdState] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)();
@@ -922,6 +916,35 @@ function useViewportRendering(viewportId, options) {
922
916
  }) || [];
923
917
  }, [viewportDisplaySets, presets]);
924
918
 
919
+ // Keep viewport in state; when not available, subscribe to VIEWPORT_DATA_CHANGED so we set it when the viewport is ready
920
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
921
+ if (!viewportId) {
922
+ setViewport(null);
923
+ return;
924
+ }
925
+ const vp = cornerstoneViewportService.getCornerstoneViewport(viewportId);
926
+ setViewport(vp ?? null);
927
+ if (vp) {
928
+ return;
929
+ }
930
+ const {
931
+ unsubscribe
932
+ } = cornerstoneViewportService.subscribe(cornerstoneViewportService.EVENTS.VIEWPORT_DATA_CHANGED, ({
933
+ viewportId: eventViewportId
934
+ }) => {
935
+ if (eventViewportId !== viewportId) {
936
+ return;
937
+ }
938
+ const next = cornerstoneViewportService.getCornerstoneViewport(viewportId);
939
+ if (next) {
940
+ setViewport(next);
941
+ }
942
+ });
943
+ return () => {
944
+ unsubscribe();
945
+ };
946
+ }, [viewportId, cornerstoneViewportService]);
947
+
925
948
  // Calculate pixel value range for the active display set
926
949
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
927
950
  if (!activeDisplaySetInstanceUID) {
@@ -931,21 +954,20 @@ function useViewportRendering(viewportId, options) {
931
954
  if (!selectedDisplaySet?.imageIds?.length) {
932
955
  return;
933
956
  }
934
- const csViewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
935
- if (!csViewport) {
957
+ if (!viewport) {
936
958
  return;
937
959
  }
938
- if (!(csViewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.BaseVolumeViewport)) {
960
+ if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.BaseVolumeViewport)) {
939
961
  return;
940
962
  }
941
- const volumeIds = csViewport.getAllVolumeIds();
963
+ const volumeIds = viewport.getAllVolumeIds();
942
964
  const volumeId = volumeIds.find(id => id.includes(activeDisplaySetInstanceUID));
943
965
  if (!volumeId) {
944
966
  return;
945
967
  }
946
968
 
947
969
  // only handle volume viewports for now
948
- const imageData = csViewport.getImageData(volumeId);
970
+ const imageData = viewport.getImageData(volumeId);
949
971
  if (!imageData) {
950
972
  return;
951
973
  }
@@ -958,7 +980,7 @@ function useViewportRendering(viewportId, options) {
958
980
  min: range[0],
959
981
  max: range[1]
960
982
  });
961
- }, [activeDisplaySetInstanceUID, displaySetService, cornerstoneViewportService, viewportId]);
983
+ }, [activeDisplaySetInstanceUID, displaySetService, viewport]);
962
984
 
963
985
  // Get the presets specifically for the active display set
964
986
  const activeDisplaySetPresets = (0,react__WEBPACK_IMPORTED_MODULE_0__.useMemo)(() => {
@@ -972,52 +994,33 @@ function useViewportRendering(viewportId, options) {
972
994
  return activePresetData.presets;
973
995
  }, [allWindowLevelPresets, activeDisplaySetInstanceUID]);
974
996
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
975
- setIs3DVolume(is3DViewport({
976
- viewportId,
977
- cornerstoneViewportService
978
- }));
979
- const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
980
-
981
- // Initialize the VOI range from the viewport
982
- if (viewport && activeDisplaySetInstanceUID) {
983
- try {
984
- let properties;
985
- if (viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.StackViewport) {
986
- properties = viewport.getProperties();
987
- if (properties.voiRange) {
988
- setVoiRange(properties.voiRange);
989
- voiRangeRef.current = properties.voiRange;
990
- }
991
- } else if (viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.BaseVolumeViewport) {
992
- // For volume viewports, find the actor for the active display set
993
- const volumeIds = viewport.getAllVolumeIds();
994
- const volumeId = volumeIds.find(id => id.includes(activeDisplaySetInstanceUID));
995
- if (volumeId) {
996
- properties = viewport.getProperties(volumeId);
997
- if (properties?.voiRange) {
998
- setVoiRange(properties.voiRange);
999
- voiRangeRef.current = properties.voiRange;
1000
- }
1001
-
1002
- // Get opacity from colormap if available
1003
- if (properties?.colormap?.opacity !== undefined) {
1004
- const isArray = Array.isArray(properties.colormap.opacity);
1005
- const opacity = isArray ? properties.colormap.opacity.reduce((max, current) => Math.max(max, current), 0) : properties.colormap.opacity;
1006
- setOpacityState(opacity);
1007
- setOpacityLinearState(opacityToLinear(opacity));
1008
- }
1009
-
1010
- // Get threshold from colormap if available
1011
- if (properties?.colormap && properties.colormap.threshold !== undefined) {
1012
- setThresholdState(properties.colormap.threshold);
1013
- }
1014
- }
1015
- }
1016
- } catch (error) {
1017
- console.error('Error initializing VOI range:', error);
997
+ setIs3DVolume(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.VolumeViewport3D);
998
+ if (!viewport || !activeDisplaySetInstanceUID) {
999
+ return;
1000
+ }
1001
+ try {
1002
+ const dataId = (0,_utils_getDataIdForViewport__WEBPACK_IMPORTED_MODULE_4__/* .getDataIdForViewport */ .V)(viewport, activeDisplaySetInstanceUID);
1003
+ const properties = dataId != null ? viewport.getProperties(dataId) : viewport.getProperties();
1004
+ if (!properties) {
1005
+ return;
1018
1006
  }
1007
+ if (properties.voiRange) {
1008
+ setVoiRange(properties.voiRange);
1009
+ voiRangeRef.current = properties.voiRange;
1010
+ }
1011
+ if (properties.colormap?.opacity !== undefined) {
1012
+ const opacityVal = properties.colormap.opacity;
1013
+ const opacity = Array.isArray(opacityVal) ? opacityVal.reduce((max, current) => Math.max(max, current), 0) : opacityVal;
1014
+ setOpacityState(opacity);
1015
+ setOpacityLinearState(opacityToLinear(opacity));
1016
+ }
1017
+ if (properties.colormap?.threshold !== undefined) {
1018
+ setThresholdState(properties.colormap.threshold);
1019
+ }
1020
+ } catch (error) {
1021
+ console.error('Error initializing VOI range:', error);
1019
1022
  }
1020
- }, [cornerstoneViewportService, viewportId, activeDisplaySetInstanceUID]);
1023
+ }, [activeDisplaySetInstanceUID, viewport]);
1021
1024
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
1022
1025
  if (!viewportId) {
1023
1026
  return;
@@ -1035,17 +1038,10 @@ function useViewportRendering(viewportId, options) {
1035
1038
  };
1036
1039
  }, [colorbarService, viewportId]);
1037
1040
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
1038
- if (!viewportId || !activeDisplaySetInstanceUID) {
1039
- return;
1040
- }
1041
- const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1042
- if (!viewport) {
1041
+ if (!activeDisplaySetInstanceUID || !viewport?.element) {
1043
1042
  return;
1044
1043
  }
1045
1044
  const element = viewport.element;
1046
- if (!element) {
1047
- return;
1048
- }
1049
1045
  const updateVOI = eventDetail => {
1050
1046
  const {
1051
1047
  range
@@ -1085,7 +1081,7 @@ function useViewportRendering(viewportId, options) {
1085
1081
  element.removeEventListener(_cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.Enums.Events.VOI_MODIFIED, updateVOI);
1086
1082
  element.removeEventListener(_cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.Enums.Events.COLORMAP_MODIFIED, updateColormap);
1087
1083
  };
1088
- }, [viewportId, activeDisplaySetInstanceUID, cornerstoneViewportService, opacityToLinear]);
1084
+ }, [activeDisplaySetInstanceUID, viewport, opacityToLinear]);
1089
1085
  const validateActiveDisplaySet = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(() => {
1090
1086
  if (!activeDisplaySetInstanceUID) {
1091
1087
  throw new Error('No active display set instance UID is available');
@@ -1238,12 +1234,8 @@ function useViewportRendering(viewportId, options) {
1238
1234
  },
1239
1235
  context: 'CORNERSTONE'
1240
1236
  });
1241
- }, [commandsManager, viewportId, validateActiveDisplaySet]);
1237
+ }, [commandsManager, validateActiveDisplaySet, viewport, viewportId]);
1242
1238
  const setOpacity = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(opacityValue => {
1243
- if (!viewportId) {
1244
- return;
1245
- }
1246
- const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1247
1239
  if (!viewport || !(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.BaseVolumeViewport)) {
1248
1240
  return;
1249
1241
  }
@@ -1274,17 +1266,13 @@ function useViewportRendering(viewportId, options) {
1274
1266
  colormap: updatedColormap
1275
1267
  }, volumeId);
1276
1268
  viewport.render();
1277
- }, [cornerstoneViewportService, viewportId, validateActiveDisplaySet, opacityToLinear]);
1269
+ }, [validateActiveDisplaySet, opacityToLinear, viewport]);
1278
1270
  const setOpacityLinear = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(linearValue => {
1279
1271
  // Convert linear UI value to actual opacity value and apply it
1280
1272
  const actualOpacity = linearToOpacity(linearValue);
1281
1273
  setOpacity(actualOpacity);
1282
1274
  }, [linearToOpacity, setOpacity]);
1283
1275
  const setThreshold = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(thresholdValue => {
1284
- if (!viewportId) {
1285
- return;
1286
- }
1287
- const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1288
1276
  if (!viewport || !(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.BaseVolumeViewport)) {
1289
1277
  return;
1290
1278
  }
@@ -1302,15 +1290,14 @@ function useViewportRendering(viewportId, options) {
1302
1290
  }
1303
1291
  }, volumeId);
1304
1292
  viewport.render();
1305
- }, [cornerstoneViewportService, viewportId, validateActiveDisplaySet]);
1293
+ }, [validateActiveDisplaySet, viewport]);
1306
1294
 
1307
1295
  // Get the current colormap for the active display set
1308
1296
  const colormap = (0,react__WEBPACK_IMPORTED_MODULE_0__.useMemo)(() => {
1309
- if (!viewportId || !activeDisplaySetInstanceUID || !viewportDisplaySets?.length) {
1297
+ if (!activeDisplaySetInstanceUID || !viewportDisplaySets?.length) {
1310
1298
  return null;
1311
1299
  }
1312
1300
  try {
1313
- const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1314
1301
  if (!viewport) {
1315
1302
  return null;
1316
1303
  }
@@ -1339,7 +1326,7 @@ function useViewportRendering(viewportId, options) {
1339
1326
  console.error('Error getting viewport colormap:', error);
1340
1327
  return colorbarProperties?.colormaps?.find(c => c.Name === 'Grayscale') || colorbarProperties?.colormaps?.[0];
1341
1328
  }
1342
- }, [cornerstoneViewportService, viewportId, activeDisplaySetInstanceUID, viewportDisplaySets, colorbarProperties?.colormaps]);
1329
+ }, [activeDisplaySetInstanceUID, viewportDisplaySets, colorbarProperties?.colormaps, viewport]);
1343
1330
 
1344
1331
  // 3D volume rendering functions
1345
1332
  const setVolumeRenderingPreset = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(preset => {
@@ -1405,7 +1392,10 @@ function useViewportRendering(viewportId, options) {
1405
1392
  setWindowLevel,
1406
1393
  setVOIRange,
1407
1394
  voiRange,
1408
- windowLevel: _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.utilities.windowLevel.toWindowLevel(voiRange?.lower, voiRange?.upper),
1395
+ windowLevel: voiRange ? _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__.utilities.windowLevel.toWindowLevel(voiRange?.lower, voiRange?.upper) : {
1396
+ windowCenter: null,
1397
+ windowWidth: null
1398
+ },
1409
1399
  // Colorbar functions
1410
1400
  hasColorbar,
1411
1401
  toggleColorbar,
@@ -1473,10 +1463,10 @@ function getCustomizationData(customizationService) {
1473
1463
  };
1474
1464
  }
1475
1465
 
1476
- /***/ }),
1466
+ /***/ },
1477
1467
 
1478
- /***/ 79063:
1479
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1468
+ /***/ 79063
1469
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
1480
1470
 
1481
1471
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1482
1472
  /* harmony export */ L: () => (/* binding */ useViewportSegmentations)
@@ -1494,7 +1484,8 @@ const excludedModalities = ['SM', 'OT', 'DOC', 'ECG'];
1494
1484
  function mapSegmentationToDisplay(segmentation, customizationService) {
1495
1485
  const {
1496
1486
  label,
1497
- segments
1487
+ segments,
1488
+ fallbackLabel
1498
1489
  } = segmentation;
1499
1490
 
1500
1491
  // Get the readable text mapping once
@@ -1555,6 +1546,7 @@ function mapSegmentationToDisplay(segmentation, customizationService) {
1555
1546
  return {
1556
1547
  ...segmentation,
1557
1548
  label,
1549
+ fallbackLabel,
1558
1550
  segments: updatedSegments
1559
1551
  };
1560
1552
  }
@@ -1657,74 +1649,36 @@ function useViewportSegmentations({
1657
1649
  return segmentationsWithRepresentations;
1658
1650
  }
1659
1651
 
1660
- /***/ }),
1652
+ /***/ },
1661
1653
 
1662
- /***/ 63081:
1663
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1654
+ /***/ 87166
1655
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
1664
1656
 
1665
- // ESM COMPAT FLAG
1666
- __webpack_require__.r(__webpack_exports__);
1667
1657
 
1668
1658
  // EXPORTS
1669
1659
  __webpack_require__.d(__webpack_exports__, {
1670
- AccordionGroup: () => (/* reexport */ AccordionGroup),
1671
- CloneChildren: () => (/* reexport */ CloneChildren),
1672
- Colorbar: () => (/* reexport */ Colorbar),
1673
- Colormap: () => (/* reexport */ Colormap),
1674
- CornerstoneViewportDownloadForm: () => (/* reexport */ utils_CornerstoneViewportDownloadForm),
1675
- DYNAMIC_VOLUME_LOADER_SCHEME: () => (/* reexport */ DYNAMIC_VOLUME_LOADER_SCHEME),
1676
- DicomUpload: () => (/* reexport */ DicomUpload_DicomUpload),
1677
- Enums: () => (/* reexport */ enums),
1678
- ImageOverlayViewerTool: () => (/* reexport */ tools_ImageOverlayViewerTool),
1679
- MeasumentsMenu: () => (/* reexport */ MeasumentsMenu),
1680
- MeasurementOrAdditionalFindingSets: () => (/* reexport */ MeasurementOrAdditionalFindingSets),
1681
- MeasurementsOrAdditionalFindings: () => (/* reexport */ MeasurementsOrAdditionalFindings),
1682
- OHIFCornerstoneViewport: () => (/* binding */ OHIFCornerstoneViewport),
1683
- PanelMeasurement: () => (/* reexport */ PanelMeasurement),
1684
- PanelSegmentation: () => (/* reexport */ PanelSegmentation),
1685
- PlanarFreehandROI: () => (/* reexport */ measurementServiceMappings_PlanarFreehandROI),
1686
- RectangleROI: () => (/* reexport */ measurementServiceMappings_RectangleROI),
1687
- SeriesMeasurementTrigger: () => (/* reexport */ SeriesMeasurementTrigger),
1688
- SeriesMeasurements: () => (/* reexport */ SeriesMeasurements),
1689
- StudyMeasurements: () => (/* reexport */ StudyMeasurements),
1690
- StudyMeasurementsActions: () => (/* reexport */ StudyMeasurementsActions),
1691
- StudySummaryFromMetadata: () => (/* reexport */ StudySummaryFromMetadata),
1692
- Types: () => (/* reexport */ types_namespaceObject),
1693
- VOLUME_LOADER_SCHEME: () => (/* reexport */ VOLUME_LOADER_SCHEME),
1694
- VolumeLighting: () => (/* reexport */ VolumeLighting),
1695
- VolumeRenderingOptions: () => (/* reexport */ VolumeRenderingOptions),
1696
- VolumeRenderingPresets: () => (/* reexport */ VolumeRenderingPresets),
1697
- VolumeRenderingQuality: () => (/* reexport */ VolumeRenderingQuality),
1698
- VolumeShade: () => (/* reexport */ VolumeShade),
1699
- VolumeShift: () => (/* reexport */ VolumeShift),
1700
- WindowLevel: () => (/* reexport */ WindowLevel),
1701
- WindowLevelActionMenu: () => (/* reexport */ WindowLevelActionMenu),
1702
- WindowLevelActionMenuContent: () => (/* reexport */ WindowLevelActionMenuContent),
1703
- WindowLevelActionMenuWrapper: () => (/* reexport */ WindowLevelActionMenuWrapper),
1660
+ _I: () => (/* reexport */ AccordionGroup),
1661
+ fX: () => (/* reexport */ enums),
1662
+ CP: () => (/* reexport */ MeasurementsOrAdditionalFindings),
1663
+ R9: () => (/* binding */ OHIFCornerstoneViewport),
1664
+ re: () => (/* reexport */ PanelMeasurement),
1665
+ rE: () => (/* reexport */ PanelSegmentation),
1666
+ V: () => (/* reexport */ SeriesMeasurements),
1667
+ B9: () => (/* reexport */ StudyMeasurements),
1668
+ _9: () => (/* reexport */ StudyMeasurementsActions),
1669
+ x3: () => (/* reexport */ StudySummaryFromMetadata),
1670
+ Rj: () => (/* reexport */ VOLUME_LOADER_SCHEME),
1704
1671
  "default": () => (/* binding */ cornerstone_src),
1705
- dicomLoaderService: () => (/* reexport */ utils_dicomLoaderService),
1706
- findNearbyToolData: () => (/* reexport */ findNearbyToolData),
1707
- getActiveViewportEnabledElement: () => (/* reexport */ getActiveViewportEnabledElement),
1708
- getEnabledElement: () => (/* reexport */ state/* getEnabledElement */.kJ),
1709
- getSOPInstanceAttributes: () => (/* reexport */ getSOPInstanceAttributes),
1710
- groupByDisplaySet: () => (/* reexport */ groupByDisplaySet),
1711
- groupByNamedSets: () => (/* reexport */ groupByNamedSets),
1712
- groupByStudy: () => (/* reexport */ groupByStudy),
1713
- measurementMappingUtils: () => (/* reexport */ utils_namespaceObject),
1714
- setEnabledElement: () => (/* reexport */ state/* setEnabledElement */.ye),
1715
- toolNames: () => (/* reexport */ toolNames),
1716
- useActiveViewportSegmentationRepresentations: () => (/* reexport */ useActiveViewportSegmentationRepresentations/* useActiveViewportSegmentationRepresentations */.c),
1717
- useLutPresentationStore: () => (/* reexport */ useLutPresentationStore/* useLutPresentationStore */.I),
1718
- useMeasurementTracking: () => (/* reexport */ useMeasurementTracking/* useMeasurementTracking */.R),
1719
- useMeasurements: () => (/* reexport */ useMeasurements/* useMeasurements */.d),
1720
- usePositionPresentationStore: () => (/* reexport */ usePositionPresentationStore/* usePositionPresentationStore */.q),
1721
- useSegmentationPresentationStore: () => (/* reexport */ useSegmentationPresentationStore/* useSegmentationPresentationStore */.v),
1722
- useSegmentations: () => (/* reexport */ useSegmentations/* useSegmentations */.j),
1723
- useSelectedSegmentationsForViewportStore: () => (/* reexport */ useSelectedSegmentationsForViewportStore),
1724
- useSynchronizersStore: () => (/* reexport */ useSynchronizersStore/* useSynchronizersStore */.U),
1725
- utils: () => (/* reexport */ src_utils)
1672
+ HA: () => (/* reexport */ utils_dicomLoaderService),
1673
+ J4: () => (/* reexport */ getSOPInstanceAttributes),
1674
+ c3: () => (/* reexport */ useActiveViewportSegmentationRepresentations/* useActiveViewportSegmentationRepresentations */.c),
1675
+ qu: () => (/* reexport */ usePositionPresentationStore/* usePositionPresentationStore */.q),
1676
+ jo: () => (/* reexport */ useSegmentations/* useSegmentations */.j),
1677
+ Wp: () => (/* reexport */ src_utils)
1726
1678
  });
1727
1679
 
1680
+ // UNUSED EXPORTS: CloneChildren, Colorbar, Colormap, CornerstoneViewportDownloadForm, DYNAMIC_VOLUME_LOADER_SCHEME, DicomUpload, ImageOverlayViewerTool, MeasumentsMenu, MeasurementOrAdditionalFindingSets, PlanarFreehandROI, RectangleROI, SeriesMeasurementTrigger, Types, VolumeLighting, VolumeRenderingOptions, VolumeRenderingPresets, VolumeRenderingQuality, VolumeShade, VolumeShift, WindowLevel, WindowLevelActionMenu, WindowLevelActionMenuContent, WindowLevelActionMenuWrapper, findNearbyToolData, getActiveViewportEnabledElement, getEnabledElement, groupByDisplaySet, groupByNamedSets, groupByStudy, measurementMappingUtils, setEnabledElement, toolNames, useLutPresentationStore, useMeasurementTracking, useMeasurements, useSegmentationPresentationStore, useSelectedSegmentationsForViewportStore, useSynchronizersStore
1681
+
1728
1682
  // NAMESPACE OBJECT: ../../../extensions/cornerstone/src/enums.ts
1729
1683
  var enums_namespaceObject = {};
1730
1684
  __webpack_require__.r(enums_namespaceObject);
@@ -1734,22 +1688,6 @@ __webpack_require__.d(enums_namespaceObject, {
1734
1688
  Ay: () => (enums)
1735
1689
  });
1736
1690
 
1737
- // NAMESPACE OBJECT: ../../../extensions/cornerstone/src/utils/measurementServiceMappings/utils/index.ts
1738
- var utils_namespaceObject = {};
1739
- __webpack_require__.r(utils_namespaceObject);
1740
- __webpack_require__.d(utils_namespaceObject, {
1741
- getDisplayUnit: () => (utils_getDisplayUnit),
1742
- getFirstAnnotationSelected: () => (getFirstAnnotationSelected),
1743
- getHandlesFromPoints: () => (getHandlesFromPoints),
1744
- getSOPInstanceAttributes: () => (getSOPInstanceAttributes),
1745
- isAnnotationSelected: () => (isAnnotationSelected),
1746
- setAnnotationSelected: () => (setAnnotationSelected)
1747
- });
1748
-
1749
- // NAMESPACE OBJECT: ../../../extensions/cornerstone/src/types/index.ts
1750
- var types_namespaceObject = {};
1751
- __webpack_require__.r(types_namespaceObject);
1752
-
1753
1691
  // EXTERNAL MODULE: ../../../node_modules/react/index.js
1754
1692
  var react = __webpack_require__(86326);
1755
1693
  // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 1 modules
@@ -1770,8 +1708,8 @@ var src = __webpack_require__(42356);
1770
1708
  var loaders = __webpack_require__(19742);
1771
1709
  // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/enums/RequestType.js
1772
1710
  var RequestType = __webpack_require__(43213);
1773
- // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/dicom-image-loader/dist/esm/index.js + 77 modules
1774
- var dicom_image_loader_dist_esm = __webpack_require__(75524);
1711
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/dicom-image-loader/dist/esm/index.js + 80 modules
1712
+ var dicom_image_loader_dist_esm = __webpack_require__(76318);
1775
1713
  ;// ../../../extensions/cornerstone/src/initWADOImageLoader.js
1776
1714
 
1777
1715
 
@@ -1810,8 +1748,8 @@ function destroy() {
1810
1748
  var ai_dist_esm = __webpack_require__(75165);
1811
1749
  // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/polymorphic-segmentation/dist/esm/index.js + 14 modules
1812
1750
  var polymorphic_segmentation_dist_esm = __webpack_require__(56983);
1813
- // EXTERNAL MODULE: ../../../extensions/default/src/index.ts + 139 modules
1814
- var default_src = __webpack_require__(39195);
1751
+ // EXTERNAL MODULE: ../../../extensions/default/src/index.ts + 140 modules
1752
+ var default_src = __webpack_require__(62851);
1815
1753
  // EXTERNAL MODULE: ../../../extensions/cornerstone/src/state.ts
1816
1754
  var state = __webpack_require__(71353);
1817
1755
  ;// ../../../extensions/cornerstone/src/utils/getViewportEnabledElement.ts
@@ -1913,7 +1851,7 @@ function onCompletedCalibrationLine(servicesManager, csToolsEvent) {
1913
1851
  reject('UIDialogService is not initiated');
1914
1852
  return;
1915
1853
  }
1916
- (0,default_src.callInputDialog)({
1854
+ (0,default_src/* callInputDialog */.l5)({
1917
1855
  uiDialogService,
1918
1856
  title: 'Calibration',
1919
1857
  placeholder: 'Actual Physical distance (mm)',
@@ -2614,6 +2552,7 @@ function getHandlesFromPoints(points) {
2614
2552
  }), {});
2615
2553
  }
2616
2554
  ;// ../../../extensions/cornerstone/src/utils/measurementServiceMappings/utils/selection.ts
2555
+ /* unused harmony import specifier */ var cs3dToolAnnotationUtils;
2617
2556
 
2618
2557
 
2619
2558
  /**
@@ -2622,7 +2561,7 @@ function getHandlesFromPoints(points) {
2622
2561
  * @returns boolean
2623
2562
  */
2624
2563
  function isAnnotationSelected(annotationUID) {
2625
- return dist_esm.annotation.selection.isAnnotationSelected(annotationUID);
2564
+ return cs3dToolAnnotationUtils.selection.isAnnotationSelected(annotationUID);
2626
2565
  }
2627
2566
 
2628
2567
  /**
@@ -2634,7 +2573,7 @@ function setAnnotationSelected(annotationUID, selected) {
2634
2573
  const isCurrentSelected = isAnnotationSelected(annotationUID);
2635
2574
  // branch cut, avoid invoking imaging library unnecessarily.
2636
2575
  if (isCurrentSelected !== selected) {
2637
- dist_esm.annotation.selection.setAnnotationSelected(annotationUID, selected);
2576
+ cs3dToolAnnotationUtils.selection.setAnnotationSelected(annotationUID, selected);
2638
2577
  }
2639
2578
  }
2640
2579
  function getFirstAnnotationSelected(element) {
@@ -6065,6 +6004,12 @@ const connectMeasurementServiceToTools = ({
6065
6004
  if (source?.name && source.name !== initMeasurementService_CORNERSTONE_3D_TOOLS_SOURCE_NAME) {
6066
6005
  return;
6067
6006
  }
6007
+ // Cancel any active tool manipulation (e.g., Spline/Livewire) to avoid leaving the tool
6008
+ // in a drawing state after deleting a not completed measurement, which can block viewport interactivity.
6009
+ const element = getActiveViewportEnabledElement(viewportGridService)?.viewport?.element;
6010
+ if (element) {
6011
+ (0,dist_esm.cancelActiveManipulations)(element);
6012
+ }
6068
6013
  const removedAnnotation = dist_esm.annotation.state.getAnnotation(removedMeasurementId);
6069
6014
  removeAnnotation(removedMeasurementId);
6070
6015
  // Ensure `removedAnnotation` is available before triggering the memo,
@@ -7463,7 +7408,8 @@ function _showCPURenderingModal(uiModalService, hangingProtocolService) {
7463
7408
  'viewportOverlay.topRight': [],
7464
7409
  'viewportOverlay.bottomLeft': [{
7465
7410
  id: 'WindowLevel',
7466
- inheritsFrom: 'ohif.overlayItem.windowLevel'
7411
+ inheritsFrom: 'ohif.overlayItem.windowLevel',
7412
+ title: 'Window Level'
7467
7413
  }, {
7468
7414
  id: 'ZoomLevel',
7469
7415
  inheritsFrom: 'ohif.overlayItem.zoomLevel',
@@ -7474,11 +7420,12 @@ function _showCPURenderingModal(uiModalService, hangingProtocolService) {
7474
7420
  }],
7475
7421
  'viewportOverlay.bottomRight': [{
7476
7422
  id: 'InstanceNumber',
7477
- inheritsFrom: 'ohif.overlayItem.instanceNumber'
7423
+ inheritsFrom: 'ohif.overlayItem.instanceNumber',
7424
+ title: 'Instance Number'
7478
7425
  }]
7479
7426
  });
7480
- // EXTERNAL MODULE: ../../ui-next/src/index.ts + 3075 modules
7481
- var ui_next_src = __webpack_require__(12517);
7427
+ // EXTERNAL MODULE: ../../ui-next/src/index.ts + 3085 modules
7428
+ var ui_next_src = __webpack_require__(564);
7482
7429
  // EXTERNAL MODULE: ../../../node_modules/react-i18next/dist/es/index.js + 15 modules
7483
7430
  var es = __webpack_require__(99993);
7484
7431
  ;// ../../../extensions/cornerstone/src/components/ExportSegmentationSubMenuItem.tsx
@@ -7501,37 +7448,13 @@ const ExportSegmentationSubMenuItem = ({
7501
7448
  className: "text-foreground"
7502
7449
  }), /*#__PURE__*/react.createElement("span", {
7503
7450
  className: "pl-2"
7504
- }, t('Download & Export'))), /*#__PURE__*/react.createElement(ui_next_src/* DropdownMenuPortal */.dce, null, /*#__PURE__*/react.createElement(ui_next_src/* DropdownMenuSubContent */.M56, null, /*#__PURE__*/react.createElement(ui_next_src/* DropdownMenuLabel */.lpj, {
7505
- className: "flex items-center pl-0"
7506
- }, /*#__PURE__*/react.createElement(ui_next_src/* Icons */.FI1.Download, {
7507
- className: "h-5 w-5"
7508
- }), /*#__PURE__*/react.createElement("span", {
7509
- className: "pl-1"
7510
- }, t('Download'))), segmentationRepresentationType === esm_enums.SegmentationRepresentations.Labelmap && /*#__PURE__*/react.createElement(ui_next_src/* DropdownMenuItem */._26, {
7451
+ }, t('Export'))), /*#__PURE__*/react.createElement(ui_next_src/* DropdownMenuPortal */.dce, null, /*#__PURE__*/react.createElement(ui_next_src/* DropdownMenuSubContent */.M56, null, segmentationRepresentationType === esm_enums.SegmentationRepresentations.Labelmap && /*#__PURE__*/react.createElement(ui_next_src/* DropdownMenuItem */._26, {
7511
7452
  onClick: e => {
7512
7453
  e.preventDefault();
7513
7454
  actions.downloadCSVSegmentationReport(segmentationId);
7514
7455
  },
7515
7456
  disabled: !allowExport
7516
7457
  }, t('CSV Report')), segmentationRepresentationType === esm_enums.SegmentationRepresentations.Labelmap && /*#__PURE__*/react.createElement(ui_next_src/* DropdownMenuItem */._26, {
7517
- onClick: e => {
7518
- e.preventDefault();
7519
- actions.onSegmentationDownload(segmentationId);
7520
- },
7521
- disabled: !allowExport
7522
- }, t('DICOM SEG')), /*#__PURE__*/react.createElement(ui_next_src/* DropdownMenuItem */._26, {
7523
- onClick: e => {
7524
- e.preventDefault();
7525
- actions.onSegmentationDownloadRTSS(segmentationId);
7526
- },
7527
- disabled: !allowExport
7528
- }, t('DICOM RTSS')), /*#__PURE__*/react.createElement(ui_next_src/* DropdownMenuSeparator */.mBJ, null), /*#__PURE__*/react.createElement(ui_next_src/* DropdownMenuLabel */.lpj, {
7529
- className: "flex items-center pl-0"
7530
- }, /*#__PURE__*/react.createElement(ui_next_src/* Icons */.FI1.Export, {
7531
- className: "h-5 w-5"
7532
- }), /*#__PURE__*/react.createElement("span", {
7533
- className: "pl-1 pt-1"
7534
- }, t('Export'))), segmentationRepresentationType === esm_enums.SegmentationRepresentations.Labelmap && /*#__PURE__*/react.createElement(ui_next_src/* DropdownMenuItem */._26, {
7535
7458
  onClick: e => {
7536
7459
  e.preventDefault();
7537
7460
  actions.storeSegmentation(segmentationId, 'SEG');
@@ -7608,16 +7531,6 @@ const CustomDropdownMenuContent = () => {
7608
7531
  context: 'CORNERSTONE'
7609
7532
  });
7610
7533
  },
7611
- onSegmentationDownloadRTSS: segmentationId => {
7612
- commandsManager.run('downloadRTSS', {
7613
- segmentationId
7614
- });
7615
- },
7616
- onSegmentationDownload: segmentationId => {
7617
- commandsManager.run('downloadSegmentation', {
7618
- segmentationId
7619
- });
7620
- },
7621
7534
  downloadCSVSegmentationReport: segmentationId => {
7622
7535
  commandsManager.run('downloadCSVSegmentationReport', {
7623
7536
  segmentationId
@@ -7815,7 +7728,7 @@ function SegmentationToolConfig() {
7815
7728
  });
7816
7729
  };
7817
7730
  return /*#__PURE__*/react.createElement("div", {
7818
- className: "bg-muted flex flex-col gap-2 border-b border-b-[2px] border-black px-2 py-3"
7731
+ className: "bg-muted flex flex-col gap-2 border-b border-b-[2px] border-background px-2 py-3"
7819
7732
  }, /*#__PURE__*/react.createElement("div", {
7820
7733
  className: "flex items-center gap-2"
7821
7734
  }, /*#__PURE__*/react.createElement(ui_next_src/* Switch */.dOG, {
@@ -8624,7 +8537,7 @@ const DicomUploadProgressItem = /*#__PURE__*/(0,react.memo)(({
8624
8537
  }, /*#__PURE__*/react.createElement("div", {
8625
8538
  className: "flex w-6 shrink-0 items-center justify-center"
8626
8539
  }, getStatusIcon()), /*#__PURE__*/react.createElement("div", {
8627
- className: "overflow-hidden text-ellipsis whitespace-nowrap text-white"
8540
+ className: "text-foreground overflow-hidden text-ellipsis whitespace-nowrap"
8628
8541
  }, dicomFileUploader.getFileName())), failedReason && /*#__PURE__*/react.createElement("div", {
8629
8542
  className: "pl-10"
8630
8543
  }, failedReason)), /*#__PURE__*/react.createElement("div", {
@@ -8866,7 +8779,7 @@ function DicomUploadProgress({
8866
8779
  }, [numFilesCompleted]);
8867
8780
  const getNumCompletedAndTimeRemainingComponent = () => {
8868
8781
  return /*#__PURE__*/react.createElement("div", {
8869
- className: "bg-muted flex h-14 items-center px-1 pb-4 text-lg text-white"
8782
+ className: "bg-muted text-foreground flex h-14 items-center px-1 pb-4 text-lg"
8870
8783
  }, numFilesCompleted === dicomFileUploaderArr.length ? /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("span", {
8871
8784
  className: NO_WRAP_ELLIPSIS_CLASS_NAMES
8872
8785
  }, `${dicomFileUploaderArr.length} ${dicomFileUploaderArr.length > 1 ? 'files' : 'file'} completed.`), /*#__PURE__*/react.createElement(ui_next_src/* Button */.$nd, {
@@ -8916,7 +8829,7 @@ function DicomUploadProgress({
8916
8829
  return /*#__PURE__*/react.createElement("div", {
8917
8830
  className: "flex grow flex-col"
8918
8831
  }, getNumCompletedAndTimeRemainingComponent(), /*#__PURE__*/react.createElement("div", {
8919
- className: "flex grow flex-col overflow-hidden bg-black text-lg"
8832
+ className: "flex grow flex-col overflow-hidden bg-background text-lg"
8920
8833
  }, getPercentCompleteComponent(), /*#__PURE__*/react.createElement("div", {
8921
8834
  className: "ohif-scrollbar h-1 grow overflow-y-scroll px-2"
8922
8835
  }, dicomFileUploaderArr.filter(dicomFileUploader => !showFailedOnly || dicomFileUploader.getStatus() === UploadStatus.Failed).map(dicomFileUploader => /*#__PURE__*/react.createElement(DicomUpload_DicomUploadProgressItem, {
@@ -8945,7 +8858,7 @@ function DicomUpload({
8945
8858
  onComplete,
8946
8859
  onStarted
8947
8860
  }) {
8948
- const baseClassNames = 'min-h-[375px] flex flex-col bg-black select-none rounded-lg overflow-hidden';
8861
+ const baseClassNames = 'min-h-[375px] flex flex-col bg-background select-none rounded-lg overflow-hidden';
8949
8862
  const [dicomFileUploaderArr, setDicomFileUploaderArr] = (0,react.useState)([]);
8950
8863
  const onDrop = (0,react.useCallback)(async acceptedFiles => {
8951
8864
  onStarted();
@@ -9067,7 +8980,8 @@ function ViewportDownloadFormNew({
9067
8980
  onDimensionsChange,
9068
8981
  onEnableViewport,
9069
8982
  onDisableViewport,
9070
- onDownload
8983
+ onDownload,
8984
+ onCopyToClipboard
9071
8985
  }) {
9072
8986
  const [viewportElement, setViewportElement] = (0,react.useState)(null);
9073
8987
  const [showWarningMessage, setShowWarningMessage] = (0,react.useState)(true);
@@ -9094,7 +9008,7 @@ function ViewportDownloadFormNew({
9094
9008
  "data-viewport-uid": viewportId,
9095
9009
  ref: setViewportElement
9096
9010
  }, warningState.enabled && showWarningMessage && /*#__PURE__*/react.createElement("div", {
9097
- className: "text-foreground absolute left-1/2 bottom-[5px] z-[1000] -translate-x-1/2 whitespace-nowrap rounded bg-black p-3 text-xs font-bold",
9011
+ className: "text-foreground absolute left-1/2 bottom-[5px] z-[1000] -translate-x-1/2 whitespace-nowrap rounded bg-background p-3 text-xs font-bold",
9098
9012
  style: {
9099
9013
  fontSize: '12px'
9100
9014
  }
@@ -9140,12 +9054,23 @@ function ViewportDownloadFormNew({
9140
9054
  className: "mt-2"
9141
9055
  }, /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu.Right, null, /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu.Secondary, {
9142
9056
  onClick: onClose
9143
- }, t('Common:Cancel')), /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu.Primary, {
9057
+ }, t('Common:Cancel')), /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu.Secondary, {
9058
+ onClick: async () => {
9059
+ try {
9060
+ await onCopyToClipboard();
9061
+ ui_next_src/* toast */.oRP.success(t('Image copied to clipboard'));
9062
+ onClose();
9063
+ } catch (error) {
9064
+ ui_next_src/* toast */.oRP.error(t('Failed to copy image to clipboard'));
9065
+ console.error('Failed to copy to clipboard:', error);
9066
+ }
9067
+ }
9068
+ }, t('Copy to Clipboard')), /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu.Primary, {
9144
9069
  onClick: () => {
9145
9070
  onDownload(filename || DEFAULT_FILENAME, fileType);
9146
9071
  onClose();
9147
9072
  }
9148
- }, t('Common:Save')))))));
9073
+ }, t('Save Image')))))));
9149
9074
  }
9150
9075
  /* harmony default export */ const captureViewportModalCustomization = ({
9151
9076
  'ohif.captureViewportModal': ViewportDownloadFormNew
@@ -9157,6 +9082,34 @@ function ViewportDownloadFormNew({
9157
9082
  value: 'Not For Diagnostic Use'
9158
9083
  }
9159
9084
  });
9085
+ ;// ../../../extensions/cornerstone/src/customizations/viewportScrollbarCustomization.tsx
9086
+ /**
9087
+ * Default customization values for viewport scrollbar behavior.
9088
+ * The `progress` scrollbar variant is in full mode for stack viewports and
9089
+ * acquisition-plane orthographic viewports.
9090
+ * Otherwise, viewports using the `progress` scrollbar show only the indicator.
9091
+ *
9092
+ * - `viewportScrollbar.variant`: `'progress' | 'legacy'` (default: `'progress'`)
9093
+ * - `viewportScrollbar.showLoadedEndpoints`: show loaded-range endpoint caps in full mode
9094
+ * - `viewportScrollbar.showLoadedFill`: show loaded/cached fill in full mode
9095
+ * - `viewportScrollbar.showViewedFill`: show viewed fill in full mode
9096
+ * - `viewportScrollbar.showLoadingPattern`: show loading pattern in full mode while not fully loaded
9097
+ * - `viewportScrollbar.viewedDwellMs`: delay before marking current image viewed in full mode (ms)
9098
+ * - `viewportScrollbar.loadedBatchIntervalMs`: loaded-state version batch interval in full mode (ms)
9099
+ * - `viewportScrollbar.indicator`: optional custom indicator config
9100
+ */
9101
+ function getViewportScrollbarCustomization() {
9102
+ return {
9103
+ 'viewportScrollbar.variant': 'progress',
9104
+ 'viewportScrollbar.showLoadedEndpoints': true,
9105
+ 'viewportScrollbar.showLoadedFill': true,
9106
+ 'viewportScrollbar.showViewedFill': true,
9107
+ 'viewportScrollbar.showLoadingPattern': true,
9108
+ 'viewportScrollbar.viewedDwellMs': 0,
9109
+ 'viewportScrollbar.loadedBatchIntervalMs': 200,
9110
+ 'viewportScrollbar.indicator': {}
9111
+ };
9112
+ }
9160
9113
  ;// ../../../extensions/cornerstone/src/getCustomizationModule.tsx
9161
9114
 
9162
9115
 
@@ -9171,6 +9124,7 @@ function ViewportDownloadFormNew({
9171
9124
 
9172
9125
 
9173
9126
 
9127
+
9174
9128
  function getCustomizationModule({
9175
9129
  commandsManager,
9176
9130
  servicesManager,
@@ -9195,7 +9149,8 @@ function getCustomizationModule({
9195
9149
  ...windowLevelPresetsCustomization,
9196
9150
  ...miscCustomization,
9197
9151
  ...captureViewportModalCustomization,
9198
- ...viewportDownloadWarningCustomization
9152
+ ...viewportDownloadWarningCustomization,
9153
+ ...getViewportScrollbarCustomization()
9199
9154
  }
9200
9155
  }];
9201
9156
  }
@@ -9563,17 +9518,39 @@ const CornerstoneViewportDownloadForm = ({
9563
9518
  } = activeViewportEnabledElement;
9564
9519
  const downloadViewport = renderingEngine.getViewport(VIEWPORT_ID);
9565
9520
  try {
9521
+ // Capture current viewport state
9522
+ // - properties: VOI, colormap, interpolation, etc.
9523
+ // - viewPresentation: flip/rotate/zoom presentation state added for
9524
+ // saving flip and rotation for capture
9525
+ // - viewReference: image/volume reference
9526
+ const properties = viewport.getProperties();
9527
+ const viewPresentation = viewport.getViewPresentation?.();
9528
+ const viewRef = viewport.getViewReference?.();
9566
9529
  if (downloadViewport instanceof esm.StackViewport) {
9567
9530
  const imageId = viewport.getCurrentImageId();
9568
- const properties = viewport.getProperties();
9569
9531
  await downloadViewport.setStack([imageId]);
9570
- downloadViewport.setProperties(properties);
9571
9532
  } else if (downloadViewport instanceof esm.BaseVolumeViewport) {
9572
9533
  const volumeIds = viewport.getAllVolumeIds();
9573
- downloadViewport.setVolumes([{
9534
+ await downloadViewport.setVolumes([{
9574
9535
  volumeId: volumeIds[0]
9575
9536
  }]);
9576
9537
  }
9538
+
9539
+ // Apply presentation state so captured image preserves flip/rotate
9540
+ if (viewPresentation && downloadViewport.setViewPresentation) {
9541
+ downloadViewport.setViewPresentation(viewPresentation);
9542
+ }
9543
+
9544
+ // Apply viewport display properties
9545
+ downloadViewport.setProperties(properties);
9546
+
9547
+ // Ensure correct image/volume reference
9548
+ if (viewRef && downloadViewport.setViewReference) {
9549
+ downloadViewport.setViewReference(viewRef);
9550
+ }
9551
+ downloadViewport.render();
9552
+
9553
+ // Re-apply segmentation overlays to the download viewport
9577
9554
  if (segmentationRepresentations?.length) {
9578
9555
  segmentationRepresentations.forEach(segRepresentation => {
9579
9556
  const {
@@ -9667,6 +9644,36 @@ const CornerstoneViewportDownloadForm = ({
9667
9644
  filename
9668
9645
  });
9669
9646
  };
9647
+ const handleCopyToClipboard = async () => {
9648
+ const divForDownloadViewport = document.querySelector(`div[data-viewport-uid="${VIEWPORT_ID}"]`);
9649
+ if (!divForDownloadViewport) {
9650
+ console.debug('No viewport found for copy');
9651
+ return;
9652
+ }
9653
+ try {
9654
+ const canvas = await (0,html2canvas_esm/* default */.A)(divForDownloadViewport);
9655
+
9656
+ // Clipboard API only supports PNG format in most browsers
9657
+ const blob = await new Promise((resolve, reject) => {
9658
+ canvas.toBlob(blob => {
9659
+ if (blob) {
9660
+ resolve(blob);
9661
+ } else {
9662
+ reject(new Error('Failed to create blob from canvas'));
9663
+ }
9664
+ }, 'image/png', 1.0);
9665
+ });
9666
+
9667
+ // Copy to clipboard using the Clipboard API
9668
+ await navigator.clipboard.write([new ClipboardItem({
9669
+ 'image/png': blob
9670
+ })]);
9671
+ console.log('Image copied to clipboard successfully');
9672
+ } catch (error) {
9673
+ console.error('Failed to copy image to clipboard:', error);
9674
+ throw error;
9675
+ }
9676
+ };
9670
9677
  const ViewportDownloadFormNew = customizationService.getCustomization('ohif.captureViewportModal');
9671
9678
  return /*#__PURE__*/react.createElement(ViewportDownloadFormNew, {
9672
9679
  onClose: hide,
@@ -9680,6 +9687,7 @@ const CornerstoneViewportDownloadForm = ({
9680
9687
  onEnableViewport: handleEnableViewport,
9681
9688
  onDisableViewport: handleDisableViewport,
9682
9689
  onDownload: handleDownload,
9690
+ onCopyToClipboard: handleCopyToClipboard,
9683
9691
  warningState: warningState
9684
9692
  });
9685
9693
  };
@@ -9942,6 +9950,51 @@ function generateSegmentationCSVReport(segmentationData, info) {
9942
9950
  });
9943
9951
  }
9944
9952
  ;// ../../../extensions/cornerstone/src/utils/hydrationUtils.ts
9953
+ /**
9954
+ * After SEG hydration we must refresh every viewport that shows the referenced volume so
9955
+ * presentations (including segmentation) apply to all MPR/3D tiles. Hanging-protocol matching
9956
+ * can return only the active viewport when protocol definitions omit viewportId (e.g. 3D four-up)
9957
+ * or when layout state diverges from the protocol; this merges in all grid panes that already
9958
+ * list that volume in `displaySetInstanceUIDs`.
9959
+ *
9960
+ * Only exact displaySetInstanceUID matches are used (no Frame-of-Reference inference): sibling
9961
+ * MPR planes must already share the same referenced volume UID in grid state, or HP matching
9962
+ * must list them; otherwise forcing a different UID onto a volume viewport can leave it blank.
9963
+ */
9964
+ function mergeVolumeSharingViewports(hangingProtocolUpdates, volumeUid, viewports) {
9965
+ if (!volumeUid) {
9966
+ return hangingProtocolUpdates ?? [];
9967
+ }
9968
+ const byId = new Map();
9969
+ const add = (viewportId, uids) => {
9970
+ if (!viewportId) {
9971
+ return;
9972
+ }
9973
+ byId.set(viewportId, {
9974
+ viewportId,
9975
+ displaySetInstanceUIDs: uids
9976
+ });
9977
+ };
9978
+ if (Array.isArray(hangingProtocolUpdates)) {
9979
+ for (const entry of hangingProtocolUpdates) {
9980
+ const vid = entry.viewportId ?? entry.viewportOptions?.viewportId;
9981
+ if (vid) {
9982
+ add(vid, entry.displaySetInstanceUIDs?.length ? entry.displaySetInstanceUIDs : [volumeUid]);
9983
+ }
9984
+ }
9985
+ }
9986
+ viewports.forEach(vp => {
9987
+ const uids = vp.displaySetInstanceUIDs || [];
9988
+ if (uids.includes(volumeUid)) {
9989
+ add(vp.viewportId, [volumeUid]);
9990
+ }
9991
+ });
9992
+ const merged = Array.from(byId.values());
9993
+ if (merged.length === 0 && Array.isArray(hangingProtocolUpdates) && hangingProtocolUpdates.length > 0) {
9994
+ return hangingProtocolUpdates;
9995
+ }
9996
+ return merged;
9997
+ }
9945
9998
  function getUpdatedViewportsForSegmentation({
9946
9999
  viewportId,
9947
10000
  servicesManager,
@@ -9952,7 +10005,8 @@ function getUpdatedViewportsForSegmentation({
9952
10005
  viewportGridService
9953
10006
  } = servicesManager.services;
9954
10007
  const {
9955
- isHangingProtocolLayout
10008
+ isHangingProtocolLayout,
10009
+ viewports
9956
10010
  } = viewportGridService.getState();
9957
10011
  const viewport = getTargetViewport({
9958
10012
  viewportId,
@@ -9960,7 +10014,10 @@ function getUpdatedViewportsForSegmentation({
9960
10014
  });
9961
10015
  const targetViewportId = viewport.viewportOptions.viewportId;
9962
10016
  const updatedViewports = hangingProtocolService.getViewportsRequireUpdate(targetViewportId, displaySetInstanceUIDs[0], isHangingProtocolLayout);
9963
- return updatedViewports;
10017
+ if (updatedViewports == null) {
10018
+ return updatedViewports;
10019
+ }
10020
+ return mergeVolumeSharingViewports(updatedViewports, displaySetInstanceUIDs[0], viewports);
9964
10021
  }
9965
10022
  const getTargetViewport = ({
9966
10023
  viewportId,
@@ -10520,7 +10577,14 @@ function commandsModule({
10520
10577
  }
10521
10578
  function _getActiveViewportToolGroupId() {
10522
10579
  const viewport = _getActiveViewportEnabledElement();
10523
- return toolGroupService.getToolGroupForViewport(viewport.id);
10580
+ const toolGroup = viewport && toolGroupService.getToolGroupForViewport(viewport.id);
10581
+ return toolGroup?.id;
10582
+ }
10583
+ function _usesPrimaryActivation(bindings) {
10584
+ if (!bindings?.length) {
10585
+ return true;
10586
+ }
10587
+ return bindings.some(binding => binding.mouseButton === dist_esm.Enums.MouseBindings.Primary && binding.modifierKey == null && binding.numTouchPoints == null);
10524
10588
  }
10525
10589
  function _getActiveSegmentationInfo() {
10526
10590
  const viewportId = viewportGridService.getActiveViewportId();
@@ -10756,11 +10820,26 @@ function commandsModule({
10756
10820
  segmentIndex: targetIndex
10757
10821
  } = targetSegmentation;
10758
10822
 
10823
+ // Check if the segment has voxels before computing bidirectional measurement
10824
+ const uniqueSegmentIndices = dist_esm.utilities.segmentation.getUniqueSegmentIndices(targetId);
10825
+ const hasVoxels = uniqueSegmentIndices.includes(targetIndex);
10826
+ if (!hasVoxels) {
10827
+ uiNotificationService.show({
10828
+ title: i18n_src/* default */.A.t('SegmentationPanel:Segment Bidirectional'),
10829
+ message: i18n_src/* default */.A.t('SegmentationPanel:Draw a segment before using bidirectional measurement'),
10830
+ type: 'warning'
10831
+ });
10832
+ return;
10833
+ }
10834
+
10759
10835
  // Get bidirectional measurement data
10760
10836
  const bidirectionalData = await dist_esm.utilities.segmentation.getSegmentLargestBidirectional({
10761
10837
  segmentationId: targetId,
10762
10838
  segmentIndices: [targetIndex]
10763
10839
  });
10840
+ if (!bidirectionalData.length) {
10841
+ return;
10842
+ }
10764
10843
  const activeViewportId = viewportGridService.getActiveViewportId();
10765
10844
 
10766
10845
  // Process each bidirectional measurement
@@ -10799,7 +10878,7 @@ function commandsModule({
10799
10878
  // get the active segmentIndex bidirectional annotation and jump to it
10800
10879
  const activeBidirectional = bidirectionalData.find(measurement => measurement.segmentIndex === targetIndex);
10801
10880
  commandsManager.run('jumpToMeasurement', {
10802
- uid: activeBidirectional.annotationUID
10881
+ uid: activeBidirectional?.annotationUID
10803
10882
  });
10804
10883
  },
10805
10884
  interpolateLabelmap: () => {
@@ -10962,7 +11041,7 @@ function commandsModule({
10962
11041
  return;
10963
11042
  }
10964
11043
  if (!labelConfig) {
10965
- const label = await (0,default_src.callInputDialog)({
11044
+ const label = await (0,default_src/* callInputDialog */.l5)({
10966
11045
  uiDialogService,
10967
11046
  title: i18n_src/* default */.A.t('Tools:Edit Measurement Label'),
10968
11047
  placeholder: measurement.label || i18n_src/* default */.A.t('Tools:Enter new label'),
@@ -10976,7 +11055,7 @@ function commandsModule({
10976
11055
  }
10977
11056
  return;
10978
11057
  }
10979
- const val = await (0,default_src.callInputDialogAutoComplete)({
11058
+ const val = await (0,default_src/* callInputDialogAutoComplete */.fq)({
10980
11059
  measurement,
10981
11060
  uiDialogService,
10982
11061
  labelConfig,
@@ -11099,6 +11178,9 @@ function commandsModule({
11099
11178
  uid,
11100
11179
  displayMeasurements = []
11101
11180
  }) => {
11181
+ if (!uid) {
11182
+ return;
11183
+ }
11102
11184
  measurementService.jumpToMeasurement(viewportGridService.getActiveViewportId(), uid);
11103
11185
  for (const measurement of displayMeasurements) {
11104
11186
  measurement.isActive = measurement.uid === uid;
@@ -11196,7 +11278,7 @@ function commandsModule({
11196
11278
  const labelConfig = customizationService.getCustomization('measurementLabels');
11197
11279
  const renderContent = customizationService.getCustomization('ui.labellingComponent');
11198
11280
  if (!labelConfig) {
11199
- const label = await (0,default_src.callInputDialog)({
11281
+ const label = await (0,default_src/* callInputDialog */.l5)({
11200
11282
  uiDialogService,
11201
11283
  title: i18n_src/* default */.A.t('Tools:Edit Arrow Text'),
11202
11284
  placeholder: data?.data?.label || i18n_src/* default */.A.t('Tools:Enter new text'),
@@ -11205,7 +11287,7 @@ function commandsModule({
11205
11287
  callback?.(label);
11206
11288
  return;
11207
11289
  }
11208
- const value = await (0,default_src.callInputDialogAutoComplete)({
11290
+ const value = await (0,default_src/* callInputDialogAutoComplete */.fq)({
11209
11291
  uiDialogService,
11210
11292
  labelConfig,
11211
11293
  renderContent
@@ -11369,31 +11451,46 @@ function commandsModule({
11369
11451
  toggleActiveDisabledToolbar({
11370
11452
  value,
11371
11453
  itemId,
11372
- toolGroupId
11454
+ toolGroupId,
11455
+ toolGroupIds
11373
11456
  }) {
11374
11457
  const toolName = itemId || value;
11375
- toolGroupId = toolGroupId ?? _getActiveViewportToolGroupId();
11376
- const toolGroup = toolGroupService.getToolGroup(toolGroupId);
11377
- if (!toolGroup || !toolGroup.hasTool(toolName)) {
11378
- return;
11379
- }
11380
- const toolIsActive = [dist_esm.Enums.ToolModes.Active, dist_esm.Enums.ToolModes.Enabled, dist_esm.Enums.ToolModes.Passive].includes(toolGroup.getToolOptions(toolName).mode);
11381
- toolIsActive ? toolGroup.setToolDisabled(toolName) : actions.setToolActive({
11382
- toolName,
11383
- toolGroupId
11384
- });
11385
-
11386
- // we should set the previously active tool to active after we set the
11387
- // current tool disabled
11388
- if (toolIsActive) {
11389
- const prevToolName = toolGroup.getPrevActivePrimaryToolName();
11390
- if (prevToolName !== toolName) {
11458
+ const resolvedToolGroupIds = toolGroupIds?.length ? toolGroupIds : [toolGroupId ?? _getActiveViewportToolGroupId()];
11459
+ resolvedToolGroupIds.forEach(toolGroupId => {
11460
+ const toolGroup = toolGroupService.getToolGroup(toolGroupId);
11461
+ if (!toolGroup || !toolGroup.hasTool(toolName)) {
11462
+ return;
11463
+ }
11464
+ const toolIsActive = [dist_esm.Enums.ToolModes.Active, dist_esm.Enums.ToolModes.Enabled, dist_esm.Enums.ToolModes.Passive].includes(toolGroup.getToolOptions(toolName).mode);
11465
+ if (toolIsActive) {
11466
+ toolGroup.setToolDisabled(toolName);
11467
+ const bindings = toolGroupService.getToolBindings(toolGroupId, toolName);
11468
+ if (_usesPrimaryActivation(bindings)) {
11469
+ // we should set the previously active tool to active after we set the
11470
+ // current tool disabled
11471
+ const prevToolName = toolGroup.getPrevActivePrimaryToolName();
11472
+ if (prevToolName !== toolName) {
11473
+ actions.setToolActive({
11474
+ toolName: prevToolName,
11475
+ toolGroupId
11476
+ });
11477
+ }
11478
+ }
11479
+ return;
11480
+ }
11481
+ const bindings = toolGroupService.getToolBindings(toolGroupId, toolName);
11482
+ if (_usesPrimaryActivation(bindings)) {
11391
11483
  actions.setToolActive({
11392
- toolName: prevToolName,
11393
- toolGroupId
11484
+ toolName,
11485
+ toolGroupId,
11486
+ bindings
11487
+ });
11488
+ } else {
11489
+ toolGroup.setToolActive(toolName, {
11490
+ bindings
11394
11491
  });
11395
11492
  }
11396
- }
11493
+ });
11397
11494
  },
11398
11495
  setToolActiveToolbar: ({
11399
11496
  value,
@@ -12101,7 +12198,7 @@ function commandsModule({
12101
12198
  segmentationService,
12102
12199
  viewportGridService
12103
12200
  } = servicesManager.services;
12104
- const displaySetInstanceUIDs = await (0,default_src.createReportAsync)({
12201
+ const displaySetInstanceUIDs = await (0,default_src/* createReportAsync */.Vy)({
12105
12202
  servicesManager,
12106
12203
  getReport: () => commandsManager.runCommand('storeSegmentation', args),
12107
12204
  reportType: 'Segmentation'
@@ -12178,14 +12275,15 @@ function commandsModule({
12178
12275
  * @param props.segmentationId - The ID of the segmentation to remove
12179
12276
  */
12180
12277
  removeSegmentationFromViewportCommand: ({
12181
- segmentationId
12278
+ segmentationId: displaySetInstanceUID
12182
12279
  }) => {
12183
12280
  const {
12184
- segmentationService,
12185
12281
  viewportGridService
12186
12282
  } = servicesManager.services;
12187
- segmentationService.removeSegmentationRepresentations(viewportGridService.getActiveViewportId(), {
12188
- segmentationId
12283
+ const viewportId = viewportGridService.getActiveViewportId();
12284
+ commandsManager.runCommand('removeDisplaySetLayer', {
12285
+ viewportId,
12286
+ displaySetInstanceUID
12189
12287
  });
12190
12288
  },
12191
12289
  /**
@@ -12213,7 +12311,7 @@ function commandsModule({
12213
12311
  return;
12214
12312
  }
12215
12313
  const segment = segmentation.segments[segmentIndex];
12216
- (0,default_src.callInputDialog)({
12314
+ (0,default_src/* callInputDialog */.l5)({
12217
12315
  uiDialogService,
12218
12316
  title: i18n_src/* default */.A.t('Tools:Edit Segment Label'),
12219
12317
  placeholder: i18n_src/* default */.A.t('Tools:Enter new label'),
@@ -12236,7 +12334,7 @@ function commandsModule({
12236
12334
  const {
12237
12335
  label
12238
12336
  } = segmentation;
12239
- (0,default_src.callInputDialog)({
12337
+ (0,default_src/* callInputDialog */.l5)({
12240
12338
  uiDialogService,
12241
12339
  title: i18n_src/* default */.A.t('Tools:Edit Segmentation Label'),
12242
12340
  placeholder: i18n_src/* default */.A.t('Tools:Enter new label'),
@@ -12266,7 +12364,7 @@ function commandsModule({
12266
12364
  a: color[3] / 255.0
12267
12365
  };
12268
12366
  uiDialogService.show({
12269
- content: default_src.colorPickerDialog,
12367
+ content: default_src/* colorPickerDialog */.wS,
12270
12368
  title: i18n_src/* default */.A.t('Tools:Segment Color'),
12271
12369
  contentProps: {
12272
12370
  value: rgbaColor,
@@ -12545,6 +12643,15 @@ function commandsModule({
12545
12643
  servicesManager,
12546
12644
  displaySetInstanceUIDs
12547
12645
  });
12646
+ if (!updatedViewports?.length) {
12647
+ return;
12648
+ }
12649
+ updatedViewports.forEach(({
12650
+ viewportId: csViewportId
12651
+ }) => {
12652
+ const csViewport = cornerstoneViewportService.getCornerstoneViewport(csViewportId);
12653
+ csViewport?.setNeedsRender?.();
12654
+ });
12548
12655
  actions.setDisplaySetsForViewports({
12549
12656
  viewportsToUpdate: updatedViewports.map(viewport => ({
12550
12657
  viewportId: viewport.viewportId,
@@ -13256,6 +13363,29 @@ const HYDRATE_SEG_SYNC_GROUP = {
13256
13363
  matchingRules: ['sameFOR']
13257
13364
  }
13258
13365
  };
13366
+ const viewportStructure = {
13367
+ layoutType: 'grid',
13368
+ properties: {
13369
+ rows: 1,
13370
+ columns: 3,
13371
+ layoutOptions: [{
13372
+ x: 0,
13373
+ y: 0,
13374
+ width: 1 / 3,
13375
+ height: 1
13376
+ }, {
13377
+ x: 1 / 3,
13378
+ y: 0,
13379
+ width: 1 / 3,
13380
+ height: 1
13381
+ }, {
13382
+ x: 2 / 3,
13383
+ y: 0,
13384
+ width: 1 / 3,
13385
+ height: 1
13386
+ }]
13387
+ }
13388
+ };
13259
13389
  const mpr = {
13260
13390
  id: 'mpr',
13261
13391
  name: i18next/* default */.A.t('Hps:MPR'),
@@ -13286,29 +13416,7 @@ const mpr = {
13286
13416
  },
13287
13417
  stages: [{
13288
13418
  name: 'MPR 1x3',
13289
- viewportStructure: {
13290
- layoutType: 'grid',
13291
- properties: {
13292
- rows: 1,
13293
- columns: 3,
13294
- layoutOptions: [{
13295
- x: 0,
13296
- y: 0,
13297
- width: 1 / 3,
13298
- height: 1
13299
- }, {
13300
- x: 1 / 3,
13301
- y: 0,
13302
- width: 1 / 3,
13303
- height: 1
13304
- }, {
13305
- x: 2 / 3,
13306
- y: 0,
13307
- width: 1 / 3,
13308
- height: 1
13309
- }]
13310
- }
13311
- },
13419
+ viewportStructure,
13312
13420
  viewports: [{
13313
13421
  viewportOptions: {
13314
13422
  viewportId: 'mpr-axial',
@@ -13352,36 +13460,82 @@ const mpr = {
13352
13460
  id: 'activeDisplaySet'
13353
13461
  }]
13354
13462
  }]
13355
- }]
13356
- };
13357
- ;// ../../../extensions/cornerstone/src/hps/fourUp.ts
13358
-
13359
-
13360
- const fourUp = {
13361
- id: 'fourUp',
13362
- locked: true,
13363
- name: i18next/* default */.A.t('Hps:3D four up'),
13364
- icon: 'layout-advanced-3d-four-up',
13365
- isPreset: true,
13366
- createdDate: '2023-03-15T10:29:44.894Z',
13367
- modifiedDate: '2023-03-15T10:29:44.894Z',
13368
- availableTo: {},
13369
- editableBy: {},
13370
- protocolMatchingRules: [],
13371
- imageLoadStrategy: 'interleaveCenter',
13372
- displaySetSelectors: {
13373
- activeDisplaySet: {
13374
- seriesMatchingRules: [{
13375
- weight: 1,
13376
- attribute: 'isReconstructable',
13377
- constraint: {
13378
- equals: {
13379
- value: true
13380
- }
13381
- },
13382
- required: true
13383
- }]
13384
- }
13463
+ }, {
13464
+ name: 'MPR Reformat 1x3',
13465
+ viewportStructure,
13466
+ viewports: [{
13467
+ viewportOptions: {
13468
+ viewportId: 'mpr-axial',
13469
+ toolGroupId: 'mpr',
13470
+ viewportType: 'volume',
13471
+ orientation: 'axial_reformat',
13472
+ initialImageOptions: {
13473
+ preset: 'middle'
13474
+ },
13475
+ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP]
13476
+ },
13477
+ displaySets: [{
13478
+ id: 'activeDisplaySet'
13479
+ }]
13480
+ }, {
13481
+ viewportOptions: {
13482
+ viewportId: 'mpr-sagittal',
13483
+ toolGroupId: 'mpr',
13484
+ viewportType: 'volume',
13485
+ orientation: 'sagittal_reformat',
13486
+ initialImageOptions: {
13487
+ preset: 'middle'
13488
+ },
13489
+ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP]
13490
+ },
13491
+ displaySets: [{
13492
+ id: 'activeDisplaySet'
13493
+ }]
13494
+ }, {
13495
+ viewportOptions: {
13496
+ viewportId: 'mpr-coronal',
13497
+ toolGroupId: 'mpr',
13498
+ viewportType: 'volume',
13499
+ orientation: 'coronal_reformat',
13500
+ initialImageOptions: {
13501
+ preset: 'middle'
13502
+ },
13503
+ syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP]
13504
+ },
13505
+ displaySets: [{
13506
+ id: 'activeDisplaySet'
13507
+ }]
13508
+ }]
13509
+ }]
13510
+ };
13511
+ ;// ../../../extensions/cornerstone/src/hps/fourUp.ts
13512
+
13513
+
13514
+ const fourUp = {
13515
+ id: 'fourUp',
13516
+ locked: true,
13517
+ name: i18next/* default */.A.t('Hps:3D four up'),
13518
+ icon: 'layout-advanced-3d-four-up',
13519
+ isPreset: true,
13520
+ createdDate: '2023-03-15T10:29:44.894Z',
13521
+ modifiedDate: '2023-03-15T10:29:44.894Z',
13522
+ availableTo: {},
13523
+ editableBy: {},
13524
+ protocolMatchingRules: [],
13525
+ imageLoadStrategy: 'interleaveCenter',
13526
+ displaySetSelectors: {
13527
+ activeDisplaySet: {
13528
+ seriesMatchingRules: [{
13529
+ weight: 1,
13530
+ attribute: 'isReconstructable',
13531
+ constraint: {
13532
+ equals: {
13533
+ value: true
13534
+ }
13535
+ },
13536
+ required: true
13537
+ }]
13538
+ }
13385
13539
  },
13386
13540
  stages: [{
13387
13541
  id: 'fourUpStage',
@@ -15342,6 +15496,9 @@ function ViewportDataOverlayMenu({
15342
15496
  } = (0,useViewportDisplaySets/* useViewportDisplaySets */.N)(viewportId);
15343
15497
  const [optimisticOverlayDisplaySets, setOptimisticOverlayDisplaySets] = (0,react.useState)(overlayDisplaySets);
15344
15498
  const [thresholdOpacityEnabled, setThresholdOpacityEnabled] = (0,react.useState)(false);
15499
+ (0,react.useEffect)(() => {
15500
+ setOptimisticOverlayDisplaySets(overlayDisplaySets);
15501
+ }, [backgroundDisplaySet?.displaySetInstanceUID, overlayDisplaySets]);
15345
15502
 
15346
15503
  /**
15347
15504
  * Change the background display set
@@ -15648,7 +15805,8 @@ function ViewportDataOverlayMenu({
15648
15805
  }
15649
15806
  }
15650
15807
  }, /*#__PURE__*/react.createElement(ui_next_src/* SelectTrigger */.bqE, {
15651
- className: "flex-1"
15808
+ className: "flex-1",
15809
+ "data-cy": `overlay-background-ds-select-${viewportId}`
15652
15810
  }, /*#__PURE__*/react.createElement(ui_next_src/* SelectValue */.yvm, null, (backgroundDisplaySet?.SeriesDescription || backgroundDisplaySet?.label || 'background').toUpperCase())), /*#__PURE__*/react.createElement(ui_next_src/* SelectContent */.gCo, null, potentialBackgroundDisplaySets.map(displaySet => /*#__PURE__*/react.createElement(ui_next_src/* SelectItem */.ebT, {
15653
15811
  key: displaySet.displaySetInstanceUID,
15654
15812
  value: displaySet.displaySetInstanceUID,
@@ -15923,7 +16081,7 @@ function ViewportOrientationMenu({
15923
16081
  }) : null), /*#__PURE__*/react.createElement("div", {
15924
16082
  className: "flex-1 text-left"
15925
16083
  }, "Acquisition")), /*#__PURE__*/react.createElement("div", {
15926
- className: "mx-1 my-2 border-t border-white/20"
16084
+ className: "border-input mx-1 my-2 border-t"
15927
16085
  }), /*#__PURE__*/react.createElement(ui_next_src/* Button */.$nd, {
15928
16086
  variant: "ghost",
15929
16087
  className: "flex h-7 w-full flex-shrink-0 items-center justify-start self-stretch px-1 py-0",
@@ -16264,7 +16422,7 @@ function VolumeRenderingPresetsContent({
16264
16422
  }
16265
16423
  }, /*#__PURE__*/react.createElement(ui_next_src/* Icons */.FI1.ByName, {
16266
16424
  name: preset.name,
16267
- className: selectedPreset?.name === preset.name ? 'border-highlight h-[75px] w-[95px] max-w-none rounded border-2' : 'hover:border-highlight h-[75px] w-[95px] max-w-none rounded border-2 border-black'
16425
+ className: selectedPreset?.name === preset.name ? 'border-highlight h-[75px] w-[95px] max-w-none rounded border-2' : 'hover:border-highlight h-[75px] w-[95px] max-w-none rounded border-2 border-background'
16268
16426
  }), /*#__PURE__*/react.createElement("label", {
16269
16427
  className: "text-muted-foreground mt-1 text-left text-xs"
16270
16428
  }, formatLabel(preset.name, 11)))))), /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu, {
@@ -17410,9 +17568,9 @@ function ModalityLoadBadge({
17410
17568
  if (!statusInfo.isHydrated) {
17411
17569
  return /*#__PURE__*/react.createElement("div", {
17412
17570
  "data-cy": `ModalityLoadBadge-${viewportId}`,
17413
- className: "flex h-6 cursor-default text-sm leading-6 text-white"
17571
+ className: "text-foreground flex h-6 cursor-default text-sm leading-6"
17414
17572
  }, /*#__PURE__*/react.createElement("div", {
17415
- className: "bg-customgray-100 flex min-w-[45px] items-center rounded-l-xl rounded-r p-1"
17573
+ className: "bg-popover flex min-w-[45px] items-center rounded-l-xl rounded-r p-1"
17416
17574
  }, /*#__PURE__*/react.createElement(StatusIcon, null), /*#__PURE__*/react.createElement("span", {
17417
17575
  className: "ml-1"
17418
17576
  }, statusInfo.type)), statusInfo.type !== 'SR' && /*#__PURE__*/react.createElement(ui_next_src/* ViewportActionButton */.N8H, {
@@ -18339,6 +18497,36 @@ function getToolbarModule({
18339
18497
  isActive: isPrimaryActive
18340
18498
  };
18341
18499
  }
18500
+ }, {
18501
+ name: 'evaluate.cornerstoneTool.toggleWithModifier',
18502
+ evaluate: ({
18503
+ viewportId,
18504
+ button,
18505
+ disabledText,
18506
+ toggledOnIcon,
18507
+ defaultIcon
18508
+ }) => {
18509
+ const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);
18510
+ if (!toolGroup) {
18511
+ return;
18512
+ }
18513
+ const toolName = toolbarService.getToolNameForButton(button);
18514
+ if (!toolGroup.hasTool(toolName)) {
18515
+ return getDisabledState(disabledText);
18516
+ }
18517
+ const {
18518
+ mode
18519
+ } = toolGroup.getToolOptions(toolName) ?? {};
18520
+ const isToggled = mode === dist_esm.Enums.ToolModes.Passive || mode === dist_esm.Enums.ToolModes.Active || mode === dist_esm.Enums.ToolModes.Enabled;
18521
+ const toolBindings = toolGroupService.getToolBindings(toolGroup.id, toolName);
18522
+ const hasModifierKey = toolBindings?.some(binding => binding.modifierKey != null) ?? false;
18523
+ return {
18524
+ disabled: false,
18525
+ isActive: false,
18526
+ isToggled,
18527
+ icon: isToggled && hasModifierKey && toggledOnIcon ? toggledOnIcon : defaultIcon ?? button.props.icon
18528
+ };
18529
+ }
18342
18530
  }, {
18343
18531
  name: 'evaluate.action',
18344
18532
  evaluate: () => {
@@ -18491,7 +18679,10 @@ class ToolGroupService {
18491
18679
  this.cornerstoneViewportService = void 0;
18492
18680
  this.viewportGridService = void 0;
18493
18681
  this.uiNotificationService = void 0;
18682
+ this.customizationService = void 0;
18494
18683
  this.toolGroupIds = new Set();
18684
+ this.toolBindingsMap = new Map();
18685
+ this.defaultToolBindingsMap = new Map();
18495
18686
  /**
18496
18687
  * Service-specific
18497
18688
  */
@@ -18517,11 +18708,13 @@ class ToolGroupService {
18517
18708
  const {
18518
18709
  cornerstoneViewportService,
18519
18710
  viewportGridService,
18520
- uiNotificationService
18711
+ uiNotificationService,
18712
+ customizationService
18521
18713
  } = servicesManager.services;
18522
18714
  this.cornerstoneViewportService = cornerstoneViewportService;
18523
18715
  this.viewportGridService = viewportGridService;
18524
18716
  this.uiNotificationService = uiNotificationService;
18717
+ this.customizationService = customizationService;
18525
18718
  this.listeners = {};
18526
18719
  this.EVENTS = ToolGroupService_EVENTS;
18527
18720
  Object.assign(this, src/* pubSubServiceInterface */.Ml);
@@ -18579,6 +18772,8 @@ class ToolGroupService {
18579
18772
  destroy() {
18580
18773
  dist_esm.ToolGroupManager.destroy();
18581
18774
  this.toolGroupIds = new Set();
18775
+ this.toolBindingsMap.clear();
18776
+ this.defaultToolBindingsMap.clear();
18582
18777
  esm.eventTarget.removeEventListener(dist_esm.Enums.Events.TOOL_ACTIVATED, this._onToolActivated);
18583
18778
  }
18584
18779
  destroyToolGroup(toolGroupId) {
@@ -18633,6 +18828,7 @@ class ToolGroupService {
18633
18828
  // this.changeConfigurationIfNecessary(toolGroup, volumeId);
18634
18829
  this._addTools(toolGroup, tools, configs);
18635
18830
  this._setToolsMode(toolGroup, tools);
18831
+ this._loadPersistedBindings(toolGroupId);
18636
18832
  }
18637
18833
  createToolGroupAndAddTools(toolGroupId, tools) {
18638
18834
  const toolGroup = this.createToolGroup(toolGroupId);
@@ -18672,6 +18868,84 @@ class ToolGroupService {
18672
18868
  getActivePrimaryMouseButtonTool(toolGroupId) {
18673
18869
  return this.getToolGroup(toolGroupId)?.getActivePrimaryMouseButtonTool();
18674
18870
  }
18871
+ getToolBindings(toolGroupId, toolName) {
18872
+ return this.toolBindingsMap.get(toolGroupId)?.get(toolName);
18873
+ }
18874
+ setToolBindings(toolGroupId, toolName, bindings) {
18875
+ if (!this.toolBindingsMap.has(toolGroupId)) {
18876
+ this.toolBindingsMap.set(toolGroupId, new Map());
18877
+ }
18878
+ this.toolBindingsMap.get(toolGroupId).set(toolName, this._cloneToolBindings(bindings));
18879
+ }
18880
+ getDefaultToolBindings(toolGroupId, toolName) {
18881
+ const defaultBindings = this.defaultToolBindingsMap.get(toolGroupId)?.get(toolName);
18882
+ return defaultBindings ? this._cloneToolBindings(defaultBindings) : undefined;
18883
+ }
18884
+ persistToolBindings(toolGroupId, toolName, bindings) {
18885
+ const persistedBindings = this._readPersistedToolBindings();
18886
+ if (!persistedBindings[toolGroupId]) {
18887
+ persistedBindings[toolGroupId] = {};
18888
+ }
18889
+ persistedBindings[toolGroupId][toolName] = bindings;
18890
+ this._writePersistedToolBindings(persistedBindings);
18891
+ }
18892
+ removePersistedToolBindings(toolGroupId, toolName) {
18893
+ const persistedBindings = this._readPersistedToolBindings();
18894
+ if (!persistedBindings[toolGroupId]) {
18895
+ return;
18896
+ }
18897
+ if (toolName) {
18898
+ delete persistedBindings[toolGroupId][toolName];
18899
+ if (!Object.keys(persistedBindings[toolGroupId]).length) {
18900
+ delete persistedBindings[toolGroupId];
18901
+ }
18902
+ } else {
18903
+ delete persistedBindings[toolGroupId];
18904
+ }
18905
+ this._writePersistedToolBindings(persistedBindings);
18906
+ }
18907
+
18908
+ /**
18909
+ * Applies the currently tracked bindings to the runtime tool instance.
18910
+ *
18911
+ * Note: this method may activate tools that are currently Passive or Enabled.
18912
+ * Assigning bindings is treated as making the tool interactable.
18913
+ */
18914
+ applyToolBindings(toolGroupId, toolName, options = {}) {
18915
+ const toolGroup = dist_esm.ToolGroupManager.getToolGroup(toolGroupId);
18916
+ if (!toolGroup || !toolGroup.hasTool(toolName)) {
18917
+ return;
18918
+ }
18919
+ const bindings = this.getToolBindings(toolGroupId, toolName);
18920
+ if (!bindings) {
18921
+ return;
18922
+ }
18923
+ const {
18924
+ mode
18925
+ } = toolGroup.getToolOptions(toolName);
18926
+ if (mode === dist_esm.Enums.ToolModes.Active || mode === dist_esm.Enums.ToolModes.Passive || mode === dist_esm.Enums.ToolModes.Enabled) {
18927
+ if (options.replaceExisting) {
18928
+ // Opt-in behavior for callers that need replacement semantics.
18929
+ toolGroup.setToolDisabled(toolName);
18930
+ }
18931
+ toolGroup.setToolActive(toolName, {
18932
+ bindings
18933
+ });
18934
+ }
18935
+ }
18936
+ getAllToolBindings() {
18937
+ const result = [];
18938
+ for (const [toolGroupId, toolMap] of this.toolBindingsMap) {
18939
+ for (const [toolName, bindings] of toolMap) {
18940
+ result.push({
18941
+ toolGroupId,
18942
+ toolName,
18943
+ bindings
18944
+ });
18945
+ }
18946
+ }
18947
+ return result;
18948
+ }
18675
18949
  _setToolsMode(toolGroup, tools) {
18676
18950
  const {
18677
18951
  active,
@@ -18684,6 +18958,10 @@ class ToolGroupService {
18684
18958
  toolName,
18685
18959
  bindings
18686
18960
  }) => {
18961
+ if (bindings) {
18962
+ this.setToolBindings(toolGroup.id, toolName, bindings);
18963
+ this._setDefaultToolBindingsIfMissing(toolGroup.id, toolName, bindings);
18964
+ }
18687
18965
  toolGroup.setToolActive(toolName, {
18688
18966
  bindings
18689
18967
  });
@@ -18691,26 +18969,50 @@ class ToolGroupService {
18691
18969
  }
18692
18970
  if (passive) {
18693
18971
  passive.forEach(({
18694
- toolName
18972
+ toolName,
18973
+ bindings
18695
18974
  }) => {
18975
+ if (bindings) {
18976
+ this.setToolBindings(toolGroup.id, toolName, bindings);
18977
+ this._setDefaultToolBindingsIfMissing(toolGroup.id, toolName, bindings);
18978
+ }
18696
18979
  toolGroup.setToolPassive(toolName);
18697
18980
  });
18698
18981
  }
18699
18982
  if (enabled) {
18700
18983
  enabled.forEach(({
18701
- toolName
18984
+ toolName,
18985
+ bindings
18702
18986
  }) => {
18987
+ if (bindings) {
18988
+ this.setToolBindings(toolGroup.id, toolName, bindings);
18989
+ this._setDefaultToolBindingsIfMissing(toolGroup.id, toolName, bindings);
18990
+ }
18703
18991
  toolGroup.setToolEnabled(toolName);
18704
18992
  });
18705
18993
  }
18706
18994
  if (disabled) {
18707
18995
  disabled.forEach(({
18708
- toolName
18996
+ toolName,
18997
+ bindings
18709
18998
  }) => {
18999
+ if (bindings) {
19000
+ this.setToolBindings(toolGroup.id, toolName, bindings);
19001
+ this._setDefaultToolBindingsIfMissing(toolGroup.id, toolName, bindings);
19002
+ }
18710
19003
  toolGroup.setToolDisabled(toolName);
18711
19004
  });
18712
19005
  }
18713
19006
  }
19007
+ _setDefaultToolBindingsIfMissing(toolGroupId, toolName, bindings) {
19008
+ if (!this.defaultToolBindingsMap.has(toolGroupId)) {
19009
+ this.defaultToolBindingsMap.set(toolGroupId, new Map());
19010
+ }
19011
+ const toolMap = this.defaultToolBindingsMap.get(toolGroupId);
19012
+ if (!toolMap.has(toolName)) {
19013
+ toolMap.set(toolName, this._cloneToolBindings(bindings));
19014
+ }
19015
+ }
18714
19016
  _addTools(toolGroup, tools) {
18715
19017
  const addTools = tools => {
18716
19018
  tools.forEach(({
@@ -18742,6 +19044,60 @@ class ToolGroupService {
18742
19044
  addTools(tools.disabled);
18743
19045
  }
18744
19046
  }
19047
+ _loadPersistedBindings(toolGroupId) {
19048
+ const toolGroupBindings = this._readPersistedToolBindings()[toolGroupId];
19049
+ if (!toolGroupBindings) {
19050
+ return;
19051
+ }
19052
+ const toolGroup = dist_esm.ToolGroupManager.getToolGroup(toolGroupId);
19053
+ for (const [toolName, bindings] of Object.entries(toolGroupBindings)) {
19054
+ this.setToolBindings(toolGroupId, toolName, bindings);
19055
+ if (!toolGroup || !toolGroup.hasTool(toolName)) {
19056
+ continue;
19057
+ }
19058
+ const {
19059
+ mode
19060
+ } = toolGroup.getToolOptions(toolName);
19061
+ if (mode === dist_esm.Enums.ToolModes.Active) {
19062
+ this.applyToolBindings(toolGroupId, toolName, {
19063
+ replaceExisting: true
19064
+ });
19065
+ }
19066
+ }
19067
+ }
19068
+ _readPersistedToolBindings() {
19069
+ try {
19070
+ const stored = localStorage.getItem(this._getToolBindingsStorageKey());
19071
+ if (!stored) {
19072
+ return {};
19073
+ }
19074
+ const parsed = JSON.parse(stored);
19075
+ if (!parsed || typeof parsed !== 'object') {
19076
+ return {};
19077
+ }
19078
+ return parsed;
19079
+ } catch {
19080
+ // ignore corrupt localStorage
19081
+ return {};
19082
+ }
19083
+ }
19084
+ _writePersistedToolBindings(bindings) {
19085
+ const storageKey = this._getToolBindingsStorageKey();
19086
+ if (!Object.keys(bindings).length) {
19087
+ localStorage.removeItem(storageKey);
19088
+ return;
19089
+ }
19090
+ localStorage.setItem(storageKey, JSON.stringify(bindings));
19091
+ }
19092
+ _cloneToolBindings(bindings) {
19093
+ return bindings.map(binding => ({
19094
+ ...binding
19095
+ }));
19096
+ }
19097
+ _getToolBindingsStorageKey() {
19098
+ const customizationValue = this.customizationService?.getCustomization('ohif.userPreferences.toolBindingsStorageKey');
19099
+ return typeof customizationValue === 'string' && customizationValue.length > 0 ? customizationValue : 'user-preferred-tool-bindings';
19100
+ }
18745
19101
  }
18746
19102
  _ToolGroupService = ToolGroupService;
18747
19103
  ToolGroupService.REGISTRATION = {
@@ -18829,7 +19185,12 @@ const segmentationRepresentationModifiedCallback = async (synchronizerInstance,
18829
19185
  const sourceDisplaySetUIDs = extractDisplaySetUIDs(sourceViewportInfo);
18830
19186
  const targetDisplaySetUIDs = extractDisplaySetUIDs(targetViewportInfo);
18831
19187
  const sharedDisplaySetExists = isAnyDisplaySetCommon(sourceDisplaySetUIDs, targetDisplaySetUIDs);
18832
- if (!sharedDisplaySetExists && !viewport.getFrameOfReferenceUID()) {
19188
+ const targetFrameOfReferenceUID = viewport.getFrameOfReferenceUID();
19189
+ const sourceFrameOfReferenceUID = (0,esm.getEnabledElementByViewportId)(sourceViewportId)?.viewport?.getFrameOfReferenceUID();
19190
+ if (!sharedDisplaySetExists && !targetFrameOfReferenceUID) {
19191
+ return;
19192
+ }
19193
+ if (!sharedDisplaySetExists && targetFrameOfReferenceUID !== sourceFrameOfReferenceUID) {
18833
19194
  return;
18834
19195
  }
18835
19196
  const targetViewportRepresentation = segmentationService.getSegmentationRepresentations(targetViewportId, {
@@ -19196,11 +19557,11 @@ class SegmentationService extends src/* PubSubService */.Rc {
19196
19557
  this.EVENTS = SegmentationService_EVENTS;
19197
19558
  this.destroy = () => {
19198
19559
  esm.eventTarget.removeEventListener(dist_esm.Enums.Events.SEGMENTATION_MODIFIED, this._onSegmentationModifiedFromSource);
19199
- esm.eventTarget.removeEventListener(dist_esm.Enums.Events.SEGMENTATION_REMOVED, this._onSegmentationModifiedFromSource);
19560
+ esm.eventTarget.removeEventListener(dist_esm.Enums.Events.SEGMENTATION_REMOVED, this._onSegmentationRemovedFromSource);
19200
19561
  esm.eventTarget.removeEventListener(dist_esm.Enums.Events.SEGMENTATION_DATA_MODIFIED, this._onSegmentationDataModifiedFromSource);
19201
19562
  esm.eventTarget.removeEventListener(dist_esm.Enums.Events.SEGMENTATION_REPRESENTATION_MODIFIED, this._onSegmentationRepresentationModifiedFromSource);
19202
19563
  esm.eventTarget.removeEventListener(dist_esm.Enums.Events.SEGMENTATION_REPRESENTATION_ADDED, this._onSegmentationRepresentationModifiedFromSource);
19203
- esm.eventTarget.removeEventListener(dist_esm.Enums.Events.SEGMENTATION_REPRESENTATION_REMOVED, this._onSegmentationRepresentationModifiedFromSource);
19564
+ esm.eventTarget.removeEventListener(dist_esm.Enums.Events.SEGMENTATION_REPRESENTATION_REMOVED, this._onSegmentationRepresentationRemovedFromSource);
19204
19565
  esm.eventTarget.removeEventListener(dist_esm.Enums.Events.SEGMENTATION_ADDED, this._onSegmentationAddedFromSource);
19205
19566
  this.reset();
19206
19567
  };
@@ -19261,6 +19622,16 @@ class SegmentationService extends src/* PubSubService */.Rc {
19261
19622
  viewportId
19262
19623
  });
19263
19624
  };
19625
+ this._onSegmentationRepresentationRemovedFromSource = evt => {
19626
+ const {
19627
+ segmentationId,
19628
+ viewportId
19629
+ } = evt.detail;
19630
+ this._broadcastEvent(this.EVENTS.SEGMENTATION_REPRESENTATION_REMOVED, {
19631
+ segmentationId,
19632
+ viewportId
19633
+ });
19634
+ };
19264
19635
  this._onSegmentationModifiedFromSource = evt => {
19265
19636
  const {
19266
19637
  segmentationId
@@ -19277,6 +19648,14 @@ class SegmentationService extends src/* PubSubService */.Rc {
19277
19648
  segmentationId
19278
19649
  });
19279
19650
  };
19651
+ this._onSegmentationRemovedFromSource = evt => {
19652
+ const {
19653
+ segmentationId
19654
+ } = evt.detail;
19655
+ this._broadcastEvent(this.EVENTS.SEGMENTATION_REMOVED, {
19656
+ segmentationId
19657
+ });
19658
+ };
19280
19659
  this._onAnnotationCutMergeProcessCompletedFromSource = evt => {
19281
19660
  const {
19282
19661
  segmentationId
@@ -19482,6 +19861,7 @@ class SegmentationService extends src/* PubSubService */.Rc {
19482
19861
  },
19483
19862
  config: {
19484
19863
  label,
19864
+ fallbackLabel: `S:${displaySet.SeriesNumber} ${displaySet.Modality}`,
19485
19865
  segments: options?.segments && Object.keys(options.segments).length > 0 ? options.segments : {
19486
19866
  1: {
19487
19867
  label: `${i18n_src/* default */.A.t('Segment')} 1`,
@@ -19613,6 +19993,7 @@ class SegmentationService extends src/* PubSubService */.Rc {
19613
19993
  },
19614
19994
  config: {
19615
19995
  label: segDisplaySet.SeriesDescription,
19996
+ fallbackLabel: `S:${segDisplaySet.SeriesNumber} ${segDisplaySet.Modality}`,
19616
19997
  segments
19617
19998
  }
19618
19999
  };
@@ -19673,7 +20054,8 @@ class SegmentationService extends src/* PubSubService */.Rc {
19673
20054
  }
19674
20055
  },
19675
20056
  config: {
19676
- label: rtDisplaySet.SeriesDescription
20057
+ label: rtDisplaySet.SeriesDescription,
20058
+ fallbackLabel: `S:${rtDisplaySet.SeriesNumber} ${rtDisplaySet.Modality}`
19677
20059
  }
19678
20060
  };
19679
20061
  const segments = {};
@@ -20170,14 +20552,14 @@ class SegmentationService extends src/* PubSubService */.Rc {
20170
20552
  }
20171
20553
  /**
20172
20554
  * Clears segmentation representations from the viewport.
20173
- * Unlike removeSegmentationRepresentations, this doesn't update
20555
+ * Unlike removeRepresentationsFromViewport, this doesn't update
20174
20556
  * removed display set and representation maps.
20175
20557
  * We track removed segmentations manually to avoid re-adding them
20176
20558
  * when the display set is added again.
20177
20559
  * @param viewportId - The viewport ID to clear segmentation representations from.
20178
20560
  */
20179
20561
  clearSegmentationRepresentations(viewportId) {
20180
- this.removeSegmentationRepresentations(viewportId);
20562
+ this.removeRepresentationsFromViewport(viewportId);
20181
20563
  }
20182
20564
 
20183
20565
  /**
@@ -20192,7 +20574,7 @@ class SegmentationService extends src/* PubSubService */.Rc {
20192
20574
  }
20193
20575
 
20194
20576
  /**
20195
- * It removes the segmentation representations from the viewport.
20577
+ * Removes segmentation representations from the viewport.
20196
20578
  * @param viewportId - The viewport id to remove the segmentation representations from.
20197
20579
  * @param specifier - The specifier to remove the segmentation representations.
20198
20580
  *
@@ -20202,7 +20584,7 @@ class SegmentationService extends src/* PubSubService */.Rc {
20202
20584
  * If a type specifier is provided, only the segmentation representation with the specified type are removed.
20203
20585
  * If both a segmentationId and type specifier are provided, only the segmentation representation with the specified segmentationId and type are removed.
20204
20586
  */
20205
- removeSegmentationRepresentations(viewportId, specifier = {}) {
20587
+ removeRepresentationsFromViewport(viewportId, specifier = {}) {
20206
20588
  dist_esm.segmentation.removeSegmentationRepresentations(viewportId, specifier);
20207
20589
  }
20208
20590
 
@@ -20558,6 +20940,7 @@ class SegmentationService extends src/* PubSubService */.Rc {
20558
20940
  id: id,
20559
20941
  segmentationId,
20560
20942
  label: segmentation.label,
20943
+ fallbackLabel: segmentation.fallbackLabel,
20561
20944
  active,
20562
20945
  type,
20563
20946
  visible,
@@ -20570,11 +20953,11 @@ class SegmentationService extends src/* PubSubService */.Rc {
20570
20953
  }
20571
20954
  _initSegmentationService() {
20572
20955
  esm.eventTarget.addEventListener(dist_esm.Enums.Events.SEGMENTATION_MODIFIED, this._onSegmentationModifiedFromSource);
20573
- esm.eventTarget.addEventListener(dist_esm.Enums.Events.SEGMENTATION_REMOVED, this._onSegmentationModifiedFromSource);
20956
+ esm.eventTarget.addEventListener(dist_esm.Enums.Events.SEGMENTATION_REMOVED, this._onSegmentationRemovedFromSource);
20574
20957
  esm.eventTarget.addEventListener(dist_esm.Enums.Events.SEGMENTATION_DATA_MODIFIED, this._onSegmentationDataModifiedFromSource);
20575
20958
  esm.eventTarget.addEventListener(dist_esm.Enums.Events.SEGMENTATION_REPRESENTATION_MODIFIED, this._onSegmentationRepresentationModifiedFromSource);
20576
20959
  esm.eventTarget.addEventListener(dist_esm.Enums.Events.SEGMENTATION_REPRESENTATION_ADDED, this._onSegmentationRepresentationModifiedFromSource);
20577
- esm.eventTarget.addEventListener(dist_esm.Enums.Events.SEGMENTATION_REPRESENTATION_REMOVED, this._onSegmentationRepresentationModifiedFromSource);
20960
+ esm.eventTarget.addEventListener(dist_esm.Enums.Events.SEGMENTATION_REPRESENTATION_REMOVED, this._onSegmentationRepresentationRemovedFromSource);
20578
20961
  esm.eventTarget.addEventListener(dist_esm.Enums.Events.SEGMENTATION_ADDED, this._onSegmentationAddedFromSource);
20579
20962
  esm.eventTarget.addEventListener(dist_esm.Enums.Events.ANNOTATION_CUT_MERGE_PROCESS_COMPLETED, this._onAnnotationCutMergeProcessCompletedFromSource);
20580
20963
  }
@@ -20780,6 +21163,7 @@ const ORTHOGRAPHIC = 'orthographic';
20780
21163
  const VOLUME_3D = 'volume3d';
20781
21164
  const VIDEO = 'video';
20782
21165
  const WHOLESLIDE = 'wholeslide';
21166
+ const ECG = 'ecg';
20783
21167
  function getCornerstoneViewportType(viewportType, displaySets) {
20784
21168
  const lowerViewportType = displaySets?.[0]?.viewportType?.toLowerCase() || viewportType.toLowerCase();
20785
21169
  if (lowerViewportType === STACK) {
@@ -20791,13 +21175,16 @@ function getCornerstoneViewportType(viewportType, displaySets) {
20791
21175
  if (lowerViewportType === WHOLESLIDE) {
20792
21176
  return esm.Enums.ViewportType.WHOLE_SLIDE;
20793
21177
  }
21178
+ if (lowerViewportType === ECG) {
21179
+ return esm.Enums.ViewportType.ECG;
21180
+ }
20794
21181
  if (lowerViewportType === VOLUME || lowerViewportType === ORTHOGRAPHIC) {
20795
21182
  return esm.Enums.ViewportType.ORTHOGRAPHIC;
20796
21183
  }
20797
21184
  if (lowerViewportType === VOLUME_3D) {
20798
21185
  return esm.Enums.ViewportType.VOLUME_3D;
20799
21186
  }
20800
- throw new Error(`Invalid viewport type: ${viewportType}. Valid types are: stack, volume, video, wholeslide`);
21187
+ throw new Error(`Invalid viewport type: ${viewportType}. Valid types are: stack, volume, video, wholeslide, ecg`);
20801
21188
  }
20802
21189
  ;// ../../../extensions/cornerstone/src/services/CornerstoneCacheService/CornerstoneCacheService.ts
20803
21190
  var _CornerstoneCacheService;
@@ -21104,15 +21491,24 @@ function getCornerstoneBlendMode(blendMode) {
21104
21491
  const AXIAL = 'axial';
21105
21492
  const SAGITTAL = 'sagittal';
21106
21493
  const CORONAL = 'coronal';
21494
+ const AXIAL_REFORMAT = 'axial_reformat';
21495
+ const SAGITTAL_REFORMAT = 'sagittal_reformat';
21496
+ const CORONAL_REFORMAT = 'coronal_reformat';
21107
21497
  function getCornerstoneOrientation(orientation) {
21108
21498
  if (orientation) {
21109
21499
  switch (orientation.toLowerCase()) {
21110
21500
  case AXIAL:
21111
21501
  return esm.Enums.OrientationAxis.AXIAL;
21502
+ case AXIAL_REFORMAT:
21503
+ return esm.Enums.OrientationAxis.AXIAL_REFORMAT;
21112
21504
  case SAGITTAL:
21113
21505
  return esm.Enums.OrientationAxis.SAGITTAL;
21506
+ case SAGITTAL_REFORMAT:
21507
+ return esm.Enums.OrientationAxis.SAGITTAL_REFORMAT;
21114
21508
  case CORONAL:
21115
21509
  return esm.Enums.OrientationAxis.CORONAL;
21510
+ case CORONAL_REFORMAT:
21511
+ return esm.Enums.OrientationAxis.CORONAL_REFORMAT;
21116
21512
  default:
21117
21513
  return esm.Enums.OrientationAxis.ACQUISITION;
21118
21514
  }
@@ -21385,6 +21781,32 @@ const CornerstoneViewportService_EVENTS = {
21385
21781
  };
21386
21782
  const MIN_STACK_VIEWPORTS_TO_ENQUEUE_RESIZE = 12;
21387
21783
  const MIN_VOLUME_VIEWPORTS_TO_ENQUEUE_RESIZE = 6;
21784
+ function getVolumeActorReferencedIds(viewport) {
21785
+ const actors = viewport.getActors?.() ?? [];
21786
+ return actors.filter(ac => ac.actor?.getClassName?.() === 'vtkVolume').map(ac => ac.referencedId).filter(Boolean);
21787
+ }
21788
+ function volumeIdPrefixesMatch(existingIds, prefixLen, targetIds) {
21789
+ if (prefixLen > targetIds.length) {
21790
+ return false;
21791
+ }
21792
+ for (let i = 0; i < prefixLen; i++) {
21793
+ if (existingIds[i] !== targetIds[i]) {
21794
+ return false;
21795
+ }
21796
+ }
21797
+ return true;
21798
+ }
21799
+
21800
+ /**
21801
+ * Returns true when the viewport type matches a volume-based presentation (ORTHOGRAPHIC or VOLUME_3D).
21802
+ */
21803
+ function viewportMatchesDesiredVolumePresentation(viewport, desiredViewportInfo) {
21804
+ const desiredType = desiredViewportInfo.getViewportType();
21805
+ if (viewport.type !== desiredType) {
21806
+ return false;
21807
+ }
21808
+ return desiredType === esm.Enums.ViewportType.ORTHOGRAPHIC || desiredType === esm.Enums.ViewportType.VOLUME_3D;
21809
+ }
21388
21810
  const WITH_NAVIGATION = {
21389
21811
  withNavigation: true,
21390
21812
  withOrientation: false
@@ -22072,6 +22494,15 @@ class CornerstoneViewportService extends src/* PubSubService */.Rc {
22072
22494
  /**
22073
22495
  * Sets the image data for the given viewport.
22074
22496
  */
22497
+ async _setEcgViewport(viewport, viewportData) {
22498
+ const [displaySet] = viewportData.data;
22499
+ const imageId = displaySet.imageIds?.[0];
22500
+ if (!imageId) {
22501
+ console.error('[CornerstoneViewportService] ECG display set has no imageId');
22502
+ return;
22503
+ }
22504
+ return viewport.setEcg(imageId);
22505
+ }
22075
22506
  async _setOtherViewport(viewport, viewportData, viewportInfo, _presentations = {}) {
22076
22507
  const [displaySet] = viewportData.data;
22077
22508
  return viewport.setDataIds(displaySet.imageIds, {
@@ -22140,32 +22571,25 @@ class CornerstoneViewportService extends src/* PubSubService */.Rc {
22140
22571
  if (initialImageIndexToUse === undefined || initialImageIndexToUse === null || initialImageIndexToUse < 0) {
22141
22572
  initialImageIndexToUse = this._getInitialImageIndexForViewport(viewportInfo, imageIds) || 0;
22142
22573
  }
22143
- return viewport.setStack(imageIds, initialImageIndexToUse).then(() => {
22574
+ await viewport.setStack(imageIds, initialImageIndexToUse);
22575
+ viewport.setProperties({
22576
+ ...properties
22577
+ });
22578
+ this.setPresentations(viewport.id, presentations, viewportInfo);
22579
+ await this._addOverlayRepresentations(overlayProcessingResults);
22580
+ if (displayArea) {
22581
+ viewport.setDisplayArea(displayArea);
22582
+ }
22583
+ if (rotation) {
22144
22584
  viewport.setProperties({
22145
- ...properties
22585
+ rotation
22146
22586
  });
22147
- this.setPresentations(viewport.id, presentations, viewportInfo);
22148
- if (overlayProcessingResults?.length) {
22149
- overlayProcessingResults.forEach(overlayProcessingResult => {
22150
- if (overlayProcessingResult?.addOverlayFn) {
22151
- overlayProcessingResult.addOverlayFn();
22152
- }
22153
- });
22154
- }
22155
- if (displayArea) {
22156
- viewport.setDisplayArea(displayArea);
22157
- }
22158
- if (rotation) {
22159
- viewport.setProperties({
22160
- rotation
22161
- });
22162
- }
22163
- if (flipHorizontal) {
22164
- viewport.setCamera({
22165
- flipHorizontal: true
22166
- });
22167
- }
22168
- });
22587
+ }
22588
+ if (flipHorizontal) {
22589
+ viewport.setCamera({
22590
+ flipHorizontal: true
22591
+ });
22592
+ }
22169
22593
  }
22170
22594
  _getInitialImageIndexForViewport(viewportInfo, imageIds) {
22171
22595
  const initialImageOptions = viewportInfo.getInitialImageOptions();
@@ -22388,16 +22812,34 @@ class CornerstoneViewportService extends src/* PubSubService */.Rc {
22388
22812
  }
22389
22813
  });
22390
22814
  }
22391
- await viewport.setVolumes(volumeInputArray);
22392
- if (overlayProcessingResults?.length) {
22393
- overlayProcessingResults.forEach(({
22394
- addOverlayFn
22395
- }) => {
22396
- if (addOverlayFn) {
22397
- addOverlayFn();
22815
+ const baseVolumeInputs = filteredVolumeInputArray.map(({
22816
+ volumeInput
22817
+ }) => volumeInput);
22818
+ const nextBaseVolumeIds = baseVolumeInputs.map(v => v.volumeId);
22819
+ const existingVolumeIds = getVolumeActorReferencedIds(viewport);
22820
+ let skippedIdenticalBaseVolumes = false;
22821
+ if (baseVolumeInputs.length) {
22822
+ const singleBaseViewport = nextBaseVolumeIds.length === 1;
22823
+
22824
+ // Only skip setVolumes() when the viewport type already matches the desired OHIF type
22825
+ // (ORTHOGRAPHIC / VOLUME_3D); otherwise a stack → MPR switch with the same volumeId
22826
+ // would incorrectly skip rebuilding the viewport.
22827
+ if (singleBaseViewport && existingVolumeIds.length >= nextBaseVolumeIds.length && volumeIdPrefixesMatch(existingVolumeIds, nextBaseVolumeIds.length, nextBaseVolumeIds) && viewportMatchesDesiredVolumePresentation(viewport, viewportInfo)) {
22828
+ // Same primary volume already loaded (e.g. labelmap / extra actors after it) — avoid
22829
+ // setVolumes(), which tears down all actors and blanks MPR during SEG hydrate.
22830
+ skippedIdenticalBaseVolumes = true;
22831
+ } else if (existingVolumeIds.length && nextBaseVolumeIds.length > existingVolumeIds.length && volumeIdPrefixesMatch(existingVolumeIds, existingVolumeIds.length, nextBaseVolumeIds) && typeof viewport.addVolumes === 'function') {
22832
+ const toAdd = baseVolumeInputs.slice(existingVolumeIds.length);
22833
+ if (toAdd.length) {
22834
+ await viewport.addVolumes(toAdd);
22398
22835
  }
22399
- });
22836
+ } else {
22837
+ await viewport.setVolumes(baseVolumeInputs);
22838
+ }
22839
+ } else if (volumeInputArray.length) {
22840
+ await viewport.setVolumes(volumeInputArray);
22400
22841
  }
22842
+ await this._addOverlayRepresentations(overlayProcessingResults);
22401
22843
  viewport.render();
22402
22844
  volumesProperties.forEach(({
22403
22845
  properties,
@@ -22409,7 +22851,10 @@ class CornerstoneViewportService extends src/* PubSubService */.Rc {
22409
22851
  });
22410
22852
  });
22411
22853
  this.setPresentations(viewport.id, presentations);
22412
- if (!presentations.positionPresentation) {
22854
+ // Presentations apply segmentation (hydrated labelmap etc.) after the render above — redraw so
22855
+ // every orthographic/3D tile shows the updated scene (fixes MPR siblings blank after SEG hydrate).
22856
+ viewport.render();
22857
+ if (!presentations.positionPresentation && !skippedIdenticalBaseVolumes) {
22413
22858
  const imageIndex = this._getInitialImageIndexForViewport(viewportInfo);
22414
22859
  if (imageIndex !== undefined) {
22415
22860
  esm.utilities.jumpToSlice(viewport.element, {
@@ -22460,7 +22905,7 @@ class CornerstoneViewportService extends src/* PubSubService */.Rc {
22460
22905
  const {
22461
22906
  predecessorImageId
22462
22907
  } = displaySet;
22463
- segmentationService.addSegmentationRepresentation(viewport.id, {
22908
+ const segmentationRepresentationPromise = segmentationService.addSegmentationRepresentation(viewport.id, {
22464
22909
  segmentationId,
22465
22910
  predecessorImageId,
22466
22911
  type: representationType,
@@ -22468,11 +22913,21 @@ class CornerstoneViewportService extends src/* PubSubService */.Rc {
22468
22913
  blendMode: viewport?.getBlendMode?.() === 1 ? dist_esm_enums.BlendModes.LABELMAP_EDGE_PROJECTION_BLEND : undefined
22469
22914
  }
22470
22915
  });
22471
-
22472
22916
  // store the segmentation presentation id in the viewport info
22473
22917
  this.storePresentation({
22474
22918
  viewportId: viewport.id
22475
22919
  });
22920
+ return segmentationRepresentationPromise;
22921
+ }
22922
+ async _addOverlayRepresentations(overlayProcessingResults) {
22923
+ if (!overlayProcessingResults?.length) {
22924
+ return;
22925
+ }
22926
+ for (const overlayProcessingResult of overlayProcessingResults) {
22927
+ if (overlayProcessingResult?.addOverlayFn) {
22928
+ await overlayProcessingResult.addOverlayFn();
22929
+ }
22930
+ }
22476
22931
  }
22477
22932
 
22478
22933
  // Todo: keepCamera is an interim solution until we have a better solution for
@@ -22507,6 +22962,9 @@ class CornerstoneViewportService extends src/* PubSubService */.Rc {
22507
22962
  if ([esm.VolumeViewport, esm.VolumeViewport3D].some(type => viewport instanceof type)) {
22508
22963
  return this._setVolumeViewport(viewport, viewportData, viewportInfo, presentations);
22509
22964
  }
22965
+ if (viewport instanceof esm.ECGViewport) {
22966
+ return this._setEcgViewport(viewport, viewportData);
22967
+ }
22510
22968
  return this._setOtherViewport(viewport, viewportData, viewportInfo, presentations);
22511
22969
  }
22512
22970
 
@@ -22549,8 +23007,8 @@ class CornerstoneViewportService extends src/* PubSubService */.Rc {
22549
23007
  if (!displaySet) {
22550
23008
  return;
22551
23009
  }
22552
- if (displaySet.frameOfReferenceUID) {
22553
- return displaySet.frameOfReferenceUID;
23010
+ if (displaySet.FrameOfReferenceUID) {
23011
+ return displaySet.FrameOfReferenceUID;
22554
23012
  }
22555
23013
  if (displaySet.Modality === 'SEG') {
22556
23014
  const {
@@ -22728,6 +23186,8 @@ CornerstoneViewportService.REGISTRATION = {
22728
23186
  }
22729
23187
  };
22730
23188
  /* harmony default export */ const ViewportService_CornerstoneViewportService = (CornerstoneViewportService);
23189
+ // EXTERNAL MODULE: ../../../extensions/cornerstone/src/utils/getDataIdForViewport.ts
23190
+ var getDataIdForViewport = __webpack_require__(67142);
22731
23191
  ;// ../../../extensions/cornerstone/src/types/Colorbar.ts
22732
23192
  // Position options
22733
23193
 
@@ -22770,6 +23230,7 @@ var _ColorbarService;
22770
23230
 
22771
23231
 
22772
23232
 
23233
+
22773
23234
  class ColorbarService extends src/* PubSubService */.Rc {
22774
23235
  constructor(servicesManager) {
22775
23236
  super(ColorbarService.EVENTS);
@@ -22793,23 +23254,6 @@ class ColorbarService extends src/* PubSubService */.Rc {
22793
23254
  this.servicesManager = servicesManager;
22794
23255
  }
22795
23256
 
22796
- /**
22797
- * Gets the appropriate data ID for a viewport and display set
22798
- * @param viewport - The viewport instance
22799
- * @param displaySetInstanceUID - The display set instance UID to identify data
22800
- * @returns The appropriate data ID for the viewport type (volumeId for volume viewports, undefined for stack)
22801
- */
22802
- getDataIdForViewport(viewport, displaySetInstanceUID) {
22803
- // For volume viewports, find the matching volumeId
22804
- if (viewport.getAllVolumeIds) {
22805
- const volumeIds = viewport.getAllVolumeIds() || [];
22806
- return volumeIds.length > 0 ? volumeIds.find(id => id.includes(displaySetInstanceUID)) || undefined : undefined;
22807
- }
22808
-
22809
- // For other viewports, no specific dataId is needed for now
22810
- return undefined;
22811
- }
22812
-
22813
23257
  /**
22814
23258
  * Adds a colorbar to a specific viewport identified by `viewportId`, using the provided `displaySetInstanceUIDs` and `options`.
22815
23259
  * This method prepares the colorbar state that will be used by the ViewportColorbarsContainer component.
@@ -22841,7 +23285,7 @@ class ColorbarService extends src/* PubSubService */.Rc {
22841
23285
  if (displaySet.isOverlayDisplaySet) {
22842
23286
  return;
22843
23287
  }
22844
- const dataId = this.getDataIdForViewport(viewport, displaySetInstanceUID);
23288
+ const dataId = (0,getDataIdForViewport/* getDataIdForViewport */.V)(viewport, displaySetInstanceUID);
22845
23289
  const properties = dataId ? viewport.getProperties(dataId) : viewport.getProperties();
22846
23290
  const colormap = properties?.colormap;
22847
23291
  if (activeColormapName && !colormap) {
@@ -22979,7 +23423,7 @@ class ColorbarService extends src/* PubSubService */.Rc {
22979
23423
  }
22980
23424
 
22981
23425
  // Get the appropriate dataId for this viewport/displaySet combination
22982
- const dataId = this.getDataIdForViewport(viewport, displaySetInstanceUID);
23426
+ const dataId = (0,getDataIdForViewport/* getDataIdForViewport */.V)(viewport, displaySetInstanceUID);
22983
23427
 
22984
23428
  // Set properties with or without dataId based on what the viewport supports
22985
23429
  viewport.setProperties({
@@ -23005,6 +23449,54 @@ ColorbarService.REGISTRATION = {
23005
23449
  ;// ../../../extensions/cornerstone/src/services/ColorbarService/index.ts
23006
23450
 
23007
23451
  /* harmony default export */ const services_ColorbarService = (ColorbarService);
23452
+ ;// ../../../extensions/cornerstone/src/services/ViewedDataService/ViewedDataService.ts
23453
+ var _ViewedDataService;
23454
+
23455
+ class ViewedDataService extends src/* PubSubService */.Rc {
23456
+ constructor() {
23457
+ super(ViewedDataService.EVENTS);
23458
+ this.viewedDataIds = new Set();
23459
+ }
23460
+ markDataViewed(dataId) {
23461
+ if (!dataId || this.viewedDataIds.has(dataId)) {
23462
+ return;
23463
+ }
23464
+ this.viewedDataIds.add(dataId);
23465
+ this._broadcastEvent(this.EVENTS.VIEWED_DATA_CHANGED, {
23466
+ viewedDataId: dataId
23467
+ });
23468
+ }
23469
+ isDataViewed(dataId) {
23470
+ if (!dataId) {
23471
+ return false;
23472
+ }
23473
+ return this.viewedDataIds.has(dataId);
23474
+ }
23475
+ clearViewedData() {
23476
+ this.viewedDataIds.clear();
23477
+ this._broadcastEvent(this.EVENTS.VIEWED_DATA_CHANGED, {
23478
+ viewedDataCleared: true
23479
+ });
23480
+ }
23481
+ subscribeViewedDataChanges(listener) {
23482
+ return this.subscribe(this.EVENTS.VIEWED_DATA_CHANGED, listener);
23483
+ }
23484
+ }
23485
+ _ViewedDataService = ViewedDataService;
23486
+ ViewedDataService.EVENTS = {
23487
+ VIEWED_DATA_CHANGED: 'event::viewedDataChanged'
23488
+ };
23489
+ ViewedDataService.REGISTRATION = {
23490
+ name: 'viewedDataService',
23491
+ altName: 'ViewedDataService',
23492
+ create: () => {
23493
+ return new _ViewedDataService();
23494
+ }
23495
+ };
23496
+ /* harmony default export */ const ViewedDataService_ViewedDataService = (ViewedDataService);
23497
+ ;// ../../../extensions/cornerstone/src/services/ViewedDataService/index.ts
23498
+
23499
+ /* harmony default export */ const services_ViewedDataService = (ViewedDataService_ViewedDataService);
23008
23500
  ;// ../../../extensions/cornerstone/src/types/Presentation.ts
23009
23501
 
23010
23502
 
@@ -23249,12 +23741,114 @@ const createFrameViewSynchronizer = synchronizerName => {
23249
23741
 
23250
23742
  // EXTERNAL MODULE: ../../../node_modules/dcmjs/build/dcmjs.es.js
23251
23743
  var dcmjs_es = __webpack_require__(5842);
23744
+ ;// ../../../extensions/cornerstone/src/utils/ecgMetadata.ts
23745
+ /**
23746
+ * Decode a multiplexed Int16 buffer into per-channel arrays.
23747
+ * Layout: sample0ch0, sample0ch1 ... sample0chN, sample1ch0, …
23748
+ * Note: DICOM ECG data is canonically SS (signed short). The sampleInterpretation
23749
+ * field is forwarded to ECGViewport for its own use; the raw buffer is always
23750
+ * treated as Int16 because Cornerstone ECGViewport expects Int16Array[].
23751
+ */
23752
+ function decodeInt16Multiplex(buffer, numberOfChannels, numberOfSamples) {
23753
+ const src = new Int16Array(buffer);
23754
+ const channels = [];
23755
+ for (let ch = 0; ch < numberOfChannels; ch++) {
23756
+ const out = new Int16Array(numberOfSamples);
23757
+ for (let s = 0; s < numberOfSamples; s++) {
23758
+ out[s] = src[s * numberOfChannels + ch];
23759
+ }
23760
+ channels.push(out);
23761
+ }
23762
+ return channels;
23763
+ }
23764
+
23765
+ /**
23766
+ * Decode a base64 InlineBinary string into a raw ArrayBuffer.
23767
+ */
23768
+ function base64ToArrayBuffer(base64) {
23769
+ const binaryStr = atob(base64);
23770
+ const bytes = new Uint8Array(binaryStr.length);
23771
+ for (let i = 0; i < binaryStr.length; i++) {
23772
+ bytes[i] = binaryStr.charCodeAt(i);
23773
+ }
23774
+ return bytes.buffer;
23775
+ }
23776
+ /**
23777
+ * Parse the naturalized DICOM instance's WaveformSequence and build the ecgModule
23778
+ * that Cornerstone's ECGViewport.setEcg() expects via
23779
+ * metaData.get(MetadataModules.ECG, imageId).
23780
+ *
23781
+ * Returns null if the instance has no WaveformSequence.
23782
+ */
23783
+ function buildEcgModule(instance, userAuthenticationService) {
23784
+ const waveformGroups = instance?.WaveformSequence;
23785
+ if (!waveformGroups?.length) {
23786
+ return null;
23787
+ }
23788
+
23789
+ // Use the first (and typically only) multiplex group
23790
+ const group = waveformGroups[0];
23791
+ const numberOfChannels = group.NumberOfWaveformChannels ?? 0;
23792
+ const numberOfSamples = group.NumberOfWaveformSamples ?? 0;
23793
+ const samplingFrequency = group.SamplingFrequency ?? 1;
23794
+ const bitsAllocated = group.WaveformBitsAllocated ?? 16;
23795
+ const sampleInterpretation = group.WaveformSampleInterpretation ?? 'SS';
23796
+ const multiplexGroupLabel = group.MultiplexGroupLabel ?? '';
23797
+ const channelDefinitionSequence = (group.ChannelDefinitionSequence ?? []).map(ch => ({
23798
+ channelSourceSequence: {
23799
+ codeMeaning: ch?.ChannelSourceSequence?.[0]?.CodeMeaning ?? ch?.ChannelSourceSequence?.[0]?.codeMeaning ?? ''
23800
+ }
23801
+ }));
23802
+ const retrieveBulkData = async () => {
23803
+ const waveformData = group.WaveformData;
23804
+ if (!waveformData) {
23805
+ console.warn('[ECGViewport] No WaveformData found on instance');
23806
+ return [];
23807
+ }
23808
+ let buffer;
23809
+ if (waveformData.InlineBinary) {
23810
+ buffer = base64ToArrayBuffer(waveformData.InlineBinary);
23811
+ } else if (waveformData.BulkDataURI) {
23812
+ const headers = {
23813
+ Accept: 'application/octet-stream'
23814
+ };
23815
+ const authHeader = userAuthenticationService?.getAuthorizationHeader?.();
23816
+ if (authHeader) {
23817
+ Object.assign(headers, authHeader);
23818
+ }
23819
+ const response = await fetch(waveformData.BulkDataURI, {
23820
+ headers
23821
+ });
23822
+ if (!response.ok) {
23823
+ throw new Error(`[ECGViewport] Failed to fetch waveform BulkDataURI: ${response.status}`);
23824
+ }
23825
+ buffer = await response.arrayBuffer();
23826
+ } else {
23827
+ console.warn('[ECGViewport] WaveformData has no InlineBinary or BulkDataURI');
23828
+ return [];
23829
+ }
23830
+ return decodeInt16Multiplex(buffer, numberOfChannels, numberOfSamples);
23831
+ };
23832
+ return {
23833
+ numberOfWaveformChannels: numberOfChannels,
23834
+ numberOfWaveformSamples: numberOfSamples,
23835
+ samplingFrequency,
23836
+ waveformBitsAllocated: bitsAllocated,
23837
+ waveformSampleInterpretation: sampleInterpretation,
23838
+ multiplexGroupLabel,
23839
+ channelDefinitionSequence,
23840
+ waveformData: {
23841
+ retrieveBulkData
23842
+ }
23843
+ };
23844
+ }
23252
23845
  ;// ../../../extensions/cornerstone/src/getSopClassHandlerModule.js
23253
23846
 
23254
23847
 
23255
23848
 
23256
23849
 
23257
23850
 
23851
+
23258
23852
  const {
23259
23853
  MetadataModules
23260
23854
  } = esm.Enums;
@@ -23265,9 +23859,9 @@ const {
23265
23859
  denaturalizeDataset
23266
23860
  } = dcmjs_es/* default.data */.Ay.data.DicomMetaDictionary;
23267
23861
  const {
23268
- transferDenaturalizedDataset,
23269
- fixMultiValueKeys
23270
- } = default_src.dicomWebUtils;
23862
+ /* transferDenaturalizedDataset */ "If": transferDenaturalizedDataset,
23863
+ /* fixMultiValueKeys */ "Uk": fixMultiValueKeys
23864
+ } = default_src/* dicomWebUtils */.CA;
23271
23865
  const SOP_CLASS_UIDS = {
23272
23866
  VL_WHOLE_SLIDE_MICROSCOPY_IMAGE_STORAGE: '1.2.840.10008.5.1.4.1.1.77.1.6'
23273
23867
  };
@@ -23393,8 +23987,92 @@ function getDicomMicroscopySopClassHandler({
23393
23987
  getDisplaySetsFromSeries
23394
23988
  };
23395
23989
  }
23990
+
23991
+ /**
23992
+ * DICOM Waveform SOP Class UIDs for ECG / cardiac electrophysiology.
23993
+ * Reference: https://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_B.5.html
23994
+ */
23995
+ const ECG_SOP_CLASS_UIDS = {
23996
+ TWELVE_LEAD_ECG_WAVEFORM_STORAGE: '1.2.840.10008.5.1.4.1.1.9.1.1',
23997
+ GENERAL_ECG_WAVEFORM_STORAGE: '1.2.840.10008.5.1.4.1.1.9.1.2',
23998
+ AMBULATORY_ECG_WAVEFORM_STORAGE: '1.2.840.10008.5.1.4.1.1.9.1.3',
23999
+ HEMODYNAMIC_WAVEFORM_STORAGE: '1.2.840.10008.5.1.4.1.1.9.2.1',
24000
+ CARDIAC_ELECTROPHYSIOLOGY_WAVEFORM_STORAGE: '1.2.840.10008.5.1.4.1.1.9.3.1'
24001
+ };
24002
+ const ecgSopClassUids = Object.values(ECG_SOP_CLASS_UIDS);
24003
+ const DicomEcgSOPClassHandlerId = '@ohif/extension-cornerstone.sopClassHandlerModule.DicomEcgSopClassHandler';
24004
+ function _getEcgDisplaySetsFromSeries(instances, servicesManager) {
24005
+ const {
24006
+ userAuthenticationService
24007
+ } = servicesManager.services;
24008
+ return instances.map(instance => {
24009
+ const {
24010
+ Modality,
24011
+ SOPInstanceUID
24012
+ } = instance;
24013
+ const {
24014
+ SeriesDescription,
24015
+ SeriesNumber,
24016
+ SeriesDate
24017
+ } = instance;
24018
+ const {
24019
+ SeriesInstanceUID,
24020
+ StudyInstanceUID,
24021
+ SOPClassUID
24022
+ } = instance;
24023
+ const imageId = instance.imageId;
24024
+
24025
+ // Register ECG metadata in the OHIF metadata provider so that
24026
+ // Cornerstone's ECGViewport can retrieve it via metaData.get('ecgModule', imageId).
24027
+ if (imageId) {
24028
+ const ecgModule = buildEcgModule(instance, userAuthenticationService);
24029
+ if (ecgModule) {
24030
+ esm.utilities.genericMetadataProvider.addRaw(imageId, {
24031
+ type: MetadataModules.ECG,
24032
+ metadata: ecgModule
24033
+ });
24034
+ }
24035
+ }
24036
+ return {
24037
+ Modality,
24038
+ displaySetInstanceUID: getSopClassHandlerModule_utils.guid(),
24039
+ SeriesDescription,
24040
+ SeriesNumber,
24041
+ SeriesDate,
24042
+ SOPInstanceUID,
24043
+ SeriesInstanceUID,
24044
+ StudyInstanceUID,
24045
+ SOPClassHandlerId: DicomEcgSOPClassHandlerId,
24046
+ SOPClassUID,
24047
+ referencedImages: null,
24048
+ measurements: null,
24049
+ viewportType: esm.Enums.ViewportType.ECG,
24050
+ instances: [instance],
24051
+ instance,
24052
+ thumbnailSrc: null,
24053
+ isDerivedDisplaySet: false,
24054
+ isLoaded: false,
24055
+ sopClassUids: ecgSopClassUids,
24056
+ numImageFrames: 0,
24057
+ numInstances: 1,
24058
+ imageIds: imageId ? [imageId] : [],
24059
+ supportsWindowLevel: false,
24060
+ label: SeriesDescription || 'ECG'
24061
+ };
24062
+ });
24063
+ }
24064
+ function getDicomEcgSopClassHandler({
24065
+ servicesManager
24066
+ }) {
24067
+ const getDisplaySetsFromSeries = instances => _getEcgDisplaySetsFromSeries(instances, servicesManager);
24068
+ return {
24069
+ name: 'DicomEcgSopClassHandler',
24070
+ sopClassUids: ecgSopClassUids,
24071
+ getDisplaySetsFromSeries
24072
+ };
24073
+ }
23396
24074
  function getSopClassHandlerModule(params) {
23397
- return [getDicomMicroscopySopClassHandler(params)];
24075
+ return [getDicomMicroscopySopClassHandler(params), getDicomEcgSopClassHandler(params)];
23398
24076
  }
23399
24077
  // EXTERNAL MODULE: ../../../extensions/cornerstone/src/hooks/useActiveViewportSegmentationRepresentations.ts
23400
24078
  var useActiveViewportSegmentationRepresentations = __webpack_require__(9234);
@@ -23424,7 +24102,7 @@ function SegmentationUtilityButton(props) {
23424
24102
  isActive,
23425
24103
  id
23426
24104
  } = props;
23427
- const activeSegmentationUtility = (0,default_src.useUIStateStore)(store => store.uiState.activeSegmentationUtility);
24105
+ const activeSegmentationUtility = (0,default_src/* useUIStateStore */.FS)(store => store.uiState.activeSegmentationUtility);
23428
24106
  const toolButtonClassName = (0,ui_next_src.cn)('w-7 h-7 text-primary hover:text-primary hover:!bg-primary/30', className, isActive && 'bg-primary/30');
23429
24107
  const handleMouseDownCapture = (0,react.useCallback)(event => {
23430
24108
  if (activeSegmentationUtility === id) {
@@ -23555,7 +24233,7 @@ function PanelSegmentation({
23555
24233
  segmentationsWithRepresentations,
23556
24234
  disabled
23557
24235
  } = (0,useActiveViewportSegmentationRepresentations/* useActiveViewportSegmentationRepresentations */.c)();
23558
- const setUIState = (0,default_src.useUIStateStore)(store => store.setUIState);
24236
+ const setUIState = (0,default_src/* useUIStateStore */.FS)(store => store.setUIState);
23559
24237
 
23560
24238
  // useEffect for handling clicks on any of the non-active viewports.
23561
24239
  // The ViewportGrid stops the propagation of pointer/mouse events
@@ -23816,7 +24494,7 @@ function PanelSegmentation({
23816
24494
  IconContainer: components_SegmentationUtilityButton
23817
24495
  }, /*#__PURE__*/react.createElement("div", {
23818
24496
  className: "flex flex-wrap gap-[3px] bg-transparent pb-[2px] pl-[8px] pt-[6px]"
23819
- }, /*#__PURE__*/react.createElement(default_src.Toolbar, {
24497
+ }, /*#__PURE__*/react.createElement(default_src/* Toolbar */.M7, {
23820
24498
  buttonSection: buttonSection
23821
24499
  })));
23822
24500
  };
@@ -24343,12 +25021,12 @@ function DefaultAccordion(props) {
24343
25021
  if (!allChildren || !groups) {
24344
25022
  return null;
24345
25023
  }
24346
- if (Boolean(asChild)) {
25024
+ if (asChild) {
24347
25025
  return /*#__PURE__*/react.cloneElement(props.children, props);
24348
25026
  }
24349
25027
  return /*#__PURE__*/react.createElement(ui_next_src/* Accordion */.nD3, {
24350
25028
  type: grouping.type || 'multiple',
24351
- className: "text-white",
25029
+ className: "text-foreground",
24352
25030
  defaultValue: defaultValue
24353
25031
  }, [...groups.entries()].map(([key, group]) => {
24354
25032
  return /*#__PURE__*/react.createElement(ui_next_src/* AccordionItem */.AsP, {
@@ -24826,7 +25504,7 @@ function PanelMeasurement(props) {
24826
25504
  return EmptyComponent ? /*#__PURE__*/react.createElement(EmptyComponent, {
24827
25505
  items: displayMeasurements
24828
25506
  }) : /*#__PURE__*/react.createElement("span", {
24829
- className: "text-white"
25507
+ className: "text-foreground"
24830
25508
  }, "No Measurements");
24831
25509
  }
24832
25510
  if (children) {
@@ -24891,7 +25569,7 @@ const getPanelModule = ({
24891
25569
  } = (0,es/* useTranslation */.Bd)('SegmentationPanel');
24892
25570
  const tKey = `${props.segmentationRepresentationTypes?.[0] ?? 'Segmentation'} tools`;
24893
25571
  const tValue = t(tKey);
24894
- return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(default_src.Toolbox, {
25572
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(default_src/* Toolbox */.OO, {
24895
25573
  buttonSectionId: toolSectionMap[props.segmentationRepresentationTypes?.[0]],
24896
25574
  title: tValue
24897
25575
  }), /*#__PURE__*/react.createElement(PanelSegmentation, {
@@ -25245,7 +25923,7 @@ function promptHydrationDialog({
25245
25923
  customizationService
25246
25924
  } = servicesManager.services;
25247
25925
  const extensionManager = servicesManager._extensionManager;
25248
- const appConfig = extensionManager._appConfig;
25926
+ const appConfig = extensionManager.appConfig;
25249
25927
 
25250
25928
  // Todo: make this use enum from the extension, we should move the enum
25251
25929
  const standardMode = appConfig?.measurementTrackingMode === 'standard';
@@ -25262,20 +25940,30 @@ function promptHydrationDialog({
25262
25940
  if (type === HydrationType.SEG) {
25263
25941
  // SEG needs setTimeout
25264
25942
  window.setTimeout(async () => {
25265
- const isHydrated = await hydrateCallback({
25266
- segDisplaySet: displaySet,
25267
- viewportId
25268
- });
25269
- resolve(isHydrated);
25943
+ try {
25944
+ const isHydrated = await hydrateCallback({
25945
+ segDisplaySet: displaySet,
25946
+ viewportId
25947
+ });
25948
+ resolve(isHydrated);
25949
+ } catch (error) {
25950
+ reject(error);
25951
+ }
25270
25952
  }, 0);
25271
25953
  } else if (type === HydrationType.RTSTRUCT) {
25272
25954
  // RT hydration
25273
- const isHydrated = await hydrateCallback({
25274
- rtDisplaySet: displaySet,
25275
- viewportId,
25276
- servicesManager
25277
- });
25278
- resolve(isHydrated);
25955
+ window.setTimeout(async () => {
25956
+ try {
25957
+ const isHydrated = await hydrateCallback({
25958
+ rtDisplaySet: displaySet,
25959
+ viewportId,
25960
+ servicesManager
25961
+ });
25962
+ resolve(isHydrated);
25963
+ } catch (error) {
25964
+ reject(error);
25965
+ }
25966
+ }, 0);
25279
25967
  } else if (type === HydrationType.SR) {
25280
25968
  // SR has a different result structure
25281
25969
  const hydrationResult = await hydrateCallback(displaySet);
@@ -25368,7 +26056,8 @@ const setUpSegmentationEventHandlers = ({
25368
26056
  const {
25369
26057
  segmentationService,
25370
26058
  customizationService,
25371
- displaySetService
26059
+ displaySetService,
26060
+ viewportGridService
25372
26061
  } = servicesManager.services;
25373
26062
  const {
25374
26063
  unsubscribe: unsubscribeSegmentationDataModifiedHandler
@@ -25413,12 +26102,42 @@ const setUpSegmentationEventHandlers = ({
25413
26102
  };
25414
26103
  displaySetService.addDisplaySets(segmentationDisplaySet);
25415
26104
  });
26105
+ const {
26106
+ unsubscribe: unsubscribeSegmentationRemoved
26107
+ } = segmentationService.subscribe(segmentationService.EVENTS.SEGMENTATION_REMOVED, ({
26108
+ segmentationId
26109
+ }) => {
26110
+ const displaySet = displaySetService.getDisplaySetByUID(segmentationId);
26111
+
26112
+ // Remove the display set layer from all viewports that have it
26113
+ if (displaySet) {
26114
+ const state = viewportGridService.getState();
26115
+ const viewports = state.viewports;
26116
+
26117
+ // Find all viewports that contain this segmentation's display set as a layer
26118
+ for (const [viewportId, viewport] of viewports.entries()) {
26119
+ const displaySetInstanceUIDs = viewport.displaySetInstanceUIDs || [];
26120
+ if (displaySetInstanceUIDs.includes(segmentationId)) {
26121
+ // Remove the display set layer from this viewport
26122
+ commandsManager.runCommand('removeDisplaySetLayer', {
26123
+ viewportId,
26124
+ displaySetInstanceUID: segmentationId
26125
+ });
26126
+ }
26127
+ }
26128
+
26129
+ // Delete the display set from the service if it was made in client
26130
+ if (displaySet.madeInClient) {
26131
+ displaySetService.deleteDisplaySet(segmentationId);
26132
+ }
26133
+ }
26134
+ });
25416
26135
  const {
25417
26136
  unsubscribeSelectedSegmentationsForViewportEvents
25418
26137
  } = setUpSelectedSegmentationsForViewportHandler({
25419
26138
  segmentationService
25420
26139
  });
25421
- const unsubscriptions = [unsubscribeSegmentationDataModifiedHandler, unsubscribeSegmentationModifiedHandler, unsubscribeSegmentationCreated, ...unsubscribeSelectedSegmentationsForViewportEvents];
26140
+ const unsubscriptions = [unsubscribeSegmentationDataModifiedHandler, unsubscribeSegmentationModifiedHandler, unsubscribeSegmentationCreated, unsubscribeSegmentationRemoved, ...unsubscribeSelectedSegmentationsForViewportEvents];
25422
26141
  return {
25423
26142
  unsubscriptions
25424
26143
  };
@@ -25561,7 +26280,7 @@ function PanelAccordionTrigger(props) {
25561
26280
  }, /*#__PURE__*/react.createElement("button", {
25562
26281
  onClick: onClickDefault.bind(props)
25563
26282
  }, /*#__PURE__*/react.createElement("span", {
25564
- className: `inline-flex rounded-l border-r border-black ${isActive ? 'bg-highlight' : 'bg-muted'}`
26283
+ className: `inline-flex rounded-l border-r border-background ${isActive ? 'bg-highlight' : 'bg-muted'}`
25565
26284
  }, count !== undefined ? /*#__PURE__*/react.createElement("span", {
25566
26285
  className: "px-2"
25567
26286
  }, count) : null, colorHex && /*#__PURE__*/react.createElement(ui_next_src/* ColorCircle */.cd8, {
@@ -25810,13 +26529,14 @@ function src_extends() { return src_extends = Object.assign ? Object.assign.bind
25810
26529
 
25811
26530
 
25812
26531
 
26532
+
25813
26533
 
25814
26534
 
25815
26535
  const {
25816
26536
  imageRetrieveMetadataProvider
25817
26537
  } = esm.utilities;
25818
26538
  const Component = /*#__PURE__*/react.lazy(() => {
25819
- return __webpack_require__.e(/* import() */ 147).then(__webpack_require__.bind(__webpack_require__, 30147));
26539
+ return __webpack_require__.e(/* import() */ 3754).then(__webpack_require__.bind(__webpack_require__, 33754));
25820
26540
  });
25821
26541
  const OHIFCornerstoneViewport = props => {
25822
26542
  return /*#__PURE__*/react.createElement(react.Suspense, {
@@ -25909,9 +26629,10 @@ const cornerstoneExtension = {
25909
26629
  useLutPresentationStore/* useLutPresentationStore */.I.getState().clearLutPresentationStore();
25910
26630
  usePositionPresentationStore/* usePositionPresentationStore */.q.getState().clearPositionPresentationStore();
25911
26631
  useSynchronizersStore/* useSynchronizersStore */.U.getState().clearSynchronizersStore();
25912
- default_src.useToggleOneUpViewportGridStore.getState().clearToggleOneUpViewportGridStore();
26632
+ default_src/* useToggleOneUpViewportGridStore */.Yd.getState().clearToggleOneUpViewportGridStore();
25913
26633
  useSegmentationPresentationStore/* useSegmentationPresentationStore */.v.getState().clearSegmentationPresentationStore();
25914
26634
  useSelectedSegmentationsForViewportStore.getState().clearSelectedSegmentationsForViewportStore();
26635
+ servicesManager.services.viewedDataService?.clearViewedData();
25915
26636
  segmentationService.removeAllSegmentations();
25916
26637
  },
25917
26638
  /**
@@ -25929,6 +26650,7 @@ const cornerstoneExtension = {
25929
26650
  servicesManager.registerService(services_SegmentationService.REGISTRATION);
25930
26651
  servicesManager.registerService(services_CornerstoneCacheService.REGISTRATION);
25931
26652
  servicesManager.registerService(services_ColorbarService.REGISTRATION);
26653
+ servicesManager.registerService(services_ViewedDataService.REGISTRATION);
25932
26654
  const {
25933
26655
  syncGroupService
25934
26656
  } = servicesManager.services;
@@ -26000,10 +26722,10 @@ const cornerstoneExtension = {
26000
26722
 
26001
26723
  /* harmony default export */ const cornerstone_src = (cornerstoneExtension);
26002
26724
 
26003
- /***/ }),
26725
+ /***/ },
26004
26726
 
26005
- /***/ 71353:
26006
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
26727
+ /***/ 71353
26728
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
26007
26729
 
26008
26730
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
26009
26731
  /* harmony export */ cL: () => (/* binding */ reset),
@@ -26042,10 +26764,10 @@ const reset = () => {
26042
26764
  };
26043
26765
 
26044
26766
 
26045
- /***/ }),
26767
+ /***/ },
26046
26768
 
26047
- /***/ 46026:
26048
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
26769
+ /***/ 46026
26770
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
26049
26771
 
26050
26772
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
26051
26773
  /* harmony export */ FG: () => (/* binding */ JOIN_STR),
@@ -26085,10 +26807,10 @@ const addUniqueIndex = (arr, key, viewports, isUpdatingSameViewport) => {
26085
26807
  };
26086
26808
 
26087
26809
 
26088
- /***/ }),
26810
+ /***/ },
26089
26811
 
26090
- /***/ 10182:
26091
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
26812
+ /***/ 10182
26813
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
26092
26814
 
26093
26815
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
26094
26816
  /* harmony export */ I: () => (/* binding */ useLutPresentationStore)
@@ -26200,10 +26922,10 @@ const useLutPresentationStore = (0,zustand__WEBPACK_IMPORTED_MODULE_0__/* .creat
26200
26922
  name: 'LutPresentationStore'
26201
26923
  }) : createLutPresentationStore);
26202
26924
 
26203
- /***/ }),
26925
+ /***/ },
26204
26926
 
26205
- /***/ 44646:
26206
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
26927
+ /***/ 44646
26928
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
26207
26929
 
26208
26930
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
26209
26931
  /* harmony export */ q: () => (/* binding */ usePositionPresentationStore)
@@ -26311,10 +27033,10 @@ const usePositionPresentationStore = (0,zustand__WEBPACK_IMPORTED_MODULE_0__/* .
26311
27033
  name: 'PositionPresentationStore'
26312
27034
  }) : createPositionPresentationStore);
26313
27035
 
26314
- /***/ }),
27036
+ /***/ },
26315
27037
 
26316
- /***/ 2847:
26317
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
27038
+ /***/ 2847
27039
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
26318
27040
 
26319
27041
 
26320
27042
  // EXPORTS
@@ -26426,20 +27148,34 @@ const _getSegmentationPresentationId = ({
26426
27148
  if (!viewport?.viewportOptions || !viewport.displaySetInstanceUIDs?.length) {
26427
27149
  return;
26428
27150
  }
27151
+ const {
27152
+ displaySetService
27153
+ } = servicesManager.services;
26429
27154
  const {
26430
27155
  displaySetInstanceUIDs,
26431
27156
  viewportOptions
26432
27157
  } = viewport;
27158
+
27159
+ // Match keys used by updateStoredSegmentationPresentation (referenced volume only).
27160
+ // Including overlay UIDs (e.g. SEG) produced ids like "MR&SEG" while the store
27161
+ // entry is under "MR", so hydrated segmentations never applied and viewports could mis-render.
27162
+ const nonOverlayUIDs = displaySetInstanceUIDs.filter(uid => {
27163
+ const ds = displaySetService.getDisplaySetByUID(uid);
27164
+ return ds && !ds.isOverlayDisplaySet;
27165
+ });
27166
+ if (!nonOverlayUIDs.length) {
27167
+ return;
27168
+ }
26433
27169
  let orientation = viewportOptions.orientation;
26434
27170
  if (!orientation) {
26435
27171
  // Calculate orientation from the viewport sample image
26436
- const displaySet = servicesManager.services.displaySetService.getDisplaySetByUID(displaySetInstanceUIDs[0]);
26437
- const sampleImage = displaySet.images?.[0];
27172
+ const displaySet = displaySetService.getDisplaySetByUID(nonOverlayUIDs[0]);
27173
+ const sampleImage = displaySet?.images?.[0];
26438
27174
  const imageOrientationPatient = sampleImage?.ImageOrientationPatient;
26439
27175
  orientation = getViewportOrientationFromImageOrientationPatient(imageOrientationPatient);
26440
27176
  }
26441
27177
  const segmentationPresentationArr = [];
26442
- segmentationPresentationArr.push(...displaySetInstanceUIDs);
27178
+ segmentationPresentationArr.push(...nonOverlayUIDs);
26443
27179
 
26444
27180
  // Uncomment if unique indexing is needed
26445
27181
  // addUniqueIndex(
@@ -26520,10 +27256,10 @@ const useSegmentationPresentationStore = (0,esm/* create */.vt)()(DEBUG_STORE ?
26520
27256
  name: 'Segmentation Presentation Store'
26521
27257
  }) : createSegmentationPresentationStore);
26522
27258
 
26523
- /***/ }),
27259
+ /***/ },
26524
27260
 
26525
- /***/ 68578:
26526
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
27261
+ /***/ 68578
27262
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
26527
27263
 
26528
27264
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
26529
27265
  /* harmony export */ U: () => (/* binding */ useSynchronizersStore)
@@ -26584,6 +27320,32 @@ const useSynchronizersStore = (0,zustand__WEBPACK_IMPORTED_MODULE_0__/* .create
26584
27320
  name: 'SynchronizersStore'
26585
27321
  }) : createSynchronizersStore);
26586
27322
 
26587
- /***/ })
27323
+ /***/ },
27324
+
27325
+ /***/ 67142
27326
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
27327
+
27328
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
27329
+ /* harmony export */ V: () => (/* binding */ getDataIdForViewport)
27330
+ /* harmony export */ });
27331
+ /**
27332
+ * Resolves the data ID (e.g. volumeId) for a viewport and display set.
27333
+ * For viewports with multiple volumes/actors, returns the id that matches the display set; otherwise undefined.
27334
+ * Use this to call viewport.getProperties(dataId) in a viewport-type-agnostic way.
27335
+ *
27336
+ * @param viewport - Viewport instance (stack, volume, or future types with optional getAllVolumeIds)
27337
+ * @param displaySetInstanceUID - Display set instance UID to match
27338
+ * @returns volumeId (or equivalent) for multi-actor viewports, undefined for single-actor
27339
+ */
27340
+ function getDataIdForViewport(viewport, displaySetInstanceUID) {
27341
+ const vp = viewport;
27342
+ if (typeof vp.getAllVolumeIds !== 'function') {
27343
+ return undefined;
27344
+ }
27345
+ const volumeIds = vp.getAllVolumeIds() || [];
27346
+ return volumeIds.length > 0 ? volumeIds.find(id => id.includes(displaySetInstanceUID)) ?? undefined : undefined;
27347
+ }
27348
+
27349
+ /***/ }
26588
27350
 
26589
27351
  }]);