From 5cbdd5ee051a0d078159934d8cbaf7c42c13a0f0 Mon Sep 17 00:00:00 2001 From: rodrigobasilio2022 Date: Wed, 9 Aug 2023 06:53:53 -0300 Subject: [PATCH 1/3] new mode that auto hydrates derived sequences --- extensions/cornerstone-dicom-rt/src/index.tsx | 2 + .../cornerstone-dicom-seg/src/index.tsx | 4 +- modes/autoload/.webpack/webpack.dev.js | 13 + modes/autoload/.webpack/webpack.prod.js | 59 ++ modes/autoload/LICENSE | 21 + modes/autoload/README.md | 4 + modes/autoload/babel.config.js | 1 + modes/autoload/package.json | 52 ++ modes/autoload/src/id.js | 5 + modes/autoload/src/index.js | 274 ++++++++ modes/autoload/src/initToolGroups.js | 260 ++++++++ modes/autoload/src/loadDerivedDisplaySets.ts | 151 +++++ modes/autoload/src/toolbarButtons.js | 608 ++++++++++++++++++ platform/app/.webpack/webpack.pwa.js | 3 +- platform/app/pluginConfig.json | 4 + 15 files changed, 1459 insertions(+), 2 deletions(-) create mode 100644 modes/autoload/.webpack/webpack.dev.js create mode 100644 modes/autoload/.webpack/webpack.prod.js create mode 100644 modes/autoload/LICENSE create mode 100644 modes/autoload/README.md create mode 100644 modes/autoload/babel.config.js create mode 100644 modes/autoload/package.json create mode 100644 modes/autoload/src/id.js create mode 100644 modes/autoload/src/index.js create mode 100644 modes/autoload/src/initToolGroups.js create mode 100644 modes/autoload/src/loadDerivedDisplaySets.ts create mode 100644 modes/autoload/src/toolbarButtons.js diff --git a/extensions/cornerstone-dicom-rt/src/index.tsx b/extensions/cornerstone-dicom-rt/src/index.tsx index 7d552977674..ee922c5f888 100644 --- a/extensions/cornerstone-dicom-rt/src/index.tsx +++ b/extensions/cornerstone-dicom-rt/src/index.tsx @@ -2,6 +2,7 @@ import { id } from './id'; import React from 'react'; import { Types } from '@ohif/core'; import getSopClassHandlerModule from './getSopClassHandlerModule'; +import hydrateRTDisplaySet from './utils/_hydrateRT'; const Component = React.lazy(() => { return import( @@ -59,3 +60,4 @@ const extension: Types.Extensions.Extension = { }; export default extension; +export { hydrateRTDisplaySet }; diff --git a/extensions/cornerstone-dicom-seg/src/index.tsx b/extensions/cornerstone-dicom-seg/src/index.tsx index 04ce5f98cb6..a0397b6155d 100644 --- a/extensions/cornerstone-dicom-seg/src/index.tsx +++ b/extensions/cornerstone-dicom-seg/src/index.tsx @@ -6,6 +6,7 @@ import { Types } from '@ohif/core'; import getSopClassHandlerModule from './getSopClassHandlerModule'; import PanelSegmentation from './panels/PanelSegmentation'; import getHangingProtocolModule from './getHangingProtocolModule'; +import hydrateSEGDisplaySet from './utils/_hydrateSEG'; const Component = React.lazy(() => { return import( @@ -88,4 +89,5 @@ const extension = { getHangingProtocolModule, }; -export default extension; \ No newline at end of file +export default extension; +export { hydrateSEGDisplaySet }; diff --git a/modes/autoload/.webpack/webpack.dev.js b/modes/autoload/.webpack/webpack.dev.js new file mode 100644 index 00000000000..2bc3ced0b9b --- /dev/null +++ b/modes/autoload/.webpack/webpack.dev.js @@ -0,0 +1,13 @@ +const path = require('path'); +const webpackCommon = require('./../../../.webpack/webpack.base.js'); +const SRC_DIR = path.join(__dirname, '../src'); +const DIST_DIR = path.join(__dirname, '../dist'); + +const ENTRY = { + app: `${SRC_DIR}/index.js`, +}; + + +module.exports = (env, argv) => { + return webpackCommon(env, argv, { SRC_DIR, DIST_DIR, ENTRY }); +}; diff --git a/modes/autoload/.webpack/webpack.prod.js b/modes/autoload/.webpack/webpack.prod.js new file mode 100644 index 00000000000..29e721312e9 --- /dev/null +++ b/modes/autoload/.webpack/webpack.prod.js @@ -0,0 +1,59 @@ +const webpack = require('webpack'); +const { merge } = require('webpack-merge'); +const path = require('path'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); + +const pkg = require('./../package.json'); +const webpackCommon = require('./../../../.webpack/webpack.base.js'); + +const ROOT_DIR = path.join(__dirname, './../'); +const SRC_DIR = path.join(__dirname, '../src'); +const DIST_DIR = path.join(__dirname, '../dist'); +const ENTRY = { + app: `${SRC_DIR}/index.js`, +}; + +module.exports = (env, argv) => { + const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR, ENTRY }); + + return merge(commonConfig, { + stats: { + colors: true, + hash: true, + timings: true, + assets: true, + chunks: false, + chunkModules: false, + modules: false, + children: false, + warnings: true, + }, + optimization: { + minimize: true, + sideEffects: false, + }, + output: { + path: ROOT_DIR, + library: 'ohif-mode-autoload', + libraryTarget: 'umd', + libraryExport: 'default', + filename: pkg.main, + }, + externals: [ + /\b(vtk.js)/, + /\b(dcmjs)/, + /\b(gl-matrix)/, + /^@ohif/, + /^@cornerstonejs/, + ], + plugins: [ + new webpack.optimize.LimitChunkCountPlugin({ + maxChunks: 1, + }), + // new MiniCssExtractPlugin({ + // filename: './dist/[name].css', + // chunkFilename: './dist/[id].css', + // }), + ], + }); +}; diff --git a/modes/autoload/LICENSE b/modes/autoload/LICENSE new file mode 100644 index 00000000000..19e20dd35ca --- /dev/null +++ b/modes/autoload/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Open Health Imaging Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/modes/autoload/README.md b/modes/autoload/README.md new file mode 100644 index 00000000000..d4679838dc6 --- /dev/null +++ b/modes/autoload/README.md @@ -0,0 +1,4 @@ +# Auto loading derived sequences Mode + +## Introduction +Auto loading derived sequences mode allows you to automatically loads related derived sequences (SEG, SR, RTSTRUCT) when user opens an image series. diff --git a/modes/autoload/babel.config.js b/modes/autoload/babel.config.js new file mode 100644 index 00000000000..325ca2a8ee7 --- /dev/null +++ b/modes/autoload/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../../babel.config.js'); diff --git a/modes/autoload/package.json b/modes/autoload/package.json new file mode 100644 index 00000000000..9fdc3c0ce9b --- /dev/null +++ b/modes/autoload/package.json @@ -0,0 +1,52 @@ +{ + "name": "@ohif/mode-autoload", + "version": "3.7.0-beta.43", + "description": "Auto load derived series longitudinal Workflow", + "author": "OHIF", + "license": "MIT", + "repository": "OHIF/Viewers", + "main": "dist/ohif-mode-autoload.js", + "module": "src/index.js", + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1.16.0" + }, + "files": [ + "dist", + "README.md" + ], + "publishConfig": { + "access": "public" + }, + "keywords": [ + "ohif-mode" + ], + "scripts": { + "dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo", + "dev:cornerstone": "yarn run dev", + "build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js", + "build:package": "yarn run build", + "start": "yarn run dev", + "test:unit": "jest --watchAll", + "test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests" + }, + "peerDependencies": { + "@ohif/core": "3.7.0-beta.43", + "@ohif/extension-cornerstone": "3.7.0-beta.43", + "@ohif/extension-cornerstone-dicom-rt": "3.7.0-beta.43", + "@ohif/extension-cornerstone-dicom-seg": "3.7.0-beta.43", + "@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.43", + "@ohif/extension-default": "3.7.0-beta.43", + "@ohif/extension-dicom-pdf": "3.7.0-beta.43", + "@ohif/extension-dicom-video": "3.7.0-beta.43", + "@ohif/extension-measurement-tracking": "3.7.0-beta.43" + }, + "dependencies": { + "@babel/runtime": "^7.20.13" + }, + "devDependencies": { + "webpack": "^5.50.0", + "webpack-merge": "^5.7.3" + } +} diff --git a/modes/autoload/src/id.js b/modes/autoload/src/id.js new file mode 100644 index 00000000000..ebe5acd98ae --- /dev/null +++ b/modes/autoload/src/id.js @@ -0,0 +1,5 @@ +import packageJson from '../package.json'; + +const id = packageJson.name; + +export { id }; diff --git a/modes/autoload/src/index.js b/modes/autoload/src/index.js new file mode 100644 index 00000000000..9c798ff690c --- /dev/null +++ b/modes/autoload/src/index.js @@ -0,0 +1,274 @@ +import { hotkeys } from '@ohif/core'; +import toolbarButtons from './toolbarButtons.js'; +import { id } from './id.js'; +import initToolGroups from './initToolGroups.js'; +import loadDerivedDisplaySets from './loadDerivedDisplaySets'; +import { eventTarget, EVENTS } from '@cornerstonejs/core'; + +// 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', 'RTSTRUCT']; + +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 dicomRt = { + viewport: '@ohif/extension-cornerstone-dicom-rt.viewportModule.dicom-rt', + sopClassHandler: + '@ohif/extension-cornerstone-dicom-rt.sopClassHandlerModule.dicom-rt', +}; + +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-cornerstone-dicom-rt': '^3.0.0', + '@ohif/extension-dicom-pdf': '^3.0.1', + '@ohif/extension-dicom-video': '^3.0.1', +}; + +function modeFactory({ modeConfiguration }) { + let _activatePanelTriggersSubscriptions = []; + let boundedLoadDerivedDisplaySets; + return { + // TODO: We're using this as a route segment + // We should not be. + id, + routeName: 'autoload', + displayName: 'Auto load derived series Viewer', + /** + * Lifecycle hooks + */ + onModeEnter: ({ servicesManager, extensionManager, commandsManager }) => { + const { + measurementService, + toolbarService, + toolGroupService, + panelService, + segmentationService, + } = servicesManager.services; + + boundedLoadDerivedDisplaySets = loadDerivedDisplaySets.bind( + null, + servicesManager, + extensionManager + ); + 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', + ]); + + // // ActivatePanel event trigger for when a segmentation or measurement is added. + // // Do not force activation so as to respect the state the user may have left the UI in. + // _activatePanelTriggersSubscriptions = [ + // ...panelService.addActivatePanelTriggers(dicomSeg.panel, [ + // { + // sourcePubSubService: segmentationService, + // sourceEvents: [ + // segmentationService.EVENTS.SEGMENTATION_PIXEL_DATA_CREATED, + // ], + // }, + // ]), + // ...panelService.addActivatePanelTriggers(tracked.measurements, [ + // { + // sourcePubSubService: measurementService, + // sourceEvents: [ + // measurementService.EVENTS.MEASUREMENT_ADDED, + // measurementService.EVENTS.RAW_MEASUREMENT_ADDED, + // ], + // }, + // ]), + // ]; + eventTarget.addEventListener( + EVENTS.STACK_VIEWPORT_NEW_STACK, + boundedLoadDerivedDisplaySets + ); + }, + onModeExit: ({ servicesManager }) => { + const { + toolGroupService, + syncGroupService, + toolbarService, + segmentationService, + cornerstoneViewportService, + } = servicesManager.services; + + eventTarget.removeEventListener( + EVENTS.STACK_VIEWPORT_NEW_STACK, + boundedLoadDerivedDisplaySets + ); + _activatePanelTriggersSubscriptions.forEach(sub => sub.unsubscribe()); + _activatePanelTriggersSubscriptions = []; + + 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: 'longitudinal', + /*init: ({ servicesManager, extensionManager }) => { + //defaultViewerRouteInit + },*/ + layoutTemplate: () => { + return { + id: ohif.layout, + props: { + leftPanels: [tracked.thumbnailList], + rightPanels: [dicomSeg.panel, tracked.measurements], + rightPanelDefaultClosed: true, + 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], + }, + { + namespace: dicomRt.viewport, + displaySetsToDisplay: [dicomRt.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, + dicomRt.sopClassHandler, + ], + hotkeys: [...hotkeys.defaults.hotkeyBindings], + ...modeConfiguration, + }; +} + +const mode = { + id, + modeFactory, + extensionDependencies, +}; + +export default mode; +export { initToolGroups, toolbarButtons }; diff --git a/modes/autoload/src/initToolGroups.js b/modes/autoload/src/initToolGroups.js new file mode 100644 index 00000000000..b8e88db909a --- /dev/null +++ b/modes/autoload/src/initToolGroups.js @@ -0,0 +1,260 @@ +function initDefaultToolGroup( + extensionManager, + toolGroupService, + commandsManager, + toolGroupId +) { + const utilityModule = extensionManager.getModuleEntry( + '@ohif/extension-cornerstone.utilityModule.tools' + ); + + const { toolNames, Enums } = utilityModule.exports; + + const tools = { + active: [ + { + toolName: toolNames.WindowLevel, + bindings: [{ mouseButton: Enums.MouseBindings.Primary }], + }, + { + toolName: toolNames.Pan, + bindings: [{ mouseButton: Enums.MouseBindings.Auxiliary }], + }, + { + toolName: toolNames.Zoom, + bindings: [{ mouseButton: Enums.MouseBindings.Secondary }], + }, + { toolName: toolNames.StackScrollMouseWheel, bindings: [] }, + ], + passive: [ + { toolName: toolNames.Length }, + { toolName: toolNames.ArrowAnnotate }, + { toolName: toolNames.Bidirectional }, + { toolName: toolNames.DragProbe }, + { toolName: toolNames.EllipticalROI }, + { toolName: toolNames.CircleROI }, + { toolName: toolNames.RectangleROI }, + { toolName: toolNames.StackScroll }, + { toolName: toolNames.Angle }, + { toolName: toolNames.CobbAngle }, + { toolName: toolNames.PlanarFreehandROI }, + { toolName: toolNames.Magnify }, + { toolName: toolNames.SegmentationDisplay }, + { toolName: toolNames.CalibrationLine }, + ], + // enabled + // disabled + disabled: [{ toolName: toolNames.ReferenceLines }], + }; + + const toolsConfig = { + [toolNames.ArrowAnnotate]: { + getTextCallback: (callback, eventDetails) => + commandsManager.runCommand('arrowTextCallback', { + callback, + eventDetails, + }), + + changeTextCallback: (data, eventDetails, callback) => + commandsManager.runCommand('arrowTextCallback', { + callback, + data, + eventDetails, + }), + }, + }; + + toolGroupService.createToolGroupAndAddTools(toolGroupId, tools, toolsConfig); +} + +function initSRToolGroup(extensionManager, toolGroupService, commandsManager) { + const SRUtilityModule = extensionManager.getModuleEntry( + '@ohif/extension-cornerstone-dicom-sr.utilityModule.tools' + ); + + const CS3DUtilityModule = extensionManager.getModuleEntry( + '@ohif/extension-cornerstone.utilityModule.tools' + ); + + const { toolNames: SRToolNames } = SRUtilityModule.exports; + const { toolNames, Enums } = CS3DUtilityModule.exports; + const tools = { + active: [ + { + toolName: toolNames.WindowLevel, + bindings: [ + { + mouseButton: Enums.MouseBindings.Primary, + }, + ], + }, + { + toolName: toolNames.Pan, + bindings: [ + { + mouseButton: Enums.MouseBindings.Auxiliary, + }, + ], + }, + { + toolName: toolNames.Zoom, + bindings: [ + { + mouseButton: Enums.MouseBindings.Secondary, + }, + ], + }, + { + toolName: toolNames.StackScrollMouseWheel, + bindings: [], + }, + ], + passive: [ + { toolName: SRToolNames.SRLength }, + { toolName: SRToolNames.SRArrowAnnotate }, + { toolName: SRToolNames.SRBidirectional }, + { toolName: SRToolNames.SREllipticalROI }, + { toolName: SRToolNames.SRCircleROI }, + ], + enabled: [ + { + toolName: SRToolNames.DICOMSRDisplay, + bindings: [], + }, + ], + // disabled + }; + + const toolsConfig = { + [toolNames.ArrowAnnotate]: { + getTextCallback: (callback, eventDetails) => + commandsManager.runCommand('arrowTextCallback', { + callback, + eventDetails, + }), + + changeTextCallback: (data, eventDetails, callback) => + commandsManager.runCommand('arrowTextCallback', { + callback, + data, + eventDetails, + }), + }, + }; + + const toolGroupId = 'SRToolGroup'; + toolGroupService.createToolGroupAndAddTools(toolGroupId, tools, toolsConfig); +} + +function initMPRToolGroup(extensionManager, toolGroupService, commandsManager) { + const utilityModule = extensionManager.getModuleEntry( + '@ohif/extension-cornerstone.utilityModule.tools' + ); + + const { toolNames, Enums } = utilityModule.exports; + + const tools = { + active: [ + { + toolName: toolNames.WindowLevel, + bindings: [{ mouseButton: Enums.MouseBindings.Primary }], + }, + { + toolName: toolNames.Pan, + bindings: [{ mouseButton: Enums.MouseBindings.Auxiliary }], + }, + { + toolName: toolNames.Zoom, + bindings: [{ mouseButton: Enums.MouseBindings.Secondary }], + }, + { toolName: toolNames.StackScrollMouseWheel, bindings: [] }, + ], + passive: [ + { toolName: toolNames.Length }, + { toolName: toolNames.ArrowAnnotate }, + { toolName: toolNames.Bidirectional }, + { toolName: toolNames.DragProbe }, + { toolName: toolNames.EllipticalROI }, + { toolName: toolNames.CircleROI }, + { toolName: toolNames.RectangleROI }, + { toolName: toolNames.StackScroll }, + { toolName: toolNames.Angle }, + { toolName: toolNames.CobbAngle }, + { toolName: toolNames.PlanarFreehandROI }, + { toolName: toolNames.SegmentationDisplay }, + ], + disabled: [ + { toolName: toolNames.Crosshairs }, + { toolName: toolNames.ReferenceLines }, + ], + + // enabled + // disabled + }; + + const toolsConfig = { + [toolNames.Crosshairs]: { + viewportIndicators: false, + autoPan: { + enabled: false, + panSize: 10, + }, + }, + [toolNames.ArrowAnnotate]: { + getTextCallback: (callback, eventDetails) => + commandsManager.runCommand('arrowTextCallback', { + callback, + eventDetails, + }), + + changeTextCallback: (data, eventDetails, callback) => + commandsManager.runCommand('arrowTextCallback', { + callback, + data, + eventDetails, + }), + }, + }; + + toolGroupService.createToolGroupAndAddTools('mpr', tools, toolsConfig); +} +function initVolume3DToolGroup(extensionManager, toolGroupService) { + const utilityModule = extensionManager.getModuleEntry( + '@ohif/extension-cornerstone.utilityModule.tools' + ); + + const { toolNames, Enums } = utilityModule.exports; + + const tools = { + active: [ + { + toolName: toolNames.TrackballRotateTool, + bindings: [{ mouseButton: Enums.MouseBindings.Primary }], + }, + { + toolName: toolNames.Zoom, + bindings: [{ mouseButton: Enums.MouseBindings.Secondary }], + }, + { + toolName: toolNames.Pan, + bindings: [{ mouseButton: Enums.MouseBindings.Auxiliary }], + }, + ], + }; + + toolGroupService.createToolGroupAndAddTools('volume3d', tools); +} + +function initToolGroups(extensionManager, toolGroupService, commandsManager) { + initDefaultToolGroup( + extensionManager, + toolGroupService, + commandsManager, + 'default' + ); + initSRToolGroup(extensionManager, toolGroupService, commandsManager); + initMPRToolGroup(extensionManager, toolGroupService, commandsManager); + initVolume3DToolGroup(extensionManager, toolGroupService); +} + +export default initToolGroups; diff --git a/modes/autoload/src/loadDerivedDisplaySets.ts b/modes/autoload/src/loadDerivedDisplaySets.ts new file mode 100644 index 00000000000..e92ac497f65 --- /dev/null +++ b/modes/autoload/src/loadDerivedDisplaySets.ts @@ -0,0 +1,151 @@ +import { hydrateSEGDisplaySet } from '@ohif/extension-cornerstone-dicom-seg'; +import { hydrateRTDisplaySet } from '@ohif/extension-cornerstone-dicom-rt'; +import { hydrateStructuredReport } from '@ohif/extension-cornerstone-dicom-sr'; +import { cache as cs3DCache, volumeLoader } from '@cornerstonejs/core'; + +const delay = 0; + +function getDerivedSequences(displaySetUID, servicesManager) { + const { displaySetService } = servicesManager.services; + + const displaySetCache = displaySetService.getDisplaySetCache(); + const derivedDisplaySets = [...displaySetCache.values()].filter(ds => { + if (ds?.getReferenceDisplaySet) { + ds?.getReferenceDisplaySet(); + } + return ( + (ds?.referencedDisplaySetInstanceUID === displaySetUID || + ds.Modality === 'SR') && + !ds?.isHydrated + ); + }); + return derivedDisplaySets; +} + +export default function loadDerivedDisplaySets( + servicesManager, + extensionManager, + evt +) { + async function checkVolume(displaySet, imageIds) { + const VOLUME_LOADER_SCHEME = 'cornerstoneStreamingImageVolume'; + const volumeLoaderSchema = + displaySet.volumeLoaderSchema ?? VOLUME_LOADER_SCHEME; + + const volumeId = `${volumeLoaderSchema}:${displaySet.displaySetInstanceUID}`; + + let volume = cs3DCache.getVolume(volumeId); + + if (!volume) { + volume = await volumeLoader.createAndCacheVolume(volumeId, { imageIds }); + } + } + + const { + userAuthenticationService, + segmentationService, + displaySetService, + viewportGridService, + } = servicesManager.services; + + const { viewports } = viewportGridService.getState(); + const { viewportId, imageIds } = evt.detail; + let viewportIndex = -1; + for (let i = 0; i < viewports.length; i++) { + if ((viewports[i].viewportId = viewportId)) { + viewportIndex = i; + break; + } + } + const mainViewport = viewports[viewportIndex]; + if (viewportIndex > -1) { + if (mainViewport.displaySetInstanceUIDs.length === 1) { + const mainDisplaySet = displaySetService.getDisplaySetByUID( + mainViewport.displaySetInstanceUIDs[0] + ); + const derivedDisplaySets = getDerivedSequences( + mainViewport.displaySetInstanceUIDs[0], + servicesManager + ); + + derivedDisplaySets.forEach(async displaySet => { + const headers = userAuthenticationService.getAuthorizationHeader(); + await checkVolume(mainDisplaySet, imageIds); + await displaySet.load({ headers }); + const derivedDisplaySetInstanceUID = displaySet.displaySetInstanceUID; + + if (displaySet.Modality === 'SEG') { + let segmentationId = null; + + // We need the hydration to notify panels about the new segmentation added + const suppressEvents = false; + + segmentationId = await segmentationService.createSegmentationForSEGDisplaySet( + displaySet, + segmentationId, + suppressEvents + ); + setTimeout(() => { + if ( + !mainViewport.displaySetInstanceUIDs.includes( + derivedDisplaySetInstanceUID + ) + ) { + mainViewport.displaySetInstanceUIDs.push( + derivedDisplaySetInstanceUID + ); + } + hydrateSEGDisplaySet({ + segDisplaySet: displaySet, + viewportIndex, + servicesManager, + }); + }, delay); + } else if (displaySet.Modality === 'RTSTRUCT') { + let segmentationId = null; + + // We need the hydration to notify panels about the new segmentation added + const suppressEvents = false; + + segmentationId = await segmentationService.createSegmentationForRTDisplaySet( + displaySet, + segmentationId, + suppressEvents + ); + setTimeout(() => { + if ( + !mainViewport.displaySetInstanceUIDs.includes( + derivedDisplaySetInstanceUID + ) + ) { + mainViewport.displaySetInstanceUIDs.push( + derivedDisplaySetInstanceUID + ); + } + hydrateRTDisplaySet({ + rtDisplaySet: displaySet, + viewportIndex, + servicesManager, + }); + }, delay); + } else if (displaySet.Modality === 'SR') { + setTimeout(() => { + if ( + !mainViewport.displaySetInstanceUIDs.includes( + derivedDisplaySetInstanceUID + ) + ) { + mainViewport.displaySetInstanceUIDs.push( + derivedDisplaySetInstanceUID + ); + } + hydrateStructuredReport( + { servicesManager, extensionManager }, + derivedDisplaySetInstanceUID + ); + }, delay); + } + }); + } + } +} diff --git a/modes/autoload/src/toolbarButtons.js b/modes/autoload/src/toolbarButtons.js new file mode 100644 index 00000000000..92de37e89dd --- /dev/null +++ b/modes/autoload/src/toolbarButtons.js @@ -0,0 +1,608 @@ +// TODO: torn, can either bake this here; or have to create a whole new button type +// Only ways that you can pass in a custom React component for render :l +import { + // ExpandableToolbarButton, + // ListMenu, + WindowLevelMenuItem, +} from '@ohif/ui'; +import { defaults } from '@ohif/core'; + +const { windowLevelPresets } = defaults; +/** + * + * @param {*} type - 'tool' | 'action' | 'toggle' + * @param {*} id + * @param {*} icon + * @param {*} label + */ +function _createButton(type, id, icon, label, commands, tooltip, uiType) { + return { + id, + icon, + label, + type, + commands, + tooltip, + uiType, + }; +} + +const _createActionButton = _createButton.bind(null, 'action'); +const _createToggleButton = _createButton.bind(null, 'toggle'); +const _createToolButton = _createButton.bind(null, 'tool'); + +/** + * + * @param {*} preset - preset number (from above import) + * @param {*} title + * @param {*} subtitle + */ +function _createWwwcPreset(preset, title, subtitle) { + return { + id: preset.toString(), + title, + subtitle, + type: 'action', + commands: [ + { + commandName: 'setWindowLevel', + commandOptions: { + ...windowLevelPresets[preset], + }, + context: 'CORNERSTONE', + }, + ], + }; +} + +const toolGroupIds = ['default', 'mpr', 'SRToolGroup']; + +/** + * Creates an array of 'setToolActive' commands for the given toolName - one for + * each toolGroupId specified in toolGroupIds. + * @param {string} toolName + * @returns {Array} an array of 'setToolActive' commands + */ +function _createSetToolActiveCommands(toolName) { + const temp = toolGroupIds.map(toolGroupId => ({ + commandName: 'setToolActive', + commandOptions: { + toolGroupId, + toolName, + }, + context: 'CORNERSTONE', + })); + return temp; +} + +const toolbarButtons = [ + // Measurement + { + id: 'MeasurementTools', + type: 'ohif.splitButton', + props: { + groupId: 'MeasurementTools', + isRadio: true, // ? + // Switch? + primary: _createToolButton( + 'Length', + 'tool-length', + 'Length', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'Length', + }, + context: 'CORNERSTONE', + }, + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'SRLength', + toolGroupId: 'SRToolGroup', + }, + // we can use the setToolActive command for this from Cornerstone commandsModule + context: 'CORNERSTONE', + }, + ], + 'Length' + ), + secondary: { + icon: 'chevron-down', + label: '', + isActive: true, + tooltip: 'More Measure Tools', + }, + items: [ + _createToolButton( + 'Length', + 'tool-length', + 'Length', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'Length', + }, + context: 'CORNERSTONE', + }, + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'SRLength', + toolGroupId: 'SRToolGroup', + }, + // we can use the setToolActive command for this from Cornerstone commandsModule + context: 'CORNERSTONE', + }, + ], + 'Length Tool' + ), + _createToolButton( + 'Bidirectional', + 'tool-bidirectional', + 'Bidirectional', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'Bidirectional', + }, + context: 'CORNERSTONE', + }, + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'SRBidirectional', + toolGroupId: 'SRToolGroup', + }, + context: 'CORNERSTONE', + }, + ], + 'Bidirectional Tool' + ), + _createToolButton( + 'ArrowAnnotate', + 'tool-annotate', + 'Annotation', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'ArrowAnnotate', + }, + context: 'CORNERSTONE', + }, + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'SRArrowAnnotate', + toolGroupId: 'SRToolGroup', + }, + context: 'CORNERSTONE', + }, + ], + 'Arrow Annotate' + ), + _createToolButton( + 'EllipticalROI', + 'tool-elipse', + 'Ellipse', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'EllipticalROI', + }, + context: 'CORNERSTONE', + }, + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'SREllipticalROI', + toolGroupId: 'SRToolGroup', + }, + context: 'CORNERSTONE', + }, + ], + 'Ellipse Tool' + ), + _createToolButton( + 'CircleROI', + 'tool-circle', + 'Circle', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'CircleROI', + }, + context: 'CORNERSTONE', + }, + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'SRCircleROI', + toolGroupId: 'SRToolGroup', + }, + context: 'CORNERSTONE', + }, + ], + 'Circle Tool' + ), + ], + }, + }, + // Zoom.. + { + id: 'Zoom', + type: 'ohif.radioGroup', + props: { + type: 'tool', + icon: 'tool-zoom', + label: 'Zoom', + commands: _createSetToolActiveCommands('Zoom'), + }, + }, + // Window Level + Presets... + { + id: 'WindowLevel', + type: 'ohif.splitButton', + props: { + groupId: 'WindowLevel', + primary: _createToolButton( + 'WindowLevel', + 'tool-window-level', + 'Window Level', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'WindowLevel', + }, + context: 'CORNERSTONE', + }, + ], + 'Window Level' + ), + secondary: { + icon: 'chevron-down', + label: 'W/L Manual', + isActive: true, + tooltip: 'W/L Presets', + }, + isAction: true, // ? + renderer: WindowLevelMenuItem, + items: [ + _createWwwcPreset(1, 'Soft tissue', '400 / 40'), + _createWwwcPreset(2, 'Lung', '1500 / -600'), + _createWwwcPreset(3, 'Liver', '150 / 90'), + _createWwwcPreset(4, 'Bone', '2500 / 480'), + _createWwwcPreset(5, 'Brain', '80 / 40'), + ], + }, + }, + // Pan... + { + id: 'Pan', + type: 'ohif.radioGroup', + props: { + type: 'tool', + icon: 'tool-move', + label: 'Pan', + commands: _createSetToolActiveCommands('Pan'), + }, + }, + { + id: 'Capture', + type: 'ohif.action', + props: { + icon: 'tool-capture', + label: 'Capture', + type: 'action', + commands: [ + { + commandName: 'showDownloadViewportModal', + commandOptions: {}, + context: 'CORNERSTONE', + }, + ], + }, + }, + { + id: 'Layout', + type: 'ohif.layoutSelector', + props: { + rows: 3, + columns: 3, + }, + }, + { + id: 'MPR', + type: 'ohif.action', + props: { + type: 'toggle', + icon: 'icon-mpr', + label: 'MPR', + commands: [ + { + commandName: 'toggleHangingProtocol', + commandOptions: { + protocolId: 'mpr', + }, + context: 'DEFAULT', + }, + ], + }, + }, + { + id: 'Crosshairs', + type: 'ohif.radioGroup', + props: { + type: 'tool', + icon: 'tool-crosshair', + label: 'Crosshairs', + commands: [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'Crosshairs', + toolGroupId: 'mpr', + }, + context: 'CORNERSTONE', + }, + ], + }, + }, + // More... + { + id: 'MoreTools', + type: 'ohif.splitButton', + props: { + isRadio: true, // ? + groupId: 'MoreTools', + primary: _createActionButton( + 'Reset', + 'tool-reset', + 'Reset View', + [ + { + commandName: 'resetViewport', + commandOptions: {}, + context: 'CORNERSTONE', + }, + ], + 'Reset' + ), + secondary: { + icon: 'chevron-down', + label: '', + isActive: true, + tooltip: 'More Tools', + }, + items: [ + _createActionButton( + 'Reset', + 'tool-reset', + 'Reset View', + [ + { + commandName: 'resetViewport', + commandOptions: {}, + context: 'CORNERSTONE', + }, + ], + 'Reset' + ), + _createActionButton( + 'rotate-right', + 'tool-rotate-right', + 'Rotate Right', + [ + { + commandName: 'rotateViewportCW', + commandOptions: {}, + context: 'CORNERSTONE', + }, + ], + 'Rotate +90' + ), + _createActionButton( + 'flip-horizontal', + 'tool-flip-horizontal', + 'Flip Horizontally', + [ + { + commandName: 'flipViewportHorizontal', + commandOptions: {}, + context: 'CORNERSTONE', + }, + ], + 'Flip Horizontal' + ), + _createToggleButton('StackImageSync', 'link', 'Stack Image Sync', [ + { + commandName: 'toggleStackImageSync', + commandOptions: {}, + context: 'CORNERSTONE', + }, + ]), + _createToggleButton( + 'ReferenceLines', + 'tool-referenceLines', // change this with the new icon + 'Reference Lines', + [ + { + commandName: 'toggleReferenceLines', + commandOptions: {}, + context: 'CORNERSTONE', + }, + ] + ), + _createToolButton( + 'StackScroll', + 'tool-stack-scroll', + 'Stack Scroll', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'StackScroll', + }, + context: 'CORNERSTONE', + }, + ], + 'Stack Scroll' + ), + _createActionButton( + 'invert', + 'tool-invert', + 'Invert', + [ + { + commandName: 'invertViewport', + commandOptions: {}, + context: 'CORNERSTONE', + }, + ], + 'Invert Colors' + ), + _createToolButton( + 'Probe', + 'tool-probe', + 'Probe', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'DragProbe', + }, + context: 'CORNERSTONE', + }, + ], + 'Probe' + ), + _createToggleButton( + 'cine', + 'tool-cine', + 'Cine', + [ + { + commandName: 'toggleCine', + context: 'CORNERSTONE', + }, + ], + 'Cine' + ), + _createToolButton( + 'Angle', + 'tool-angle', + 'Angle', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'Angle', + }, + context: 'CORNERSTONE', + }, + ], + 'Angle' + ), + + // Next two tools can be added once icons are added + // _createToolButton( + // 'Cobb Angle', + // 'tool-cobb-angle', + // 'Cobb Angle', + // [ + // { + // commandName: 'setToolActive', + // commandOptions: { + // toolName: 'CobbAngle', + // }, + // context: 'CORNERSTONE', + // }, + // ], + // 'Cobb Angle' + // ), + // _createToolButton( + // 'Planar Freehand ROI', + // 'tool-freehand', + // 'PlanarFreehandROI', + // [ + // { + // commandName: 'setToolActive', + // commandOptions: { + // toolName: 'PlanarFreehandROI', + // }, + // context: 'CORNERSTONE', + // }, + // ], + // 'Planar Freehand ROI' + // ), + _createToolButton( + 'Magnify', + 'tool-magnify', + 'Magnify', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'Magnify', + }, + context: 'CORNERSTONE', + }, + ], + 'Magnify' + ), + _createToolButton( + 'Rectangle', + 'tool-rectangle', + 'Rectangle', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'RectangleROI', + }, + context: 'CORNERSTONE', + }, + ], + 'Rectangle' + ), + _createToolButton( + 'CalibrationLine', + 'tool-calibration', + 'Calibration', + [ + { + commandName: 'setToolActive', + commandOptions: { + toolName: 'CalibrationLine', + }, + context: 'CORNERSTONE', + }, + ], + 'Calibration Line' + ), + _createActionButton( + 'TagBrowser', + 'list-bullets', + 'Dicom Tag Browser', + [ + { + commandName: 'openDICOMTagViewer', + commandOptions: {}, + context: 'DEFAULT', + }, + ], + 'Dicom Tag Browser' + ), + ], + }, + }, +]; + +export default toolbarButtons; diff --git a/platform/app/.webpack/webpack.pwa.js b/platform/app/.webpack/webpack.pwa.js index 8d98c40a7a7..aac92a85217 100644 --- a/platform/app/.webpack/webpack.pwa.js +++ b/platform/app/.webpack/webpack.pwa.js @@ -54,7 +54,7 @@ module.exports = (env, argv) => { path: DIST_DIR, filename: isProdBuild ? '[name].bundle.[chunkhash].js' : '[name].js', publicPath: PUBLIC_URL, // Used by HtmlWebPackPlugin for asset prefix - devtoolModuleFilenameTemplate: function(info) { + devtoolModuleFilenameTemplate: function (info) { if (isProdBuild) { return `webpack:///${info.resourcePath}`; } else { @@ -69,6 +69,7 @@ module.exports = (env, argv) => { // Hoisted Yarn Workspace Modules path.resolve(__dirname, '../../../node_modules'), SRC_DIR, + path.resolve(__dirname, 'modes/autoload/node_modules'), ], }, plugins: [ diff --git a/platform/app/pluginConfig.json b/platform/app/pluginConfig.json index 2f892db6c86..8ed3472729b 100644 --- a/platform/app/pluginConfig.json +++ b/platform/app/pluginConfig.json @@ -72,6 +72,10 @@ "packageName": "@ohif/mode-basic-dev-mode", "default": false, "version": "3.0.0" + }, + { + "packageName": "@ohif/mode-autoload", + "version": "3.7.0-beta.43" } ], "public": [ From 31e312240039e62d0d70eea0cfcf2bf54a60545a Mon Sep 17 00:00:00 2001 From: rodrigobasilio2022 Date: Wed, 9 Aug 2023 10:41:09 -0300 Subject: [PATCH 2/3] Removing the mode --- modes/autoload/.webpack/webpack.dev.js | 13 - modes/autoload/.webpack/webpack.prod.js | 59 -- modes/autoload/LICENSE | 21 - modes/autoload/README.md | 4 - modes/autoload/babel.config.js | 1 - modes/autoload/package.json | 52 -- modes/autoload/src/id.js | 5 - modes/autoload/src/index.js | 274 --------- modes/autoload/src/initToolGroups.js | 260 -------- modes/autoload/src/loadDerivedDisplaySets.ts | 151 ----- modes/autoload/src/toolbarButtons.js | 608 ------------------- 11 files changed, 1448 deletions(-) delete mode 100644 modes/autoload/.webpack/webpack.dev.js delete mode 100644 modes/autoload/.webpack/webpack.prod.js delete mode 100644 modes/autoload/LICENSE delete mode 100644 modes/autoload/README.md delete mode 100644 modes/autoload/babel.config.js delete mode 100644 modes/autoload/package.json delete mode 100644 modes/autoload/src/id.js delete mode 100644 modes/autoload/src/index.js delete mode 100644 modes/autoload/src/initToolGroups.js delete mode 100644 modes/autoload/src/loadDerivedDisplaySets.ts delete mode 100644 modes/autoload/src/toolbarButtons.js diff --git a/modes/autoload/.webpack/webpack.dev.js b/modes/autoload/.webpack/webpack.dev.js deleted file mode 100644 index 2bc3ced0b9b..00000000000 --- a/modes/autoload/.webpack/webpack.dev.js +++ /dev/null @@ -1,13 +0,0 @@ -const path = require('path'); -const webpackCommon = require('./../../../.webpack/webpack.base.js'); -const SRC_DIR = path.join(__dirname, '../src'); -const DIST_DIR = path.join(__dirname, '../dist'); - -const ENTRY = { - app: `${SRC_DIR}/index.js`, -}; - - -module.exports = (env, argv) => { - return webpackCommon(env, argv, { SRC_DIR, DIST_DIR, ENTRY }); -}; diff --git a/modes/autoload/.webpack/webpack.prod.js b/modes/autoload/.webpack/webpack.prod.js deleted file mode 100644 index 29e721312e9..00000000000 --- a/modes/autoload/.webpack/webpack.prod.js +++ /dev/null @@ -1,59 +0,0 @@ -const webpack = require('webpack'); -const { merge } = require('webpack-merge'); -const path = require('path'); -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); - -const pkg = require('./../package.json'); -const webpackCommon = require('./../../../.webpack/webpack.base.js'); - -const ROOT_DIR = path.join(__dirname, './../'); -const SRC_DIR = path.join(__dirname, '../src'); -const DIST_DIR = path.join(__dirname, '../dist'); -const ENTRY = { - app: `${SRC_DIR}/index.js`, -}; - -module.exports = (env, argv) => { - const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR, ENTRY }); - - return merge(commonConfig, { - stats: { - colors: true, - hash: true, - timings: true, - assets: true, - chunks: false, - chunkModules: false, - modules: false, - children: false, - warnings: true, - }, - optimization: { - minimize: true, - sideEffects: false, - }, - output: { - path: ROOT_DIR, - library: 'ohif-mode-autoload', - libraryTarget: 'umd', - libraryExport: 'default', - filename: pkg.main, - }, - externals: [ - /\b(vtk.js)/, - /\b(dcmjs)/, - /\b(gl-matrix)/, - /^@ohif/, - /^@cornerstonejs/, - ], - plugins: [ - new webpack.optimize.LimitChunkCountPlugin({ - maxChunks: 1, - }), - // new MiniCssExtractPlugin({ - // filename: './dist/[name].css', - // chunkFilename: './dist/[id].css', - // }), - ], - }); -}; diff --git a/modes/autoload/LICENSE b/modes/autoload/LICENSE deleted file mode 100644 index 19e20dd35ca..00000000000 --- a/modes/autoload/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 Open Health Imaging Foundation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/modes/autoload/README.md b/modes/autoload/README.md deleted file mode 100644 index d4679838dc6..00000000000 --- a/modes/autoload/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Auto loading derived sequences Mode - -## Introduction -Auto loading derived sequences mode allows you to automatically loads related derived sequences (SEG, SR, RTSTRUCT) when user opens an image series. diff --git a/modes/autoload/babel.config.js b/modes/autoload/babel.config.js deleted file mode 100644 index 325ca2a8ee7..00000000000 --- a/modes/autoload/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../babel.config.js'); diff --git a/modes/autoload/package.json b/modes/autoload/package.json deleted file mode 100644 index 9fdc3c0ce9b..00000000000 --- a/modes/autoload/package.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "@ohif/mode-autoload", - "version": "3.7.0-beta.43", - "description": "Auto load derived series longitudinal Workflow", - "author": "OHIF", - "license": "MIT", - "repository": "OHIF/Viewers", - "main": "dist/ohif-mode-autoload.js", - "module": "src/index.js", - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1.16.0" - }, - "files": [ - "dist", - "README.md" - ], - "publishConfig": { - "access": "public" - }, - "keywords": [ - "ohif-mode" - ], - "scripts": { - "dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo", - "dev:cornerstone": "yarn run dev", - "build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js", - "build:package": "yarn run build", - "start": "yarn run dev", - "test:unit": "jest --watchAll", - "test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests" - }, - "peerDependencies": { - "@ohif/core": "3.7.0-beta.43", - "@ohif/extension-cornerstone": "3.7.0-beta.43", - "@ohif/extension-cornerstone-dicom-rt": "3.7.0-beta.43", - "@ohif/extension-cornerstone-dicom-seg": "3.7.0-beta.43", - "@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.43", - "@ohif/extension-default": "3.7.0-beta.43", - "@ohif/extension-dicom-pdf": "3.7.0-beta.43", - "@ohif/extension-dicom-video": "3.7.0-beta.43", - "@ohif/extension-measurement-tracking": "3.7.0-beta.43" - }, - "dependencies": { - "@babel/runtime": "^7.20.13" - }, - "devDependencies": { - "webpack": "^5.50.0", - "webpack-merge": "^5.7.3" - } -} diff --git a/modes/autoload/src/id.js b/modes/autoload/src/id.js deleted file mode 100644 index ebe5acd98ae..00000000000 --- a/modes/autoload/src/id.js +++ /dev/null @@ -1,5 +0,0 @@ -import packageJson from '../package.json'; - -const id = packageJson.name; - -export { id }; diff --git a/modes/autoload/src/index.js b/modes/autoload/src/index.js deleted file mode 100644 index 9c798ff690c..00000000000 --- a/modes/autoload/src/index.js +++ /dev/null @@ -1,274 +0,0 @@ -import { hotkeys } from '@ohif/core'; -import toolbarButtons from './toolbarButtons.js'; -import { id } from './id.js'; -import initToolGroups from './initToolGroups.js'; -import loadDerivedDisplaySets from './loadDerivedDisplaySets'; -import { eventTarget, EVENTS } from '@cornerstonejs/core'; - -// 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', 'RTSTRUCT']; - -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 dicomRt = { - viewport: '@ohif/extension-cornerstone-dicom-rt.viewportModule.dicom-rt', - sopClassHandler: - '@ohif/extension-cornerstone-dicom-rt.sopClassHandlerModule.dicom-rt', -}; - -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-cornerstone-dicom-rt': '^3.0.0', - '@ohif/extension-dicom-pdf': '^3.0.1', - '@ohif/extension-dicom-video': '^3.0.1', -}; - -function modeFactory({ modeConfiguration }) { - let _activatePanelTriggersSubscriptions = []; - let boundedLoadDerivedDisplaySets; - return { - // TODO: We're using this as a route segment - // We should not be. - id, - routeName: 'autoload', - displayName: 'Auto load derived series Viewer', - /** - * Lifecycle hooks - */ - onModeEnter: ({ servicesManager, extensionManager, commandsManager }) => { - const { - measurementService, - toolbarService, - toolGroupService, - panelService, - segmentationService, - } = servicesManager.services; - - boundedLoadDerivedDisplaySets = loadDerivedDisplaySets.bind( - null, - servicesManager, - extensionManager - ); - 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', - ]); - - // // ActivatePanel event trigger for when a segmentation or measurement is added. - // // Do not force activation so as to respect the state the user may have left the UI in. - // _activatePanelTriggersSubscriptions = [ - // ...panelService.addActivatePanelTriggers(dicomSeg.panel, [ - // { - // sourcePubSubService: segmentationService, - // sourceEvents: [ - // segmentationService.EVENTS.SEGMENTATION_PIXEL_DATA_CREATED, - // ], - // }, - // ]), - // ...panelService.addActivatePanelTriggers(tracked.measurements, [ - // { - // sourcePubSubService: measurementService, - // sourceEvents: [ - // measurementService.EVENTS.MEASUREMENT_ADDED, - // measurementService.EVENTS.RAW_MEASUREMENT_ADDED, - // ], - // }, - // ]), - // ]; - eventTarget.addEventListener( - EVENTS.STACK_VIEWPORT_NEW_STACK, - boundedLoadDerivedDisplaySets - ); - }, - onModeExit: ({ servicesManager }) => { - const { - toolGroupService, - syncGroupService, - toolbarService, - segmentationService, - cornerstoneViewportService, - } = servicesManager.services; - - eventTarget.removeEventListener( - EVENTS.STACK_VIEWPORT_NEW_STACK, - boundedLoadDerivedDisplaySets - ); - _activatePanelTriggersSubscriptions.forEach(sub => sub.unsubscribe()); - _activatePanelTriggersSubscriptions = []; - - 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: 'longitudinal', - /*init: ({ servicesManager, extensionManager }) => { - //defaultViewerRouteInit - },*/ - layoutTemplate: () => { - return { - id: ohif.layout, - props: { - leftPanels: [tracked.thumbnailList], - rightPanels: [dicomSeg.panel, tracked.measurements], - rightPanelDefaultClosed: true, - 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], - }, - { - namespace: dicomRt.viewport, - displaySetsToDisplay: [dicomRt.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, - dicomRt.sopClassHandler, - ], - hotkeys: [...hotkeys.defaults.hotkeyBindings], - ...modeConfiguration, - }; -} - -const mode = { - id, - modeFactory, - extensionDependencies, -}; - -export default mode; -export { initToolGroups, toolbarButtons }; diff --git a/modes/autoload/src/initToolGroups.js b/modes/autoload/src/initToolGroups.js deleted file mode 100644 index b8e88db909a..00000000000 --- a/modes/autoload/src/initToolGroups.js +++ /dev/null @@ -1,260 +0,0 @@ -function initDefaultToolGroup( - extensionManager, - toolGroupService, - commandsManager, - toolGroupId -) { - const utilityModule = extensionManager.getModuleEntry( - '@ohif/extension-cornerstone.utilityModule.tools' - ); - - const { toolNames, Enums } = utilityModule.exports; - - const tools = { - active: [ - { - toolName: toolNames.WindowLevel, - bindings: [{ mouseButton: Enums.MouseBindings.Primary }], - }, - { - toolName: toolNames.Pan, - bindings: [{ mouseButton: Enums.MouseBindings.Auxiliary }], - }, - { - toolName: toolNames.Zoom, - bindings: [{ mouseButton: Enums.MouseBindings.Secondary }], - }, - { toolName: toolNames.StackScrollMouseWheel, bindings: [] }, - ], - passive: [ - { toolName: toolNames.Length }, - { toolName: toolNames.ArrowAnnotate }, - { toolName: toolNames.Bidirectional }, - { toolName: toolNames.DragProbe }, - { toolName: toolNames.EllipticalROI }, - { toolName: toolNames.CircleROI }, - { toolName: toolNames.RectangleROI }, - { toolName: toolNames.StackScroll }, - { toolName: toolNames.Angle }, - { toolName: toolNames.CobbAngle }, - { toolName: toolNames.PlanarFreehandROI }, - { toolName: toolNames.Magnify }, - { toolName: toolNames.SegmentationDisplay }, - { toolName: toolNames.CalibrationLine }, - ], - // enabled - // disabled - disabled: [{ toolName: toolNames.ReferenceLines }], - }; - - const toolsConfig = { - [toolNames.ArrowAnnotate]: { - getTextCallback: (callback, eventDetails) => - commandsManager.runCommand('arrowTextCallback', { - callback, - eventDetails, - }), - - changeTextCallback: (data, eventDetails, callback) => - commandsManager.runCommand('arrowTextCallback', { - callback, - data, - eventDetails, - }), - }, - }; - - toolGroupService.createToolGroupAndAddTools(toolGroupId, tools, toolsConfig); -} - -function initSRToolGroup(extensionManager, toolGroupService, commandsManager) { - const SRUtilityModule = extensionManager.getModuleEntry( - '@ohif/extension-cornerstone-dicom-sr.utilityModule.tools' - ); - - const CS3DUtilityModule = extensionManager.getModuleEntry( - '@ohif/extension-cornerstone.utilityModule.tools' - ); - - const { toolNames: SRToolNames } = SRUtilityModule.exports; - const { toolNames, Enums } = CS3DUtilityModule.exports; - const tools = { - active: [ - { - toolName: toolNames.WindowLevel, - bindings: [ - { - mouseButton: Enums.MouseBindings.Primary, - }, - ], - }, - { - toolName: toolNames.Pan, - bindings: [ - { - mouseButton: Enums.MouseBindings.Auxiliary, - }, - ], - }, - { - toolName: toolNames.Zoom, - bindings: [ - { - mouseButton: Enums.MouseBindings.Secondary, - }, - ], - }, - { - toolName: toolNames.StackScrollMouseWheel, - bindings: [], - }, - ], - passive: [ - { toolName: SRToolNames.SRLength }, - { toolName: SRToolNames.SRArrowAnnotate }, - { toolName: SRToolNames.SRBidirectional }, - { toolName: SRToolNames.SREllipticalROI }, - { toolName: SRToolNames.SRCircleROI }, - ], - enabled: [ - { - toolName: SRToolNames.DICOMSRDisplay, - bindings: [], - }, - ], - // disabled - }; - - const toolsConfig = { - [toolNames.ArrowAnnotate]: { - getTextCallback: (callback, eventDetails) => - commandsManager.runCommand('arrowTextCallback', { - callback, - eventDetails, - }), - - changeTextCallback: (data, eventDetails, callback) => - commandsManager.runCommand('arrowTextCallback', { - callback, - data, - eventDetails, - }), - }, - }; - - const toolGroupId = 'SRToolGroup'; - toolGroupService.createToolGroupAndAddTools(toolGroupId, tools, toolsConfig); -} - -function initMPRToolGroup(extensionManager, toolGroupService, commandsManager) { - const utilityModule = extensionManager.getModuleEntry( - '@ohif/extension-cornerstone.utilityModule.tools' - ); - - const { toolNames, Enums } = utilityModule.exports; - - const tools = { - active: [ - { - toolName: toolNames.WindowLevel, - bindings: [{ mouseButton: Enums.MouseBindings.Primary }], - }, - { - toolName: toolNames.Pan, - bindings: [{ mouseButton: Enums.MouseBindings.Auxiliary }], - }, - { - toolName: toolNames.Zoom, - bindings: [{ mouseButton: Enums.MouseBindings.Secondary }], - }, - { toolName: toolNames.StackScrollMouseWheel, bindings: [] }, - ], - passive: [ - { toolName: toolNames.Length }, - { toolName: toolNames.ArrowAnnotate }, - { toolName: toolNames.Bidirectional }, - { toolName: toolNames.DragProbe }, - { toolName: toolNames.EllipticalROI }, - { toolName: toolNames.CircleROI }, - { toolName: toolNames.RectangleROI }, - { toolName: toolNames.StackScroll }, - { toolName: toolNames.Angle }, - { toolName: toolNames.CobbAngle }, - { toolName: toolNames.PlanarFreehandROI }, - { toolName: toolNames.SegmentationDisplay }, - ], - disabled: [ - { toolName: toolNames.Crosshairs }, - { toolName: toolNames.ReferenceLines }, - ], - - // enabled - // disabled - }; - - const toolsConfig = { - [toolNames.Crosshairs]: { - viewportIndicators: false, - autoPan: { - enabled: false, - panSize: 10, - }, - }, - [toolNames.ArrowAnnotate]: { - getTextCallback: (callback, eventDetails) => - commandsManager.runCommand('arrowTextCallback', { - callback, - eventDetails, - }), - - changeTextCallback: (data, eventDetails, callback) => - commandsManager.runCommand('arrowTextCallback', { - callback, - data, - eventDetails, - }), - }, - }; - - toolGroupService.createToolGroupAndAddTools('mpr', tools, toolsConfig); -} -function initVolume3DToolGroup(extensionManager, toolGroupService) { - const utilityModule = extensionManager.getModuleEntry( - '@ohif/extension-cornerstone.utilityModule.tools' - ); - - const { toolNames, Enums } = utilityModule.exports; - - const tools = { - active: [ - { - toolName: toolNames.TrackballRotateTool, - bindings: [{ mouseButton: Enums.MouseBindings.Primary }], - }, - { - toolName: toolNames.Zoom, - bindings: [{ mouseButton: Enums.MouseBindings.Secondary }], - }, - { - toolName: toolNames.Pan, - bindings: [{ mouseButton: Enums.MouseBindings.Auxiliary }], - }, - ], - }; - - toolGroupService.createToolGroupAndAddTools('volume3d', tools); -} - -function initToolGroups(extensionManager, toolGroupService, commandsManager) { - initDefaultToolGroup( - extensionManager, - toolGroupService, - commandsManager, - 'default' - ); - initSRToolGroup(extensionManager, toolGroupService, commandsManager); - initMPRToolGroup(extensionManager, toolGroupService, commandsManager); - initVolume3DToolGroup(extensionManager, toolGroupService); -} - -export default initToolGroups; diff --git a/modes/autoload/src/loadDerivedDisplaySets.ts b/modes/autoload/src/loadDerivedDisplaySets.ts deleted file mode 100644 index e92ac497f65..00000000000 --- a/modes/autoload/src/loadDerivedDisplaySets.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { hydrateSEGDisplaySet } from '@ohif/extension-cornerstone-dicom-seg'; -import { hydrateRTDisplaySet } from '@ohif/extension-cornerstone-dicom-rt'; -import { hydrateStructuredReport } from '@ohif/extension-cornerstone-dicom-sr'; -import { cache as cs3DCache, volumeLoader } from '@cornerstonejs/core'; - -const delay = 0; - -function getDerivedSequences(displaySetUID, servicesManager) { - const { displaySetService } = servicesManager.services; - - const displaySetCache = displaySetService.getDisplaySetCache(); - const derivedDisplaySets = [...displaySetCache.values()].filter(ds => { - if (ds?.getReferenceDisplaySet) { - ds?.getReferenceDisplaySet(); - } - return ( - (ds?.referencedDisplaySetInstanceUID === displaySetUID || - ds.Modality === 'SR') && - !ds?.isHydrated - ); - }); - return derivedDisplaySets; -} - -export default function loadDerivedDisplaySets( - servicesManager, - extensionManager, - evt -) { - async function checkVolume(displaySet, imageIds) { - const VOLUME_LOADER_SCHEME = 'cornerstoneStreamingImageVolume'; - const volumeLoaderSchema = - displaySet.volumeLoaderSchema ?? VOLUME_LOADER_SCHEME; - - const volumeId = `${volumeLoaderSchema}:${displaySet.displaySetInstanceUID}`; - - let volume = cs3DCache.getVolume(volumeId); - - if (!volume) { - volume = await volumeLoader.createAndCacheVolume(volumeId, { imageIds }); - } - } - - const { - userAuthenticationService, - segmentationService, - displaySetService, - viewportGridService, - } = servicesManager.services; - - const { viewports } = viewportGridService.getState(); - const { viewportId, imageIds } = evt.detail; - let viewportIndex = -1; - for (let i = 0; i < viewports.length; i++) { - if ((viewports[i].viewportId = viewportId)) { - viewportIndex = i; - break; - } - } - const mainViewport = viewports[viewportIndex]; - if (viewportIndex > -1) { - if (mainViewport.displaySetInstanceUIDs.length === 1) { - const mainDisplaySet = displaySetService.getDisplaySetByUID( - mainViewport.displaySetInstanceUIDs[0] - ); - const derivedDisplaySets = getDerivedSequences( - mainViewport.displaySetInstanceUIDs[0], - servicesManager - ); - - derivedDisplaySets.forEach(async displaySet => { - const headers = userAuthenticationService.getAuthorizationHeader(); - await checkVolume(mainDisplaySet, imageIds); - await displaySet.load({ headers }); - const derivedDisplaySetInstanceUID = displaySet.displaySetInstanceUID; - - if (displaySet.Modality === 'SEG') { - let segmentationId = null; - - // We need the hydration to notify panels about the new segmentation added - const suppressEvents = false; - - segmentationId = await segmentationService.createSegmentationForSEGDisplaySet( - displaySet, - segmentationId, - suppressEvents - ); - setTimeout(() => { - if ( - !mainViewport.displaySetInstanceUIDs.includes( - derivedDisplaySetInstanceUID - ) - ) { - mainViewport.displaySetInstanceUIDs.push( - derivedDisplaySetInstanceUID - ); - } - hydrateSEGDisplaySet({ - segDisplaySet: displaySet, - viewportIndex, - servicesManager, - }); - }, delay); - } else if (displaySet.Modality === 'RTSTRUCT') { - let segmentationId = null; - - // We need the hydration to notify panels about the new segmentation added - const suppressEvents = false; - - segmentationId = await segmentationService.createSegmentationForRTDisplaySet( - displaySet, - segmentationId, - suppressEvents - ); - setTimeout(() => { - if ( - !mainViewport.displaySetInstanceUIDs.includes( - derivedDisplaySetInstanceUID - ) - ) { - mainViewport.displaySetInstanceUIDs.push( - derivedDisplaySetInstanceUID - ); - } - hydrateRTDisplaySet({ - rtDisplaySet: displaySet, - viewportIndex, - servicesManager, - }); - }, delay); - } else if (displaySet.Modality === 'SR') { - setTimeout(() => { - if ( - !mainViewport.displaySetInstanceUIDs.includes( - derivedDisplaySetInstanceUID - ) - ) { - mainViewport.displaySetInstanceUIDs.push( - derivedDisplaySetInstanceUID - ); - } - hydrateStructuredReport( - { servicesManager, extensionManager }, - derivedDisplaySetInstanceUID - ); - }, delay); - } - }); - } - } -} diff --git a/modes/autoload/src/toolbarButtons.js b/modes/autoload/src/toolbarButtons.js deleted file mode 100644 index 92de37e89dd..00000000000 --- a/modes/autoload/src/toolbarButtons.js +++ /dev/null @@ -1,608 +0,0 @@ -// TODO: torn, can either bake this here; or have to create a whole new button type -// Only ways that you can pass in a custom React component for render :l -import { - // ExpandableToolbarButton, - // ListMenu, - WindowLevelMenuItem, -} from '@ohif/ui'; -import { defaults } from '@ohif/core'; - -const { windowLevelPresets } = defaults; -/** - * - * @param {*} type - 'tool' | 'action' | 'toggle' - * @param {*} id - * @param {*} icon - * @param {*} label - */ -function _createButton(type, id, icon, label, commands, tooltip, uiType) { - return { - id, - icon, - label, - type, - commands, - tooltip, - uiType, - }; -} - -const _createActionButton = _createButton.bind(null, 'action'); -const _createToggleButton = _createButton.bind(null, 'toggle'); -const _createToolButton = _createButton.bind(null, 'tool'); - -/** - * - * @param {*} preset - preset number (from above import) - * @param {*} title - * @param {*} subtitle - */ -function _createWwwcPreset(preset, title, subtitle) { - return { - id: preset.toString(), - title, - subtitle, - type: 'action', - commands: [ - { - commandName: 'setWindowLevel', - commandOptions: { - ...windowLevelPresets[preset], - }, - context: 'CORNERSTONE', - }, - ], - }; -} - -const toolGroupIds = ['default', 'mpr', 'SRToolGroup']; - -/** - * Creates an array of 'setToolActive' commands for the given toolName - one for - * each toolGroupId specified in toolGroupIds. - * @param {string} toolName - * @returns {Array} an array of 'setToolActive' commands - */ -function _createSetToolActiveCommands(toolName) { - const temp = toolGroupIds.map(toolGroupId => ({ - commandName: 'setToolActive', - commandOptions: { - toolGroupId, - toolName, - }, - context: 'CORNERSTONE', - })); - return temp; -} - -const toolbarButtons = [ - // Measurement - { - id: 'MeasurementTools', - type: 'ohif.splitButton', - props: { - groupId: 'MeasurementTools', - isRadio: true, // ? - // Switch? - primary: _createToolButton( - 'Length', - 'tool-length', - 'Length', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'Length', - }, - context: 'CORNERSTONE', - }, - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'SRLength', - toolGroupId: 'SRToolGroup', - }, - // we can use the setToolActive command for this from Cornerstone commandsModule - context: 'CORNERSTONE', - }, - ], - 'Length' - ), - secondary: { - icon: 'chevron-down', - label: '', - isActive: true, - tooltip: 'More Measure Tools', - }, - items: [ - _createToolButton( - 'Length', - 'tool-length', - 'Length', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'Length', - }, - context: 'CORNERSTONE', - }, - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'SRLength', - toolGroupId: 'SRToolGroup', - }, - // we can use the setToolActive command for this from Cornerstone commandsModule - context: 'CORNERSTONE', - }, - ], - 'Length Tool' - ), - _createToolButton( - 'Bidirectional', - 'tool-bidirectional', - 'Bidirectional', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'Bidirectional', - }, - context: 'CORNERSTONE', - }, - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'SRBidirectional', - toolGroupId: 'SRToolGroup', - }, - context: 'CORNERSTONE', - }, - ], - 'Bidirectional Tool' - ), - _createToolButton( - 'ArrowAnnotate', - 'tool-annotate', - 'Annotation', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'ArrowAnnotate', - }, - context: 'CORNERSTONE', - }, - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'SRArrowAnnotate', - toolGroupId: 'SRToolGroup', - }, - context: 'CORNERSTONE', - }, - ], - 'Arrow Annotate' - ), - _createToolButton( - 'EllipticalROI', - 'tool-elipse', - 'Ellipse', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'EllipticalROI', - }, - context: 'CORNERSTONE', - }, - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'SREllipticalROI', - toolGroupId: 'SRToolGroup', - }, - context: 'CORNERSTONE', - }, - ], - 'Ellipse Tool' - ), - _createToolButton( - 'CircleROI', - 'tool-circle', - 'Circle', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'CircleROI', - }, - context: 'CORNERSTONE', - }, - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'SRCircleROI', - toolGroupId: 'SRToolGroup', - }, - context: 'CORNERSTONE', - }, - ], - 'Circle Tool' - ), - ], - }, - }, - // Zoom.. - { - id: 'Zoom', - type: 'ohif.radioGroup', - props: { - type: 'tool', - icon: 'tool-zoom', - label: 'Zoom', - commands: _createSetToolActiveCommands('Zoom'), - }, - }, - // Window Level + Presets... - { - id: 'WindowLevel', - type: 'ohif.splitButton', - props: { - groupId: 'WindowLevel', - primary: _createToolButton( - 'WindowLevel', - 'tool-window-level', - 'Window Level', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'WindowLevel', - }, - context: 'CORNERSTONE', - }, - ], - 'Window Level' - ), - secondary: { - icon: 'chevron-down', - label: 'W/L Manual', - isActive: true, - tooltip: 'W/L Presets', - }, - isAction: true, // ? - renderer: WindowLevelMenuItem, - items: [ - _createWwwcPreset(1, 'Soft tissue', '400 / 40'), - _createWwwcPreset(2, 'Lung', '1500 / -600'), - _createWwwcPreset(3, 'Liver', '150 / 90'), - _createWwwcPreset(4, 'Bone', '2500 / 480'), - _createWwwcPreset(5, 'Brain', '80 / 40'), - ], - }, - }, - // Pan... - { - id: 'Pan', - type: 'ohif.radioGroup', - props: { - type: 'tool', - icon: 'tool-move', - label: 'Pan', - commands: _createSetToolActiveCommands('Pan'), - }, - }, - { - id: 'Capture', - type: 'ohif.action', - props: { - icon: 'tool-capture', - label: 'Capture', - type: 'action', - commands: [ - { - commandName: 'showDownloadViewportModal', - commandOptions: {}, - context: 'CORNERSTONE', - }, - ], - }, - }, - { - id: 'Layout', - type: 'ohif.layoutSelector', - props: { - rows: 3, - columns: 3, - }, - }, - { - id: 'MPR', - type: 'ohif.action', - props: { - type: 'toggle', - icon: 'icon-mpr', - label: 'MPR', - commands: [ - { - commandName: 'toggleHangingProtocol', - commandOptions: { - protocolId: 'mpr', - }, - context: 'DEFAULT', - }, - ], - }, - }, - { - id: 'Crosshairs', - type: 'ohif.radioGroup', - props: { - type: 'tool', - icon: 'tool-crosshair', - label: 'Crosshairs', - commands: [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'Crosshairs', - toolGroupId: 'mpr', - }, - context: 'CORNERSTONE', - }, - ], - }, - }, - // More... - { - id: 'MoreTools', - type: 'ohif.splitButton', - props: { - isRadio: true, // ? - groupId: 'MoreTools', - primary: _createActionButton( - 'Reset', - 'tool-reset', - 'Reset View', - [ - { - commandName: 'resetViewport', - commandOptions: {}, - context: 'CORNERSTONE', - }, - ], - 'Reset' - ), - secondary: { - icon: 'chevron-down', - label: '', - isActive: true, - tooltip: 'More Tools', - }, - items: [ - _createActionButton( - 'Reset', - 'tool-reset', - 'Reset View', - [ - { - commandName: 'resetViewport', - commandOptions: {}, - context: 'CORNERSTONE', - }, - ], - 'Reset' - ), - _createActionButton( - 'rotate-right', - 'tool-rotate-right', - 'Rotate Right', - [ - { - commandName: 'rotateViewportCW', - commandOptions: {}, - context: 'CORNERSTONE', - }, - ], - 'Rotate +90' - ), - _createActionButton( - 'flip-horizontal', - 'tool-flip-horizontal', - 'Flip Horizontally', - [ - { - commandName: 'flipViewportHorizontal', - commandOptions: {}, - context: 'CORNERSTONE', - }, - ], - 'Flip Horizontal' - ), - _createToggleButton('StackImageSync', 'link', 'Stack Image Sync', [ - { - commandName: 'toggleStackImageSync', - commandOptions: {}, - context: 'CORNERSTONE', - }, - ]), - _createToggleButton( - 'ReferenceLines', - 'tool-referenceLines', // change this with the new icon - 'Reference Lines', - [ - { - commandName: 'toggleReferenceLines', - commandOptions: {}, - context: 'CORNERSTONE', - }, - ] - ), - _createToolButton( - 'StackScroll', - 'tool-stack-scroll', - 'Stack Scroll', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'StackScroll', - }, - context: 'CORNERSTONE', - }, - ], - 'Stack Scroll' - ), - _createActionButton( - 'invert', - 'tool-invert', - 'Invert', - [ - { - commandName: 'invertViewport', - commandOptions: {}, - context: 'CORNERSTONE', - }, - ], - 'Invert Colors' - ), - _createToolButton( - 'Probe', - 'tool-probe', - 'Probe', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'DragProbe', - }, - context: 'CORNERSTONE', - }, - ], - 'Probe' - ), - _createToggleButton( - 'cine', - 'tool-cine', - 'Cine', - [ - { - commandName: 'toggleCine', - context: 'CORNERSTONE', - }, - ], - 'Cine' - ), - _createToolButton( - 'Angle', - 'tool-angle', - 'Angle', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'Angle', - }, - context: 'CORNERSTONE', - }, - ], - 'Angle' - ), - - // Next two tools can be added once icons are added - // _createToolButton( - // 'Cobb Angle', - // 'tool-cobb-angle', - // 'Cobb Angle', - // [ - // { - // commandName: 'setToolActive', - // commandOptions: { - // toolName: 'CobbAngle', - // }, - // context: 'CORNERSTONE', - // }, - // ], - // 'Cobb Angle' - // ), - // _createToolButton( - // 'Planar Freehand ROI', - // 'tool-freehand', - // 'PlanarFreehandROI', - // [ - // { - // commandName: 'setToolActive', - // commandOptions: { - // toolName: 'PlanarFreehandROI', - // }, - // context: 'CORNERSTONE', - // }, - // ], - // 'Planar Freehand ROI' - // ), - _createToolButton( - 'Magnify', - 'tool-magnify', - 'Magnify', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'Magnify', - }, - context: 'CORNERSTONE', - }, - ], - 'Magnify' - ), - _createToolButton( - 'Rectangle', - 'tool-rectangle', - 'Rectangle', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'RectangleROI', - }, - context: 'CORNERSTONE', - }, - ], - 'Rectangle' - ), - _createToolButton( - 'CalibrationLine', - 'tool-calibration', - 'Calibration', - [ - { - commandName: 'setToolActive', - commandOptions: { - toolName: 'CalibrationLine', - }, - context: 'CORNERSTONE', - }, - ], - 'Calibration Line' - ), - _createActionButton( - 'TagBrowser', - 'list-bullets', - 'Dicom Tag Browser', - [ - { - commandName: 'openDICOMTagViewer', - commandOptions: {}, - context: 'DEFAULT', - }, - ], - 'Dicom Tag Browser' - ), - ], - }, - }, -]; - -export default toolbarButtons; From 7a356a0b2beeb303e6b2e9b9639b2f1b1d404b09 Mon Sep 17 00:00:00 2001 From: rodrigobasilio2022 Date: Wed, 9 Aug 2023 10:44:24 -0300 Subject: [PATCH 3/3] Restoring files change related to mode --- platform/app/.webpack/webpack.pwa.js | 3 +-- platform/app/pluginConfig.json | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/platform/app/.webpack/webpack.pwa.js b/platform/app/.webpack/webpack.pwa.js index aac92a85217..8d98c40a7a7 100644 --- a/platform/app/.webpack/webpack.pwa.js +++ b/platform/app/.webpack/webpack.pwa.js @@ -54,7 +54,7 @@ module.exports = (env, argv) => { path: DIST_DIR, filename: isProdBuild ? '[name].bundle.[chunkhash].js' : '[name].js', publicPath: PUBLIC_URL, // Used by HtmlWebPackPlugin for asset prefix - devtoolModuleFilenameTemplate: function (info) { + devtoolModuleFilenameTemplate: function(info) { if (isProdBuild) { return `webpack:///${info.resourcePath}`; } else { @@ -69,7 +69,6 @@ module.exports = (env, argv) => { // Hoisted Yarn Workspace Modules path.resolve(__dirname, '../../../node_modules'), SRC_DIR, - path.resolve(__dirname, 'modes/autoload/node_modules'), ], }, plugins: [ diff --git a/platform/app/pluginConfig.json b/platform/app/pluginConfig.json index 8ed3472729b..2f892db6c86 100644 --- a/platform/app/pluginConfig.json +++ b/platform/app/pluginConfig.json @@ -72,10 +72,6 @@ "packageName": "@ohif/mode-basic-dev-mode", "default": false, "version": "3.0.0" - }, - { - "packageName": "@ohif/mode-autoload", - "version": "3.7.0-beta.43" } ], "public": [