* [WIP] Fix contour annotations RTSS saving * fix: Export image sop image reference provider * Fixes for download with filename * Updates to fix metadata issues with CS3D * Updates to save menu * Fixing some additional re-save metadata * Add support for saving with predecessor image sequence * PR comment fixes * fix: Load RTSS after save * fix segmentation save * fix load of mixed seg/rt studies * Use frame module to get information on the frame shown * Fix study browser to use instances.length when numImageFrames not present * fix: Load of display set split from multiple non-FOR referenes * Fix RT and SEG applying to wrong series because of using referenced series sequence without checkout sop instances * Fix save seg * Update to released CS3D versions * test: Add revokeObjectURL to test download blob * Add hard dependency on mode-basic to fix build order issues * fix: build * Try to fix build segmentation * PR comments * PR comment update
250 lines
8.0 KiB
TypeScript
250 lines
8.0 KiB
TypeScript
import { id } from './id';
|
|
import toolbarButtons from './toolbarButtons';
|
|
import initToolGroups from './initToolGroups';
|
|
import setUpAutoTabSwitchHandler from './utils/setUpAutoTabSwitchHandler';
|
|
import { ohif, cornerstone, extensionDependencies, dicomRT, segmentation } from '@ohif/mode-basic';
|
|
export * from './toolbarButtons';
|
|
|
|
function modeFactory({ modeConfiguration }) {
|
|
const _unsubscriptions = [];
|
|
return {
|
|
/**
|
|
* Mode ID, which should be unique among modes used by the viewer. This ID
|
|
* is used to identify the mode in the viewer's state.
|
|
*/
|
|
id,
|
|
routeName: 'segmentation',
|
|
/**
|
|
* Mode name, which is displayed in the viewer's UI in the workList, for the
|
|
* user to select the mode.
|
|
*/
|
|
displayName: 'Segmentation',
|
|
/**
|
|
* Runs when the Mode Route is mounted to the DOM. Usually used to initialize
|
|
* Services and other resources.
|
|
*/
|
|
onModeEnter: ({ servicesManager, extensionManager, commandsManager }: withAppTypes) => {
|
|
const {
|
|
measurementService,
|
|
toolbarService,
|
|
toolGroupService,
|
|
segmentationService,
|
|
viewportGridService,
|
|
panelService,
|
|
} = servicesManager.services;
|
|
|
|
measurementService.clearMeasurements();
|
|
|
|
// Init Default and SR ToolGroups
|
|
initToolGroups(extensionManager, toolGroupService, commandsManager);
|
|
|
|
toolbarService.register(toolbarButtons);
|
|
|
|
toolbarService.updateSection(toolbarService.sections.primary, [
|
|
'WindowLevel',
|
|
'Pan',
|
|
'Zoom',
|
|
'TrackballRotate',
|
|
'Capture',
|
|
'Layout',
|
|
'Crosshairs',
|
|
'MoreTools',
|
|
]);
|
|
|
|
toolbarService.updateSection(toolbarService.sections.viewportActionMenu.topLeft, [
|
|
'orientationMenu',
|
|
'dataOverlayMenu',
|
|
]);
|
|
|
|
toolbarService.updateSection(toolbarService.sections.viewportActionMenu.bottomMiddle, [
|
|
'AdvancedRenderingControls',
|
|
]);
|
|
|
|
toolbarService.updateSection('AdvancedRenderingControls', [
|
|
'windowLevelMenuEmbedded',
|
|
'voiManualControlMenu',
|
|
'Colorbar',
|
|
'opacityMenu',
|
|
'thresholdMenu',
|
|
]);
|
|
|
|
toolbarService.updateSection(toolbarService.sections.viewportActionMenu.topRight, [
|
|
'modalityLoadBadge',
|
|
'trackingStatus',
|
|
'navigationComponent',
|
|
]);
|
|
|
|
toolbarService.updateSection(toolbarService.sections.viewportActionMenu.bottomLeft, [
|
|
'windowLevelMenu',
|
|
]);
|
|
|
|
toolbarService.updateSection('MoreTools', [
|
|
'Reset',
|
|
'rotate-right',
|
|
'flipHorizontal',
|
|
'ReferenceLines',
|
|
'ImageOverlayViewer',
|
|
'StackScroll',
|
|
'invert',
|
|
'Cine',
|
|
'Magnify',
|
|
'TagBrowser',
|
|
]);
|
|
|
|
toolbarService.updateSection(toolbarService.sections.labelMapSegmentationToolbox, [
|
|
'LabelMapTools',
|
|
]);
|
|
toolbarService.updateSection(toolbarService.sections.contourSegmentationToolbox, [
|
|
'ContourTools',
|
|
]);
|
|
|
|
toolbarService.updateSection('LabelMapTools', [
|
|
'LabelmapSlicePropagation',
|
|
'BrushTools',
|
|
'MarkerLabelmap',
|
|
'RegionSegmentPlus',
|
|
'Shapes',
|
|
'LabelMapEditWithContour',
|
|
]);
|
|
toolbarService.updateSection('ContourTools', [
|
|
'PlanarFreehandContourSegmentationTool',
|
|
'SculptorTool',
|
|
'SplineContourSegmentationTool',
|
|
'LivewireContourSegmentationTool',
|
|
]);
|
|
|
|
toolbarService.updateSection(toolbarService.sections.labelMapSegmentationUtilities, [
|
|
'LabelMapUtilities',
|
|
]);
|
|
toolbarService.updateSection(toolbarService.sections.contourSegmentationUtilities, [
|
|
'ContourUtilities',
|
|
]);
|
|
|
|
toolbarService.updateSection('LabelMapUtilities', [
|
|
'InterpolateLabelmap',
|
|
'SegmentBidirectional',
|
|
]);
|
|
toolbarService.updateSection('ContourUtilities', [
|
|
'LogicalContourOperations',
|
|
'SimplifyContours',
|
|
'SmoothContours',
|
|
]);
|
|
|
|
toolbarService.updateSection('BrushTools', ['Brush', 'Eraser', 'Threshold']);
|
|
|
|
const { unsubscribeAutoTabSwitchEvents } = setUpAutoTabSwitchHandler({
|
|
segmentationService,
|
|
viewportGridService,
|
|
panelService,
|
|
});
|
|
|
|
_unsubscriptions.push(...unsubscribeAutoTabSwitchEvents);
|
|
},
|
|
onModeExit: ({ servicesManager }: withAppTypes) => {
|
|
const {
|
|
toolGroupService,
|
|
syncGroupService,
|
|
segmentationService,
|
|
cornerstoneViewportService,
|
|
uiDialogService,
|
|
uiModalService,
|
|
} = servicesManager.services;
|
|
|
|
_unsubscriptions.forEach(unsubscribe => unsubscribe());
|
|
_unsubscriptions.length = 0;
|
|
|
|
uiDialogService.hideAll();
|
|
uiModalService.hide();
|
|
toolGroupService.destroy();
|
|
syncGroupService.destroy();
|
|
segmentationService.destroy();
|
|
cornerstoneViewportService.destroy();
|
|
},
|
|
/** */
|
|
validationTags: {
|
|
study: [],
|
|
series: [],
|
|
},
|
|
/**
|
|
* A boolean return value that indicates whether the mode is valid for the
|
|
* modalities of the selected studies. Currently we don't have stack viewport
|
|
* segmentations and we should exclude them
|
|
*/
|
|
isValidMode: ({ modalities }) => {
|
|
// Don't show the mode if the selected studies have only one modality
|
|
// that is not supported by the mode
|
|
const modalitiesArray = modalities.split('\\');
|
|
return {
|
|
valid:
|
|
modalitiesArray.length === 1
|
|
? !['SM', 'ECG', 'OT', 'DOC'].includes(modalitiesArray[0])
|
|
: true,
|
|
description:
|
|
'The mode does not support studies that ONLY include the following modalities: SM, OT, DOC',
|
|
};
|
|
},
|
|
/**
|
|
* Mode Routes are used to define the mode's behavior. A list of Mode Route
|
|
* that includes the mode's path and the layout to be used. The layout will
|
|
* include the components that are used in the layout. For instance, if the
|
|
* default layoutTemplate is used (id: '@ohif/extension-default.layoutTemplateModule.viewerLayout')
|
|
* it will include the leftPanels, rightPanels, and viewports. However, if
|
|
* you define another layoutTemplate that includes a Footer for instance,
|
|
* you should provide the Footer component here too. Note: We use Strings
|
|
* to reference the component's ID as they are registered in the internal
|
|
* ExtensionManager. The template for the string is:
|
|
* `${extensionId}.{moduleType}.${componentId}`.
|
|
*/
|
|
routes: [
|
|
{
|
|
path: 'template',
|
|
layoutTemplate: ({ location, servicesManager }) => {
|
|
return {
|
|
id: ohif.layout,
|
|
props: {
|
|
leftPanels: [ohif.thumbnailList],
|
|
leftPanelResizable: true,
|
|
rightPanels: [
|
|
cornerstone.labelMapSegmentationPanel,
|
|
cornerstone.contourSegmentationPanel,
|
|
],
|
|
rightPanelResizable: true,
|
|
// leftPanelClosed: true,
|
|
viewports: [
|
|
{
|
|
namespace: cornerstone.viewport,
|
|
displaySetsToDisplay: [ohif.sopClassHandler],
|
|
},
|
|
{
|
|
namespace: segmentation.viewport,
|
|
displaySetsToDisplay: [segmentation.sopClassHandler],
|
|
},
|
|
{
|
|
namespace: dicomRT.viewport,
|
|
displaySetsToDisplay: [dicomRT.sopClassHandler],
|
|
},
|
|
],
|
|
},
|
|
};
|
|
},
|
|
},
|
|
],
|
|
/** List of extensions that are used by the mode */
|
|
extensions: extensionDependencies,
|
|
/** HangingProtocol used by the mode */
|
|
// Commented out to just use the most applicable registered hanging protocol
|
|
// The example is used for a grid layout to specify that as a preferred layout
|
|
hangingProtocol: ['@ohif/mnGrid'],
|
|
/** SopClassHandlers used by the mode */
|
|
sopClassHandlers: [ohif.sopClassHandler, segmentation.sopClassHandler, dicomRT.sopClassHandler],
|
|
};
|
|
}
|
|
|
|
const mode = {
|
|
id,
|
|
modeFactory,
|
|
extensionDependencies,
|
|
};
|
|
|
|
export default mode;
|