import { hotkeys } from '@ohif/core'; import toolbarButtons from './toolbarButtons.js'; import { id } from './id.js'; import initToolGroups from './initToolGroups.js'; // Allow this mode by excluding non-imaging modalities such as SR, SEG // Also, SM is not a simple imaging modalities, so exclude it. const NON_IMAGE_MODALITIES = ['SM', 'ECG', 'SR', 'SEG']; const ohif = { layout: '@ohif/extension-default.layoutTemplateModule.viewerLayout', sopClassHandler: '@ohif/extension-default.sopClassHandlerModule.stack', thumbnailList: '@ohif/extension-default.panelModule.seriesList', }; const tracked = { measurements: '@ohif/extension-measurement-tracking.panelModule.trackedMeasurements', thumbnailList: '@ohif/extension-measurement-tracking.panelModule.seriesList', viewport: '@ohif/extension-measurement-tracking.viewportModule.cornerstone-tracked', }; const dicomsr = { sopClassHandler: '@ohif/extension-cornerstone-dicom-sr.sopClassHandlerModule.dicom-sr', viewport: '@ohif/extension-cornerstone-dicom-sr.viewportModule.dicom-sr', }; const dicomvideo = { sopClassHandler: '@ohif/extension-dicom-video.sopClassHandlerModule.dicom-video', viewport: '@ohif/extension-dicom-video.viewportModule.dicom-video', }; const dicompdf = { sopClassHandler: '@ohif/extension-dicom-pdf.sopClassHandlerModule.dicom-pdf', viewport: '@ohif/extension-dicom-pdf.viewportModule.dicom-pdf', }; const dicomSeg = { sopClassHandler: '@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg', viewport: '@ohif/extension-cornerstone-dicom-seg.viewportModule.dicom-seg', panel: '@ohif/extension-cornerstone-dicom-seg.panelModule.panelSegmentation', }; const extensionDependencies = { // Can derive the versions at least process.env.from npm_package_version '@ohif/extension-default': '^3.0.0', '@ohif/extension-cornerstone': '^3.0.0', '@ohif/extension-measurement-tracking': '^3.0.0', '@ohif/extension-cornerstone-dicom-sr': '^3.0.0', '@ohif/extension-cornerstone-dicom-seg': '^3.0.0', '@ohif/extension-dicom-pdf': '^3.0.1', '@ohif/extension-dicom-video': '^3.0.1', }; function modeFactory() { return { // TODO: We're using this as a route segment // We should not be. id, routeName: 'basic-test', displayName: 'Basic Test Mode', /** * Lifecycle hooks */ onModeEnter: ({ servicesManager, extensionManager, commandsManager }) => { const { MeasurementService, ToolBarService, ToolGroupService, } = servicesManager.services; MeasurementService.clearMeasurements(); // Init Default and SR ToolGroups initToolGroups(extensionManager, ToolGroupService, commandsManager); let unsubscribe; const activateTool = () => { ToolBarService.recordInteraction({ groupId: 'WindowLevel', itemId: 'WindowLevel', interactionType: 'tool', commands: [ { commandName: 'setToolActive', commandOptions: { toolName: 'WindowLevel', }, context: 'CORNERSTONE', }, ], }); // We don't need to reset the active tool whenever a viewport is getting // added to the toolGroup. unsubscribe(); }; // Since we only have one viewport for the basic cs3d mode and it has // only one hanging protocol, we can just use the first viewport ({ unsubscribe } = ToolGroupService.subscribe( ToolGroupService.EVENTS.VIEWPORT_ADDED, activateTool )); ToolBarService.init(extensionManager); ToolBarService.addButtons(toolbarButtons); ToolBarService.createButtonSection('primary', [ 'MeasurementTools', 'Zoom', 'WindowLevel', 'Pan', 'Capture', 'Layout', 'MPR', 'Crosshairs', 'MoreTools', ]); }, onModeExit: ({ servicesManager }) => { const { ToolGroupService, SyncGroupService, ToolBarService, SegmentationService, CornerstoneViewportService, } = servicesManager.services; ToolBarService.reset(); ToolGroupService.destroy(); SyncGroupService.destroy(); SegmentationService.destroy(); CornerstoneViewportService.destroy(); }, validationTags: { study: [], series: [], }, isValidMode: function({ modalities }) { const modalities_list = modalities.split('\\'); // Exclude non-image modalities return !!modalities_list.filter( modality => NON_IMAGE_MODALITIES.indexOf(modality) === -1 ).length; }, routes: [ { path: 'basic-test', /*init: ({ servicesManager, extensionManager }) => { //defaultViewerRouteInit },*/ layoutTemplate: () => { return { id: ohif.layout, props: { leftPanels: [tracked.thumbnailList], rightPanels: [dicomSeg.panel, tracked.measurements], // rightPanelDefaultClosed: true, // optional prop to start with collapse panels viewports: [ { namespace: tracked.viewport, displaySetsToDisplay: [ohif.sopClassHandler], }, { namespace: dicomsr.viewport, displaySetsToDisplay: [dicomsr.sopClassHandler], }, { namespace: dicomvideo.viewport, displaySetsToDisplay: [dicomvideo.sopClassHandler], }, { namespace: dicompdf.viewport, displaySetsToDisplay: [dicompdf.sopClassHandler], }, { namespace: dicomSeg.viewport, displaySetsToDisplay: [dicomSeg.sopClassHandler], }, ], }, }; }, }, ], extensions: extensionDependencies, // Default protocol gets self-registered by default in the init hangingProtocol: 'default', // Order is important in sop class handlers when two handlers both use // the same sop class under different situations. In that case, the more // general handler needs to come last. For this case, the dicomvideo must // come first to remove video transfer syntax before ohif uses images sopClassHandlers: [ dicomvideo.sopClassHandler, dicomSeg.sopClassHandler, ohif.sopClassHandler, dicompdf.sopClassHandler, dicomsr.sopClassHandler, ], hotkeys: [...hotkeys.defaults.hotkeyBindings], }; } const mode = { id, modeFactory, extensionDependencies, }; export default mode;