diff --git a/plugins/ohifv3/extensions/monai-label/package.json b/plugins/ohifv3/extensions/monai-label/package.json index e96570b1c..9472d5975 100644 --- a/plugins/ohifv3/extensions/monai-label/package.json +++ b/plugins/ohifv3/extensions/monai-label/package.json @@ -1,71 +1,71 @@ -{ - "name": "@ohif/extension-monai-label", - "version": "3.0.0", - "description": "OHIFv3 extension for MONAI Label", - "author": "OHIF,NVIDIA,KCL", - "license": "MIT", - "main": "dist/ohif-extension-monai-label.umd.js", - "module": "src/index.tsx", - "files": [ - "dist/**", - "public/**", - "README.md" - ], - "repository": "OHIF/Viewers", - "keywords": [ - "ohif-extension" - ], - "publishConfig": { - "access": "public" - }, - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1.18.0" - }, - "scripts": { - "clean": "shx rm -rf dist", - "clean:deep": "yarn run clean && shx rm -rf node_modules", - "dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo", - "build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js", - "build:package-1": "yarn run build", - "start": "yarn run dev", - "test:unit": "jest --watchAll", - "test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests" - }, - "peerDependencies": { - "@ohif/core": "3.10.0-beta.5", - "@ohif/extension-cornerstone": "3.10.0-beta.5", - "@ohif/extension-default": "3.10.0-beta.5", - "@ohif/i18n": "3.10.0-beta.5", - "prop-types": "^15.6.2", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-i18next": "^12.2.2", - "react-router": "^6.23.1", - "react-router-dom": "^6.23.1" - }, - "dependencies": { - "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^2.2.3", - "@cornerstonejs/core": "^2.2.3", - "@kitware/vtk.js": "32.1.0", - "react-color": "^2.19.3", - "md5.js": "^1.3.5", - "axios": "^0.21.1", - "arraybuffer-concat": "^0.0.1", - "ndarray": "^1.0.19", - "nrrd-js": "^0.2.1", - "pako": "^2.0.3", - "bootstrap": "^5.0.2", - "react-select": "^4.3.1", - "chroma-js": "^2.1.2" - }, - "devDependencies": { - "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^2.2.3", - "@cornerstonejs/core": "^2.2.3", - "@cornerstonejs/tools": "^2.2.3", - "react-color": "^2.19.3" - } -} +{ + "name": "@ohif/extension-monai-label", + "version": "3.0.0", + "description": "OHIFv3 extension for MONAI Label", + "author": "OHIF,NVIDIA,KCL", + "license": "MIT", + "main": "dist/ohif-extension-monai-label.umd.js", + "module": "src/index.tsx", + "files": [ + "dist/**", + "public/**", + "README.md" + ], + "repository": "OHIF/Viewers", + "keywords": [ + "ohif-extension" + ], + "publishConfig": { + "access": "public" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1.18.0" + }, + "scripts": { + "clean": "shx rm -rf dist", + "clean:deep": "yarn run clean && shx rm -rf node_modules", + "dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo", + "build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js", + "build:package-1": "yarn run build", + "start": "yarn run dev", + "test:unit": "jest --watchAll", + "test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests" + }, + "peerDependencies": { + "@ohif/core": "3.11.0", + "@ohif/extension-cornerstone": "3.11.0", + "@ohif/extension-default": "3.11.0", + "@ohif/i18n": "3.11.0", + "prop-types": "^15.6.2", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-i18next": "^12.2.2", + "react-router": "^6.23.1", + "react-router-dom": "^6.23.1" + }, + "dependencies": { + "@babel/runtime": "^7.20.13", + "@cornerstonejs/adapters": "^3.32.5", + "@cornerstonejs/core": "^3.32.5", + "@kitware/vtk.js": "32.12.0", + "react-color": "^2.19.3", + "md5.js": "^1.3.5", + "axios": "^0.21.1", + "arraybuffer-concat": "^0.0.1", + "ndarray": "^1.0.19", + "nrrd-js": "^0.2.1", + "pako": "^2.0.3", + "bootstrap": "^5.0.2", + "react-select": "^4.3.1", + "chroma-js": "^2.1.2" + }, + "devDependencies": { + "@babel/runtime": "^7.20.13", + "@cornerstonejs/adapters": "^3.32.5", + "@cornerstonejs/core": "^3.32.5", + "@cornerstonejs/tools": "^3.32.5", + "react-color": "^2.19.3" + } +} diff --git a/plugins/ohifv3/extensions/monai-label/src/components/OptionsInputDialog.tsx b/plugins/ohifv3/extensions/monai-label/src/components/OptionsInputDialog.tsx index 2c6f74c6d..3e4a1d33d 100644 --- a/plugins/ohifv3/extensions/monai-label/src/components/OptionsInputDialog.tsx +++ b/plugins/ohifv3/extensions/monai-label/src/components/OptionsInputDialog.tsx @@ -1,61 +1,82 @@ -/* -Copyright (c) MONAI Consortium -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React from 'react'; -import { Dialog, ButtonEnums } from '@ohif/ui'; -import OptionsForm from './actions/OptionsForm'; - -function optionsInputDialog(uiDialogService, config, info, callback) { - const dialogId = 'monai-label-options'; - const optionsRef = React.createRef(); - - const onSubmitHandler = ({ action }) => { - switch (action.id) { - case 'save': - callback(optionsRef.current.state.config, action.id); - uiDialogService.dismiss({ id: dialogId }); - break; - case 'cancel': - callback({}, action.id); - uiDialogService.dismiss({ id: dialogId }); - break; - case 'reset': - optionsRef.current.onReset(); - break; - } - }; - - uiDialogService.create({ - id: dialogId, - centralize: true, - isDraggable: false, - showOverlay: true, - content: Dialog, - contentProps: { - title: 'Options / Configurations', - noCloseButton: true, - onClose: () => uiDialogService.dismiss({ id: dialogId }), - actions: [ - { id: 'reset', text: 'Reset', type: ButtonEnums.type.secondary }, - { id: 'cancel', text: 'Cancel', type: ButtonEnums.type.secondary }, - { id: 'save', text: 'Confirm', type: ButtonEnums.type.primary }, - ], - onSubmit: onSubmitHandler, - body: () => { - return ; - }, - }, - }); -} - -export default optionsInputDialog; +/* +Copyright (c) MONAI Consortium +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, Button } from '@ohif/ui-next'; +import OptionsForm from './actions/OptionsForm'; + +function OptionsInputDialogComponent({ config, info, callback, hide }) { + const optionsRef = React.useRef(null); + + const handleSave = () => { + if (optionsRef.current) { + callback(optionsRef.current.state.config, 'save'); + } + hide(); + }; + + const handleCancel = () => { + callback({}, 'cancel'); + hide(); + }; + + const handleReset = () => { + if (optionsRef.current) { + optionsRef.current.onReset(); + } + }; + + return ( + !open && handleCancel()}> + + + Options / Configurations + + +
+ +
+ + + + + + +
+
+ ); +} + +function optionsInputDialog(uiDialogService, config, info, callback) { + const dialogId = 'monai-label-options'; + + uiDialogService.show({ + id: dialogId, + title: 'Options / Configurations', + content: OptionsInputDialogComponent, + shouldCloseOnEsc: true, + contentProps: { + config, + info, + callback, + }, + }); +} + +export default optionsInputDialog; diff --git a/plugins/ohifv3/extensions/monai-label/src/components/SettingsTable.tsx b/plugins/ohifv3/extensions/monai-label/src/components/SettingsTable.tsx index 73a5350ec..57d4c82c0 100644 --- a/plugins/ohifv3/extensions/monai-label/src/components/SettingsTable.tsx +++ b/plugins/ohifv3/extensions/monai-label/src/components/SettingsTable.tsx @@ -1,111 +1,111 @@ -/* -Copyright (c) MONAI Consortium -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React, { Component } from 'react'; - -import './SettingsTable.css'; -import { Icon } from '@ohif/ui'; -import { CookieUtils } from '../utils/GenericUtils'; - -export default class SettingsTable extends Component { - onInfo: any; - - constructor(props) { - super(props); - this.onInfo = props.onInfo; - - const url = CookieUtils.getCookieString( - 'MONAILABEL_SERVER_URL', - 'http://' + window.location.host.split(':')[0] + ':8000/' - ); - const overlap_segments = CookieUtils.getCookieBool( - 'MONAILABEL_OVERLAP_SEGMENTS', - true - ); - const export_format = CookieUtils.getCookieString( - 'MONAILABEL_EXPORT_FORMAT', - 'NRRD' - ); - - this.state = { - url: url, - overlap_segments: overlap_segments, - export_format: export_format, - }; - } - - - onBlurSeverURL = (evt) => { - const url = evt.target.value; - this.setState({ url: url }); - CookieUtils.setCookie('MONAILABEL_SERVER_URL', url); - console.log('Settings onBlurSeverURL', url); - }; - - onConnect = () => { - const url = document.getElementById('monailabelServerURL').value; - this.setState({ url: url }); - CookieUtils.setCookie('MONAILABEL_SERVER_URL', url); - console.log('Connecting Server', url); - this.onInfo(url); - }; - - render() { - return ( - - - - - - - - - - - - - - -
Server:
- -   - -
- - Info - -   |   - - Logs - -
- ); - } -} +/* +Copyright (c) MONAI Consortium +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { Component } from 'react'; + +import './SettingsTable.css'; +import { Icons } from '@ohif/ui-next'; +import { CookieUtils } from '../utils/GenericUtils'; + +export default class SettingsTable extends Component { + onInfo: any; + + constructor(props) { + super(props); + this.onInfo = props.onInfo; + + const url = CookieUtils.getCookieString( + 'MONAILABEL_SERVER_URL', + 'http://' + window.location.host.split(':')[0] + ':8000/' + ); + const overlap_segments = CookieUtils.getCookieBool( + 'MONAILABEL_OVERLAP_SEGMENTS', + true + ); + const export_format = CookieUtils.getCookieString( + 'MONAILABEL_EXPORT_FORMAT', + 'NRRD' + ); + + this.state = { + url: url, + overlap_segments: overlap_segments, + export_format: export_format, + }; + } + + + onBlurSeverURL = (evt) => { + const url = evt.target.value; + this.setState({ url: url }); + CookieUtils.setCookie('MONAILABEL_SERVER_URL', url); + console.log('Settings onBlurSeverURL', url); + }; + + onConnect = () => { + const url = document.getElementById('monailabelServerURL').value; + this.setState({ url: url }); + CookieUtils.setCookie('MONAILABEL_SERVER_URL', url); + console.log('Connecting Server', url); + this.onInfo(url); + }; + + render() { + return ( + + + + + + + + + + + + + + +
Server:
+ +   + +
+ + Info + +   |   + + Logs + +
+ ); + } +} diff --git a/plugins/ohifv3/modes/monai-label/babel.config.js b/plugins/ohifv3/modes/monai-label/babel.config.js index 92fbbdeaf..501694096 100644 --- a/plugins/ohifv3/modes/monai-label/babel.config.js +++ b/plugins/ohifv3/modes/monai-label/babel.config.js @@ -10,7 +10,7 @@ module.exports = { modules: 'commonjs', debug: false, }, - "@babel/preset-typescript", + '@babel/preset-typescript', ], '@babel/preset-react', ], diff --git a/plugins/ohifv3/modes/monai-label/package.json b/plugins/ohifv3/modes/monai-label/package.json index b9d8028d7..efb619015 100644 --- a/plugins/ohifv3/modes/monai-label/package.json +++ b/plugins/ohifv3/modes/monai-label/package.json @@ -1,70 +1,70 @@ -{ - "name": "@ohif/mode-monai-label", - "version": "3.0.0", - "description": "OHIFv3 mode for MONAI Label", - "author": "OHIF,NVIDIA,KCL", - "license": "MIT", - "main": "dist/umd/mode-monai-label/index.umd.js", - "files": [ - "dist/**", - "public/**", - "README.md" - ], - "repository": "OHIF/Viewers", - "keywords": [ - "ohif-mode" - ], - "publishConfig": { - "access": "public" - }, - "module": "src/index.tsx", - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1.16.0" - }, - "scripts": { - "clean": "shx rm -rf dist", - "clean:deep": "yarn run clean && shx rm -rf node_modules", - "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.10.0-beta.5" - }, - "dependencies": { - "@babel/runtime": "^7.20.13", - "i18next": "^17.0.3" - }, - "devDependencies": { - "@babel/core": "7.24.7", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.17.3", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-runtime": "7.24.7", - "@babel/plugin-transform-typescript": "^7.13.0", - "@babel/preset-env": "7.23.2", - "@babel/preset-react": "^7.16.7", - "@babel/preset-typescript": "^7.13.0", - "@svgr/webpack": "^8.1.0", - "babel-eslint": "^10.1.0", - "babel-loader": "^8.0.0-beta.4", - "clean-webpack-plugin": "^4.0.0", - "copy-webpack-plugin": "^10.2.0", - "cross-env": "^7.0.3", - "dotenv": "^14.1.0", - "eslint": "^8.39.0", - "eslint-loader": "^2.0.0", - "webpack": "5.94.0", - "webpack-cli": "^4.7.2", - "webpack-merge": "^5.7.3" - } -} +{ + "name": "@ohif/mode-monai-label", + "version": "3.0.0", + "description": "OHIFv3 mode for MONAI Label", + "author": "OHIF,NVIDIA,KCL", + "license": "MIT", + "main": "dist/ohif-mode-monai-label.umd.js", + "files": [ + "dist/**", + "public/**", + "README.md" + ], + "repository": "OHIF/Viewers", + "keywords": [ + "ohif-mode" + ], + "publishConfig": { + "access": "public" + }, + "module": "src/index.tsx", + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1.16.0" + }, + "scripts": { + "clean": "shx rm -rf dist", + "clean:deep": "yarn run clean && shx rm -rf node_modules", + "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.11.0" + }, + "dependencies": { + "@babel/runtime": "^7.20.13", + "i18next": "^17.0.3" + }, + "devDependencies": { + "@babel/core": "7.24.7", + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.17.3", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.16.7", + "@babel/plugin-transform-runtime": "7.24.7", + "@babel/plugin-transform-typescript": "^7.13.0", + "@babel/preset-env": "7.23.2", + "@babel/preset-react": "^7.16.7", + "@babel/preset-typescript": "^7.13.0", + "@svgr/webpack": "^8.1.0", + "babel-eslint": "^10.1.0", + "babel-loader": "^8.0.0-beta.4", + "clean-webpack-plugin": "^4.0.0", + "copy-webpack-plugin": "^10.2.0", + "cross-env": "^7.0.3", + "dotenv": "^14.1.0", + "eslint": "^8.39.0", + "eslint-loader": "^2.0.0", + "webpack": "5.95.0", + "webpack-cli": "^4.7.2", + "webpack-merge": "^5.7.3" + } +} diff --git a/plugins/ohifv3/modes/monai-label/src/index.tsx b/plugins/ohifv3/modes/monai-label/src/index.tsx index 301219d03..11afe3283 100644 --- a/plugins/ohifv3/modes/monai-label/src/index.tsx +++ b/plugins/ohifv3/modes/monai-label/src/index.tsx @@ -1,173 +1,205 @@ -import { hotkeys } from '@ohif/core'; -import { id } from './id'; -import toolbarButtons from './toolbarButtons'; -import initToolGroups from './initToolGroups'; - -const monailabel = { - monaiLabel: '@ohif/extension-monai-label.panelModule.monailabel', -}; - -const ohif = { - layout: '@ohif/extension-default.layoutTemplateModule.viewerLayout', - sopClassHandler: '@ohif/extension-default.sopClassHandlerModule.stack', - hangingProtocol: '@ohif/extension-default.hangingProtocolModule.default', - leftPanel: '@ohif/extension-default.panelModule.seriesList', - rightPanel: '@ohif/extension-default.panelModule.measure', -}; - -const cornerstone = { - viewport: '@ohif/extension-cornerstone.viewportModule.cornerstone', - panelTool: '@ohif/extension-cornerstone.panelModule.panelSegmentationWithTools', -}; - -const segmentation = { - sopClassHandler: '@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg', - viewport: '@ohif/extension-cornerstone-dicom-seg.viewportModule.dicom-seg', -}; - -/** - * Just two dependencies to be able to render a viewport with panels in order - * to make sure that the mode is working. - */ -const extensionDependencies = { - '@ohif/extension-default': '^3.0.0', - '@ohif/extension-cornerstone': '^3.0.0', - '@ohif/extension-cornerstone-dicom-seg': '^3.0.0', - '@ohif/extension-monai-label': '^3.0.0', -}; - -function modeFactory({ modeConfiguration }) { - 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: 'monai-label', - /** - * Mode name, which is displayed in the viewer's UI in the workList, for the - * user to select the mode. - */ - displayName: 'MONAI Label', - /** - * 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 } = servicesManager.services; - - measurementService.clearMeasurements(); - - // Init Default and SR ToolGroups - initToolGroups(extensionManager, toolGroupService, commandsManager); - - toolbarService.addButtons(toolbarButtons); - // toolbarService.addButtons(segmentationButtons); - - toolbarService.createButtonSection('primary', [ - 'WindowLevel', - 'Pan', - 'Zoom', - 'TrackballRotate', - 'Capture', - 'Layout', - 'MPR', - 'Crosshairs', - 'MoreTools', - ]); - toolbarService.createButtonSection('segmentationToolbox', ['BrushTools', 'Shapes']); - }, - onModeExit: ({ servicesManager }: withAppTypes) => { - const { - toolGroupService, - syncGroupService, - segmentationService, - cornerstoneViewportService, - uiDialogService, - uiModalService, - } = servicesManager.services; - - uiDialogService.dismissAll(); - 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.includes('CT') || modalitiesArray.includes('MR'), - 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: 'monai-label', - layoutTemplate: ({ location, servicesManager }) => { - return { - id: ohif.layout, - props: { - rightPanelDefaultClosed: false, - /* leftPanelDefaultClosed: true, */ - leftPanels: [ohif.leftPanel], - rightPanels: [monailabel.monaiLabel], - viewports: [ - { - namespace: cornerstone.viewport, - displaySetsToDisplay: [ohif.sopClassHandler], - }, - { - namespace: segmentation.viewport, - displaySetsToDisplay: [segmentation.sopClassHandler], - }, - ], - }, - }; - }, - }, - ], - /** List of extensions that are used by the mode */ - extensions: extensionDependencies, - /** HangingProtocol used by the mode */ - hangingProtocol: 'mpr', - // hangingProtocol: [''], - /** SopClassHandlers used by the mode */ - sopClassHandlers: [ohif.sopClassHandler, segmentation.sopClassHandler], - /** hotkeys for mode */ - hotkeys: [...hotkeys.defaults.hotkeyBindings], - }; -} - -const mode = { - id, - modeFactory, - extensionDependencies, -}; - -export default mode; +import { hotkeys } from '@ohif/core'; +import { id } from './id'; +import toolbarButtons from './toolbarButtons'; +import initToolGroups from './initToolGroups'; + +const monailabel = { + monaiLabel: '@ohif/extension-monai-label.panelModule.monailabel', +}; + +const ohif = { + layout: '@ohif/extension-default.layoutTemplateModule.viewerLayout', + sopClassHandler: '@ohif/extension-default.sopClassHandlerModule.stack', + hangingProtocol: '@ohif/extension-default.hangingProtocolModule.default', + leftPanel: '@ohif/extension-default.panelModule.seriesList', + rightPanel: '@ohif/extension-default.panelModule.measure', +}; + +const cornerstone = { + viewport: '@ohif/extension-cornerstone.viewportModule.cornerstone', + panelTool: '@ohif/extension-cornerstone.panelModule.panelSegmentationWithTools', +}; + +const segmentation = { + sopClassHandler: '@ohif/extension-cornerstone-dicom-seg.sopClassHandlerModule.dicom-seg', + viewport: '@ohif/extension-cornerstone-dicom-seg.viewportModule.dicom-seg', +}; + +/** + * Just two dependencies to be able to render a viewport with panels in order + * to make sure that the mode is working. + */ +const extensionDependencies = { + '@ohif/extension-default': '^3.0.0', + '@ohif/extension-cornerstone': '^3.0.0', + '@ohif/extension-cornerstone-dicom-seg': '^3.0.0', + '@ohif/extension-monai-label': '^3.0.0', +}; + +function modeFactory({ modeConfiguration }) { + 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: 'monai-label', + /** + * Mode name, which is displayed in the viewer's UI in the workList, for the + * user to select the mode. + */ + displayName: 'MONAI Label', + /** + * 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 } = 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.topRight, [ + 'modalityLoadBadge', + 'trackingStatus', + 'navigationComponent', + ]); + + toolbarService.updateSection(toolbarService.sections.viewportActionMenu.bottomLeft, [ + 'windowLevelMenu', + ]); + + toolbarService.updateSection('MoreTools', [ + 'Reset', + 'rotate-right', + 'flipHorizontal', + 'ReferenceLines', + 'ImageOverlayViewer', + 'StackScroll', + 'invert', + 'Probe', + 'Cine', + 'Angle', + 'Magnify', + 'RectangleROI', + 'CalibrationLine', + 'TagBrowser', + 'AdvancedMagnify', + 'UltrasoundDirectionalTool', + 'WindowLevelRegion', + ]); + }, + onModeExit: ({ servicesManager }: withAppTypes) => { + const { + toolGroupService, + syncGroupService, + segmentationService, + cornerstoneViewportService, + uiDialogService, + uiModalService, + } = servicesManager.services; + + 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.includes('CT') || modalitiesArray.includes('MR'), + 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: 'monai-label', + layoutTemplate: ({ location, servicesManager }) => { + return { + id: ohif.layout, + props: { + rightPanelDefaultClosed: false, + /* leftPanelDefaultClosed: true, */ + leftPanels: [ohif.leftPanel], + rightPanels: [monailabel.monaiLabel], + viewports: [ + { + namespace: cornerstone.viewport, + displaySetsToDisplay: [ohif.sopClassHandler], + }, + { + namespace: segmentation.viewport, + displaySetsToDisplay: [segmentation.sopClassHandler], + }, + ], + }, + }; + }, + }, + ], + /** List of extensions that are used by the mode */ + extensions: extensionDependencies, + /** HangingProtocol used by the mode */ + hangingProtocol: 'mpr', + // hangingProtocol: [''], + /** SopClassHandlers used by the mode */ + sopClassHandlers: [ohif.sopClassHandler, segmentation.sopClassHandler], + /** hotkeys for mode */ + hotkeys: [...hotkeys.defaults.hotkeyBindings], + }; +} + +const mode = { + id, + modeFactory, + extensionDependencies, +}; + +export default mode; diff --git a/plugins/ohifv3/modes/monai-label/src/initToolGroups.js b/plugins/ohifv3/modes/monai-label/src/initToolGroups.ts similarity index 63% rename from plugins/ohifv3/modes/monai-label/src/initToolGroups.js rename to plugins/ohifv3/modes/monai-label/src/initToolGroups.ts index 2f540d32a..b61711cc2 100644 --- a/plugins/ohifv3/modes/monai-label/src/initToolGroups.js +++ b/plugins/ohifv3/modes/monai-label/src/initToolGroups.ts @@ -1,182 +1,126 @@ -const colours = { - 'viewport-0': 'rgb(200, 0, 0)', - 'viewport-1': 'rgb(200, 200, 0)', - 'viewport-2': 'rgb(0, 200, 0)', -}; - -const colorsByOrientation = { - axial: 'rgb(200, 0, 0)', - sagittal: 'rgb(200, 200, 0)', - coronal: 'rgb(0, 200, 0)', -}; - -function createTools(utilityModule) { - const { toolNames, Enums } = utilityModule.exports; - return { - 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.StackScroll, bindings: [{ mouseButton: Enums.MouseBindings.Wheel }] }, - ], - passive: [ - { - toolName: 'CircularBrush', - parentTool: 'Brush', - configuration: { - activeStrategy: 'FILL_INSIDE_CIRCLE', - }, - }, - { - toolName: 'CircularEraser', - parentTool: 'Brush', - configuration: { - activeStrategy: 'ERASE_INSIDE_CIRCLE', - }, - }, - { - toolName: 'SphereBrush', - parentTool: 'Brush', - configuration: { - activeStrategy: 'FILL_INSIDE_SPHERE', - }, - }, - { - toolName: 'SphereEraser', - parentTool: 'Brush', - configuration: { - activeStrategy: 'ERASE_INSIDE_SPHERE', - }, - }, - { - toolName: 'ThresholdCircularBrush', - parentTool: 'Brush', - configuration: { - activeStrategy: 'THRESHOLD_INSIDE_CIRCLE', - }, - }, - { - toolName: 'ThresholdSphereBrush', - parentTool: 'Brush', - configuration: { - activeStrategy: 'THRESHOLD_INSIDE_SPHERE', - }, - }, - { - toolName: 'ThresholdCircularBrushDynamic', - parentTool: 'Brush', - configuration: { - activeStrategy: 'THRESHOLD_INSIDE_CIRCLE', - // preview: { - // enabled: true, - // }, - strategySpecificConfiguration: { - // to use the use the center segment index to determine - // if inside -> same segment, if outside -> eraser - // useCenterSegmentIndex: true, - THRESHOLD: { - isDynamic: true, - dynamicRadius: 3, - }, - }, - }, - }, - { toolName: toolNames.CircleScissors }, - { toolName: toolNames.RectangleScissors }, - { toolName: toolNames.SphereScissors }, - { toolName: toolNames.StackScroll }, - { toolName: toolNames.Magnify }, - { toolName: toolNames.WindowLevelRegion }, - - { toolName: toolNames.UltrasoundDirectional }, - { toolName: 'ProbeMONAILabel' } - ], - disabled: [{ toolName: toolNames.ReferenceLines }, { toolName: toolNames.AdvancedMagnify }], - }; -} - -function initDefaultToolGroup(extensionManager, toolGroupService, commandsManager, toolGroupId) { - const utilityModule = extensionManager.getModuleEntry( - '@ohif/extension-cornerstone.utilityModule.tools' - ); - const tools = createTools(utilityModule); - toolGroupService.createToolGroupAndAddTools(toolGroupId, tools); -} - -function initMPRToolGroup(extensionManager, toolGroupService, commandsManager) { - const utilityModule = extensionManager.getModuleEntry( - '@ohif/extension-cornerstone.utilityModule.tools' - ); - const servicesManager = extensionManager._servicesManager; - const { cornerstoneViewportService } = servicesManager.services; - const tools = createTools(utilityModule); - tools.disabled.push( - { - toolName: utilityModule.exports.toolNames.Crosshairs, - configuration: { - viewportIndicators: true, - viewportIndicatorsConfig: { - circleRadius: 5, - xOffset: 0.95, - yOffset: 0.05, - }, - disableOnPassive: true, - autoPan: { - enabled: false, - panSize: 10, - }, - getReferenceLineColor: viewportId => { - const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId); - const viewportOptions = viewportInfo?.viewportOptions; - if (viewportOptions) { - return ( - colours[viewportOptions.id] || - colorsByOrientation[viewportOptions.orientation] || - '#0c0' - ); - } else { - console.warn('missing viewport?', viewportId); - return '#0c0'; - } - }, - }, - }, - { toolName: utilityModule.exports.toolNames.ReferenceLines } - ); - toolGroupService.createToolGroupAndAddTools('mpr', tools); -} - -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'); - initMPRToolGroup(extensionManager, toolGroupService, commandsManager); - initVolume3DToolGroup(extensionManager, toolGroupService); -} - -export default initToolGroups; +const colours = { + 'viewport-0': 'rgb(200, 0, 0)', + 'viewport-1': 'rgb(200, 200, 0)', + 'viewport-2': 'rgb(0, 200, 0)', +}; + +const colorsByOrientation = { + axial: 'rgb(200, 0, 0)', + sagittal: 'rgb(200, 200, 0)', + coronal: 'rgb(0, 200, 0)', +}; + +function createTools({ utilityModule, commandsManager }) { + 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 }, { numTouchPoints: 2 }], + }, + { + toolName: toolNames.StackScroll, + bindings: [{ mouseButton: Enums.MouseBindings.Wheel }, { numTouchPoints: 3 }], + }, + ], + passive: [ + { toolName: toolNames.StackScroll }, + { toolName: toolNames.Magnify }, + { toolName: toolNames.WindowLevelRegion }, + { toolName: toolNames.UltrasoundDirectional }, + { toolName: 'ProbeMONAILabel' } + ], + disabled: [{ toolName: toolNames.ReferenceLines }, { toolName: toolNames.AdvancedMagnify }], + }; + + return tools; +} + +function initDefaultToolGroup(extensionManager, toolGroupService, commandsManager, toolGroupId) { + const utilityModule = extensionManager.getModuleEntry( + '@ohif/extension-cornerstone.utilityModule.tools' + ); + const tools = createTools({ commandsManager, utilityModule }); + toolGroupService.createToolGroupAndAddTools(toolGroupId, tools); +} + +function initMPRToolGroup(extensionManager, toolGroupService, commandsManager) { + const utilityModule = extensionManager.getModuleEntry( + '@ohif/extension-cornerstone.utilityModule.tools' + ); + const servicesManager = extensionManager._servicesManager; + const { cornerstoneViewportService } = servicesManager.services; + const tools = createTools({ commandsManager, utilityModule }); + tools.disabled.push( + { + toolName: utilityModule.exports.toolNames.Crosshairs, + configuration: { + viewportIndicators: true, + viewportIndicatorsConfig: { + circleRadius: 5, + xOffset: 0.95, + yOffset: 0.05, + }, + disableOnPassive: true, + autoPan: { + enabled: false, + panSize: 10, + }, + getReferenceLineColor: viewportId => { + const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId); + const viewportOptions = viewportInfo?.viewportOptions; + if (viewportOptions) { + return ( + colours[viewportOptions.id] || + colorsByOrientation[viewportOptions.orientation] || + '#0c0' + ); + } else { + console.warn('missing viewport?', viewportId); + return '#0c0'; + } + }, + }, + }, + { toolName: utilityModule.exports.toolNames.ReferenceLines } + ); + toolGroupService.createToolGroupAndAddTools('mpr', tools); +} + +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 }, { numTouchPoints: 2 }], + }, + { + toolName: toolNames.Pan, + bindings: [{ mouseButton: Enums.MouseBindings.Auxiliary }], + }, + ], + }; + + toolGroupService.createToolGroupAndAddTools('volume3d', tools); +} + +function initToolGroups(extensionManager, toolGroupService, commandsManager) { + initDefaultToolGroup(extensionManager, toolGroupService, commandsManager, 'default'); + initMPRToolGroup(extensionManager, toolGroupService, commandsManager); + initVolume3DToolGroup(extensionManager, toolGroupService); +} + +export default initToolGroups; diff --git a/plugins/ohifv3/modes/monai-label/src/toolbarButtons.js b/plugins/ohifv3/modes/monai-label/src/toolbarButtons.js deleted file mode 100644 index a59c994eb..000000000 --- a/plugins/ohifv3/modes/monai-label/src/toolbarButtons.js +++ /dev/null @@ -1,291 +0,0 @@ -import type { Button } from '@ohif/core/types'; -import { ToolbarService, ViewportGridService } from '@ohif/core'; - -const { createButton } = ToolbarService; - -const ReferenceLinesListeners: RunCommand = [ - { - commandName: 'setSourceViewportForReferenceLinesTool', - context: 'CORNERSTONE', - }, -]; - -export const setToolActiveToolbar = { - commandName: 'setToolActiveToolbar', - commandOptions: { - toolGroupIds: ['default', 'mpr', 'SRToolGroup', 'volume3d'], - }, -}; - -const toolbarButtons: Button[] = [ - { - id: 'Zoom', - uiType: 'ohif.radioGroup', - props: { - icon: 'tool-zoom', - label: 'Zoom', - commands: setToolActiveToolbar, - evaluate: 'evaluate.cornerstoneTool', - }, - }, - { - id: 'WindowLevel', - uiType: 'ohif.radioGroup', - props: { - icon: 'tool-window-level', - label: 'Window Level', - commands: setToolActiveToolbar, - evaluate: 'evaluate.cornerstoneTool', - }, - }, - { - id: 'Pan', - uiType: 'ohif.radioGroup', - props: { - icon: 'tool-move', - label: 'Pan', - commands: setToolActiveToolbar, - evaluate: 'evaluate.cornerstoneTool', - }, - }, - { - id: 'TrackballRotate', - uiType: 'ohif.radioGroup', - props: { - type: 'tool', - icon: 'tool-3d-rotate', - label: '3D Rotate', - commands: setToolActiveToolbar, - evaluate: { - name: 'evaluate.cornerstoneTool', - disabledText: 'Select a 3D viewport to enable this tool', - }, - }, - }, - { - id: 'Capture', - uiType: 'ohif.radioGroup', - props: { - icon: 'tool-capture', - label: 'Capture', - commands: 'showDownloadViewportModal', - evaluate: [ - 'evaluate.action', - { - name: 'evaluate.viewport.supported', - unsupportedViewportTypes: ['video', 'wholeSlide'], - }, - ], - }, - }, - { - id: 'Layout', - uiType: 'ohif.layoutSelector', - props: { - rows: 3, - columns: 4, - evaluate: 'evaluate.action', - commands: 'setViewportGridLayout', - }, - }, - { - id: 'Crosshairs', - uiType: 'ohif.radioGroup', - props: { - icon: 'tool-crosshair', - label: 'Crosshairs', - commands: { - commandName: 'setToolActiveToolbar', - commandOptions: { - toolGroupIds: ['mpr'], - }, - }, - evaluate: { - name: 'evaluate.cornerstoneTool', - disabledText: 'Select an MPR viewport to enable this tool', - }, - }, - }, - { - id: 'MoreTools', - uiType: 'ohif.splitButton', - props: { - groupId: 'MoreTools', - evaluate: 'evaluate.group.promoteToPrimaryIfCornerstoneToolNotActiveInTheList', - primary: createButton({ - id: 'Reset', - icon: 'tool-reset', - tooltip: 'Reset View', - label: 'Reset', - commands: 'resetViewport', - evaluate: 'evaluate.action', - }), - secondary: { - icon: 'chevron-down', - label: '', - tooltip: 'More Tools', - }, - items: [ - createButton({ - id: 'Reset', - icon: 'tool-reset', - label: 'Reset View', - tooltip: 'Reset View', - commands: 'resetViewport', - evaluate: 'evaluate.action', - }), - createButton({ - id: 'rotate-right', - icon: 'tool-rotate-right', - label: 'Rotate Right', - tooltip: 'Rotate +90', - commands: 'rotateViewportCW', - evaluate: 'evaluate.action', - }), - createButton({ - id: 'flipHorizontal', - icon: 'tool-flip-horizontal', - label: 'Flip Horizontal', - tooltip: 'Flip Horizontally', - commands: 'flipViewportHorizontal', - evaluate: [ - 'evaluate.viewportProperties.toggle', - { - name: 'evaluate.viewport.supported', - unsupportedViewportTypes: ['volume3d'], - }, - ], - }), - createButton({ - id: 'ReferenceLines', - icon: 'tool-referenceLines', - label: 'Reference Lines', - tooltip: 'Show Reference Lines', - commands: 'toggleEnabledDisabledToolbar', - listeners: { - [ViewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED]: ReferenceLinesListeners, - [ViewportGridService.EVENTS.VIEWPORTS_READY]: ReferenceLinesListeners, - }, - evaluate: 'evaluate.cornerstoneTool.toggle', - }), - createButton({ - id: 'ImageOverlayViewer', - icon: 'toggle-dicom-overlay', - label: 'Image Overlay', - tooltip: 'Toggle Image Overlay', - commands: 'toggleEnabledDisabledToolbar', - evaluate: 'evaluate.cornerstoneTool.toggle', - }), - createButton({ - id: 'StackScroll', - icon: 'tool-stack-scroll', - label: 'Stack Scroll', - tooltip: 'Stack Scroll', - commands: setToolActiveToolbar, - evaluate: 'evaluate.cornerstoneTool', - }), - createButton({ - id: 'invert', - icon: 'tool-invert', - label: 'Invert', - tooltip: 'Invert Colors', - commands: 'invertViewport', - evaluate: 'evaluate.viewportProperties.toggle', - }), - createButton({ - id: 'Probe', - icon: 'tool-probe', - label: 'Probe', - tooltip: 'Probe', - commands: setToolActiveToolbar, - evaluate: 'evaluate.cornerstoneTool', - }), - createButton({ - id: 'Cine', - icon: 'tool-cine', - label: 'Cine', - tooltip: 'Cine', - commands: 'toggleCine', - evaluate: [ - 'evaluate.cine', - { - name: 'evaluate.viewport.supported', - unsupportedViewportTypes: ['volume3d'], - }, - ], - }), - createButton({ - id: 'Angle', - icon: 'tool-angle', - label: 'Angle', - tooltip: 'Angle', - commands: setToolActiveToolbar, - evaluate: 'evaluate.cornerstoneTool', - }), - createButton({ - id: 'Magnify', - icon: 'tool-magnify', - label: 'Zoom-in', - tooltip: 'Zoom-in', - commands: setToolActiveToolbar, - evaluate: 'evaluate.cornerstoneTool', - }), - createButton({ - id: 'RectangleROI', - icon: 'tool-rectangle', - label: 'Rectangle', - tooltip: 'Rectangle', - commands: setToolActiveToolbar, - evaluate: 'evaluate.cornerstoneTool', - }), - createButton({ - id: 'CalibrationLine', - icon: 'tool-calibration', - label: 'Calibration', - tooltip: 'Calibration Line', - commands: setToolActiveToolbar, - evaluate: 'evaluate.cornerstoneTool', - }), - createButton({ - id: 'TagBrowser', - icon: 'dicom-tag-browser', - label: 'Dicom Tag Browser', - tooltip: 'Dicom Tag Browser', - commands: 'openDICOMTagViewer', - }), - createButton({ - id: 'AdvancedMagnify', - icon: 'icon-tool-loupe', - label: 'Magnify Probe', - tooltip: 'Magnify Probe', - commands: 'toggleActiveDisabledToolbar', - evaluate: 'evaluate.cornerstoneTool.toggle.ifStrictlyDisabled', - }), - createButton({ - id: 'UltrasoundDirectionalTool', - icon: 'icon-tool-ultrasound-bidirectional', - label: 'Ultrasound Directional', - tooltip: 'Ultrasound Directional', - commands: setToolActiveToolbar, - evaluate: [ - 'evaluate.cornerstoneTool', - { - name: 'evaluate.modality.supported', - supportedModalities: ['US'], - }, - ], - }), - createButton({ - id: 'WindowLevelRegion', - icon: 'icon-tool-window-region', - label: 'Window Level Region', - tooltip: 'Window Level Region', - commands: setToolActiveToolbar, - evaluate: 'evaluate.cornerstoneTool', - }), - ], - }, - }, -]; - -export default toolbarButtons; diff --git a/plugins/ohifv3/modes/monai-label/src/toolbarButtons.ts b/plugins/ohifv3/modes/monai-label/src/toolbarButtons.ts new file mode 100644 index 000000000..d3d289d2c --- /dev/null +++ b/plugins/ohifv3/modes/monai-label/src/toolbarButtons.ts @@ -0,0 +1,403 @@ +import type { Button } from '@ohif/core/types'; +import { ViewportGridService } from '@ohif/core'; + +const setToolActiveToolbar = { + commandName: 'setToolActiveToolbar', + commandOptions: { + toolGroupIds: ['default', 'mpr', 'SRToolGroup', 'volume3d'], + }, +}; + +const toolbarButtons: Button[] = [ + { + id: 'modalityLoadBadge', + uiType: 'ohif.modalityLoadBadge', + props: { + icon: 'Status', + label: 'Status', + tooltip: 'Status', + evaluate: { + name: 'evaluate.modalityLoadBadge', + hideWhenDisabled: true, + }, + }, + }, + { + id: 'navigationComponent', + uiType: 'ohif.navigationComponent', + props: { + icon: 'Navigation', + label: 'Navigation', + tooltip: 'Navigate between segments/measurements and manage their visibility', + evaluate: { + name: 'evaluate.navigationComponent', + hideWhenDisabled: true, + }, + }, + }, + { + id: 'trackingStatus', + uiType: 'ohif.trackingStatus', + props: { + icon: 'TrackingStatus', + label: 'Tracking Status', + tooltip: 'View and manage tracking status of measurements and annotations', + evaluate: { + name: 'evaluate.trackingStatus', + hideWhenDisabled: true, + }, + }, + }, + { + id: 'dataOverlayMenu', + uiType: 'ohif.dataOverlayMenu', + props: { + icon: 'ViewportViews', + label: 'Data Overlay', + tooltip: 'Configure data overlay options and manage foreground/background display sets', + evaluate: 'evaluate.dataOverlayMenu', + }, + }, + { + id: 'orientationMenu', + uiType: 'ohif.orientationMenu', + props: { + icon: 'OrientationSwitch', + label: 'Orientation', + tooltip: 'Change viewport orientation between axial, sagittal, coronal and reformat planes', + evaluate: { + name: 'evaluate.orientationMenu', + }, + }, + }, + { + id: 'windowLevelMenu', + uiType: 'ohif.windowLevelMenu', + props: { + icon: 'WindowLevel', + label: 'Window Level', + tooltip: 'Adjust window/level presets and customize image contrast settings', + evaluate: 'evaluate.windowLevelMenu', + }, + }, + // Section containers for original tools + { + id: 'Zoom', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-zoom', + label: 'Zoom', + commands: setToolActiveToolbar, + evaluate: 'evaluate.cornerstoneTool', + }, + }, + { + id: 'WindowLevel', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-window-level', + label: 'Window Level', + commands: setToolActiveToolbar, + evaluate: 'evaluate.cornerstoneTool', + }, + }, + { + id: 'Pan', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-move', + label: 'Pan', + commands: setToolActiveToolbar, + evaluate: 'evaluate.cornerstoneTool', + }, + }, + { + id: 'TrackballRotate', + uiType: 'ohif.toolButton', + props: { + type: 'tool', + icon: 'tool-3d-rotate', + label: '3D Rotate', + commands: setToolActiveToolbar, + evaluate: { + name: 'evaluate.cornerstoneTool', + disabledText: 'Select a 3D viewport to enable this tool', + }, + }, + }, + { + id: 'Capture', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-capture', + label: 'Capture', + commands: 'showDownloadViewportModal', + evaluate: [ + 'evaluate.action', + { + name: 'evaluate.viewport.supported', + unsupportedViewportTypes: ['video', 'wholeSlide'], + }, + ], + }, + }, + { + id: 'Layout', + uiType: 'ohif.layoutSelector', + props: { + rows: 3, + columns: 4, + commands: 'setViewportGridLayout', + evaluate: 'evaluate.action', + }, + }, + { + id: 'Crosshairs', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-crosshair', + label: 'Crosshairs', + commands: { + commandName: 'setToolActiveToolbar', + commandOptions: { + toolGroupIds: ['mpr'], + }, + }, + evaluate: { + name: 'evaluate.cornerstoneTool', + disabledText: 'Select an MPR viewport to enable this tool', + }, + }, + }, + { + id: 'MoreTools', + uiType: 'ohif.toolButtonList', + props: { + buttonSection: true, + }, + }, + { + id: 'Reset', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-reset', + label: 'Reset View', + tooltip: 'Reset View', + commands: 'resetViewport', + evaluate: 'evaluate.action', + }, + }, + { + id: 'rotate-right', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-rotate-right', + label: 'Rotate Right', + tooltip: 'Rotate +90', + commands: 'rotateViewportCW', + evaluate: 'evaluate.action', + }, + }, + { + id: 'flipHorizontal', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-flip-horizontal', + label: 'Flip Horizontal', + tooltip: 'Flip Horizontally', + commands: 'flipViewportHorizontal', + evaluate: [ + 'evaluate.viewportProperties.toggle', + { + name: 'evaluate.viewport.supported', + unsupportedViewportTypes: ['volume3d'], + }, + ], + }, + }, + { + id: 'ReferenceLines', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-referenceLines', + label: 'Reference Lines', + tooltip: 'Show Reference Lines', + commands: 'toggleEnabledDisabledToolbar', + evaluate: 'evaluate.cornerstoneTool.toggle', + }, + }, + { + id: 'ImageOverlayViewer', + uiType: 'ohif.toolButton', + props: { + icon: 'toggle-dicom-overlay', + label: 'Image Overlay', + tooltip: 'Toggle Image Overlay', + commands: 'toggleEnabledDisabledToolbar', + evaluate: 'evaluate.cornerstoneTool.toggle', + }, + }, + { + id: 'StackScroll', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-stack-scroll', + label: 'Stack Scroll', + tooltip: 'Stack Scroll', + commands: setToolActiveToolbar, + evaluate: 'evaluate.cornerstoneTool', + }, + }, + { + id: 'invert', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-invert', + label: 'Invert', + tooltip: 'Invert Colors', + commands: 'invertViewport', + evaluate: 'evaluate.viewportProperties.toggle', + }, + }, + { + id: 'Probe', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-probe', + label: 'Probe', + tooltip: 'Probe', + commands: setToolActiveToolbar, + evaluate: 'evaluate.cornerstoneTool', + }, + }, + { + id: 'Cine', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-cine', + label: 'Cine', + tooltip: 'Cine', + commands: 'toggleCine', + evaluate: [ + 'evaluate.cine', + { + name: 'evaluate.viewport.supported', + unsupportedViewportTypes: ['volume3d'], + }, + ], + }, + }, + { + id: 'Angle', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-angle', + label: 'Angle', + tooltip: 'Angle', + commands: setToolActiveToolbar, + evaluate: 'evaluate.cornerstoneTool', + }, + }, + { + id: 'Magnify', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-magnify', + label: 'Zoom-in', + tooltip: 'Zoom-in', + commands: setToolActiveToolbar, + evaluate: 'evaluate.cornerstoneTool', + }, + }, + { + id: 'RectangleROI', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-rectangle', + label: 'Rectangle', + tooltip: 'Rectangle', + commands: setToolActiveToolbar, + evaluate: 'evaluate.cornerstoneTool', + }, + }, + { + id: 'CalibrationLine', + uiType: 'ohif.toolButton', + props: { + icon: 'tool-calibration', + label: 'Calibration', + tooltip: 'Calibration Line', + commands: setToolActiveToolbar, + evaluate: [ + 'evaluate.cornerstoneTool', + { + name: 'evaluate.viewport.supported', + unsupportedViewportTypes: ['video'], + }, + ], + }, + }, + { + id: 'TagBrowser', + uiType: 'ohif.toolButton', + props: { + icon: 'dicom-tag-browser', + label: 'Dicom Tag Browser', + tooltip: 'Dicom Tag Browser', + commands: 'openDICOMTagViewer', + }, + }, + { + id: 'AdvancedMagnify', + uiType: 'ohif.toolButton', + props: { + icon: 'icon-tool-loupe', + label: 'Magnify Probe', + tooltip: 'Magnify Probe', + commands: 'toggleActiveDisabledToolbar', + evaluate: [ + 'evaluate.cornerstoneTool.toggle.ifStrictlyDisabled', + { + name: 'evaluate.viewport.supported', + unsupportedViewportTypes: ['video'], + }, + ], + }, + }, + { + id: 'UltrasoundDirectionalTool', + uiType: 'ohif.toolButton', + props: { + icon: 'icon-tool-ultrasound-bidirectional', + label: 'Ultrasound Directional', + tooltip: 'Ultrasound Directional', + commands: setToolActiveToolbar, + evaluate: [ + 'evaluate.cornerstoneTool', + { + name: 'evaluate.modality.supported', + supportedModalities: ['US'], + }, + ], + }, + }, + { + id: 'WindowLevelRegion', + uiType: 'ohif.toolButton', + props: { + icon: 'icon-tool-window-region', + label: 'Window Level Region', + tooltip: 'Window Level Region', + commands: setToolActiveToolbar, + evaluate: [ + 'evaluate.cornerstoneTool', + { + name: 'evaluate.viewport.supported', + unsupportedViewportTypes: ['video'], + }, + ], + }, + }, +]; + +export default toolbarButtons;