feat(actions): simplify action corner api through the toolbarService (#5033)
This commit is contained in:
1 parent
f71b88e639
commit
7c15bb8901
246 files changed
+7930
-4270
No files matched your search
@@ -1,23 +1,358 @@
|
||||
import { Enums } from '@cornerstonejs/tools';
|
||||
import { utils } from '@ohif/ui-next';
|
||||
import { ViewportDataOverlayMenuWrapper } from './components/ViewportDataOverlaySettingMenu/ViewportDataOverlayMenuWrapper';
|
||||
import { ViewportOrientationMenuWrapper } from './components/ViewportOrientationMenu/ViewportOrientationMenuWrapper';
|
||||
import { WindowLevelActionMenuWrapper } from './components/WindowLevelActionMenu/WindowLevelActionMenuWrapper';
|
||||
import { VOIManualControlMenuWrapper } from './components/VOIManualControlMenu';
|
||||
import { ThresholdMenuWrapper } from './components/ThresholdMenu/ThresholdMenuWrapper';
|
||||
import { OpacityMenuWrapper } from './components/OpacityMenu/OpacityMenuWrapper';
|
||||
import ModalityLoadBadge from './components/ModalityLoadBadge/ModalityLoadBadge';
|
||||
import NavigationComponent from './components/NavigationComponent/NavigationComponent';
|
||||
import TrackingStatus from './components/TrackingStatus/TrackingStatus';
|
||||
import ViewportColorbarsContainer from './components/ViewportColorbar';
|
||||
import AdvancedRenderingControls from './components/AdvancedRenderingControls';
|
||||
|
||||
const getDisabledState = (disabledText?: string) => ({
|
||||
disabled: true,
|
||||
disabledText: disabledText ?? 'Not available on the current viewport',
|
||||
});
|
||||
|
||||
export default function getToolbarModule({ commandsManager, servicesManager }: withAppTypes) {
|
||||
export default function getToolbarModule({ servicesManager, extensionManager }: withAppTypes) {
|
||||
const {
|
||||
toolGroupService,
|
||||
toolbarService,
|
||||
syncGroupService,
|
||||
cornerstoneViewportService,
|
||||
hangingProtocolService,
|
||||
colorbarService,
|
||||
displaySetService,
|
||||
viewportGridService,
|
||||
segmentationService,
|
||||
} = servicesManager.services;
|
||||
|
||||
return [
|
||||
{
|
||||
name: 'ohif.advancedRenderingControls',
|
||||
defaultComponent: AdvancedRenderingControls,
|
||||
},
|
||||
{
|
||||
name: 'evaluate.advancedRenderingControls',
|
||||
evaluate: ({ viewportId }) => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
if (!viewport) {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
const hasColorbar = colorbarService?.hasColorbar(viewportId) || false;
|
||||
return {
|
||||
disabled: !hasColorbar,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ohif.colorbar',
|
||||
defaultComponent: ViewportColorbarsContainer,
|
||||
},
|
||||
{
|
||||
name: 'ohif.trackingStatus',
|
||||
defaultComponent: TrackingStatus,
|
||||
},
|
||||
{
|
||||
name: 'evaluate.trackingStatus',
|
||||
evaluate: ({ viewportId }) => {
|
||||
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
|
||||
|
||||
if (!displaySetUIDs?.length) {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
};
|
||||
},
|
||||
},
|
||||
// ModalityLoadBadge
|
||||
{
|
||||
name: 'ohif.modalityLoadBadge',
|
||||
defaultComponent: ModalityLoadBadge,
|
||||
},
|
||||
{
|
||||
name: 'evaluate.modalityLoadBadge',
|
||||
evaluate: ({ viewportId }) => {
|
||||
// We can't use useViewportDisplaySets hook here since we're in a non-React context,
|
||||
// but we'll follow the same pattern by getting only the display sets for this viewport
|
||||
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
|
||||
|
||||
if (!displaySetUIDs?.length) {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
// Get the display sets that are specifically in this viewport
|
||||
const viewportDisplaySets = displaySetUIDs.map(uid =>
|
||||
displaySetService.getDisplaySetByUID(uid)
|
||||
);
|
||||
|
||||
// Only show status for supported types like SR, SEG, RTSTRUCT
|
||||
const isSupportedType = viewportDisplaySets.some(
|
||||
displaySet =>
|
||||
displaySet?.Modality === 'SR' ||
|
||||
displaySet?.Modality === 'SEG' ||
|
||||
displaySet?.Modality === 'RTSTRUCT'
|
||||
);
|
||||
|
||||
return {
|
||||
disabled: !isSupportedType,
|
||||
};
|
||||
},
|
||||
},
|
||||
// NavigationComponent
|
||||
{
|
||||
name: 'ohif.navigationComponent',
|
||||
defaultComponent: NavigationComponent,
|
||||
},
|
||||
{
|
||||
name: 'evaluate.navigationComponent',
|
||||
evaluate: ({ viewportId }) => {
|
||||
const { trackedMeasurementsService } = servicesManager.services;
|
||||
// Same logic as statusComponent - only show for SR, SEG, RTSTRUCT
|
||||
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
|
||||
|
||||
if (!displaySetUIDs?.length) {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
// Get the display sets that are specifically in this viewport
|
||||
const viewportDisplaySets = displaySetUIDs.map(uid =>
|
||||
displaySetService.getDisplaySetByUID(uid)
|
||||
);
|
||||
|
||||
// Check if there's a need for navigation:
|
||||
// 1. Segmentations are present (for SEG/RTSTRUCT navigation)
|
||||
// 2. There are tracked measurements in the viewport (for SR navigation)
|
||||
|
||||
// Check for SEG/RTSTRUCT navigation
|
||||
const hasSegmentation =
|
||||
segmentationService.getSegmentationRepresentations(viewportId).length > 0;
|
||||
|
||||
if (!trackedMeasurementsService) {
|
||||
return {
|
||||
disabled: !hasSegmentation,
|
||||
};
|
||||
}
|
||||
|
||||
// Check if any of the viewport's series are being tracked
|
||||
const hasTrackedInViewport = viewportDisplaySets.some(
|
||||
displaySet =>
|
||||
displaySet?.SeriesInstanceUID &&
|
||||
trackedMeasurementsService.isSeriesTracked(displaySet.SeriesInstanceUID)
|
||||
);
|
||||
|
||||
const isSRDisplaySet = viewportDisplaySets.some(
|
||||
displaySet => displaySet?.Modality === 'SR'
|
||||
);
|
||||
|
||||
// Enable navigation if:
|
||||
// - There's a segmentation to navigate (SEG/RTSTRUCT)
|
||||
// - OR there are tracked measurements in the viewport (SR/etc.)
|
||||
const needsNavigation = hasSegmentation || hasTrackedInViewport || isSRDisplaySet;
|
||||
|
||||
return {
|
||||
disabled: !needsNavigation,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ohif.dataOverlayMenu',
|
||||
defaultComponent: ViewportDataOverlayMenuWrapper,
|
||||
},
|
||||
{
|
||||
name: 'evaluate.dataOverlayMenu',
|
||||
evaluate: ({ viewportId }) => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
if (!viewport) {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
// Example: Show data overlay menu only for certain modalities
|
||||
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
|
||||
if (!displaySetUIDs?.length) {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ohif.orientationMenu',
|
||||
defaultComponent: ViewportOrientationMenuWrapper,
|
||||
},
|
||||
{
|
||||
name: 'evaluate.orientationMenu',
|
||||
evaluate: ({ viewportId }) => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
if (!viewport) {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
// Only show orientation menu for 3D capable viewports
|
||||
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
|
||||
const displaySets = displaySetUIDs.map(displaySetService.getDisplaySetByUID);
|
||||
const isNotReconstructable = displaySets.some(displaySet => !displaySet?.isReconstructable);
|
||||
|
||||
const disabled = isNotReconstructable;
|
||||
|
||||
return {
|
||||
disabled,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ohif.windowLevelMenu',
|
||||
defaultComponent: WindowLevelActionMenuWrapper,
|
||||
},
|
||||
{
|
||||
name: 'ohif.voiManualControlMenu',
|
||||
defaultComponent: VOIManualControlMenuWrapper,
|
||||
},
|
||||
{
|
||||
name: 'ohif.windowLevelMenuEmbedded',
|
||||
defaultComponent: WindowLevelActionMenuWrapper,
|
||||
},
|
||||
{
|
||||
name: 'evaluate.windowLevelMenuEmbedded',
|
||||
evaluate: () => {
|
||||
return {
|
||||
isEmbedded: true,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ohif.thresholdMenu',
|
||||
defaultComponent: ThresholdMenuWrapper,
|
||||
},
|
||||
{
|
||||
name: 'ohif.opacityMenu',
|
||||
defaultComponent: OpacityMenuWrapper,
|
||||
},
|
||||
{
|
||||
name: 'evaluate.windowLevelMenu',
|
||||
evaluate: ({ viewportId }) => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
if (!viewport) {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
|
||||
const displaySets = displaySetUIDs.map(displaySetService.getDisplaySetByUID);
|
||||
|
||||
const supportWindowLevel = displaySets.some(displaySet => displaySet?.supportsWindowLevel);
|
||||
|
||||
const isInAnySection = toolbarService.isInAnySection('windowLevelMenuEmbedded');
|
||||
|
||||
return {
|
||||
disabled: !supportWindowLevel,
|
||||
hasEmbeddedVariantToUse: !!isInAnySection,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'evaluate.voiManualControlMenu',
|
||||
evaluate: ({ viewportId }) => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
if (!viewport) {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
|
||||
const displaySets = displaySetUIDs.map(displaySetService.getDisplaySetByUID);
|
||||
|
||||
const supportWindowLevel = displaySets.some(displaySet => displaySet?.supportsWindowLevel);
|
||||
|
||||
return {
|
||||
disabled: !supportWindowLevel,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'evaluate.thresholdMenu',
|
||||
evaluate: ({ viewportId }) => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
if (!viewport) {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
if (viewport.type !== 'orthographic') {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
|
||||
if (!displaySetUIDs.length) {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'evaluate.opacityMenu',
|
||||
evaluate: ({ viewportId }) => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
if (!viewport || viewport.type !== 'orthographic') {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
|
||||
|
||||
if (displaySetUIDs.length <= 1) {
|
||||
return {
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
const displaySets = displaySetUIDs.map(displaySetService.getDisplaySetByUID);
|
||||
const hasOverlayable = displaySets.some(displaySet => displaySet?.isOverlayDisplaySet);
|
||||
|
||||
return {
|
||||
disabled: hasOverlayable,
|
||||
};
|
||||
},
|
||||
},
|
||||
// functions/helpers to be used by the toolbar buttons to decide if they should
|
||||
// enabled or not
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user