@ohif/app 3.8.0-beta.66 → 3.8.0-beta.68

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 (65) hide show
  1. package/dist/{121.bundle.fda405f29003c308ce09.js → 121.bundle.a8fc45e3d88d0a8b82a8.js} +52 -75
  2. package/dist/{155.bundle.e9fdaa40010cc784f389.js → 155.bundle.7b87a2dbfaf2c36326bd.js} +7 -16
  3. package/dist/{188.bundle.67df9790c453b185fe1d.js → 188.bundle.022af4c804b855ca2f60.js} +2 -2
  4. package/dist/{638.bundle.4d7da6fe507df0000718.js → 2.bundle.962c8d8b57c4f94324b4.js} +46 -15
  5. package/dist/{295.bundle.57700cd41fd87e1521b4.js → 295.bundle.41d7b63be6a7d726b87e.js} +75 -86
  6. package/dist/{41.bundle.b7bf03502ac3e2ddca35.js → 41.bundle.ad4a012883642620e839.js} +16 -45
  7. package/dist/425.bundle.057226d5a1a2d7dcc391.js +2957 -0
  8. package/dist/425.css +2 -0
  9. package/dist/{448.bundle.0061f5280490e1a1aa88.js → 448.bundle.1d9b1b7379fba9b8e70b.js} +5 -5
  10. package/dist/{530.bundle.72d9812f117036615a38.js → 530.bundle.632dcb0d4f5266058c8b.js} +41 -67
  11. package/dist/{544.bundle.c3009e245ceb1554c70a.js → 544.bundle.df7870b43d7aa1faed39.js} +4 -4
  12. package/dist/{559.bundle.bb2c52834fb372399002.js → 559.bundle.54fea45a10d3aa002764.js} +4 -4
  13. package/dist/{889.bundle.edf546d8738c22b94be5.js → 574.bundle.3020ab733b8f07ec50a5.js} +1005 -49
  14. package/dist/{594.bundle.483843d38640164a9aca.js → 594.bundle.fad610af7dae0c2fb048.js} +4 -4
  15. package/dist/{701.bundle.285943aebfc0efe2b4f1.js → 595.bundle.dc733f6e58d41260ba40.js} +960 -61
  16. package/dist/{699.bundle.62990e46c235ab4785db.js → 699.bundle.78297d5204cdd274d097.js} +18 -25
  17. package/dist/{724.bundle.83a4176860f750353c0b.js → 724.bundle.171eb7665e96ac0ad109.js} +13 -71
  18. package/dist/{862.bundle.999931264956ced59b33.js → 862.bundle.27cb716917daad6afddc.js} +64 -83
  19. package/dist/{270.bundle.d7d6957c20f95c675b32.js → 889.bundle.43bac729645dcd445d23.js} +5 -5
  20. package/dist/{90.bundle.49b20161b4f864100085.js → 90.bundle.5e1e4b60b575b5be1369.js} +15 -25
  21. package/dist/{905.bundle.88010c612e910657883d.js → 905.bundle.a18b495f0a6769c5aff6.js} +2 -2
  22. package/dist/{907.bundle.1206d58ae62d26beaf30.js → 907.bundle.bec0deb8a4af3b4885a4.js} +2 -2
  23. package/dist/{961.bundle.b4d84dd80e4e1113de27.js → 961.bundle.2dd02c92ec591fec7924.js} +2 -2
  24. package/dist/{app.bundle.81c01fc2e11fa9b6ccb8.js → app.bundle.b36fed4fdc5235c8fd31.js} +2446 -745
  25. package/dist/app.bundle.css +6 -4
  26. package/dist/assets/images/CT-AAA.png +0 -0
  27. package/dist/assets/images/CT-AAA2.png +0 -0
  28. package/dist/assets/images/CT-Air.png +0 -0
  29. package/dist/assets/images/CT-Bone.png +0 -0
  30. package/dist/assets/images/CT-Bones.png +0 -0
  31. package/dist/assets/images/CT-Cardiac.png +0 -0
  32. package/dist/assets/images/CT-Cardiac2.png +0 -0
  33. package/dist/assets/images/CT-Cardiac3.png +0 -0
  34. package/dist/assets/images/CT-Chest-Contrast-Enhanced.png +0 -0
  35. package/dist/assets/images/CT-Chest-Vessels.png +0 -0
  36. package/dist/assets/images/CT-Coronary-Arteries-2.png +0 -0
  37. package/dist/assets/images/CT-Coronary-Arteries-3.png +0 -0
  38. package/dist/assets/images/CT-Coronary-Arteries.png +0 -0
  39. package/dist/assets/images/CT-Cropped-Volume-Bone.png +0 -0
  40. package/dist/assets/images/CT-Fat.png +0 -0
  41. package/dist/assets/images/CT-Liver-Vasculature.png +0 -0
  42. package/dist/assets/images/CT-Lung.png +0 -0
  43. package/dist/assets/images/CT-MIP.png +0 -0
  44. package/dist/assets/images/CT-Muscle.png +0 -0
  45. package/dist/assets/images/CT-Pulmonary-Arteries.png +0 -0
  46. package/dist/assets/images/CT-Soft-Tissue.png +0 -0
  47. package/dist/assets/images/DTI-FA-Brain.png +0 -0
  48. package/dist/assets/images/MR-Angio.png +0 -0
  49. package/dist/assets/images/MR-Default.png +0 -0
  50. package/dist/assets/images/MR-MIP.png +0 -0
  51. package/dist/assets/images/MR-T2-Brain.png +0 -0
  52. package/dist/assets/images/VolumeRendering.png +0 -0
  53. package/dist/index.html +1 -1
  54. package/dist/{polySeg.bundle.a97fc68de7599f9a9fdc.js → polySeg.bundle.e7b4c29fb9173e8567b8.js} +1 -1
  55. package/dist/sw.js +1 -1
  56. package/package.json +17 -17
  57. package/dist/339.bundle.526cede81f0a9bb248e6.js +0 -2591
  58. /package/dist/{164.bundle.3f877a2272b773332317.js → 164.bundle.6a75d9824ed0e87afd36.js} +0 -0
  59. /package/dist/{191.bundle.509480b6972209d2567c.js → 191.bundle.7d89c921abefd1140d50.js} +0 -0
  60. /package/dist/{638.css → 2.css} +0 -0
  61. /package/dist/{290.bundle.8b4d7dfbc7cfe418a0f1.js → 290.bundle.952de53057f98e2c5ef0.js} +0 -0
  62. /package/dist/{342.bundle.17ec05907f93624fd494.js → 342.bundle.6e49f63ea7cea4645c0a.js} +0 -0
  63. /package/dist/{504.bundle.6d203e80d4bd8a823059.js → 504.bundle.993d7e2dec36257d4ce4.js} +0 -0
  64. /package/dist/{889.css → 574.css} +0 -0
  65. /package/dist/{701.css → 595.css} +0 -0
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
- (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[889],{
2
+ (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[574],{
3
3
 
4
- /***/ 1889:
4
+ /***/ 71574:
5
5
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
6
6
 
7
7
  // ESM COMPAT FLAG
@@ -23,10 +23,10 @@ var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
23
23
  var esm = __webpack_require__(20767);
24
24
  // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 383 modules
25
25
  var dist_esm = __webpack_require__(50719);
26
- // EXTERNAL MODULE: ../../core/src/index.ts + 67 modules
27
- var src = __webpack_require__(78198);
28
- // EXTERNAL MODULE: ../../ui/src/index.js + 497 modules
29
- var ui_src = __webpack_require__(58046);
26
+ // EXTERNAL MODULE: ../../core/src/index.ts + 68 modules
27
+ var src = __webpack_require__(85073);
28
+ // EXTERNAL MODULE: ../../ui/src/index.js + 521 modules
29
+ var ui_src = __webpack_require__(59134);
30
30
  // EXTERNAL MODULE: ../../../extensions/cornerstone/src/state.ts
31
31
  var state = __webpack_require__(71353);
32
32
  ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.css
@@ -295,7 +295,13 @@ function CustomizableViewportOverlay({
295
295
  const topRightCustomization = customizationService.getModeCustomization('cornerstoneOverlayTopRight');
296
296
  const bottomLeftCustomization = customizationService.getModeCustomization('cornerstoneOverlayBottomLeft');
297
297
  const bottomRightCustomization = customizationService.getModeCustomization('cornerstoneOverlayBottomRight');
298
- const instance = (0,react.useMemo)(() => viewportData ? getViewportInstance(viewportData, imageIndex) : null, [viewportData, imageIndex]);
298
+ const instance = (0,react.useMemo)(() => {
299
+ if (viewportData != null) {
300
+ return _getViewportInstance(viewportData, imageIndex);
301
+ } else {
302
+ return null;
303
+ }
304
+ }, [viewportData, imageIndex]);
299
305
  const instanceNumber = (0,react.useMemo)(() => viewportData ? getInstanceNumber(viewportData, viewportId, imageIndex, cornerstoneViewportService) : null, [viewportData, viewportId, imageIndex, cornerstoneViewportService]);
300
306
 
301
307
  /**
@@ -402,7 +408,12 @@ function CustomizableViewportOverlay({
402
408
  const items = customization?.items ?? defaultItems;
403
409
  return /*#__PURE__*/react.createElement(react.Fragment, null, items.map((item, index) => /*#__PURE__*/react.createElement("div", {
404
410
  key: `${keyPrefix}_${index}`
405
- }, item?.condition ? item.condition() ? _renderOverlayItem(item) : null : _renderOverlayItem(item))));
411
+ }, item?.condition ? item.condition({
412
+ instance,
413
+ formatters: {
414
+ formatDate: formatDICOMDate
415
+ }
416
+ }) ? _renderOverlayItem(item) : null : _renderOverlayItem(item))));
406
417
  }, [_renderOverlayItem]);
407
418
  return /*#__PURE__*/react.createElement(ui_src/* ViewportOverlay */.pU, {
408
419
  topLeft:
@@ -410,6 +421,31 @@ function CustomizableViewportOverlay({
410
421
  * Inline default overlay items for a more standard expansion
411
422
  */
412
423
  getContent(topLeftCustomization, [{
424
+ id: 'StudyDate',
425
+ customizationType: 'ohif.overlayItem',
426
+ label: '',
427
+ title: 'Study date',
428
+ condition: ({
429
+ instance
430
+ }) => instance && instance.StudyDate,
431
+ contentF: ({
432
+ instance,
433
+ formatters: {
434
+ formatDate
435
+ }
436
+ }) => formatDate(instance.StudyDate)
437
+ }, {
438
+ id: 'SeriesDescription',
439
+ customizationType: 'ohif.overlayItem',
440
+ label: '',
441
+ title: 'Series description',
442
+ attribute: 'SeriesDescription',
443
+ condition: ({
444
+ instance
445
+ }) => instance && instance.SeriesDescription
446
+ }], 'topLeftOverlayItem'),
447
+ topRight: getContent(topRightCustomization, [], 'topRightOverlayItem'),
448
+ bottomLeft: getContent(bottomLeftCustomization, [{
413
449
  id: 'WindowLevel',
414
450
  customizationType: 'ohif.overlayItem.windowLevel'
415
451
  }, {
@@ -419,35 +455,26 @@ function CustomizableViewportOverlay({
419
455
  const activeToolName = toolGroupService.getActiveToolForViewport(viewportId);
420
456
  return activeToolName === 'Zoom';
421
457
  }
422
- }], 'topLeftOverlayItem'),
423
- topRight: getContent(topRightCustomization, [{
458
+ }], 'bottomLeftOverlayItem'),
459
+ bottomRight: getContent(bottomRightCustomization, [{
424
460
  id: 'InstanceNumber',
425
461
  customizationType: 'ohif.overlayItem.instanceNumber'
426
- }], 'topRightOverlayItem'),
427
- bottomLeft: getContent(bottomLeftCustomization, [null], 'bottomLeftOverlayItem'),
428
- bottomRight: getContent(bottomRightCustomization, [null], 'bottomRightOverlayItem')
462
+ }], 'bottomRightOverlayItem')
429
463
  });
430
464
  }
431
- const getViewportInstance = (viewportData, imageIndex) => {
432
- const {
433
- viewportType,
434
- data
435
- } = viewportData;
465
+ function _getViewportInstance(viewportData, imageIndex) {
436
466
  let imageId = null;
437
- switch (viewportType) {
438
- case dist_esm.Enums.ViewportType.STACK:
439
- imageId = data.imageIds[imageIndex];
440
- break;
441
- case dist_esm.Enums.ViewportType.ORTHOGRAPHIC:
442
- if (data?.length === 1) {
443
- imageId = data[0].imageIds[imageIndex];
444
- }
445
- break;
446
- default:
447
- break;
467
+ if (viewportData.viewportType === dist_esm.Enums.ViewportType.STACK) {
468
+ imageId = viewportData.data.imageIds[imageIndex];
469
+ } else if (viewportData.viewportType === dist_esm.Enums.ViewportType.ORTHOGRAPHIC) {
470
+ const volumes = viewportData.data;
471
+ if (volumes && volumes.length == 1) {
472
+ const volume = volumes[0];
473
+ imageId = volume.imageIds[imageIndex];
474
+ }
448
475
  }
449
476
  return imageId ? dist_esm.metaData.get('instance', imageId) || {} : {};
450
- };
477
+ }
451
478
  const getInstanceNumber = (viewportData, viewportId, imageIndex, cornerstoneViewportService) => {
452
479
  let instanceNumber;
453
480
  switch (viewportData.viewportType) {
@@ -541,11 +568,11 @@ function VOIOverlayItem({
541
568
  }, /*#__PURE__*/react.createElement("span", {
542
569
  className: "mr-1 shrink-0"
543
570
  }, "W:"), /*#__PURE__*/react.createElement("span", {
544
- className: "ml-1 mr-2 shrink-0 font-light"
571
+ className: "ml-1 mr-2 shrink-0"
545
572
  }, windowWidth.toFixed(0)), /*#__PURE__*/react.createElement("span", {
546
573
  className: "mr-1 shrink-0"
547
574
  }, "L:"), /*#__PURE__*/react.createElement("span", {
548
- className: "ml-1 shrink-0 font-light"
575
+ className: "ml-1 shrink-0"
549
576
  }, windowCenter.toFixed(0)));
550
577
  }
551
578
 
@@ -563,9 +590,7 @@ function ZoomOverlayItem({
563
590
  }
564
591
  }, /*#__PURE__*/react.createElement("span", {
565
592
  className: "mr-1 shrink-0"
566
- }, "Zoom:"), /*#__PURE__*/react.createElement("span", {
567
- className: "font-light"
568
- }, scale.toFixed(2), "x"));
593
+ }, "Zoom:"), /*#__PURE__*/react.createElement("span", null, scale.toFixed(2), "x"));
569
594
  }
570
595
 
571
596
  /**
@@ -587,9 +612,7 @@ function InstanceNumberOverlayItem({
587
612
  }
588
613
  }, /*#__PURE__*/react.createElement("span", {
589
614
  className: "mr-1 shrink-0"
590
- }, "I:"), /*#__PURE__*/react.createElement("span", {
591
- className: "font-light"
592
- }, instanceNumber !== undefined && instanceNumber !== null ? `${instanceNumber} (${imageIndex + 1}/${numberOfSlices})` : `${imageIndex + 1}/${numberOfSlices}`));
615
+ }, "I:"), /*#__PURE__*/react.createElement("span", null, instanceNumber !== undefined && instanceNumber !== null ? `${instanceNumber} (${imageIndex + 1}/${numberOfSlices})` : `${imageIndex + 1}/${numberOfSlices}`));
593
616
  }
594
617
  CustomizableViewportOverlay.propTypes = {
595
618
  viewportData: (prop_types_default()).object,
@@ -694,20 +717,15 @@ function ViewportOrientationMarkers({
694
717
  console.log('ViewportOrientationMarkers::No viewport');
695
718
  return null;
696
719
  }
697
- const backgroundColor = ohifViewport.getViewportOptions().background;
698
-
699
- // Todo: probably this can be done in a better way in which we identify bright
700
- // background
701
- const isLight = backgroundColor ? dist_esm.utilities.isEqual(backgroundColor, [1, 1, 1]) : false;
702
720
  return orientationMarkers.map((m, index) => /*#__PURE__*/react.createElement("div", {
703
- className: classnames_default()(`${m}-mid orientation-marker`, isLight ? 'text-[#726F7E]' : 'text-[#ccc]'),
721
+ className: classnames_default()('overlay-text', `${m}-mid orientation-marker`, 'text-aqua-pale', 'text-[13px]', 'leading-5'),
704
722
  key: `${m}-mid orientation-marker`
705
723
  }, /*#__PURE__*/react.createElement("div", {
706
724
  className: "orientation-marker-value"
707
725
  }, markers[m])));
708
726
  }, [viewportData, imageSliceData, rotation, flipVertical, flipHorizontal, orientationMarkers, element]);
709
727
  return /*#__PURE__*/react.createElement("div", {
710
- className: "ViewportOrientationMarkers noselect"
728
+ className: "ViewportOrientationMarkers select-none"
711
729
  }, markers);
712
730
  }
713
731
  ViewportOrientationMarkers.propTypes = {
@@ -1049,6 +1067,908 @@ function WrappedCinePlayer({
1049
1067
  ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/CinePlayer/index.ts
1050
1068
 
1051
1069
  /* harmony default export */ const components_CinePlayer = (CinePlayer);
1070
+ // EXTERNAL MODULE: ../../../extensions/cornerstone/src/contextProviders/ViewportActionCornersProvider.tsx
1071
+ var ViewportActionCornersProvider = __webpack_require__(76255);
1072
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/OHIFViewportActionCorners.tsx
1073
+
1074
+
1075
+
1076
+ function OHIFViewportActionCorners({
1077
+ viewportId
1078
+ }) {
1079
+ const [viewportActionCornersState] = (0,ViewportActionCornersProvider/* useViewportActionCornersContext */.R4)();
1080
+ if (!viewportActionCornersState[viewportId]) {
1081
+ return null;
1082
+ }
1083
+ return /*#__PURE__*/react.createElement(ui_src/* ViewportActionCorners */.R2, {
1084
+ cornerComponents: viewportActionCornersState[viewportId]
1085
+ });
1086
+ }
1087
+ /* harmony default export */ const components_OHIFViewportActionCorners = (OHIFViewportActionCorners);
1088
+ // EXTERNAL MODULE: ../../../node_modules/react-i18next/dist/es/index.js + 15 modules
1089
+ var es = __webpack_require__(80619);
1090
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/Colormap.tsx
1091
+
1092
+
1093
+
1094
+ function Colormap({
1095
+ colormaps,
1096
+ viewportId,
1097
+ displaySets,
1098
+ commandsManager,
1099
+ serviceManager
1100
+ }) {
1101
+ const {
1102
+ cornerstoneViewportService
1103
+ } = serviceManager.services;
1104
+ const [activeDisplaySet, setActiveDisplaySet] = (0,react.useState)(displaySets[0]);
1105
+ const [showPreview, setShowPreview] = (0,react.useState)(false);
1106
+ const [prePreviewColormap, setPrePreviewColormap] = (0,react.useState)(null);
1107
+ const showPreviewRef = (0,react.useRef)(showPreview);
1108
+ showPreviewRef.current = showPreview;
1109
+ const prePreviewColormapRef = (0,react.useRef)(prePreviewColormap);
1110
+ prePreviewColormapRef.current = prePreviewColormap;
1111
+ const activeDisplaySetRef = (0,react.useRef)(activeDisplaySet);
1112
+ activeDisplaySetRef.current = activeDisplaySet;
1113
+ const onSetColorLUT = (0,react.useCallback)(props => {
1114
+ // TODO: Better way to check if it's a fusion
1115
+ const oneOpacityColormaps = ['Grayscale', 'X Ray'];
1116
+ const opacity = displaySets.length > 1 && !oneOpacityColormaps.includes(props.colormap.name) ? 0.5 : 1;
1117
+ commandsManager.run({
1118
+ commandName: 'setViewportColormap',
1119
+ commandOptions: {
1120
+ ...props,
1121
+ opacity,
1122
+ immediate: true
1123
+ },
1124
+ context: 'CORNERSTONE'
1125
+ });
1126
+ }, [commandsManager]);
1127
+ const getViewportColormap = (viewportId, displaySet) => {
1128
+ const {
1129
+ displaySetInstanceUID
1130
+ } = displaySet;
1131
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1132
+ if (viewport instanceof dist_esm.StackViewport) {
1133
+ const {
1134
+ colormap
1135
+ } = viewport.getProperties();
1136
+ if (!colormap) {
1137
+ return colormaps.find(c => c.Name === 'Grayscale') || colormaps[0];
1138
+ }
1139
+ return colormap;
1140
+ }
1141
+ const actorEntries = viewport.getActors();
1142
+ const actorEntry = actorEntries.find(entry => entry.uid.includes(displaySetInstanceUID));
1143
+ const {
1144
+ colormap
1145
+ } = viewport.getProperties(actorEntry.uid);
1146
+ if (!colormap) {
1147
+ return colormaps.find(c => c.Name === 'Grayscale') || colormaps[0];
1148
+ }
1149
+ return colormap;
1150
+ };
1151
+ const buttons = (0,react.useMemo)(() => {
1152
+ return displaySets.map((displaySet, index) => ({
1153
+ children: displaySet.Modality,
1154
+ key: index,
1155
+ style: {
1156
+ minWidth: `calc(100% / ${displaySets.length})`
1157
+ }
1158
+ }));
1159
+ }, [displaySets]);
1160
+ (0,react.useEffect)(() => {
1161
+ setActiveDisplaySet(displaySets[displaySets.length - 1]);
1162
+ }, [displaySets]);
1163
+ return /*#__PURE__*/react.createElement(react.Fragment, null, buttons.length > 1 && /*#__PURE__*/react.createElement("div", {
1164
+ className: "all-in-one-menu-item flex w-full justify-center"
1165
+ }, /*#__PURE__*/react.createElement(ui_src/* ButtonGroup */.e2, {
1166
+ onActiveIndexChange: index => {
1167
+ setActiveDisplaySet(displaySets[index]);
1168
+ setPrePreviewColormap(null);
1169
+ },
1170
+ activeIndex: displaySets.findIndex(ds => ds.displaySetInstanceUID === activeDisplaySetRef.current.displaySetInstanceUID) || 1,
1171
+ className: "w-[70%] text-[10px]"
1172
+ }, buttons.map(({
1173
+ children,
1174
+ key,
1175
+ style
1176
+ }) => /*#__PURE__*/react.createElement("div", {
1177
+ key: key,
1178
+ style: style
1179
+ }, children)))), /*#__PURE__*/react.createElement("div", {
1180
+ className: "all-in-one-menu-item flex w-full justify-center"
1181
+ }, /*#__PURE__*/react.createElement(ui_src/* SwitchButton */.L$, {
1182
+ label: "Preview in viewport",
1183
+ checked: showPreview,
1184
+ onChange: checked => {
1185
+ setShowPreview(checked);
1186
+ }
1187
+ })), /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.DividerItem */.se.VG, null), /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.ItemPanel */.se.cV, null, colormaps.map((colormap, index) => /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.Item */.se.q7, {
1188
+ key: index,
1189
+ label: colormap.description,
1190
+ onClick: () => {
1191
+ onSetColorLUT({
1192
+ viewportId,
1193
+ colormap,
1194
+ displaySetInstanceUID: activeDisplaySetRef.current.displaySetInstanceUID
1195
+ });
1196
+ setPrePreviewColormap(null);
1197
+ },
1198
+ onMouseEnter: () => {
1199
+ if (showPreviewRef.current) {
1200
+ setPrePreviewColormap(getViewportColormap(viewportId, activeDisplaySetRef.current));
1201
+ onSetColorLUT({
1202
+ viewportId,
1203
+ colormap,
1204
+ displaySetInstanceUID: activeDisplaySetRef.current.displaySetInstanceUID
1205
+ });
1206
+ }
1207
+ },
1208
+ onMouseLeave: () => {
1209
+ if (showPreviewRef.current && prePreviewColormapRef.current) {
1210
+ onSetColorLUT({
1211
+ viewportId,
1212
+ colormap: prePreviewColormapRef.current,
1213
+ displaySetInstanceUID: activeDisplaySetRef.current.displaySetInstanceUID
1214
+ });
1215
+ }
1216
+ }
1217
+ }))));
1218
+ }
1219
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/Colorbar.tsx
1220
+
1221
+
1222
+
1223
+
1224
+ function setViewportColorbar(viewportId, displaySets, commandsManager, serviceManager, colorbarOptions) {
1225
+ const {
1226
+ cornerstoneViewportService
1227
+ } = serviceManager.services;
1228
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1229
+ const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
1230
+ const backgroundColor = viewportInfo.getViewportOptions().background;
1231
+ const isLight = backgroundColor ? dist_esm.utilities.isEqual(backgroundColor, [1, 1, 1]) : false;
1232
+ if (isLight) {
1233
+ colorbarOptions.ticks = {
1234
+ position: 'left',
1235
+ style: {
1236
+ font: '12px Arial',
1237
+ color: '#000000',
1238
+ maxNumTicks: 8,
1239
+ tickSize: 5,
1240
+ tickWidth: 1,
1241
+ labelMargin: 3
1242
+ }
1243
+ };
1244
+ }
1245
+ const displaySetInstanceUIDs = [];
1246
+ if (viewport instanceof dist_esm.StackViewport) {
1247
+ displaySetInstanceUIDs.push(viewportId);
1248
+ }
1249
+ if (viewport instanceof dist_esm.VolumeViewport) {
1250
+ displaySets.forEach(ds => {
1251
+ displaySetInstanceUIDs.push(ds.displaySetInstanceUID);
1252
+ });
1253
+ }
1254
+ commandsManager.run({
1255
+ commandName: 'toggleViewportColorbar',
1256
+ commandOptions: {
1257
+ viewportId,
1258
+ options: colorbarOptions,
1259
+ displaySetInstanceUIDs
1260
+ },
1261
+ context: 'CORNERSTONE'
1262
+ });
1263
+ }
1264
+ function Colorbar({
1265
+ viewportId,
1266
+ displaySets,
1267
+ commandsManager,
1268
+ serviceManager,
1269
+ colorbarProperties
1270
+ }) {
1271
+ const {
1272
+ colorbarService
1273
+ } = serviceManager.services;
1274
+ const {
1275
+ width: colorbarWidth,
1276
+ colorbarTickPosition,
1277
+ colorbarContainerPosition,
1278
+ colormaps,
1279
+ colorbarInitialColormap
1280
+ } = colorbarProperties;
1281
+ const [showColorbar, setShowColorbar] = (0,react.useState)(colorbarService.hasColorbar(viewportId));
1282
+ const onSetColorbar = (0,react.useCallback)(() => {
1283
+ setViewportColorbar(viewportId, displaySets, commandsManager, serviceManager, {
1284
+ viewportId,
1285
+ colormaps,
1286
+ ticks: {
1287
+ position: colorbarTickPosition
1288
+ },
1289
+ width: colorbarWidth,
1290
+ position: colorbarContainerPosition,
1291
+ activeColormapName: colorbarInitialColormap
1292
+ });
1293
+ }, [commandsManager]);
1294
+ (0,react.useEffect)(() => {
1295
+ const updateColorbarState = () => {
1296
+ setShowColorbar(colorbarService.hasColorbar(viewportId));
1297
+ };
1298
+ const {
1299
+ unsubscribe
1300
+ } = colorbarService.subscribe(colorbarService.EVENTS.STATE_CHANGED, updateColorbarState);
1301
+ return () => {
1302
+ unsubscribe();
1303
+ };
1304
+ }, [viewportId]);
1305
+ return /*#__PURE__*/react.createElement("div", {
1306
+ className: "all-in-one-menu-item flex w-full justify-center"
1307
+ }, /*#__PURE__*/react.createElement(ui_src/* SwitchButton */.L$, {
1308
+ label: "Display Color bar",
1309
+ checked: showColorbar,
1310
+ onChange: () => {
1311
+ onSetColorbar();
1312
+ }
1313
+ }));
1314
+ }
1315
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevel.tsx
1316
+
1317
+
1318
+
1319
+ function WindowLevel({
1320
+ viewportId,
1321
+ commandsManager,
1322
+ presets
1323
+ }) {
1324
+ const {
1325
+ t
1326
+ } = (0,es/* useTranslation */.Bd)('WindowLevelActionMenu');
1327
+ const onSetWindowLevel = (0,react.useCallback)(props => {
1328
+ commandsManager.run({
1329
+ commandName: 'setViewportWindowLevel',
1330
+ commandOptions: {
1331
+ ...props
1332
+ },
1333
+ context: 'CORNERSTONE'
1334
+ });
1335
+ }, [commandsManager]);
1336
+ return /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.ItemPanel */.se.cV, null, /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.HeaderItem */.se.N5, null, t('Modality Presets', {
1337
+ modality: Object.keys(presets)[0]
1338
+ })), Object.values(presets)[0].map((preset, index) => /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.Item */.se.q7, {
1339
+ key: index,
1340
+ label: preset.description,
1341
+ secondaryLabel: `${preset.window} / ${preset.level}`,
1342
+ onClick: () => onSetWindowLevel({
1343
+ ...preset,
1344
+ viewportId
1345
+ })
1346
+ })));
1347
+ }
1348
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingPresetsContent.tsx
1349
+
1350
+
1351
+
1352
+
1353
+ function VolumeRenderingPresetsContent({
1354
+ presets,
1355
+ viewportId,
1356
+ commandsManager,
1357
+ onClose
1358
+ }) {
1359
+ const [filteredPresets, setFilteredPresets] = (0,react.useState)(presets);
1360
+ const [searchValue, setSearchValue] = (0,react.useState)('');
1361
+ const [selectedPreset, setSelectedPreset] = (0,react.useState)(null);
1362
+ const handleSearchChange = (0,react.useCallback)(value => {
1363
+ setSearchValue(value);
1364
+ const filtered = value ? presets.filter(preset => preset.name.toLowerCase().includes(value.toLowerCase())) : presets;
1365
+ setFilteredPresets(filtered);
1366
+ }, [presets]);
1367
+ const handleApply = (0,react.useCallback)(props => {
1368
+ commandsManager.runCommand('setViewportPreset', {
1369
+ ...props
1370
+ });
1371
+ }, [commandsManager]);
1372
+ const formatLabel = (label, maxChars) => {
1373
+ return label.length > maxChars ? `${label.slice(0, maxChars)}...` : label;
1374
+ };
1375
+ return /*#__PURE__*/react.createElement("div", {
1376
+ className: "flex min-h-full w-full flex-col justify-between"
1377
+ }, /*#__PURE__*/react.createElement("div", {
1378
+ className: "border-secondary-light h-[433px] w-full overflow-hidden rounded border bg-black px-2.5"
1379
+ }, /*#__PURE__*/react.createElement("div", {
1380
+ className: "flex h-[46px] w-full items-center justify-start"
1381
+ }, /*#__PURE__*/react.createElement("div", {
1382
+ className: "h-[26px] w-[200px]"
1383
+ }, /*#__PURE__*/react.createElement(ui_src/* InputFilterText */.Cv, {
1384
+ value: searchValue,
1385
+ onDebounceChange: handleSearchChange,
1386
+ placeholder: 'Search all'
1387
+ }))), /*#__PURE__*/react.createElement("div", {
1388
+ className: "ohif-scrollbar overflow h-[385px] w-full overflow-y-auto"
1389
+ }, /*#__PURE__*/react.createElement("div", {
1390
+ className: "grid grid-cols-4 gap-3 pt-2 pr-3"
1391
+ }, filteredPresets.map((preset, index) => /*#__PURE__*/react.createElement("div", {
1392
+ key: index,
1393
+ className: "flex cursor-pointer flex-col items-start",
1394
+ onClick: () => {
1395
+ setSelectedPreset(preset);
1396
+ handleApply({
1397
+ preset: preset.name,
1398
+ viewportId
1399
+ });
1400
+ }
1401
+ }, /*#__PURE__*/react.createElement(ui_src/* Icon */.In, {
1402
+ name: preset.name,
1403
+ className: selectedPreset?.name === preset.name ? 'border-primary-light h-[75px] w-[95px] max-w-none rounded border-2' : 'hover:border-primary-light h-[75px] w-[95px] max-w-none rounded border-2 border-black'
1404
+ }), /*#__PURE__*/react.createElement("label", {
1405
+ className: "text-aqua-pale mt-2 text-left text-xs"
1406
+ }, formatLabel(preset.name, 11))))))), /*#__PURE__*/react.createElement("footer", {
1407
+ className: "flex h-[60px] w-full items-center justify-end"
1408
+ }, /*#__PURE__*/react.createElement("div", {
1409
+ className: "flex"
1410
+ }, /*#__PURE__*/react.createElement(ui_src/* Button */.$n, {
1411
+ name: "Cancel",
1412
+ size: ui_src/* ButtonEnums.size */.Ny.Ej.medium,
1413
+ type: ui_src/* ButtonEnums.type */.Ny.NW.secondary,
1414
+ onClick: onClose
1415
+ }, ' ', "Cancel", ' '))));
1416
+ }
1417
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingPresets.tsx
1418
+
1419
+
1420
+
1421
+ function VolumeRenderingPresets({
1422
+ viewportId,
1423
+ serviceManager,
1424
+ commandsManager,
1425
+ volumeRenderingPresets
1426
+ }) {
1427
+ const {
1428
+ uiModalService
1429
+ } = serviceManager.services;
1430
+ const onClickPresets = () => {
1431
+ uiModalService.show({
1432
+ content: VolumeRenderingPresetsContent,
1433
+ title: 'Rendering Presets',
1434
+ movable: true,
1435
+ contentProps: {
1436
+ onClose: uiModalService.hide,
1437
+ presets: volumeRenderingPresets,
1438
+ viewportId,
1439
+ commandsManager
1440
+ },
1441
+ containerDimensions: 'h-[543px] w-[460px]',
1442
+ contentDimensions: 'h-[493px] w-[460px] pl-[12px]'
1443
+ });
1444
+ };
1445
+ return /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.Item */.se.q7, {
1446
+ label: "Rendering Presets",
1447
+ icon: /*#__PURE__*/react.createElement(ui_src/* Icon */.In, {
1448
+ name: "VolumeRendering"
1449
+ }),
1450
+ rightIcon: /*#__PURE__*/react.createElement(ui_src/* Icon */.In, {
1451
+ name: "action-new-dialog"
1452
+ }),
1453
+ onClick: onClickPresets
1454
+ });
1455
+ }
1456
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingQuality.tsx
1457
+
1458
+ function VolumeRenderingQuality({
1459
+ volumeRenderingQualityRange,
1460
+ commandsManager,
1461
+ serviceManager,
1462
+ viewportId
1463
+ }) {
1464
+ const {
1465
+ cornerstoneViewportService
1466
+ } = serviceManager.services;
1467
+ const {
1468
+ min,
1469
+ max,
1470
+ step
1471
+ } = volumeRenderingQualityRange;
1472
+ const [quality, setQuality] = (0,react.useState)(null);
1473
+ const onChange = (0,react.useCallback)(value => {
1474
+ commandsManager.runCommand('setVolumeRenderingQulaity', {
1475
+ viewportId,
1476
+ volumeQuality: value
1477
+ });
1478
+ setQuality(value);
1479
+ }, [commandsManager, viewportId]);
1480
+ const calculateBackground = value => {
1481
+ const percentage = (value - 0) / (1 - 0) * 100;
1482
+ return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`;
1483
+ };
1484
+ (0,react.useEffect)(() => {
1485
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1486
+ const {
1487
+ actor
1488
+ } = viewport.getActors()[0];
1489
+ const mapper = actor.getMapper();
1490
+ const image = mapper.getInputData();
1491
+ const spacing = image.getSpacing();
1492
+ const sampleDistance = mapper.getSampleDistance();
1493
+ const averageSpacing = spacing.reduce((a, b) => a + b) / 3.0;
1494
+ if (sampleDistance === averageSpacing) {
1495
+ setQuality(1);
1496
+ } else {
1497
+ setQuality(Math.sqrt(averageSpacing / (sampleDistance * 0.5)));
1498
+ }
1499
+ }, [cornerstoneViewportService, viewportId]);
1500
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
1501
+ className: "all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]"
1502
+ }, /*#__PURE__*/react.createElement("label", {
1503
+ className: "block text-white",
1504
+ htmlFor: "volume"
1505
+ }, "Quality"), quality !== null && /*#__PURE__*/react.createElement("input", {
1506
+ className: "bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg",
1507
+ value: quality,
1508
+ id: "volume",
1509
+ max: max,
1510
+ min: min,
1511
+ type: "range",
1512
+ step: step,
1513
+ onChange: e => onChange(parseInt(e.target.value, 10)),
1514
+ style: {
1515
+ background: calculateBackground((quality - min) / (max - min))
1516
+ }
1517
+ })));
1518
+ }
1519
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShift.tsx
1520
+
1521
+ function VolumeShift({
1522
+ viewportId,
1523
+ commandsManager,
1524
+ serviceManager
1525
+ }) {
1526
+ const {
1527
+ cornerstoneViewportService
1528
+ } = serviceManager.services;
1529
+ const [minShift, setMinShift] = (0,react.useState)(null);
1530
+ const [maxShift, setMaxShift] = (0,react.useState)(null);
1531
+ const [shift, setShift] = (0,react.useState)(cornerstoneViewportService.getCornerstoneViewport(viewportId)?.shiftedBy || 0);
1532
+ const [step, setStep] = (0,react.useState)(null);
1533
+ const [isBlocking, setIsBlocking] = (0,react.useState)(false);
1534
+ const prevShiftRef = (0,react.useRef)(shift);
1535
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1536
+ const {
1537
+ actor
1538
+ } = viewport.getActors()[0];
1539
+ const ofun = actor.getProperty().getScalarOpacity(0);
1540
+ (0,react.useEffect)(() => {
1541
+ if (isBlocking) {
1542
+ return;
1543
+ }
1544
+ const range = ofun.getRange();
1545
+ const transferFunctionWidth = range[1] - range[0];
1546
+ const minShift = -transferFunctionWidth;
1547
+ const maxShift = transferFunctionWidth;
1548
+ setMinShift(minShift);
1549
+ setMaxShift(maxShift);
1550
+ setStep(Math.pow(10, Math.floor(Math.log10(transferFunctionWidth / 500))));
1551
+ }, [cornerstoneViewportService, viewportId, actor, ofun, isBlocking]);
1552
+ const onChangeRange = (0,react.useCallback)(newShift => {
1553
+ const shiftDifference = newShift - prevShiftRef.current;
1554
+ prevShiftRef.current = newShift;
1555
+ viewport.shiftedBy = newShift;
1556
+ commandsManager.runCommand('shiftVolumeOpacityPoints', {
1557
+ viewportId,
1558
+ shift: shiftDifference
1559
+ });
1560
+ }, [commandsManager, viewportId, viewport]);
1561
+ const calculateBackground = value => {
1562
+ const percentage = (value - 0) / (1 - 0) * 100;
1563
+ return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`;
1564
+ };
1565
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
1566
+ className: "all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]"
1567
+ }, /*#__PURE__*/react.createElement("label", {
1568
+ className: "block text-white",
1569
+ htmlFor: "shift"
1570
+ }, "Shift"), step !== null && /*#__PURE__*/react.createElement("input", {
1571
+ className: "bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg",
1572
+ value: shift,
1573
+ onChange: e => {
1574
+ const shiftValue = parseInt(e.target.value, 10);
1575
+ setShift(shiftValue);
1576
+ onChangeRange(shiftValue);
1577
+ },
1578
+ id: "shift",
1579
+ onMouseDown: () => setIsBlocking(true),
1580
+ onMouseUp: () => setIsBlocking(false),
1581
+ max: maxShift,
1582
+ min: minShift,
1583
+ type: "range",
1584
+ step: step,
1585
+ style: {
1586
+ background: calculateBackground((shift - minShift) / (maxShift - minShift))
1587
+ }
1588
+ })));
1589
+ }
1590
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeLighting.tsx
1591
+
1592
+ function VolumeLighting({
1593
+ serviceManager,
1594
+ commandsManager,
1595
+ viewportId
1596
+ }) {
1597
+ const {
1598
+ cornerstoneViewportService
1599
+ } = serviceManager.services;
1600
+ const [ambient, setAmbient] = (0,react.useState)(null);
1601
+ const [diffuse, setDiffuse] = (0,react.useState)(null);
1602
+ const [specular, setSpecular] = (0,react.useState)(null);
1603
+ const onAmbientChange = (0,react.useCallback)(() => {
1604
+ commandsManager.runCommand('setVolumeLighting', {
1605
+ viewportId,
1606
+ options: {
1607
+ ambient
1608
+ }
1609
+ });
1610
+ }, [ambient, commandsManager, viewportId]);
1611
+ const onDiffuseChange = (0,react.useCallback)(() => {
1612
+ commandsManager.runCommand('setVolumeLighting', {
1613
+ viewportId,
1614
+ options: {
1615
+ diffuse
1616
+ }
1617
+ });
1618
+ }, [diffuse, commandsManager, viewportId]);
1619
+ const onSpecularChange = (0,react.useCallback)(() => {
1620
+ commandsManager.runCommand('setVolumeLighting', {
1621
+ viewportId,
1622
+ options: {
1623
+ specular
1624
+ }
1625
+ });
1626
+ }, [specular, commandsManager, viewportId]);
1627
+ const calculateBackground = value => {
1628
+ const percentage = (value - 0) / (1 - 0) * 100;
1629
+ return `linear-gradient(to right, #5acce6 0%, #5acce6 ${percentage}%, #3a3f99 ${percentage}%, #3a3f99 100%)`;
1630
+ };
1631
+ (0,react.useEffect)(() => {
1632
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1633
+ const {
1634
+ actor
1635
+ } = viewport.getActors()[0];
1636
+ const ambient = actor.getProperty().getAmbient();
1637
+ const diffuse = actor.getProperty().getDiffuse();
1638
+ const specular = actor.getProperty().getSpecular();
1639
+ setAmbient(ambient);
1640
+ setDiffuse(diffuse);
1641
+ setSpecular(specular);
1642
+ }, [viewportId, cornerstoneViewportService]);
1643
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
1644
+ className: "all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]"
1645
+ }, /*#__PURE__*/react.createElement("label", {
1646
+ className: "block text-white",
1647
+ htmlFor: "ambient"
1648
+ }, "Ambient"), ambient !== null && /*#__PURE__*/react.createElement("input", {
1649
+ className: "bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg",
1650
+ value: ambient,
1651
+ onChange: e => {
1652
+ setAmbient(e.target.value);
1653
+ onAmbientChange();
1654
+ },
1655
+ id: "ambient",
1656
+ max: 1,
1657
+ min: 0,
1658
+ type: "range",
1659
+ step: 0.1,
1660
+ style: {
1661
+ background: calculateBackground(ambient)
1662
+ }
1663
+ })), /*#__PURE__*/react.createElement("div", {
1664
+ className: "all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]"
1665
+ }, /*#__PURE__*/react.createElement("label", {
1666
+ className: "block text-white",
1667
+ htmlFor: "diffuse"
1668
+ }, "Diffuse"), diffuse !== null && /*#__PURE__*/react.createElement("input", {
1669
+ className: "bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg",
1670
+ value: diffuse,
1671
+ onChange: e => {
1672
+ setDiffuse(e.target.value);
1673
+ onDiffuseChange();
1674
+ },
1675
+ id: "diffuse",
1676
+ max: 1,
1677
+ min: 0,
1678
+ type: "range",
1679
+ step: 0.1,
1680
+ style: {
1681
+ background: calculateBackground(diffuse)
1682
+ }
1683
+ })), /*#__PURE__*/react.createElement("div", {
1684
+ className: "all-in-one-menu-item flex w-full flex-row !items-center justify-between gap-[10px]"
1685
+ }, /*#__PURE__*/react.createElement("label", {
1686
+ className: "block text-white",
1687
+ htmlFor: "specular"
1688
+ }, "Specular"), specular !== null && /*#__PURE__*/react.createElement("input", {
1689
+ className: "bg-inputfield-main h-2 w-[120px] cursor-pointer appearance-none rounded-lg",
1690
+ value: specular,
1691
+ onChange: e => {
1692
+ setSpecular(e.target.value);
1693
+ onSpecularChange();
1694
+ },
1695
+ id: "specular",
1696
+ max: 1,
1697
+ min: 0,
1698
+ type: "range",
1699
+ step: 0.1,
1700
+ style: {
1701
+ background: calculateBackground(specular)
1702
+ }
1703
+ })));
1704
+ }
1705
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShade.tsx
1706
+
1707
+
1708
+ function VolumeShade({
1709
+ commandsManager,
1710
+ viewportId,
1711
+ serviceManager
1712
+ }) {
1713
+ const {
1714
+ cornerstoneViewportService
1715
+ } = serviceManager.services;
1716
+ const [shade, setShade] = (0,react.useState)(true);
1717
+ const [key, setKey] = (0,react.useState)(0);
1718
+ const onShadeChange = (0,react.useCallback)(checked => {
1719
+ commandsManager.runCommand('setVolumeLighting', {
1720
+ viewportId,
1721
+ options: {
1722
+ shade: checked
1723
+ }
1724
+ });
1725
+ }, [commandsManager, viewportId]);
1726
+ (0,react.useEffect)(() => {
1727
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1728
+ const {
1729
+ actor
1730
+ } = viewport.getActors()[0];
1731
+ const shade = actor.getProperty().getShade();
1732
+ setShade(shade);
1733
+ setKey(key + 1);
1734
+ }, [viewportId, cornerstoneViewportService]);
1735
+ return /*#__PURE__*/react.createElement(ui_src/* SwitchButton */.L$, {
1736
+ key: key,
1737
+ label: "Shade",
1738
+ checked: shade,
1739
+ onChange: () => {
1740
+ setShade(!shade);
1741
+ onShadeChange(!shade);
1742
+ }
1743
+ });
1744
+ }
1745
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingOptions.tsx
1746
+
1747
+
1748
+
1749
+
1750
+
1751
+
1752
+ function VolumeRenderingOptions({
1753
+ viewportId,
1754
+ commandsManager,
1755
+ volumeRenderingQualityRange,
1756
+ serviceManager
1757
+ }) {
1758
+ return /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.ItemPanel */.se.cV, null, /*#__PURE__*/react.createElement(VolumeRenderingQuality, {
1759
+ viewportId: viewportId,
1760
+ commandsManager: commandsManager,
1761
+ serviceManager: serviceManager,
1762
+ volumeRenderingQualityRange: volumeRenderingQualityRange
1763
+ }), /*#__PURE__*/react.createElement(VolumeShift, {
1764
+ viewportId: viewportId,
1765
+ commandsManager: commandsManager,
1766
+ serviceManager: serviceManager
1767
+ }), /*#__PURE__*/react.createElement("div", {
1768
+ className: "all-in-one-menu-item flex w-full justify-start"
1769
+ }, /*#__PURE__*/react.createElement("div", {
1770
+ className: "text-aqua-pale text-[13px]"
1771
+ }, "LIGHTING")), /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.DividerItem */.se.VG, null), /*#__PURE__*/react.createElement("div", {
1772
+ className: "all-in-one-menu-item flex w-full justify-center"
1773
+ }, /*#__PURE__*/react.createElement(VolumeShade, {
1774
+ commandsManager: commandsManager,
1775
+ serviceManager: serviceManager,
1776
+ viewportId: viewportId
1777
+ })), /*#__PURE__*/react.createElement(VolumeLighting, {
1778
+ viewportId: viewportId,
1779
+ commandsManager: commandsManager,
1780
+ serviceManager: serviceManager
1781
+ }));
1782
+ }
1783
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx
1784
+
1785
+
1786
+
1787
+
1788
+
1789
+
1790
+
1791
+
1792
+
1793
+
1794
+
1795
+
1796
+ function WindowLevelActionMenu({
1797
+ viewportId,
1798
+ element,
1799
+ presets,
1800
+ verticalDirection,
1801
+ horizontalDirection,
1802
+ commandsManager,
1803
+ serviceManager,
1804
+ colorbarProperties,
1805
+ displaySets,
1806
+ volumeRenderingPresets,
1807
+ volumeRenderingQualityRange
1808
+ }) {
1809
+ const {
1810
+ colormaps,
1811
+ colorbarContainerPosition,
1812
+ colorbarInitialColormap,
1813
+ colorbarTickPosition,
1814
+ width: colorbarWidth
1815
+ } = colorbarProperties;
1816
+ const {
1817
+ colorbarService,
1818
+ cornerstoneViewportService
1819
+ } = serviceManager.services;
1820
+ const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
1821
+ const backgroundColor = viewportInfo.getViewportOptions().background;
1822
+ const isLight = backgroundColor ? dist_esm.utilities.isEqual(backgroundColor, [1, 1, 1]) : false;
1823
+ const nonImageModalities = ['SR', 'SEG', 'SM', 'RTSTRUCT', 'RTPLAN', 'RTDOSE'];
1824
+ const {
1825
+ t
1826
+ } = (0,es/* useTranslation */.Bd)('WindowLevelActionMenu');
1827
+ const [viewportGrid] = (0,ui_src/* useViewportGrid */.ih)();
1828
+ const {
1829
+ activeViewportId
1830
+ } = viewportGrid;
1831
+ const [vpHeight, setVpHeight] = (0,react.useState)(element?.clientHeight);
1832
+ const [menuKey, setMenuKey] = (0,react.useState)(0);
1833
+ const [is3DVolume, setIs3DVolume] = (0,react.useState)(false);
1834
+ const onSetColorbar = (0,react.useCallback)(() => {
1835
+ setViewportColorbar(viewportId, displaySets, commandsManager, serviceManager, {
1836
+ colormaps,
1837
+ ticks: {
1838
+ position: colorbarTickPosition
1839
+ },
1840
+ width: colorbarWidth,
1841
+ position: colorbarContainerPosition,
1842
+ activeColormapName: colorbarInitialColormap
1843
+ });
1844
+ }, [commandsManager]);
1845
+ (0,react.useEffect)(() => {
1846
+ const newVpHeight = element?.clientHeight;
1847
+ if (vpHeight !== newVpHeight) {
1848
+ setVpHeight(newVpHeight);
1849
+ }
1850
+ }, [element, vpHeight]);
1851
+ (0,react.useEffect)(() => {
1852
+ if (!colorbarService.hasColorbar(viewportId)) {
1853
+ return;
1854
+ }
1855
+ window.setTimeout(() => {
1856
+ colorbarService.removeColorbar(viewportId);
1857
+ onSetColorbar();
1858
+ }, 0);
1859
+ }, [viewportId]);
1860
+ (0,react.useEffect)(() => {
1861
+ if (colorbarService.hasColorbar(viewportId)) {
1862
+ colorbarService.removeColorbar(viewportId);
1863
+ }
1864
+ }, [displaySets]);
1865
+ (0,react.useEffect)(() => {
1866
+ setMenuKey(menuKey + 1);
1867
+ const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
1868
+ if (viewport instanceof dist_esm.VolumeViewport3D) {
1869
+ setIs3DVolume(true);
1870
+ } else {
1871
+ setIs3DVolume(false);
1872
+ }
1873
+ }, [displaySets, viewportId, presets, volumeRenderingQualityRange, volumeRenderingPresets, colorbarProperties, activeViewportId, viewportGrid]);
1874
+ return /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.IconMenu */.se.dd, {
1875
+ icon: "viewport-window-level",
1876
+ verticalDirection: verticalDirection,
1877
+ horizontalDirection: horizontalDirection,
1878
+ iconClassName: classnames_default()(
1879
+ // Visible on hover and for the active viewport
1880
+ activeViewportId === viewportId ? 'visible' : 'invisible group-hover:visible', 'flex shrink-0 cursor-pointer rounded active:text-white', isLight ? 'text-aqua-pale hover:bg-secondary-dark' : 'text-primary-light hover:bg-secondary-light/60'),
1881
+ menuStyle: {
1882
+ maxHeight: vpHeight - 32,
1883
+ minWidth: 218
1884
+ },
1885
+ onVisibilityChange: () => {
1886
+ setVpHeight(element.clientHeight);
1887
+ },
1888
+ menuKey: menuKey
1889
+ }, /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.ItemPanel */.se.cV, null, !is3DVolume && /*#__PURE__*/react.createElement(Colorbar, {
1890
+ viewportId: viewportId,
1891
+ displaySets: displaySets.filter(ds => !nonImageModalities.includes(ds.Modality)),
1892
+ commandsManager: commandsManager,
1893
+ serviceManager: serviceManager,
1894
+ colorbarProperties: colorbarProperties
1895
+ }), colormaps && !is3DVolume && /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.SubMenu */.se.g8, {
1896
+ key: "colorLUTPresets",
1897
+ itemLabel: "Color LUT",
1898
+ itemIcon: "icon-color-lut"
1899
+ }, /*#__PURE__*/react.createElement(Colormap, {
1900
+ colormaps: colormaps,
1901
+ viewportId: viewportId,
1902
+ displaySets: displaySets.filter(ds => !nonImageModalities.includes(ds.Modality)),
1903
+ commandsManager: commandsManager,
1904
+ serviceManager: serviceManager
1905
+ })), presets && !is3DVolume && /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.SubMenu */.se.g8, {
1906
+ key: "windowLevelPresets",
1907
+ itemLabel: t('Modality Window Presets', {
1908
+ modality: Object.keys(presets)[0]
1909
+ }),
1910
+ itemIcon: "viewport-window-level"
1911
+ }, /*#__PURE__*/react.createElement(WindowLevel, {
1912
+ viewportId: viewportId,
1913
+ commandsManager: commandsManager,
1914
+ presets: presets
1915
+ })), volumeRenderingPresets && is3DVolume && /*#__PURE__*/react.createElement(VolumeRenderingPresets, {
1916
+ serviceManager: serviceManager,
1917
+ viewportId: viewportId,
1918
+ commandsManager: commandsManager,
1919
+ volumeRenderingPresets: volumeRenderingPresets
1920
+ }), volumeRenderingQualityRange && is3DVolume && /*#__PURE__*/react.createElement(ui_src/* AllInOneMenu.SubMenu */.se.g8, {
1921
+ itemLabel: "Rendering Options"
1922
+ }, /*#__PURE__*/react.createElement(VolumeRenderingOptions, {
1923
+ viewportId: viewportId,
1924
+ commandsManager: commandsManager,
1925
+ volumeRenderingQualityRange: volumeRenderingQualityRange,
1926
+ serviceManager: serviceManager
1927
+ }))));
1928
+ }
1929
+ ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/components/WindowLevelActionMenu/getWindowLevelActionMenu.tsx
1930
+
1931
+
1932
+ function getWindowLevelActionMenu({
1933
+ viewportId,
1934
+ element,
1935
+ displaySets,
1936
+ servicesManager,
1937
+ commandsManager,
1938
+ verticalDirection,
1939
+ horizontalDirection
1940
+ }) {
1941
+ const {
1942
+ customizationService
1943
+ } = servicesManager.services;
1944
+ const {
1945
+ presets
1946
+ } = customizationService.get('cornerstone.windowLevelPresets');
1947
+ const colorbarProperties = customizationService.get('cornerstone.colorbar');
1948
+ const {
1949
+ volumeRenderingPresets,
1950
+ volumeRenderingQualityRange
1951
+ } = customizationService.get('cornerstone.3dVolumeRendering');
1952
+ const displaySetPresets = displaySets.filter(displaySet => presets[displaySet.Modality]).map(displaySet => {
1953
+ return {
1954
+ [displaySet.Modality]: presets[displaySet.Modality]
1955
+ };
1956
+ });
1957
+ const hasMenu = displaySetPresets.length > 0;
1958
+ return hasMenu ? /*#__PURE__*/react.createElement(WindowLevelActionMenu, {
1959
+ viewportId: viewportId,
1960
+ element: element,
1961
+ presets: displaySetPresets[0],
1962
+ verticalDirection: verticalDirection,
1963
+ horizontalDirection: horizontalDirection,
1964
+ commandsManager: commandsManager,
1965
+ serviceManager: servicesManager,
1966
+ colorbarProperties: colorbarProperties,
1967
+ displaySets: displaySets,
1968
+ volumeRenderingPresets: volumeRenderingPresets,
1969
+ volumeRenderingQualityRange: volumeRenderingQualityRange
1970
+ }) : null;
1971
+ }
1052
1972
  ;// CONCATENATED MODULE: ../../../extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx
1053
1973
 
1054
1974
 
@@ -1062,6 +1982,9 @@ function WrappedCinePlayer({
1062
1982
 
1063
1983
 
1064
1984
 
1985
+
1986
+
1987
+
1065
1988
  const STACK = 'stack';
1066
1989
 
1067
1990
  /**
@@ -1139,6 +2062,7 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1139
2062
  const [scrollbarHeight, setScrollbarHeight] = (0,react.useState)('100px');
1140
2063
  const [enabledVPElement, setEnabledVPElement] = (0,react.useState)(null);
1141
2064
  const elementRef = (0,react.useRef)();
2065
+ const [appConfig] = (0,state_0/* useAppConfig */.r)();
1142
2066
  const {
1143
2067
  measurementService,
1144
2068
  displaySetService,
@@ -1148,12 +2072,14 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1148
2072
  cornerstoneViewportService,
1149
2073
  cornerstoneCacheService,
1150
2074
  viewportGridService,
1151
- stateSyncService
2075
+ stateSyncService,
2076
+ viewportActionCornersService,
2077
+ customizationService
1152
2078
  } = servicesManager.services;
1153
2079
  const [viewportDialogState] = (0,ui_src/* useViewportDialog */.OR)();
1154
2080
  // useCallback for scroll bar height calculation
1155
2081
  const setImageScrollBarHeight = (0,react.useCallback)(() => {
1156
- const scrollbarHeight = `${elementRef.current.clientHeight - 20}px`;
2082
+ const scrollbarHeight = `${elementRef.current.clientHeight - 40}px`;
1157
2083
  setScrollbarHeight(scrollbarHeight);
1158
2084
  }, [elementRef]);
1159
2085
 
@@ -1169,6 +2095,7 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1169
2095
  const syncGroups = viewportInfo.getSyncGroups();
1170
2096
  toolGroupService.removeViewportFromToolGroup(viewportId, renderingEngineId);
1171
2097
  syncGroupService.removeViewportFromSyncGroup(viewportId, renderingEngineId, syncGroups);
2098
+ viewportActionCornersService.clear(viewportId);
1172
2099
  }, [viewportId]);
1173
2100
  const elementEnabledHandler = (0,react.useCallback)(evt => {
1174
2101
  // check this is this element reference and return early if doesn't match
@@ -1319,6 +2246,33 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1319
2246
  unsubscribeFromJumpToMeasurementEvents();
1320
2247
  };
1321
2248
  }, [displaySets, elementRef, viewportId]);
2249
+
2250
+ // Set up the window level action menu in the viewport action corners.
2251
+ (0,react.useEffect)(() => {
2252
+ // Doing an === check here because the default config value when not set is true
2253
+ if (appConfig.addWindowLevelActionMenu === false) {
2254
+ return;
2255
+ }
2256
+
2257
+ // TODO: In the future we should consider using the customization service
2258
+ // to determine if and in which corner various action components should go.
2259
+ const wlActionMenu = getWindowLevelActionMenu({
2260
+ viewportId,
2261
+ element: elementRef.current,
2262
+ displaySets,
2263
+ servicesManager,
2264
+ commandsManager,
2265
+ verticalDirection: ui_src/* AllInOneMenu.VerticalDirection */.se.mq.TopToBottom,
2266
+ horizontalDirection: ui_src/* AllInOneMenu.HorizontalDirection */.se.Iu.RightToLeft
2267
+ });
2268
+ viewportActionCornersService.setComponent({
2269
+ viewportId,
2270
+ id: 'windowLevelActionMenu',
2271
+ component: wlActionMenu,
2272
+ location: viewportActionCornersService.LOCATIONS.topRight,
2273
+ indexPriority: -100
2274
+ });
2275
+ }, [displaySets, viewportId, viewportActionCornersService, servicesManager, commandsManager]);
1322
2276
  return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
1323
2277
  className: "viewport-wrapper"
1324
2278
  }, /*#__PURE__*/react.createElement(index_esm/* default */.Ay, {
@@ -1344,7 +2298,7 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1344
2298
  viewportId: viewportId,
1345
2299
  servicesManager: servicesManager
1346
2300
  })), /*#__PURE__*/react.createElement("div", {
1347
- className: "absolute w-full"
2301
+ className: "absolute top-[24px] w-full"
1348
2302
  }, viewportDialogState.viewportId === viewportId && /*#__PURE__*/react.createElement(ui_src/* Notification */.Eg, {
1349
2303
  id: "viewport-notification",
1350
2304
  message: viewportDialogState.message,
@@ -1352,7 +2306,9 @@ const OHIFCornerstoneViewport = /*#__PURE__*/react.memo(props => {
1352
2306
  actions: viewportDialogState.actions,
1353
2307
  onSubmit: viewportDialogState.onSubmit,
1354
2308
  onOutsideClick: viewportDialogState.onOutsideClick
1355
- })));
2309
+ })), /*#__PURE__*/react.createElement(components_OHIFViewportActionCorners, {
2310
+ viewportId: viewportId
2311
+ }));
1356
2312
  }, areEqual);
1357
2313
  function _subscribeToJumpToMeasurementEvents(measurementService, displaySetService, elementRef, viewportId, displaySets, viewportGridService, cornerstoneViewportService) {
1358
2314
  const {