feat(toolbox): Refactor Toolbar and Toolbox to enable sections (#4825)
This commit is contained in:
parent
86c12246ac
commit
cc5cdfb081
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
|||||||
# Packages
|
# Packages
|
||||||
node_modules
|
node_modules
|
||||||
|
.cursor/
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
build
|
build
|
||||||
|
|||||||
314
bun.lock
314
bun.lock
@ -26,13 +26,13 @@
|
|||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@percy/cypress": "^3.1.1",
|
"@percy/cypress": "^3.1.1",
|
||||||
"@playwright/test": "^1.48.0",
|
"@playwright/test": "^1.48.0",
|
||||||
"cypress": "^14.0.0",
|
"cypress": "^14.1.0",
|
||||||
"cypress-file-upload": "^5.0.8",
|
"cypress-file-upload": "^5.0.8",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"addOns/externals/devDependencies": {
|
"addOns/externals/devDependencies": {
|
||||||
"name": "@externals/devDependencies",
|
"name": "@externals/devDependencies",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@kitware/vtk.js": "32.1.1",
|
"@kitware/vtk.js": "32.1.1",
|
||||||
@ -120,20 +120,20 @@
|
|||||||
},
|
},
|
||||||
"addOns/externals/dicom-microscopy-viewer": {
|
"addOns/externals/dicom-microscopy-viewer": {
|
||||||
"name": "@externals/dicom-microscopy-viewer",
|
"name": "@externals/dicom-microscopy-viewer",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dicom-microscopy-viewer": "^0.46.1",
|
"dicom-microscopy-viewer": "^0.46.1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"extensions/cornerstone": {
|
"extensions/cornerstone": {
|
||||||
"name": "@ohif/extension-cornerstone",
|
"name": "@ohif/extension-cornerstone",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/adapters": "^3.0.1",
|
"@cornerstonejs/adapters": "^3.0.4",
|
||||||
"@cornerstonejs/core": "^3.0.1",
|
"@cornerstonejs/core": "^3.0.4",
|
||||||
"@cornerstonejs/polymorphic-segmentation": "^3.0.1",
|
"@cornerstonejs/polymorphic-segmentation": "^3.0.1",
|
||||||
"@cornerstonejs/tools": "^3.0.1",
|
"@cornerstonejs/tools": "^3.0.4",
|
||||||
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
|
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
|
||||||
"@kitware/vtk.js": "32.1.1",
|
"@kitware/vtk.js": "32.1.1",
|
||||||
"html2canvas": "^1.4.1",
|
"html2canvas": "^1.4.1",
|
||||||
@ -150,9 +150,9 @@
|
|||||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||||
"@cornerstonejs/dicom-image-loader": "^3.0.1",
|
"@cornerstonejs/dicom-image-loader": "^3.0.4",
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/ui": "3.10.0-beta.113",
|
"@ohif/ui": "3.10.0-beta.115",
|
||||||
"dcmjs": "*",
|
"dcmjs": "*",
|
||||||
"dicom-parser": "^1.8.21",
|
"dicom-parser": "^1.8.21",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
@ -164,19 +164,19 @@
|
|||||||
},
|
},
|
||||||
"extensions/cornerstone-dicom-pmap": {
|
"extensions/cornerstone-dicom-pmap": {
|
||||||
"name": "@ohif/extension-cornerstone-dicom-pmap",
|
"name": "@ohif/extension-cornerstone-dicom-pmap",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/adapters": "^3.0.1",
|
"@cornerstonejs/adapters": "^3.0.4",
|
||||||
"@cornerstonejs/core": "^3.0.1",
|
"@cornerstonejs/core": "^3.0.4",
|
||||||
"@kitware/vtk.js": "32.1.1",
|
"@kitware/vtk.js": "32.1.1",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/i18n": "3.10.0-beta.113",
|
"@ohif/i18n": "3.10.0-beta.115",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
@ -187,16 +187,16 @@
|
|||||||
},
|
},
|
||||||
"extensions/cornerstone-dicom-rt": {
|
"extensions/cornerstone-dicom-rt": {
|
||||||
"name": "@ohif/extension-cornerstone-dicom-rt",
|
"name": "@ohif/extension-cornerstone-dicom-rt",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/i18n": "3.10.0-beta.113",
|
"@ohif/i18n": "3.10.0-beta.115",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
@ -207,19 +207,19 @@
|
|||||||
},
|
},
|
||||||
"extensions/cornerstone-dicom-seg": {
|
"extensions/cornerstone-dicom-seg": {
|
||||||
"name": "@ohif/extension-cornerstone-dicom-seg",
|
"name": "@ohif/extension-cornerstone-dicom-seg",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/adapters": "^3.0.1",
|
"@cornerstonejs/adapters": "^3.0.4",
|
||||||
"@cornerstonejs/core": "^3.0.1",
|
"@cornerstonejs/core": "^3.0.4",
|
||||||
"@kitware/vtk.js": "32.1.1",
|
"@kitware/vtk.js": "32.1.1",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/i18n": "3.10.0-beta.113",
|
"@ohif/i18n": "3.10.0-beta.115",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
@ -230,19 +230,19 @@
|
|||||||
},
|
},
|
||||||
"extensions/cornerstone-dicom-sr": {
|
"extensions/cornerstone-dicom-sr": {
|
||||||
"name": "@ohif/extension-cornerstone-dicom-sr",
|
"name": "@ohif/extension-cornerstone-dicom-sr",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/adapters": "^3.0.1",
|
"@cornerstonejs/adapters": "^3.0.4",
|
||||||
"@cornerstonejs/core": "^3.0.1",
|
"@cornerstonejs/core": "^3.0.4",
|
||||||
"@cornerstonejs/tools": "^3.0.1",
|
"@cornerstonejs/tools": "^3.0.4",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone": "3.10.0-beta.115",
|
||||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.113",
|
"@ohif/extension-measurement-tracking": "3.10.0-beta.115",
|
||||||
"@ohif/ui": "3.10.0-beta.113",
|
"@ohif/ui": "3.10.0-beta.115",
|
||||||
"dcmjs": "*",
|
"dcmjs": "*",
|
||||||
"dicom-parser": "^1.8.9",
|
"dicom-parser": "^1.8.9",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
@ -252,19 +252,19 @@
|
|||||||
},
|
},
|
||||||
"extensions/cornerstone-dynamic-volume": {
|
"extensions/cornerstone-dynamic-volume": {
|
||||||
"name": "@ohif/extension-cornerstone-dynamic-volume",
|
"name": "@ohif/extension-cornerstone-dynamic-volume",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/core": "^3.0.1",
|
"@cornerstonejs/core": "^3.0.4",
|
||||||
"@cornerstonejs/tools": "^3.0.1",
|
"@cornerstonejs/tools": "^3.0.4",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/i18n": "3.10.0-beta.113",
|
"@ohif/i18n": "3.10.0-beta.115",
|
||||||
"@ohif/ui": "3.10.0-beta.113",
|
"@ohif/ui": "3.10.0-beta.115",
|
||||||
"dcmjs": "*",
|
"dcmjs": "*",
|
||||||
"dicom-parser": "^1.8.21",
|
"dicom-parser": "^1.8.21",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
@ -274,7 +274,7 @@
|
|||||||
},
|
},
|
||||||
"extensions/default": {
|
"extensions/default": {
|
||||||
"name": "@ohif/extension-default",
|
"name": "@ohif/extension-default",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/calculate-suv": "^1.1.0",
|
"@cornerstonejs/calculate-suv": "^1.1.0",
|
||||||
@ -282,8 +282,8 @@
|
|||||||
"lodash.uniqby": "^4.7.0",
|
"lodash.uniqby": "^4.7.0",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/i18n": "3.10.0-beta.113",
|
"@ohif/i18n": "3.10.0-beta.115",
|
||||||
"dcmjs": "*",
|
"dcmjs": "*",
|
||||||
"dicomweb-client": "^0.10.4",
|
"dicomweb-client": "^0.10.4",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
@ -297,7 +297,7 @@
|
|||||||
},
|
},
|
||||||
"extensions/dicom-microscopy": {
|
"extensions/dicom-microscopy": {
|
||||||
"name": "@ohif/extension-dicom-microscopy",
|
"name": "@ohif/extension-dicom-microscopy",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/codec-charls": "^1.2.3",
|
"@cornerstonejs/codec-charls": "^1.2.3",
|
||||||
@ -308,10 +308,10 @@
|
|||||||
"mathjs": "^12.4.2",
|
"mathjs": "^12.4.2",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/i18n": "3.10.0-beta.113",
|
"@ohif/i18n": "3.10.0-beta.115",
|
||||||
"@ohif/ui": "3.10.0-beta.113",
|
"@ohif/ui": "3.10.0-beta.115",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
@ -322,14 +322,14 @@
|
|||||||
},
|
},
|
||||||
"extensions/dicom-pdf": {
|
"extensions/dicom-pdf": {
|
||||||
"name": "@ohif/extension-dicom-pdf",
|
"name": "@ohif/extension-dicom-pdf",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/ui": "3.10.0-beta.113",
|
"@ohif/ui": "3.10.0-beta.115",
|
||||||
"dcmjs": "*",
|
"dcmjs": "*",
|
||||||
"dicom-parser": "^1.8.9",
|
"dicom-parser": "^1.8.9",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
@ -339,14 +339,14 @@
|
|||||||
},
|
},
|
||||||
"extensions/dicom-video": {
|
"extensions/dicom-video": {
|
||||||
"name": "@ohif/extension-dicom-video",
|
"name": "@ohif/extension-dicom-video",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/ui": "3.10.0-beta.113",
|
"@ohif/ui": "3.10.0-beta.115",
|
||||||
"dcmjs": "*",
|
"dcmjs": "*",
|
||||||
"dicom-parser": "^1.8.9",
|
"dicom-parser": "^1.8.9",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
@ -356,20 +356,20 @@
|
|||||||
},
|
},
|
||||||
"extensions/measurement-tracking": {
|
"extensions/measurement-tracking": {
|
||||||
"name": "@ohif/extension-measurement-tracking",
|
"name": "@ohif/extension-measurement-tracking",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@ohif/ui": "3.10.0-beta.113",
|
"@ohif/ui": "3.10.0-beta.115",
|
||||||
"@xstate/react": "^3.2.2",
|
"@xstate/react": "^3.2.2",
|
||||||
"xstate": "^4.10.0",
|
"xstate": "^4.10.0",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@cornerstonejs/core": "^3.0.1",
|
"@cornerstonejs/core": "^3.0.4",
|
||||||
"@cornerstonejs/tools": "^3.0.1",
|
"@cornerstonejs/tools": "^3.0.4",
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/ui": "3.10.0-beta.113",
|
"@ohif/ui": "3.10.0-beta.115",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"dcmjs": "*",
|
"dcmjs": "*",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
@ -382,14 +382,14 @@
|
|||||||
},
|
},
|
||||||
"extensions/test-extension": {
|
"extensions/test-extension": {
|
||||||
"name": "@ohif/extension-test",
|
"name": "@ohif/extension-test",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/ui": "3.10.0-beta.113",
|
"@ohif/ui": "3.10.0-beta.115",
|
||||||
"dcmjs": "0.38.0",
|
"dcmjs": "0.38.0",
|
||||||
"dicom-parser": "^1.8.9",
|
"dicom-parser": "^1.8.9",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
@ -399,14 +399,14 @@
|
|||||||
},
|
},
|
||||||
"extensions/tmtv": {
|
"extensions/tmtv": {
|
||||||
"name": "@ohif/extension-tmtv",
|
"name": "@ohif/extension-tmtv",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/ui": "3.10.0-beta.113",
|
"@ohif/ui": "3.10.0-beta.115",
|
||||||
"dcmjs": "*",
|
"dcmjs": "*",
|
||||||
"dicom-parser": "^1.8.9",
|
"dicom-parser": "^1.8.9",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
@ -416,7 +416,7 @@
|
|||||||
},
|
},
|
||||||
"modes/basic-dev-mode": {
|
"modes/basic-dev-mode": {
|
||||||
"name": "@ohif/mode-basic-dev-mode",
|
"name": "@ohif/mode-basic-dev-mode",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"i18next": "^17.0.3",
|
"i18next": "^17.0.3",
|
||||||
@ -426,17 +426,17 @@
|
|||||||
"webpack-merge": "^5.7.3",
|
"webpack-merge": "^5.7.3",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.113",
|
"@ohif/extension-dicom-pdf": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-video": "3.10.0-beta.113",
|
"@ohif/extension-dicom-video": "3.10.0-beta.115",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"modes/basic-test-mode": {
|
"modes/basic-test-mode": {
|
||||||
"name": "@ohif/mode-test",
|
"name": "@ohif/mode-test",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"i18next": "^17.0.3",
|
"i18next": "^17.0.3",
|
||||||
@ -446,19 +446,19 @@
|
|||||||
"webpack-merge": "^5.7.3",
|
"webpack-merge": "^5.7.3",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.113",
|
"@ohif/extension-dicom-pdf": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-video": "3.10.0-beta.113",
|
"@ohif/extension-dicom-video": "3.10.0-beta.115",
|
||||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.113",
|
"@ohif/extension-measurement-tracking": "3.10.0-beta.115",
|
||||||
"@ohif/extension-test": "3.10.0-beta.113",
|
"@ohif/extension-test": "3.10.0-beta.115",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"modes/longitudinal": {
|
"modes/longitudinal": {
|
||||||
"name": "@ohif/mode-longitudinal",
|
"name": "@ohif/mode-longitudinal",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"i18next": "^17.0.3",
|
"i18next": "^17.0.3",
|
||||||
@ -468,32 +468,32 @@
|
|||||||
"webpack-merge": "^5.7.3",
|
"webpack-merge": "^5.7.3",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.113",
|
"@ohif/extension-dicom-pdf": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-video": "3.10.0-beta.113",
|
"@ohif/extension-dicom-video": "3.10.0-beta.115",
|
||||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.113",
|
"@ohif/extension-measurement-tracking": "3.10.0-beta.115",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"modes/microscopy": {
|
"modes/microscopy": {
|
||||||
"name": "@ohif/mode-microscopy",
|
"name": "@ohif/mode-microscopy",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"i18next": "^17.0.3",
|
"i18next": "^17.0.3",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-microscopy": "3.10.0-beta.113",
|
"@ohif/extension-dicom-microscopy": "3.10.0-beta.115",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"modes/preclinical-4d": {
|
"modes/preclinical-4d": {
|
||||||
"name": "@ohif/mode-preclinical-4d",
|
"name": "@ohif/mode-preclinical-4d",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
},
|
},
|
||||||
@ -502,17 +502,17 @@
|
|||||||
"webpack-merge": "^5.7.3",
|
"webpack-merge": "^5.7.3",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dynamic-volume": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dynamic-volume": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/extension-tmtv": "3.10.0-beta.113",
|
"@ohif/extension-tmtv": "3.10.0-beta.115",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"modes/segmentation": {
|
"modes/segmentation": {
|
||||||
"name": "@ohif/mode-segmentation",
|
"name": "@ohif/mode-segmentation",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"i18next": "^17.0.3",
|
"i18next": "^17.0.3",
|
||||||
@ -544,19 +544,19 @@
|
|||||||
"webpack-merge": "^5.7.3",
|
"webpack-merge": "^5.7.3",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.113",
|
"@ohif/extension-dicom-pdf": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-video": "3.10.0-beta.113",
|
"@ohif/extension-dicom-video": "3.10.0-beta.115",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"modes/tmtv": {
|
"modes/tmtv": {
|
||||||
"name": "@ohif/mode-tmtv",
|
"name": "@ohif/mode-tmtv",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"i18next": "^17.0.3",
|
"i18next": "^17.0.3",
|
||||||
@ -566,43 +566,43 @@
|
|||||||
"webpack-merge": "^5.7.3",
|
"webpack-merge": "^5.7.3",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.113",
|
"@ohif/extension-dicom-pdf": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-video": "3.10.0-beta.113",
|
"@ohif/extension-dicom-video": "3.10.0-beta.115",
|
||||||
"@ohif/extension-measurement-tracking": "3.10.0-beta.113",
|
"@ohif/extension-measurement-tracking": "3.10.0-beta.115",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"platform/app": {
|
"platform/app": {
|
||||||
"name": "@ohif/app",
|
"name": "@ohif/app",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/codec-charls": "^1.2.3",
|
"@cornerstonejs/codec-charls": "^1.2.3",
|
||||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||||
"@cornerstonejs/dicom-image-loader": "^3.0.1",
|
"@cornerstonejs/dicom-image-loader": "^3.0.4",
|
||||||
"@emotion/serialize": "^1.1.3",
|
"@emotion/serialize": "^1.1.3",
|
||||||
"@ohif/core": "3.10.0-beta.113",
|
"@ohif/core": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.115",
|
||||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.113",
|
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.115",
|
||||||
"@ohif/extension-default": "3.10.0-beta.113",
|
"@ohif/extension-default": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-microscopy": "3.10.0-beta.113",
|
"@ohif/extension-dicom-microscopy": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-pdf": "3.10.0-beta.113",
|
"@ohif/extension-dicom-pdf": "3.10.0-beta.115",
|
||||||
"@ohif/extension-dicom-video": "3.10.0-beta.113",
|
"@ohif/extension-dicom-video": "3.10.0-beta.115",
|
||||||
"@ohif/extension-test": "3.10.0-beta.113",
|
"@ohif/extension-test": "3.10.0-beta.115",
|
||||||
"@ohif/i18n": "3.10.0-beta.113",
|
"@ohif/i18n": "3.10.0-beta.115",
|
||||||
"@ohif/mode-basic-dev-mode": "3.10.0-beta.113",
|
"@ohif/mode-basic-dev-mode": "3.10.0-beta.115",
|
||||||
"@ohif/mode-longitudinal": "3.10.0-beta.113",
|
"@ohif/mode-longitudinal": "3.10.0-beta.115",
|
||||||
"@ohif/mode-microscopy": "3.10.0-beta.113",
|
"@ohif/mode-microscopy": "3.10.0-beta.115",
|
||||||
"@ohif/mode-test": "3.10.0-beta.113",
|
"@ohif/mode-test": "3.10.0-beta.115",
|
||||||
"@ohif/ui": "3.10.0-beta.113",
|
"@ohif/ui": "3.10.0-beta.115",
|
||||||
"@ohif/ui-next": "3.10.0-beta.113",
|
"@ohif/ui-next": "3.10.0-beta.115",
|
||||||
"@svgr/webpack": "^8.1.0",
|
"@svgr/webpack": "^8.1.0",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
@ -643,7 +643,7 @@
|
|||||||
},
|
},
|
||||||
"platform/cli": {
|
"platform/cli": {
|
||||||
"name": "@ohif/cli",
|
"name": "@ohif/cli",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"bin": {
|
"bin": {
|
||||||
"ohif-cli": "src/index.js"
|
"ohif-cli": "src/index.js"
|
||||||
},
|
},
|
||||||
@ -667,7 +667,7 @@
|
|||||||
},
|
},
|
||||||
"platform/core": {
|
"platform/core": {
|
||||||
"name": "@ohif/core",
|
"name": "@ohif/core",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"dcmjs": "*",
|
"dcmjs": "*",
|
||||||
@ -692,15 +692,15 @@
|
|||||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||||
"@cornerstonejs/dicom-image-loader": "^3.0.1",
|
"@cornerstonejs/dicom-image-loader": "^3.0.4",
|
||||||
"@ohif/ui": "3.10.0-beta.113",
|
"@ohif/ui": "3.10.0-beta.115",
|
||||||
"cornerstone-math": "0.1.9",
|
"cornerstone-math": "0.1.9",
|
||||||
"dicom-parser": "^1.8.21",
|
"dicom-parser": "^1.8.21",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"platform/i18n": {
|
"platform/i18n": {
|
||||||
"name": "@ohif/i18n",
|
"name": "@ohif/i18n",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"i18next-locize-backend": "^2.0.0",
|
"i18next-locize-backend": "^2.0.0",
|
||||||
@ -725,7 +725,7 @@
|
|||||||
},
|
},
|
||||||
"platform/ui": {
|
"platform/ui": {
|
||||||
"name": "@ohif/ui",
|
"name": "@ohif/ui",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@testing-library/react": "^13.1.0",
|
"@testing-library/react": "^13.1.0",
|
||||||
"browser-detect": "^0.2.28",
|
"browser-detect": "^0.2.28",
|
||||||
@ -785,7 +785,7 @@
|
|||||||
},
|
},
|
||||||
"platform/ui-next": {
|
"platform/ui-next": {
|
||||||
"name": "@ohif/ui-next",
|
"name": "@ohif/ui-next",
|
||||||
"version": "3.10.0-beta.113",
|
"version": "3.10.0-beta.115",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/react-accordion": "^1.2.0",
|
"@radix-ui/react-accordion": "^1.2.0",
|
||||||
"@radix-ui/react-checkbox": "^1.1.1",
|
"@radix-ui/react-checkbox": "^1.1.1",
|
||||||
@ -1092,7 +1092,7 @@
|
|||||||
|
|
||||||
"@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="],
|
"@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="],
|
||||||
|
|
||||||
"@cornerstonejs/adapters": ["@cornerstonejs/adapters@3.0.1", "", { "dependencies": { "@babel/runtime-corejs2": "^7.17.8", "buffer": "^6.0.3", "dcmjs": "^0.29.8", "gl-matrix": "^3.4.3", "ndarray": "^1.0.19" }, "peerDependencies": { "@cornerstonejs/core": "^3.0.1", "@cornerstonejs/tools": "^3.0.1" } }, "sha512-Ym6s4cTpMkojap5QZ8MXZ8hDbs2TMMN/ypqU7wKMwAY2LGoltoeGw0Z/7LL+iostbaSw3fVs+TZzJSKhKw8Bug=="],
|
"@cornerstonejs/adapters": ["@cornerstonejs/adapters@3.0.4", "", { "dependencies": { "@babel/runtime-corejs2": "^7.17.8", "buffer": "^6.0.3", "dcmjs": "^0.29.8", "gl-matrix": "^3.4.3", "ndarray": "^1.0.19" }, "peerDependencies": { "@cornerstonejs/core": "^3.0.4", "@cornerstonejs/tools": "^3.0.4" } }, "sha512-TJtW0biDf0wgi+XxQFqvKXT/Cf8ueyUruohH9n/RJsWiyE8z1/LOBxOqCZNkToGGs1EbO51T/PMPIUWordW43w=="],
|
||||||
|
|
||||||
"@cornerstonejs/calculate-suv": ["@cornerstonejs/calculate-suv@1.1.0", "", {}, "sha512-Q9XraiDJif9aMFArD2iEuDO/HXbcRVCqB7KfaHgDrdTTjgDFovS91Psbdim7crypRSvE6dh/+HKeFNHdvNkA6w=="],
|
"@cornerstonejs/calculate-suv": ["@cornerstonejs/calculate-suv@1.1.0", "", {}, "sha512-Q9XraiDJif9aMFArD2iEuDO/HXbcRVCqB7KfaHgDrdTTjgDFovS91Psbdim7crypRSvE6dh/+HKeFNHdvNkA6w=="],
|
||||||
|
|
||||||
@ -1104,13 +1104,13 @@
|
|||||||
|
|
||||||
"@cornerstonejs/codec-openjph": ["@cornerstonejs/codec-openjph@2.4.7", "", {}, "sha512-qvP4q4JDib7mi9r7LqKOwqz7YZ8gjtDX4ZCezeYf8+eb7MBXCz5uXAMeVF3yz9Axw4XiIMdB/pqXkm8tqCl13w=="],
|
"@cornerstonejs/codec-openjph": ["@cornerstonejs/codec-openjph@2.4.7", "", {}, "sha512-qvP4q4JDib7mi9r7LqKOwqz7YZ8gjtDX4ZCezeYf8+eb7MBXCz5uXAMeVF3yz9Axw4XiIMdB/pqXkm8tqCl13w=="],
|
||||||
|
|
||||||
"@cornerstonejs/core": ["@cornerstonejs/core@3.0.1", "", { "dependencies": { "@kitware/vtk.js": "32.9.0", "comlink": "^4.4.1", "gl-matrix": "^3.4.3" } }, "sha512-K+cOoN/TzJIPRRoaWWNkhJ+2CdkBBX8BA64DG0aBVOthlwJPRqK2YQE6PTTVRx18mjMA4to/m3de0emFNKrTzQ=="],
|
"@cornerstonejs/core": ["@cornerstonejs/core@3.0.4", "", { "dependencies": { "@kitware/vtk.js": "32.9.0", "comlink": "^4.4.1", "gl-matrix": "^3.4.3" } }, "sha512-6rMiqhBjyz3wsalPOAFjThfPUJnWVOs7Xqe3xLFvqd1qIFW1q42bqlQ7ak2DRMUMtC1nLURk6YIMhkWxK+t+7A=="],
|
||||||
|
|
||||||
"@cornerstonejs/dicom-image-loader": ["@cornerstonejs/dicom-image-loader@3.0.1", "", { "dependencies": { "@cornerstonejs/codec-charls": "^1.2.3", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.2", "@cornerstonejs/codec-openjph": "^2.4.5", "comlink": "^4.4.1", "jpeg-lossless-decoder-js": "^2.1.0", "pako": "^2.0.4", "uuid": "^9.0.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.0.1", "dicom-parser": "^1.8.9" } }, "sha512-t4bI6rVOt4J8YOHRR9Mh9ClInajc98qqI6fwsByiXmtc2Y4INrZ1uaRspFnOJBosbr+EwsJBV7iT2yt6Jk6CjA=="],
|
"@cornerstonejs/dicom-image-loader": ["@cornerstonejs/dicom-image-loader@3.0.4", "", { "dependencies": { "@cornerstonejs/codec-charls": "^1.2.3", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.2", "@cornerstonejs/codec-openjph": "^2.4.5", "comlink": "^4.4.1", "jpeg-lossless-decoder-js": "^2.1.0", "pako": "^2.0.4", "uuid": "^9.0.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.0.4", "dicom-parser": "^1.8.9" } }, "sha512-w0NoutE7+/C2FeT1YHo0cnMJpZ17ARH0qwyGwWockFwuJkUVjRcU5ZW1sT0ABNOPUHqZse/K/YmH2IX+ppaScQ=="],
|
||||||
|
|
||||||
"@cornerstonejs/polymorphic-segmentation": ["@cornerstonejs/polymorphic-segmentation@3.0.1", "", { "dependencies": { "@icr/polyseg-wasm": "0.4.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.0.1", "@cornerstonejs/tools": "^3.0.1", "@kitware/vtk.js": "^32.9.0" } }, "sha512-oCT+U7iTv5oKDHOcEobtZ9gez2aNh/uJkyudO+edd5ndzwXpU+mXp/wre5D9xH5CBCigFG3nDJTZJrpzUHYKfg=="],
|
"@cornerstonejs/polymorphic-segmentation": ["@cornerstonejs/polymorphic-segmentation@3.0.1", "", { "dependencies": { "@icr/polyseg-wasm": "0.4.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.0.1", "@cornerstonejs/tools": "^3.0.1", "@kitware/vtk.js": "^32.9.0" } }, "sha512-oCT+U7iTv5oKDHOcEobtZ9gez2aNh/uJkyudO+edd5ndzwXpU+mXp/wre5D9xH5CBCigFG3nDJTZJrpzUHYKfg=="],
|
||||||
|
|
||||||
"@cornerstonejs/tools": ["@cornerstonejs/tools@3.0.1", "", { "dependencies": { "@types/offscreencanvas": "2019.7.3", "comlink": "^4.4.1", "lodash.get": "^4.4.2" }, "peerDependencies": { "@cornerstonejs/core": "^3.0.1", "@kitware/vtk.js": "32.9.0", "@types/d3-array": "^3.0.4", "@types/d3-interpolate": "^3.0.1", "d3-array": "^3.2.3", "d3-interpolate": "^3.0.1", "gl-matrix": "^3.4.3" } }, "sha512-fRjoXJ46mdpYc5JZ/FUn0g1vCK4LohnNjgZl+O72HK2reMdc5/dQeCueJCT+tBMay04sJMUHm0tAke2DN10FBQ=="],
|
"@cornerstonejs/tools": ["@cornerstonejs/tools@3.0.4", "", { "dependencies": { "@types/offscreencanvas": "2019.7.3", "comlink": "^4.4.1", "lodash.get": "^4.4.2" }, "peerDependencies": { "@cornerstonejs/core": "^3.0.4", "@kitware/vtk.js": "32.9.0", "@types/d3-array": "^3.0.4", "@types/d3-interpolate": "^3.0.1", "d3-array": "^3.2.3", "d3-interpolate": "^3.0.1", "gl-matrix": "^3.4.3" } }, "sha512-gkenXhOS6lYYmQhKDwayojeObTU/KiG9k+JEC/hoOBhRdoFZljyXfQtnljKFHL+G9rkdbNKxXq/a3+C9Bn7EVg=="],
|
||||||
|
|
||||||
"@csstools/postcss-cascade-layers": ["@csstools/postcss-cascade-layers@1.1.1", "", { "dependencies": { "@csstools/selector-specificity": "^2.0.2", "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.2" } }, "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA=="],
|
"@csstools/postcss-cascade-layers": ["@csstools/postcss-cascade-layers@1.1.1", "", { "dependencies": { "@csstools/selector-specificity": "^2.0.2", "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.2" } }, "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA=="],
|
||||||
|
|
||||||
@ -2638,7 +2638,7 @@
|
|||||||
|
|
||||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||||
|
|
||||||
"cypress": ["cypress@14.0.1", "", { "dependencies": { "@cypress/request": "^3.0.6", "@cypress/xvfb": "^1.2.4", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", "blob-util": "^2.0.2", "bluebird": "^3.7.2", "buffer": "^5.7.1", "cachedir": "^2.3.0", "chalk": "^4.1.0", "check-more-types": "^2.24.0", "ci-info": "^4.0.0", "cli-cursor": "^3.1.0", "cli-table3": "~0.6.1", "commander": "^6.2.1", "common-tags": "^1.8.0", "dayjs": "^1.10.4", "debug": "^4.3.4", "enquirer": "^2.3.6", "eventemitter2": "6.4.7", "execa": "4.1.0", "executable": "^4.1.1", "extract-zip": "2.0.1", "figures": "^3.2.0", "fs-extra": "^9.1.0", "getos": "^3.2.1", "is-installed-globally": "~0.4.0", "lazy-ass": "^1.6.0", "listr2": "^3.8.3", "lodash": "^4.17.21", "log-symbols": "^4.0.0", "minimist": "^1.2.8", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", "process": "^0.11.10", "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", "semver": "^7.5.3", "supports-color": "^8.1.1", "tmp": "~0.2.3", "tree-kill": "1.2.2", "untildify": "^4.0.0", "yauzl": "^2.10.0" }, "bin": { "cypress": "bin/cypress" } }, "sha512-gBAvKZE3f6eBaW1v8OtrwAFP90rjNZjjOO40M2KvOvmwVXk96Ps5Yjyck1EzGkXmNCaC/8kXFOY/1KD/wsaWpQ=="],
|
"cypress": ["cypress@14.1.0", "", { "dependencies": { "@cypress/request": "^3.0.7", "@cypress/xvfb": "^1.2.4", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", "blob-util": "^2.0.2", "bluebird": "^3.7.2", "buffer": "^5.7.1", "cachedir": "^2.3.0", "chalk": "^4.1.0", "check-more-types": "^2.24.0", "ci-info": "^4.1.0", "cli-cursor": "^3.1.0", "cli-table3": "~0.6.1", "commander": "^6.2.1", "common-tags": "^1.8.0", "dayjs": "^1.10.4", "debug": "^4.3.4", "enquirer": "^2.3.6", "eventemitter2": "6.4.7", "execa": "4.1.0", "executable": "^4.1.1", "extract-zip": "2.0.1", "figures": "^3.2.0", "fs-extra": "^9.1.0", "getos": "^3.2.1", "is-installed-globally": "~0.4.0", "lazy-ass": "^1.6.0", "listr2": "^3.8.3", "lodash": "^4.17.21", "log-symbols": "^4.0.0", "minimist": "^1.2.8", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", "process": "^0.11.10", "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", "semver": "^7.5.3", "supports-color": "^8.1.1", "tmp": "~0.2.3", "tree-kill": "1.2.2", "untildify": "^4.0.0", "yauzl": "^2.10.0" }, "bin": { "cypress": "bin/cypress" } }, "sha512-pPPj8Uu9NwjaaiXAEcjYZZmgsq6v9Zs1Nw6a+zRF+ANgYSNhH4S32SjFRsvMcuOHR/8dp4GBJhBPqIPSs+TxaA=="],
|
||||||
|
|
||||||
"cypress-file-upload": ["cypress-file-upload@5.0.8", "", { "peerDependencies": { "cypress": ">3.0.0" } }, "sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g=="],
|
"cypress-file-upload": ["cypress-file-upload@5.0.8", "", { "peerDependencies": { "cypress": ">3.0.0" } }, "sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g=="],
|
||||||
|
|
||||||
|
|||||||
@ -46,8 +46,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/adapters": "^3.0.1",
|
"@cornerstonejs/adapters": "^3.0.4",
|
||||||
"@cornerstonejs/core": "^3.0.1",
|
"@cornerstonejs/core": "^3.0.4",
|
||||||
"@kitware/vtk.js": "32.1.1",
|
"@kitware/vtk.js": "32.1.1",
|
||||||
"react-color": "^2.19.3"
|
"react-color": "^2.19.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,8 +46,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/adapters": "^3.0.1",
|
"@cornerstonejs/adapters": "^3.0.4",
|
||||||
"@cornerstonejs/core": "^3.0.1",
|
"@cornerstonejs/core": "^3.0.4",
|
||||||
"@kitware/vtk.js": "32.1.1",
|
"@kitware/vtk.js": "32.1.1",
|
||||||
"react-color": "^2.19.3"
|
"react-color": "^2.19.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -329,9 +329,19 @@ const commandsModule = ({
|
|||||||
},
|
},
|
||||||
setThresholdRange: ({
|
setThresholdRange: ({
|
||||||
value,
|
value,
|
||||||
toolNames = ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
toolNames = [
|
||||||
|
'ThresholdCircularBrush',
|
||||||
|
'ThresholdSphereBrush',
|
||||||
|
'ThresholdCircularBrushDynamic',
|
||||||
|
'ThresholdSphereBrushDynamic',
|
||||||
|
],
|
||||||
}) => {
|
}) => {
|
||||||
toolGroupService.getToolGroupIds()?.forEach(toolGroupId => {
|
const toolGroupIds = toolGroupService.getToolGroupIds();
|
||||||
|
if (!toolGroupIds?.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const toolGroupId of toolGroupIds) {
|
||||||
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
|
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
|
||||||
toolNames?.forEach(toolName => {
|
toolNames?.forEach(toolName => {
|
||||||
toolGroup.setToolConfiguration(toolName, {
|
toolGroup.setToolConfiguration(toolName, {
|
||||||
@ -340,7 +350,7 @@ const commandsModule = ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -46,9 +46,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/adapters": "^3.0.1",
|
"@cornerstonejs/adapters": "^3.0.4",
|
||||||
"@cornerstonejs/core": "^3.0.1",
|
"@cornerstonejs/core": "^3.0.4",
|
||||||
"@cornerstonejs/tools": "^3.0.1",
|
"@cornerstonejs/tools": "^3.0.4",
|
||||||
"classnames": "^2.3.2"
|
"classnames": "^2.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,8 +42,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/core": "^3.0.1",
|
"@cornerstonejs/core": "^3.0.4",
|
||||||
"@cornerstonejs/tools": "^3.0.1",
|
"@cornerstonejs/tools": "^3.0.4",
|
||||||
"classnames": "^2.3.2"
|
"classnames": "^2.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { DynamicDataPanel } from './panels';
|
import { DynamicDataPanel } from './panels';
|
||||||
import { Toolbox } from '@ohif/ui-next';
|
import { Toolbox } from '@ohif/extension-default';
|
||||||
import { PanelSegmentation } from '@ohif/extension-cornerstone';
|
import { PanelSegmentation } from '@ohif/extension-cornerstone';
|
||||||
import DynamicExport from './panels/DynamicExport';
|
import DynamicExport from './panels/DynamicExport';
|
||||||
|
|
||||||
@ -19,9 +19,6 @@ function getPanelModule({ commandsManager, extensionManager, servicesManager, co
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Toolbox
|
<Toolbox
|
||||||
commandsManager={commandsManager}
|
|
||||||
servicesManager={servicesManager}
|
|
||||||
extensionManager={extensionManager}
|
|
||||||
buttonSectionId="dynamic-toolbox"
|
buttonSectionId="dynamic-toolbox"
|
||||||
title="Threshold Tools"
|
title="Threshold Tools"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -38,7 +38,7 @@
|
|||||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||||
"@cornerstonejs/dicom-image-loader": "^3.0.1",
|
"@cornerstonejs/dicom-image-loader": "^3.0.4",
|
||||||
"@ohif/core": "3.10.0-beta.116",
|
"@ohif/core": "3.10.0-beta.116",
|
||||||
"@ohif/ui": "3.10.0-beta.116",
|
"@ohif/ui": "3.10.0-beta.116",
|
||||||
"dcmjs": "*",
|
"dcmjs": "*",
|
||||||
@ -51,10 +51,10 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.13",
|
"@babel/runtime": "^7.20.13",
|
||||||
"@cornerstonejs/adapters": "^3.0.1",
|
"@cornerstonejs/adapters": "^3.0.4",
|
||||||
"@cornerstonejs/core": "^3.0.1",
|
"@cornerstonejs/core": "^3.0.4",
|
||||||
"@cornerstonejs/polymorphic-segmentation": "^3.0.1",
|
"@cornerstonejs/polymorphic-segmentation": "^3.0.1",
|
||||||
"@cornerstonejs/tools": "^3.0.1",
|
"@cornerstonejs/tools": "^3.0.4",
|
||||||
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
|
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
|
||||||
"@kitware/vtk.js": "32.1.1",
|
"@kitware/vtk.js": "32.1.1",
|
||||||
"html2canvas": "^1.4.1",
|
"html2canvas": "^1.4.1",
|
||||||
|
|||||||
@ -388,7 +388,12 @@ function commandsModule({
|
|||||||
arrowTextCallback: ({ callback }) => {
|
arrowTextCallback: ({ callback }) => {
|
||||||
const labelConfig = customizationService.getCustomization('measurementLabels');
|
const labelConfig = customizationService.getCustomization('measurementLabels');
|
||||||
const renderContent = customizationService.getCustomization('ui.labellingComponent');
|
const renderContent = customizationService.getCustomization('ui.labellingComponent');
|
||||||
callInputDialogAutoComplete(uiDialogService, callback, {}, labelConfig, renderContent);
|
|
||||||
|
callInputDialogAutoComplete({
|
||||||
|
uiDialogService,
|
||||||
|
labelConfig,
|
||||||
|
renderContent,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
toggleCine: () => {
|
toggleCine: () => {
|
||||||
const { viewports } = viewportGridService.getState();
|
const { viewports } = viewportGridService.getState();
|
||||||
|
|||||||
@ -23,7 +23,6 @@ export function getWindowLevelActionMenu({
|
|||||||
const WindowLevelActionMenu = customizationService.getCustomization(
|
const WindowLevelActionMenu = customizationService.getCustomization(
|
||||||
'viewportActionMenu.windowLevelActionMenu'
|
'viewportActionMenu.windowLevelActionMenu'
|
||||||
);
|
);
|
||||||
console.debug('🚀 ~ WindowLevelActionMenu:', WindowLevelActionMenu);
|
|
||||||
const displaySetPresets = displaySets
|
const displaySetPresets = displaySets
|
||||||
.filter(displaySet => presets[displaySet.Modality])
|
.filter(displaySet => presets[displaySet.Modality])
|
||||||
.map(displaySet => {
|
.map(displaySet => {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Toolbox } from '@ohif/ui-next';
|
import { Toolbox } from '@ohif/extension-default';
|
||||||
import PanelSegmentation from './panels/PanelSegmentation';
|
import PanelSegmentation from './panels/PanelSegmentation';
|
||||||
import ActiveViewportWindowLevel from './components/ActiveViewportWindowLevel';
|
import ActiveViewportWindowLevel from './components/ActiveViewportWindowLevel';
|
||||||
import PanelMeasurement from './panels/PanelMeasurement';
|
import PanelMeasurement from './panels/PanelMeasurement';
|
||||||
@ -36,14 +36,8 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Toolbox
|
<Toolbox
|
||||||
commandsManager={commandsManager}
|
|
||||||
servicesManager={servicesManager}
|
|
||||||
extensionManager={extensionManager}
|
|
||||||
buttonSectionId="segmentationToolbox"
|
buttonSectionId="segmentationToolbox"
|
||||||
title="Segmentation Tools"
|
title="Segmentation Tools"
|
||||||
configuration={{
|
|
||||||
...configuration,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<PanelSegmentation
|
<PanelSegmentation
|
||||||
commandsManager={commandsManager}
|
commandsManager={commandsManager}
|
||||||
|
|||||||
@ -87,61 +87,10 @@ export default function getToolbarModule({ commandsManager, servicesManager }: w
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
// Todo: isActive right now is used for nested buttons where the primary
|
|
||||||
// button needs to be fully rounded (vs partial rounded) when active
|
|
||||||
// otherwise it does not have any other use
|
|
||||||
isActive: isPrimaryActive,
|
isActive: isPrimaryActive,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'evaluate.group.promoteToPrimaryIfCornerstoneToolNotActiveInTheList',
|
|
||||||
evaluate: ({ viewportId, button, itemId }) => {
|
|
||||||
const { items } = button.props;
|
|
||||||
|
|
||||||
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);
|
|
||||||
|
|
||||||
if (!toolGroup) {
|
|
||||||
return {
|
|
||||||
primary: button.props.primary,
|
|
||||||
items,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const activeToolName = toolGroup.getActivePrimaryMouseButtonTool();
|
|
||||||
|
|
||||||
// check if the active toolName is part of the items then we need
|
|
||||||
// to move it to the primary button
|
|
||||||
const activeToolIndex = items.findIndex(item => {
|
|
||||||
const toolName = toolbarService.getToolNameForButton(item);
|
|
||||||
return toolName === activeToolName;
|
|
||||||
});
|
|
||||||
|
|
||||||
// if there is an active tool in the items dropdown bound to the primary mouse/touch
|
|
||||||
// we should show that no matter what
|
|
||||||
if (activeToolIndex > -1) {
|
|
||||||
return {
|
|
||||||
primary: items[activeToolIndex],
|
|
||||||
items,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!itemId) {
|
|
||||||
return {
|
|
||||||
primary: button.props.primary,
|
|
||||||
items,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// other wise we can move the clicked tool to the primary button
|
|
||||||
const clickedItemProps = items.find(item => item.id === itemId || item.itemId === itemId);
|
|
||||||
|
|
||||||
return {
|
|
||||||
primary: clickedItemProps,
|
|
||||||
items,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'evaluate.action',
|
name: 'evaluate.action',
|
||||||
evaluate: () => {
|
evaluate: () => {
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
|
|||||||
import debounce from 'lodash.debounce';
|
import debounce from 'lodash.debounce';
|
||||||
import { roundNumber } from '@ohif/core/src/utils';
|
import { roundNumber } from '@ohif/core/src/utils';
|
||||||
import { SegmentationData } from '../services/SegmentationService/SegmentationService';
|
import { SegmentationData } from '../services/SegmentationService/SegmentationService';
|
||||||
|
import { useSystem } from '@ohif/core';
|
||||||
|
|
||||||
function mapSegmentationToDisplay(segmentation, customizationService) {
|
function mapSegmentationToDisplay(segmentation, customizationService) {
|
||||||
const { label, segments } = segmentation;
|
const { label, segments } = segmentation;
|
||||||
@ -83,11 +84,12 @@ function mapSegmentationToDisplay(segmentation, customizationService) {
|
|||||||
* @param options.debounceTime - Debounce time in milliseconds for updates.
|
* @param options.debounceTime - Debounce time in milliseconds for updates.
|
||||||
* @returns An array of segmentation data.
|
* @returns An array of segmentation data.
|
||||||
*/
|
*/
|
||||||
export function useSegmentations({
|
export function useSegmentations(options: {
|
||||||
servicesManager,
|
subscribeToDataModified?: boolean;
|
||||||
subscribeToDataModified = false,
|
debounceTime?: number;
|
||||||
debounceTime = 0,
|
}): SegmentationData[] {
|
||||||
}: withAppTypes<{ debounceTime?: number }>): SegmentationData[] {
|
const { subscribeToDataModified = false, debounceTime = 0 } = options || {};
|
||||||
|
const { servicesManager } = useSystem();
|
||||||
const { segmentationService, customizationService } = servicesManager.services;
|
const { segmentationService, customizationService } = servicesManager.services;
|
||||||
|
|
||||||
const [segmentations, setSegmentations] = useState<SegmentationData[]>([]);
|
const [segmentations, setSegmentations] = useState<SegmentationData[]>([]);
|
||||||
|
|||||||
@ -1,17 +1,24 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { ToolButton } from '@ohif/ui-next';
|
import { ToolButton } from '@ohif/ui-next';
|
||||||
|
import { useToolbar } from '@ohif/core/src/hooks/useToolbar';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps the ToolButtonList component to handle the OHIF toolbar button structure
|
* Wraps the ToolButtonList component to handle the OHIF toolbar button structure
|
||||||
* @param props - Component props
|
* @param props - Component props
|
||||||
* @returns Component
|
* @returns Component
|
||||||
*/
|
*/
|
||||||
export function ToolBoxButtonGroupWrapper({ groupId, items, onInteraction, ...props }) {
|
export function ToolBoxButtonGroupWrapper({ groupId, buttonSection, ...props }) {
|
||||||
if (!items || !groupId) {
|
const { onInteraction, toolbarButtons } = useToolbar({
|
||||||
|
buttonSection,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!groupId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const items = toolbarButtons.map(button => button.componentProps);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-popover flex flex-row space-x-1 rounded-md px-0 py-0">
|
<div className="bg-popover flex flex-row space-x-1 rounded-md px-0 py-0">
|
||||||
{items.map(item => (
|
{items.map(item => (
|
||||||
@ -20,16 +27,22 @@ export function ToolBoxButtonGroupWrapper({ groupId, items, onInteraction, ...pr
|
|||||||
key={item.id}
|
key={item.id}
|
||||||
size="small"
|
size="small"
|
||||||
className={props.disabled && 'text-primary'}
|
className={props.disabled && 'text-primary'}
|
||||||
onInteraction={() =>
|
onInteraction={event => {
|
||||||
onInteraction?.({ groupId, itemId: item.id, commands: item.commands })
|
onInteraction?.({
|
||||||
}
|
event,
|
||||||
|
groupId,
|
||||||
|
commands: item.commands,
|
||||||
|
itemId: item.id,
|
||||||
|
item,
|
||||||
|
});
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ToolBoxButtonWrapper({ onInteraction, ...props }) {
|
export function ToolBoxButtonWrapper({ onInteraction, options, ...props }) {
|
||||||
return (
|
return (
|
||||||
<div className="bg-popover flex flex-row rounded-md px-0 py-0">
|
<div className="bg-popover flex flex-row rounded-md px-0 py-0">
|
||||||
<ToolButton
|
<ToolButton
|
||||||
@ -37,7 +50,14 @@ export function ToolBoxButtonWrapper({ onInteraction, ...props }) {
|
|||||||
id={props.id}
|
id={props.id}
|
||||||
size="small"
|
size="small"
|
||||||
className={classNames(props.disabled && 'text-primary')}
|
className={classNames(props.disabled && 'text-primary')}
|
||||||
onInteraction={() => onInteraction?.({ itemId: props.id, commands: props.commands })}
|
onInteraction={event => {
|
||||||
|
onInteraction?.({
|
||||||
|
event,
|
||||||
|
itemId: props.id,
|
||||||
|
commands: props.commands,
|
||||||
|
options,
|
||||||
|
});
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -7,23 +7,11 @@ import {
|
|||||||
ToolButtonListItem,
|
ToolButtonListItem,
|
||||||
ToolButtonListDivider,
|
ToolButtonListDivider,
|
||||||
} from '@ohif/ui-next';
|
} from '@ohif/ui-next';
|
||||||
|
import { useToolbar } from '@ohif/core/src';
|
||||||
interface ButtonItem {
|
|
||||||
id: string;
|
|
||||||
icon?: string;
|
|
||||||
label?: string;
|
|
||||||
tooltip?: string;
|
|
||||||
isActive?: boolean;
|
|
||||||
disabledText?: string;
|
|
||||||
commands?: Record<string, unknown>;
|
|
||||||
disabled?: boolean;
|
|
||||||
className?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ToolButtonListWrapperProps {
|
interface ToolButtonListWrapperProps {
|
||||||
groupId: string;
|
groupId: string;
|
||||||
primary: ButtonItem;
|
buttonSection: string;
|
||||||
items: ButtonItem[];
|
|
||||||
onInteraction?: (details: {
|
onInteraction?: (details: {
|
||||||
groupId: string;
|
groupId: string;
|
||||||
itemId: string;
|
itemId: string;
|
||||||
@ -39,10 +27,22 @@ interface ToolButtonListWrapperProps {
|
|||||||
*/
|
*/
|
||||||
export default function ToolButtonListWrapper({
|
export default function ToolButtonListWrapper({
|
||||||
groupId,
|
groupId,
|
||||||
primary,
|
buttonSection,
|
||||||
items,
|
|
||||||
onInteraction,
|
|
||||||
}: ToolButtonListWrapperProps) {
|
}: ToolButtonListWrapperProps) {
|
||||||
|
const { onInteraction, toolbarButtons } = useToolbar({
|
||||||
|
buttonSection,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!toolbarButtons?.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const primary =
|
||||||
|
toolbarButtons.find(button => button.componentProps.isActive)?.componentProps ||
|
||||||
|
toolbarButtons[0].componentProps;
|
||||||
|
|
||||||
|
const items = toolbarButtons.map(button => button.componentProps);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToolButtonList>
|
<ToolButtonList>
|
||||||
<ToolButtonListDefault>
|
<ToolButtonListDefault>
|
||||||
@ -63,20 +63,22 @@ export default function ToolButtonListWrapper({
|
|||||||
<ToolButtonListDivider className={primary.isActive ? 'opacity-0' : 'opacity-100'} />
|
<ToolButtonListDivider className={primary.isActive ? 'opacity-0' : 'opacity-100'} />
|
||||||
<div data-cy={`${groupId}-split-button-secondary`}>
|
<div data-cy={`${groupId}-split-button-secondary`}>
|
||||||
<ToolButtonListDropDown>
|
<ToolButtonListDropDown>
|
||||||
{items.map(item => (
|
{items.map(item => {
|
||||||
<ToolButtonListItem
|
return (
|
||||||
key={item.id}
|
<ToolButtonListItem
|
||||||
{...item}
|
key={item.id}
|
||||||
data-cy={item.id}
|
{...item}
|
||||||
data-tool={item.id}
|
data-cy={item.id}
|
||||||
data-active={item.isActive}
|
data-tool={item.id}
|
||||||
onSelect={() =>
|
data-active={item.isActive}
|
||||||
onInteraction?.({ groupId, itemId: item.id, commands: item.commands })
|
onSelect={() =>
|
||||||
}
|
onInteraction?.({ groupId, itemId: item.id, commands: item.commands })
|
||||||
>
|
}
|
||||||
<span className="pl-1">{item.label || item.tooltip || item.id}</span>
|
>
|
||||||
</ToolButtonListItem>
|
<span className="pl-1">{item.label || item.tooltip || item.id}</span>
|
||||||
))}
|
</ToolButtonListItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</ToolButtonListDropDown>
|
</ToolButtonListDropDown>
|
||||||
</div>
|
</div>
|
||||||
</ToolButtonList>
|
</ToolButtonList>
|
||||||
|
|||||||
@ -19,6 +19,7 @@ function ToolbarButtonGroupWithServices({ groupId, items, onInteraction, size })
|
|||||||
groupId,
|
groupId,
|
||||||
itemId: item.id,
|
itemId: item.id,
|
||||||
commands: item.commands,
|
commands: item.commands,
|
||||||
|
item,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
// Note: this is necessary since tooltip will add
|
// Note: this is necessary since tooltip will add
|
||||||
|
|||||||
@ -23,7 +23,7 @@ function ToolbarSplitButtonWithServices({
|
|||||||
onInteraction({
|
onInteraction({
|
||||||
groupId,
|
groupId,
|
||||||
itemId: item.id,
|
itemId: item.id,
|
||||||
commands: item.commands,
|
item,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
|
|||||||
@ -16,6 +16,10 @@ import { panelGroupDefinition } from './constants/panels';
|
|||||||
* @param width the max and min width to set on the element
|
* @param width the max and min width to set on the element
|
||||||
*/
|
*/
|
||||||
const setMinMaxWidth = (elem, width?) => {
|
const setMinMaxWidth = (elem, width?) => {
|
||||||
|
if (!elem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
elem.style.minWidth = width === undefined ? '' : `${width}px`;
|
elem.style.minWidth = width === undefined ? '' : `${width}px`;
|
||||||
elem.style.maxWidth = elem.style.minWidth;
|
elem.style.maxWidth = elem.style.minWidth;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -20,7 +20,9 @@ function ReportDialog({ dataSources, hide, onSave, onCancel }: ReportDialogProps
|
|||||||
dataSources?.[0]?.value ?? null
|
dataSources?.[0]?.value ?? null
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSave = (reportName: string) => {
|
const [reportName, setReportName] = useState('');
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
onSave({
|
onSave({
|
||||||
reportName,
|
reportName,
|
||||||
dataSource: selectedDataSource,
|
dataSource: selectedDataSource,
|
||||||
@ -62,7 +64,11 @@ function ReportDialog({ dataSources, hide, onSave, onCancel }: ReportDialogProps
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={showDataSourceSelect ? 'mt-1 w-2/3' : 'w-full'}>
|
<div className={showDataSourceSelect ? 'mt-1 w-2/3' : 'w-full'}>
|
||||||
<InputDialog>
|
<InputDialog
|
||||||
|
value={reportName}
|
||||||
|
onChange={setReportName}
|
||||||
|
submitOnEnter
|
||||||
|
>
|
||||||
<InputDialog.Field>
|
<InputDialog.Field>
|
||||||
<InputDialog.Input placeholder="Report name" />
|
<InputDialog.Input placeholder="Report name" />
|
||||||
</InputDialog.Field>
|
</InputDialog.Field>
|
||||||
|
|||||||
@ -60,27 +60,6 @@ export default function getToolbarModule({ commandsManager, servicesManager }: w
|
|||||||
name: 'ohif.progressDropdown',
|
name: 'ohif.progressDropdown',
|
||||||
defaultComponent: ProgressDropdownWithService,
|
defaultComponent: ProgressDropdownWithService,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'evaluate.group.promoteToPrimary',
|
|
||||||
evaluate: ({ viewportId, button, itemId }) => {
|
|
||||||
const { items } = button.props;
|
|
||||||
|
|
||||||
if (!itemId) {
|
|
||||||
return {
|
|
||||||
primary: button.props.primary,
|
|
||||||
items,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// other wise we can move the clicked tool to the primary button
|
|
||||||
const clickedItemProps = items.find(item => item.id === itemId || item.itemId === itemId);
|
|
||||||
|
|
||||||
return {
|
|
||||||
primary: clickedItemProps,
|
|
||||||
items,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'evaluate.cine',
|
name: 'evaluate.cine',
|
||||||
evaluate: () => {
|
evaluate: () => {
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import promptLabelAnnotation from './utils/promptLabelAnnotation';
|
|||||||
import usePatientInfo from './hooks/usePatientInfo';
|
import usePatientInfo from './hooks/usePatientInfo';
|
||||||
import { PanelStudyBrowserHeader } from './Panels/StudyBrowser/PanelStudyBrowserHeader';
|
import { PanelStudyBrowserHeader } from './Panels/StudyBrowser/PanelStudyBrowserHeader';
|
||||||
import * as utils from './utils';
|
import * as utils from './utils';
|
||||||
|
import { Toolbox } from './utils';
|
||||||
import MoreDropdownMenu from './Components/MoreDropdownMenu';
|
import MoreDropdownMenu from './Components/MoreDropdownMenu';
|
||||||
import requestDisplaySetCreationForStudy from './Panels/requestDisplaySetCreationForStudy';
|
import requestDisplaySetCreationForStudy from './Panels/requestDisplaySetCreationForStudy';
|
||||||
const defaultExtension: Types.Extensions.Extension = {
|
const defaultExtension: Types.Extensions.Extension = {
|
||||||
@ -97,6 +98,7 @@ export {
|
|||||||
usePatientInfo,
|
usePatientInfo,
|
||||||
PanelStudyBrowserHeader,
|
PanelStudyBrowserHeader,
|
||||||
utils,
|
utils,
|
||||||
|
Toolbox,
|
||||||
MoreDropdownMenu,
|
MoreDropdownMenu,
|
||||||
requestDisplaySetCreationForStudy,
|
requestDisplaySetCreationForStudy,
|
||||||
callInputDialog,
|
callInputDialog,
|
||||||
|
|||||||
122
extensions/default/src/utils/Toolbox.tsx
Normal file
122
extensions/default/src/utils/Toolbox.tsx
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { PanelSection, ToolSettings } from '@ohif/ui-next';
|
||||||
|
import { useSystem, useToolbar } from '@ohif/core';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
interface ButtonProps {
|
||||||
|
isActive?: boolean;
|
||||||
|
options?: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A toolbox is a collection of buttons and commands that they invoke, used to provide
|
||||||
|
* custom control panels to users. This component is a generic UI component that
|
||||||
|
* interacts with services and commands in a generic fashion. While it might
|
||||||
|
* seem unconventional to import it from the UI and integrate it into the JSX,
|
||||||
|
* it belongs in the UI components as there isn't anything in this component that
|
||||||
|
* couldn't be used for a completely different type of app. It plays a crucial
|
||||||
|
* role in enhancing the app with a toolbox by providing a way to integrate
|
||||||
|
* and display various tools and their corresponding options
|
||||||
|
*/
|
||||||
|
export function Toolbox({ buttonSectionId, title }: { buttonSectionId: string; title: string }) {
|
||||||
|
const { servicesManager } = useSystem();
|
||||||
|
const { toolbarService } = servicesManager.services;
|
||||||
|
|
||||||
|
const { toolbarButtons: toolboxSections, onInteraction } = useToolbar({
|
||||||
|
servicesManager,
|
||||||
|
buttonSection: buttonSectionId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!toolboxSections.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we have proper button sections at the top level.
|
||||||
|
if (!toolboxSections.every(section => section.componentProps.buttonSection)) {
|
||||||
|
throw new Error(
|
||||||
|
'Toolbox accepts only button sections at the top level, not buttons. Create at least one button section.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to check a list of buttons for an active tool.
|
||||||
|
const findActiveOptions = (buttons: any[]): unknown => {
|
||||||
|
for (const tool of buttons) {
|
||||||
|
if (tool.componentProps.isActive) {
|
||||||
|
return tool.componentProps.options;
|
||||||
|
}
|
||||||
|
if (tool.componentProps.buttonSection) {
|
||||||
|
const nestedButtons = toolbarService.getButtonPropsInButtonSection(
|
||||||
|
tool.componentProps.buttonSection
|
||||||
|
) as ButtonProps[];
|
||||||
|
const activeNested = nestedButtons.find(nested => nested.isActive);
|
||||||
|
if (activeNested) {
|
||||||
|
return activeNested.options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Look for active tool options across all sections.
|
||||||
|
const activeToolOptions = toolboxSections.reduce((activeOptions, section) => {
|
||||||
|
if (activeOptions) {
|
||||||
|
return activeOptions;
|
||||||
|
}
|
||||||
|
const sectionId = section.componentProps.buttonSection;
|
||||||
|
const buttons = toolbarService.getButtonSection(sectionId);
|
||||||
|
return findActiveOptions(buttons);
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
// Define the interaction handler once.
|
||||||
|
const handleInteraction = ({ itemId }: { itemId: string }) => {
|
||||||
|
onInteraction?.({ itemId });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PanelSection>
|
||||||
|
<PanelSection.Header>
|
||||||
|
<span>{title}</span>
|
||||||
|
</PanelSection.Header>
|
||||||
|
<PanelSection.Content className="flex-shrink-0 border-none">
|
||||||
|
{toolboxSections.map(section => {
|
||||||
|
const sectionId = section.componentProps.buttonSection;
|
||||||
|
const buttons = toolbarService.getButtonSection(sectionId) as any[];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={sectionId}
|
||||||
|
className="bg-muted flex flex-wrap space-x-2 py-2 px-1"
|
||||||
|
>
|
||||||
|
{buttons.map(tool => {
|
||||||
|
if (!tool) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { id, Component, componentProps } = tool;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={id}
|
||||||
|
className={classnames('ml-1')}
|
||||||
|
>
|
||||||
|
<Component
|
||||||
|
{...componentProps}
|
||||||
|
id={id}
|
||||||
|
onInteraction={handleInteraction}
|
||||||
|
size="toolbox"
|
||||||
|
servicesManager={servicesManager}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{activeToolOptions && (
|
||||||
|
<div className="bg-primary-dark h-auto px-2">
|
||||||
|
<ToolSettings options={activeToolOptions} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</PanelSection.Content>
|
||||||
|
</PanelSection>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -57,6 +57,10 @@ export async function callInputDialog({
|
|||||||
submitOnEnter = true,
|
submitOnEnter = true,
|
||||||
}: {
|
}: {
|
||||||
uiDialogService: AppTypes.UIDialogService;
|
uiDialogService: AppTypes.UIDialogService;
|
||||||
|
defaultValue?: string;
|
||||||
|
title?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
submitOnEnter?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const dialogId = 'dialog-enter-annotation';
|
const dialogId = 'dialog-enter-annotation';
|
||||||
|
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
export { addIcon } from './addIcon';
|
export { addIcon } from './addIcon';
|
||||||
|
export * from './Toolbox';
|
||||||
|
|||||||
@ -32,8 +32,8 @@
|
|||||||
"start": "yarn run dev"
|
"start": "yarn run dev"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@cornerstonejs/core": "^3.0.1",
|
"@cornerstonejs/core": "^3.0.4",
|
||||||
"@cornerstonejs/tools": "^3.0.1",
|
"@cornerstonejs/tools": "^3.0.4",
|
||||||
"@ohif/core": "3.10.0-beta.116",
|
"@ohif/core": "3.10.0-beta.116",
|
||||||
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.116",
|
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.116",
|
||||||
"@ohif/extension-default": "3.10.0-beta.116",
|
"@ohif/extension-default": "3.10.0-beta.116",
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import React, { useState, useCallback, useReducer, useEffect } from 'react';
|
import React, { useCallback, useReducer } from 'react';
|
||||||
import { Button } from '@ohif/ui';
|
import { Button } from '@ohif/ui';
|
||||||
import ROIThresholdConfiguration, {
|
import ROIThresholdConfiguration, {
|
||||||
ROI_STAT,
|
ROI_STAT,
|
||||||
} from './PanelROIThresholdSegmentation/ROIThresholdConfiguration';
|
} from './PanelROIThresholdSegmentation/ROIThresholdConfiguration';
|
||||||
import * as cs3dTools from '@cornerstonejs/tools';
|
import * as cs3dTools from '@cornerstonejs/tools';
|
||||||
|
import { useSystem } from '@ohif/core';
|
||||||
|
import { useSegmentations } from '@ohif/extension-cornerstone';
|
||||||
|
|
||||||
const LOWER_CT_THRESHOLD_DEFAULT = -1024;
|
const LOWER_CT_THRESHOLD_DEFAULT = -1024;
|
||||||
const UPPER_CT_THRESHOLD_DEFAULT = 1024;
|
const UPPER_CT_THRESHOLD_DEFAULT = 1024;
|
||||||
@ -40,9 +42,10 @@ function reducer(state, action) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function RectangleROIOptions({ servicesManager, commandsManager }: withAppTypes) {
|
function RectangleROIOptions() {
|
||||||
const { segmentationService } = servicesManager.services;
|
const { commandsManager } = useSystem();
|
||||||
const [selectedSegmentationId, setSelectedSegmentationId] = useState(null);
|
const segmentations = useSegmentations();
|
||||||
|
const activeSegmentation = segmentations[0];
|
||||||
|
|
||||||
const runCommand = useCallback(
|
const runCommand = useCallback(
|
||||||
(commandName, commandOptions = {}) => {
|
(commandName, commandOptions = {}) => {
|
||||||
@ -61,58 +64,20 @@ function RectangleROIOptions({ servicesManager, commandsManager }: withAppTypes)
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleROIThresholding = useCallback(() => {
|
const handleROIThresholding = useCallback(() => {
|
||||||
const segmentationId = selectedSegmentationId;
|
if (!activeSegmentation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const segmentationId = activeSegmentation.segmentationId;
|
||||||
const activeSegmentIndex =
|
const activeSegmentIndex =
|
||||||
cs3dTools.segmentation.segmentIndex.getActiveSegmentIndex(segmentationId);
|
cs3dTools.segmentation.segmentIndex.getActiveSegmentIndex(segmentationId);
|
||||||
|
|
||||||
// run the threshold based on the active segment index
|
|
||||||
// Todo: later find a way to associate each rectangle with a segment (e.g., maybe with color?)
|
|
||||||
runCommand('thresholdSegmentationByRectangleROITool', {
|
runCommand('thresholdSegmentationByRectangleROITool', {
|
||||||
segmentationId,
|
segmentationId,
|
||||||
config,
|
config,
|
||||||
segmentIndex: activeSegmentIndex,
|
segmentIndex: activeSegmentIndex,
|
||||||
});
|
});
|
||||||
}, [selectedSegmentationId, config]);
|
}, [activeSegmentation, config]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const segmentations = segmentationService.getSegmentationRepresentations();
|
|
||||||
|
|
||||||
if (!segmentations.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isActive = segmentations.find(seg => seg.isActive);
|
|
||||||
setSelectedSegmentationId(isActive.id);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update UI based on segmentation changes (added, removed, updated)
|
|
||||||
*/
|
|
||||||
useEffect(() => {
|
|
||||||
// ~~ Subscription
|
|
||||||
const updated = segmentationService.EVENTS.SEGMENTATION_MODIFIED;
|
|
||||||
const subscriptions = [];
|
|
||||||
|
|
||||||
[updated].forEach(evt => {
|
|
||||||
const { unsubscribe } = segmentationService.subscribe(evt, () => {
|
|
||||||
const segmentations = segmentationService.getSegmentationRepresentations();
|
|
||||||
|
|
||||||
if (!segmentations.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isActive = segmentations.find(seg => seg.isActive);
|
|
||||||
setSelectedSegmentationId(isActive.id);
|
|
||||||
});
|
|
||||||
subscriptions.push(unsubscribe);
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
subscriptions.forEach(unsub => {
|
|
||||||
unsub();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="invisible-scrollbar mb-2 flex flex-col overflow-y-auto overflow-x-hidden">
|
<div className="invisible-scrollbar mb-2 flex flex-col overflow-y-auto overflow-x-hidden">
|
||||||
@ -121,7 +86,7 @@ function RectangleROIOptions({ servicesManager, commandsManager }: withAppTypes)
|
|||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
runCommand={runCommand}
|
runCommand={runCommand}
|
||||||
/>
|
/>
|
||||||
{selectedSegmentationId !== null && (
|
{activeSegmentation && (
|
||||||
<Button
|
<Button
|
||||||
className="mt-2 !h-[26px] !w-[75px]"
|
className="mt-2 !h-[26px] !w-[75px]"
|
||||||
onClick={handleROIThresholding}
|
onClick={handleROIThresholding}
|
||||||
|
|||||||
@ -102,7 +102,7 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
|
|||||||
// corrected PT vs the non-attenuation correct PT)
|
// corrected PT vs the non-attenuation correct PT)
|
||||||
|
|
||||||
let ptDisplaySet = null;
|
let ptDisplaySet = null;
|
||||||
for (const [viewportId, viewportDetails] of viewportMatchDetails) {
|
for (const [, viewportDetails] of viewportMatchDetails) {
|
||||||
const { displaySetsInfo } = viewportDetails;
|
const { displaySetsInfo } = viewportDetails;
|
||||||
const displaySets = displaySetsInfo.map(({ displaySetInstanceUID }) =>
|
const displaySets = displaySetsInfo.map(({ displaySetInstanceUID }) =>
|
||||||
displaySetService.getDisplaySetByUID(displaySetInstanceUID)
|
displaySetService.getDisplaySetByUID(displaySetInstanceUID)
|
||||||
@ -199,15 +199,21 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
|
|||||||
|
|
||||||
const { representationData } = segmentation;
|
const { representationData } = segmentation;
|
||||||
const { displaySetMatchDetails: matchDetails } = hangingProtocolService.getMatchDetails();
|
const { displaySetMatchDetails: matchDetails } = hangingProtocolService.getMatchDetails();
|
||||||
const volumeLoaderScheme = 'cornerstoneStreamingImageVolume'; // Loader id which defines which volume loader to use
|
const ctDisplaySetMatch = matchDetails.get('ctDisplaySet');
|
||||||
|
const ptDisplaySetMatch = matchDetails.get('ptDisplaySet');
|
||||||
|
|
||||||
const ctDisplaySet = matchDetails.get('ctDisplaySet');
|
const ctDisplaySet = displaySetService.getDisplaySetByUID(
|
||||||
const ctVolumeId = `${volumeLoaderScheme}:${ctDisplaySet.displaySetInstanceUID}`; // VolumeId with loader id + volume id
|
ctDisplaySetMatch.displaySetInstanceUID
|
||||||
|
);
|
||||||
|
const ptDisplaySet = displaySetService.getDisplaySetByUID(
|
||||||
|
ptDisplaySetMatch.displaySetInstanceUID
|
||||||
|
);
|
||||||
|
|
||||||
const { volumeId: segVolumeId } = representationData[
|
const { volumeId: segVolumeId } = representationData[
|
||||||
SegmentationRepresentations.Labelmap
|
SegmentationRepresentations.Labelmap
|
||||||
] as csTools.Types.LabelmapToolOperationDataVolume;
|
] as csTools.Types.LabelmapToolOperationDataVolume;
|
||||||
const { referencedVolumeId } = cs.cache.getVolume(segVolumeId);
|
|
||||||
|
const labelmapVolume = cs.cache.getVolume(segVolumeId);
|
||||||
|
|
||||||
const annotationUIDs = _getAnnotationsSelectedByToolNames(ROI_THRESHOLD_MANUAL_TOOL_IDS);
|
const annotationUIDs = _getAnnotationsSelectedByToolNames(ROI_THRESHOLD_MANUAL_TOOL_IDS);
|
||||||
|
|
||||||
@ -220,71 +226,40 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const labelmapVolume = cs.cache.getVolume(segmentationId);
|
|
||||||
let referencedVolume = cs.cache.getVolume(referencedVolumeId);
|
|
||||||
const ctReferencedVolume = cs.cache.getVolume(ctVolumeId);
|
|
||||||
|
|
||||||
// check if viewport is
|
|
||||||
|
|
||||||
if (!referencedVolume) {
|
|
||||||
throw new Error('No Reference volume found');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!labelmapVolume) {
|
|
||||||
throw new Error('No Reference labelmap found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const annotation = csTools.annotation.state.getAnnotation(annotationUIDs[0]);
|
|
||||||
|
|
||||||
const {
|
|
||||||
metadata: {
|
|
||||||
enabledElement: { viewport },
|
|
||||||
},
|
|
||||||
} = annotation;
|
|
||||||
|
|
||||||
const showingReferenceVolume = viewport.hasVolumeId(referencedVolumeId);
|
|
||||||
|
|
||||||
if (!showingReferenceVolume) {
|
|
||||||
// if the reference volume is not being displayed, we can't
|
|
||||||
// rely on it for thresholding, we have couple of options here
|
|
||||||
// 1. We choose whatever volume is being displayed
|
|
||||||
// 2. We check if it is a fusion viewport, we pick the volume
|
|
||||||
// that matches the size and dimensions of the labelmap. This might
|
|
||||||
// happen if the 4D PT is converted to a computed volume and displayed
|
|
||||||
// and wants to threshold the labelmap
|
|
||||||
// 3. We throw an error
|
|
||||||
const displaySetInstanceUIDs = viewportGridService.getDisplaySetsUIDsForViewport(
|
|
||||||
viewport.id
|
|
||||||
);
|
|
||||||
|
|
||||||
displaySetInstanceUIDs.forEach(displaySetInstanceUID => {
|
|
||||||
const volume = cs.cache
|
|
||||||
.getVolumes()
|
|
||||||
.find(volume => volume.volumeId.includes(displaySetInstanceUID));
|
|
||||||
|
|
||||||
if (
|
|
||||||
cs.utilities.isEqual(volume.dimensions, labelmapVolume.dimensions) &&
|
|
||||||
cs.utilities.isEqual(volume.spacing, labelmapVolume.spacing)
|
|
||||||
) {
|
|
||||||
referencedVolume = volume;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { ptLower, ptUpper, ctLower, ctUpper } = getThresholdValues(
|
const { ptLower, ptUpper, ctLower, ctUpper } = getThresholdValues(
|
||||||
annotationUIDs,
|
annotationUIDs,
|
||||||
[referencedVolume, ctReferencedVolume],
|
ptDisplaySet,
|
||||||
config
|
config
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { imageIds: ptImageIds } = ptDisplaySet;
|
||||||
|
|
||||||
|
const ptVolumeInfo = cs.cache.getVolumeContainingImageId(ptImageIds[0]);
|
||||||
|
|
||||||
|
if (!ptVolumeInfo) {
|
||||||
|
uiNotificationService.error('No PT volume found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { imageIds: ctImageIds } = ctDisplaySet;
|
||||||
|
const ctVolumeInfo = cs.cache.getVolumeContainingImageId(ctImageIds[0]);
|
||||||
|
|
||||||
|
if (!ctVolumeInfo) {
|
||||||
|
uiNotificationService.error('No CT volume found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ptVolume = ptVolumeInfo.volume;
|
||||||
|
const ctVolume = ctVolumeInfo.volume;
|
||||||
|
|
||||||
return csTools.utilities.segmentation.rectangleROIThresholdVolumeByRange(
|
return csTools.utilities.segmentation.rectangleROIThresholdVolumeByRange(
|
||||||
annotationUIDs,
|
annotationUIDs,
|
||||||
labelmapVolume,
|
labelmapVolume,
|
||||||
[
|
[
|
||||||
{ volume: referencedVolume, lower: ptLower, upper: ptUpper },
|
{ volume: ptVolume, lower: ptLower, upper: ptUpper },
|
||||||
{ volume: ctReferencedVolume, lower: ctLower, upper: ctUpper },
|
{ volume: ctVolume, lower: ctLower, upper: ctUpper },
|
||||||
],
|
],
|
||||||
{ overwrite: true, segmentIndex }
|
{ overwrite: true, segmentIndex, segmentationId }
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
calculateSuvPeak: async ({ segmentationId, segmentIndex }) => {
|
calculateSuvPeak: async ({ segmentationId, segmentIndex }) => {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { PanelPetSUV, PanelROIThresholdExport } from './Panels';
|
import { PanelPetSUV, PanelROIThresholdExport } from './Panels';
|
||||||
import { Toolbox } from '@ohif/ui-next';
|
import { Toolbox } from '@ohif/extension-default';
|
||||||
import PanelTMTV from './Panels/PanelTMTV';
|
import PanelTMTV from './Panels/PanelTMTV';
|
||||||
|
|
||||||
function getPanelModule({ commandsManager, extensionManager, servicesManager }) {
|
function getPanelModule({ commandsManager, extensionManager, servicesManager }) {
|
||||||
@ -17,9 +17,6 @@ function getPanelModule({ commandsManager, extensionManager, servicesManager })
|
|||||||
const wrappedROIThresholdToolbox = () => {
|
const wrappedROIThresholdToolbox = () => {
|
||||||
return (
|
return (
|
||||||
<Toolbox
|
<Toolbox
|
||||||
commandsManager={commandsManager}
|
|
||||||
servicesManager={servicesManager}
|
|
||||||
extensionManager={extensionManager}
|
|
||||||
buttonSectionId="ROIThresholdToolbox"
|
buttonSectionId="ROIThresholdToolbox"
|
||||||
title="Threshold Tools"
|
title="Threshold Tools"
|
||||||
/>
|
/>
|
||||||
@ -39,9 +36,6 @@ function getPanelModule({ commandsManager, extensionManager, servicesManager })
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Toolbox
|
<Toolbox
|
||||||
commandsManager={commandsManager}
|
|
||||||
servicesManager={servicesManager}
|
|
||||||
extensionManager={extensionManager}
|
|
||||||
buttonSectionId="ROIThresholdToolbox"
|
buttonSectionId="ROIThresholdToolbox"
|
||||||
title="Threshold Tools"
|
title="Threshold Tools"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import RectangleROIOptions from './Panels/RectangleROIOptions';
|
import RectangleROIOptions from './Panels/RectangleROIOptions';
|
||||||
|
|
||||||
export default function getToolbarModule({ commandsManager, servicesManager }) {
|
export default function getToolbarModule() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
name: 'tmtv.RectangleROIThresholdOptions',
|
name: 'tmtv.RectangleROIThresholdOptions',
|
||||||
defaultComponent: () => RectangleROIOptions({ commandsManager, servicesManager }),
|
defaultComponent: RectangleROIOptions,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,17 @@
|
|||||||
|
import { cache } from '@cornerstonejs/core';
|
||||||
import * as csTools from '@cornerstonejs/tools';
|
import * as csTools from '@cornerstonejs/tools';
|
||||||
|
|
||||||
function getRoiStats(referencedVolume, annotations) {
|
function getRoiStats(displaySet, annotations) {
|
||||||
// roiStats
|
const { imageIds } = displaySet;
|
||||||
const { imageData } = referencedVolume;
|
|
||||||
const values = imageData.getPointData().getScalars().getData();
|
const ptVolumeInfo = cache.getVolumeContainingImageId(imageIds[0]);
|
||||||
|
|
||||||
|
if (!ptVolumeInfo) {
|
||||||
|
throw new Error('No volume found for display set');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { volume } = ptVolumeInfo;
|
||||||
|
const { voxelManager } = volume;
|
||||||
|
|
||||||
// Todo: add support for other strategies
|
// Todo: add support for other strategies
|
||||||
const { fn, baseValue } = _getStrategyFn('max');
|
const { fn, baseValue } = _getStrategyFn('max');
|
||||||
@ -11,25 +19,25 @@ function getRoiStats(referencedVolume, annotations) {
|
|||||||
|
|
||||||
const boundsIJK = csTools.utilities.rectangleROITool.getBoundsIJKFromRectangleAnnotations(
|
const boundsIJK = csTools.utilities.rectangleROITool.getBoundsIJKFromRectangleAnnotations(
|
||||||
annotations,
|
annotations,
|
||||||
referencedVolume
|
volume
|
||||||
);
|
);
|
||||||
|
|
||||||
const [[iMin, iMax], [jMin, jMax], [kMin, kMax]] = boundsIJK;
|
// Use the voxelManager's forEach method to iterate over the bounds
|
||||||
|
voxelManager.forEach(
|
||||||
for (let i = iMin; i <= iMax; i++) {
|
({ value: voxelValue }) => {
|
||||||
for (let j = jMin; j <= jMax; j++) {
|
value = fn(voxelValue, value);
|
||||||
for (let k = kMin; k <= kMax; k++) {
|
},
|
||||||
const offset = imageData.computeOffsetIndex([i, j, k]);
|
{
|
||||||
value = fn(values[offset], value);
|
boundsIJK,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getThresholdValues(
|
function getThresholdValues(
|
||||||
annotationUIDs,
|
annotationUIDs,
|
||||||
referencedVolumes,
|
ptDisplaySet,
|
||||||
config
|
config
|
||||||
): { ptLower: number; ptUpper: number; ctLower: number; ctUpper: number } {
|
): { ptLower: number; ptUpper: number; ctLower: number; ctUpper: number } {
|
||||||
if (config.strategy === 'range') {
|
if (config.strategy === 'range') {
|
||||||
@ -46,7 +54,7 @@ function getThresholdValues(
|
|||||||
csTools.annotation.state.getAnnotation(annotationUID)
|
csTools.annotation.state.getAnnotation(annotationUID)
|
||||||
);
|
);
|
||||||
|
|
||||||
const ptValue = getRoiStats(referencedVolumes[0], annotations);
|
const ptValue = getRoiStats(ptDisplaySet, annotations);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ctLower: -Infinity,
|
ctLower: -Infinity,
|
||||||
|
|||||||
@ -96,7 +96,7 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
|
|
||||||
toolbarService.addButtons(toolbarButtons);
|
toolbarService.addButtons(toolbarButtons);
|
||||||
toolbarService.createButtonSection('primary', [
|
toolbarService.createButtonSection('primary', [
|
||||||
'MeasurementTools',
|
'measurementSection',
|
||||||
'Zoom',
|
'Zoom',
|
||||||
'WindowLevel',
|
'WindowLevel',
|
||||||
'Pan',
|
'Pan',
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { WindowLevelMenuItem } from '@ohif/ui';
|
import { WindowLevelMenuItem } from '@ohif/ui';
|
||||||
import { defaults, ToolbarService } from '@ohif/core';
|
import { defaults } from '@ohif/core';
|
||||||
import type { Button } from '@ohif/core/types';
|
import type { Button } from '@ohif/core/types';
|
||||||
|
|
||||||
const { windowLevelPresets } = defaults;
|
const { windowLevelPresets } = defaults;
|
||||||
@ -9,74 +9,110 @@ function _createWwwcPreset(preset, title, subtitle) {
|
|||||||
id: preset.toString(),
|
id: preset.toString(),
|
||||||
title,
|
title,
|
||||||
subtitle,
|
subtitle,
|
||||||
commands: [
|
commands: {
|
||||||
{
|
commandName: 'setWindowLevel',
|
||||||
commandName: 'setWindowLevel',
|
commandOptions: {
|
||||||
commandOptions: {
|
...windowLevelPresets[preset],
|
||||||
...windowLevelPresets[preset],
|
|
||||||
},
|
|
||||||
context: 'CORNERSTONE',
|
|
||||||
},
|
},
|
||||||
],
|
context: 'CORNERSTONE',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function _createSetToolActiveCommands(toolName, toolGroupIds = ['default', 'mpr']) {
|
export const setToolActiveToolbar = {
|
||||||
return toolGroupIds.map(toolGroupId => ({
|
commandName: 'setToolActive',
|
||||||
commandName: 'setToolActive',
|
commandOptions: {
|
||||||
commandOptions: {
|
toolGroupIds: ['default', 'mpr'],
|
||||||
toolGroupId,
|
},
|
||||||
toolName,
|
context: 'CORNERSTONE',
|
||||||
},
|
};
|
||||||
context: 'CORNERSTONE',
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const toolbarButtons: Button[] = [
|
const toolbarButtons: Button[] = [
|
||||||
|
// sections
|
||||||
{
|
{
|
||||||
id: 'MeasurementTools',
|
id: 'measurementSection',
|
||||||
uiType: 'ohif.toolButtonList',
|
uiType: 'ohif.toolButtonList',
|
||||||
props: {
|
props: {
|
||||||
groupId: 'MeasurementTools',
|
buttonSection: 'measurementSection',
|
||||||
evaluate: 'evaluate.group.promoteToPrimaryIfCornerstoneToolNotActiveInTheList',
|
groupId: 'measurementSection',
|
||||||
primary: ToolbarService.createButton({
|
},
|
||||||
id: 'Length',
|
},
|
||||||
icon: 'tool-length',
|
{
|
||||||
label: 'Length',
|
id: 'MoreTools',
|
||||||
tooltip: 'Length Tool',
|
uiType: 'ohif.toolButtonList',
|
||||||
commands: _createSetToolActiveCommands('Length'),
|
props: {
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
buttonSection: 'moreToolsSection',
|
||||||
}),
|
groupId: 'MoreTools',
|
||||||
secondary: {
|
},
|
||||||
icon: 'chevron-down',
|
},
|
||||||
tooltip: 'More Measure Tools',
|
|
||||||
|
// tool defs
|
||||||
|
{
|
||||||
|
id: 'Length',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-length',
|
||||||
|
label: 'Length',
|
||||||
|
tooltip: 'Length Tool',
|
||||||
|
commands: {
|
||||||
|
...setToolActiveToolbar,
|
||||||
|
commandOptions: {
|
||||||
|
...setToolActiveToolbar.commandOptions,
|
||||||
|
toolName: 'Length',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
items: [
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
ToolbarService.createButton({
|
},
|
||||||
id: 'Bidirectional',
|
},
|
||||||
icon: 'tool-bidirectional',
|
{
|
||||||
label: 'Bidirectional',
|
id: 'Bidirectional',
|
||||||
tooltip: 'Bidirectional Tool',
|
uiType: 'ohif.toolButton',
|
||||||
commands: _createSetToolActiveCommands('Bidirectional'),
|
props: {
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
icon: 'tool-bidirectional',
|
||||||
}),
|
label: 'Bidirectional',
|
||||||
ToolbarService.createButton({
|
tooltip: 'Bidirectional Tool',
|
||||||
id: 'EllipticalROI',
|
commands: {
|
||||||
icon: 'tool-ellipse',
|
...setToolActiveToolbar,
|
||||||
label: 'Ellipse',
|
commandOptions: {
|
||||||
tooltip: 'Ellipse ROI',
|
...setToolActiveToolbar.commandOptions,
|
||||||
commands: _createSetToolActiveCommands('EllipticalROI'),
|
toolName: 'Bidirectional',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
},
|
||||||
}),
|
},
|
||||||
ToolbarService.createButton({
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
id: 'CircleROI',
|
},
|
||||||
icon: 'tool-circle',
|
},
|
||||||
label: 'Circle',
|
{
|
||||||
tooltip: 'Circle Tool',
|
id: 'EllipticalROI',
|
||||||
commands: _createSetToolActiveCommands('CircleROI'),
|
uiType: 'ohif.toolButton',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
props: {
|
||||||
}),
|
icon: 'tool-ellipse',
|
||||||
],
|
label: 'Ellipse',
|
||||||
|
tooltip: 'Ellipse ROI',
|
||||||
|
commands: {
|
||||||
|
...setToolActiveToolbar,
|
||||||
|
commandOptions: {
|
||||||
|
...setToolActiveToolbar.commandOptions,
|
||||||
|
toolName: 'EllipticalROI',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'CircleROI',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-circle',
|
||||||
|
label: 'Circle',
|
||||||
|
tooltip: 'Circle Tool',
|
||||||
|
commands: {
|
||||||
|
...setToolActiveToolbar,
|
||||||
|
commandOptions: {
|
||||||
|
...setToolActiveToolbar.commandOptions,
|
||||||
|
toolName: 'CircleROI',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -85,35 +121,15 @@ const toolbarButtons: Button[] = [
|
|||||||
props: {
|
props: {
|
||||||
icon: 'tool-zoom',
|
icon: 'tool-zoom',
|
||||||
label: 'Zoom',
|
label: 'Zoom',
|
||||||
commands: _createSetToolActiveCommands('Zoom'),
|
tooltip: 'Zoom',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
commands: {
|
||||||
},
|
...setToolActiveToolbar,
|
||||||
},
|
commandOptions: {
|
||||||
{
|
...setToolActiveToolbar.commandOptions,
|
||||||
id: 'WindowLevel',
|
toolName: 'Zoom',
|
||||||
uiType: 'ohif.toolButtonList',
|
},
|
||||||
props: {
|
|
||||||
groupId: 'WindowLevel',
|
|
||||||
primary: ToolbarService.createButton({
|
|
||||||
id: 'WindowLevel',
|
|
||||||
icon: 'tool-window-level',
|
|
||||||
label: 'Window Level',
|
|
||||||
tooltip: 'Window Level',
|
|
||||||
commands: _createSetToolActiveCommands('WindowLevel'),
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
secondary: {
|
|
||||||
icon: 'chevron-down',
|
|
||||||
tooltip: 'W/L Presets',
|
|
||||||
},
|
},
|
||||||
renderer: WindowLevelMenuItem,
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
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'),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -122,7 +138,14 @@ const toolbarButtons: Button[] = [
|
|||||||
props: {
|
props: {
|
||||||
icon: 'tool-move',
|
icon: 'tool-move',
|
||||||
label: 'Pan',
|
label: 'Pan',
|
||||||
commands: _createSetToolActiveCommands('Pan'),
|
tooltip: 'Pan',
|
||||||
|
commands: {
|
||||||
|
...setToolActiveToolbar,
|
||||||
|
commandOptions: {
|
||||||
|
...setToolActiveToolbar.commandOptions,
|
||||||
|
toolName: 'Pan',
|
||||||
|
},
|
||||||
|
},
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -132,12 +155,8 @@ const toolbarButtons: Button[] = [
|
|||||||
props: {
|
props: {
|
||||||
icon: 'tool-capture',
|
icon: 'tool-capture',
|
||||||
label: 'Capture',
|
label: 'Capture',
|
||||||
commands: [
|
tooltip: 'Capture',
|
||||||
{
|
commands: 'showDownloadViewportModal',
|
||||||
commandName: 'showDownloadViewportModal',
|
|
||||||
context: 'CORNERSTONE',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: [
|
evaluate: [
|
||||||
'evaluate.action',
|
'evaluate.action',
|
||||||
{
|
{
|
||||||
@ -154,106 +173,86 @@ const toolbarButtons: Button[] = [
|
|||||||
rows: 3,
|
rows: 3,
|
||||||
columns: 4,
|
columns: 4,
|
||||||
evaluate: 'evaluate.action',
|
evaluate: 'evaluate.action',
|
||||||
commands: [
|
commands: 'setViewportGridLayout',
|
||||||
{
|
},
|
||||||
commandName: 'setViewportGridLayout',
|
},
|
||||||
},
|
|
||||||
],
|
{
|
||||||
|
id: 'Reset',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-reset',
|
||||||
|
label: 'Reset View',
|
||||||
|
tooltip: 'Reset View',
|
||||||
|
commands: 'resetViewport',
|
||||||
|
evaluate: 'evaluate.action',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'MoreTools',
|
id: 'RotateRight',
|
||||||
uiType: 'ohif.toolButtonList',
|
uiType: 'ohif.toolButton',
|
||||||
props: {
|
props: {
|
||||||
groupId: 'MoreTools',
|
icon: 'tool-rotate-right',
|
||||||
evaluate: 'evaluate.group.promoteToPrimaryIfCornerstoneToolNotActiveInTheList',
|
label: 'Rotate Right',
|
||||||
primary: ToolbarService.createButton({
|
tooltip: 'Rotate Right +90',
|
||||||
id: 'Reset',
|
commands: 'rotateViewportCW',
|
||||||
icon: 'tool-reset',
|
evaluate: 'evaluate.action',
|
||||||
label: 'Reset View',
|
},
|
||||||
tooltip: 'Reset View',
|
},
|
||||||
commands: [
|
{
|
||||||
{
|
id: 'FlipHorizontal',
|
||||||
commandName: 'resetViewport',
|
uiType: 'ohif.toolButton',
|
||||||
context: 'CORNERSTONE',
|
props: {
|
||||||
},
|
icon: 'tool-flip-horizontal',
|
||||||
],
|
label: 'Flip Horizontally',
|
||||||
evaluate: 'evaluate.action',
|
tooltip: 'Flip Horizontally',
|
||||||
}),
|
commands: 'flipViewportHorizontal',
|
||||||
secondary: {
|
evaluate: 'evaluate.action',
|
||||||
icon: 'chevron-down',
|
},
|
||||||
tooltip: 'More Tools',
|
},
|
||||||
|
{
|
||||||
|
id: 'StackScroll',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-stack-scroll',
|
||||||
|
label: 'Stack Scroll',
|
||||||
|
tooltip: 'Stack Scroll',
|
||||||
|
commands: {
|
||||||
|
...setToolActiveToolbar,
|
||||||
|
commandOptions: {
|
||||||
|
...setToolActiveToolbar.commandOptions,
|
||||||
|
toolName: 'StackScroll',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
items: [
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
ToolbarService.createButton({
|
},
|
||||||
id: 'Reset',
|
},
|
||||||
icon: 'tool-reset',
|
{
|
||||||
label: 'Reset View',
|
id: 'Invert',
|
||||||
tooltip: 'Reset View',
|
uiType: 'ohif.toolButton',
|
||||||
commands: [
|
props: {
|
||||||
{
|
icon: 'tool-invert',
|
||||||
commandName: 'resetViewport',
|
label: 'Invert Colors',
|
||||||
context: 'CORNERSTONE',
|
tooltip: 'Invert Colors',
|
||||||
},
|
commands: 'invertViewport',
|
||||||
],
|
evaluate: 'evaluate.action',
|
||||||
evaluate: 'evaluate.action',
|
},
|
||||||
}),
|
},
|
||||||
ToolbarService.createButton({
|
{
|
||||||
id: 'RotateRight',
|
id: 'CalibrationLine',
|
||||||
icon: 'tool-rotate-right',
|
uiType: 'ohif.toolButton',
|
||||||
label: 'Rotate Right',
|
props: {
|
||||||
tooltip: 'Rotate Right +90',
|
icon: 'tool-calibration',
|
||||||
commands: [
|
label: 'Calibration Line',
|
||||||
{
|
tooltip: 'Calibration Line',
|
||||||
commandName: 'rotateViewportCW',
|
commands: {
|
||||||
context: 'CORNERSTONE',
|
...setToolActiveToolbar,
|
||||||
},
|
commandOptions: {
|
||||||
],
|
...setToolActiveToolbar.commandOptions,
|
||||||
evaluate: 'evaluate.action',
|
toolName: 'CalibrationLine',
|
||||||
}),
|
},
|
||||||
ToolbarService.createButton({
|
},
|
||||||
id: 'FlipHorizontal',
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
icon: 'tool-flip-horizontal',
|
|
||||||
label: 'Flip Horizontally',
|
|
||||||
tooltip: 'Flip Horizontally',
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
commandName: 'flipViewportHorizontal',
|
|
||||||
context: 'CORNERSTONE',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: 'evaluate.action',
|
|
||||||
}),
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'StackScroll',
|
|
||||||
icon: 'tool-stack-scroll',
|
|
||||||
label: 'Stack Scroll',
|
|
||||||
tooltip: 'Stack Scroll',
|
|
||||||
commands: _createSetToolActiveCommands('StackScroll'),
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'Invert',
|
|
||||||
icon: 'tool-invert',
|
|
||||||
label: 'Invert Colors',
|
|
||||||
tooltip: 'Invert Colors',
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
commandName: 'invertViewport',
|
|
||||||
context: 'CORNERSTONE',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: 'evaluate.action',
|
|
||||||
}),
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'CalibrationLine',
|
|
||||||
icon: 'tool-calibration',
|
|
||||||
label: 'Calibration Line',
|
|
||||||
tooltip: 'Calibration Line',
|
|
||||||
commands: _createSetToolActiveCommands('CalibrationLine'),
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import toolbarButtons from './toolbarButtons';
|
import toolbarButtons from './toolbarButtons';
|
||||||
import { id } from './id';
|
import { id } from './id';
|
||||||
import initToolGroups from './initToolGroups';
|
import initToolGroups from './initToolGroups';
|
||||||
import moreTools from './moreTools';
|
|
||||||
import i18n from 'i18next';
|
import i18n from 'i18next';
|
||||||
|
|
||||||
// Allow this mode by excluding non-imaging modalities such as SR, SEG
|
// Allow this mode by excluding non-imaging modalities such as SR, SEG
|
||||||
@ -53,7 +52,6 @@ const dicomPmap = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const extensionDependencies = {
|
const extensionDependencies = {
|
||||||
// Can derive the versions at least process.env.from npm_package_version
|
|
||||||
'@ohif/extension-default': '^3.0.0',
|
'@ohif/extension-default': '^3.0.0',
|
||||||
'@ohif/extension-cornerstone': '^3.0.0',
|
'@ohif/extension-cornerstone': '^3.0.0',
|
||||||
'@ohif/extension-measurement-tracking': '^3.0.0',
|
'@ohif/extension-measurement-tracking': '^3.0.0',
|
||||||
@ -67,8 +65,6 @@ const extensionDependencies = {
|
|||||||
|
|
||||||
function modeFactory() {
|
function modeFactory() {
|
||||||
return {
|
return {
|
||||||
// TODO: We're using this as a route segment
|
|
||||||
// We should not be.
|
|
||||||
id,
|
id,
|
||||||
routeName: 'basic-test',
|
routeName: 'basic-test',
|
||||||
displayName: i18n.t('Modes:Basic Test Mode'),
|
displayName: i18n.t('Modes:Basic Test Mode'),
|
||||||
@ -89,11 +85,12 @@ function modeFactory() {
|
|||||||
'@ohif/extension-test.customizationModule.custom-context-menu',
|
'@ohif/extension-test.customizationModule.custom-context-menu',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
toolbarService.addButtons([...toolbarButtons, ...moreTools]);
|
toolbarService.addButtons(toolbarButtons);
|
||||||
|
console.debug('toolbarButtons', toolbarButtons);
|
||||||
toolbarService.createButtonSection('primary', [
|
toolbarService.createButtonSection('primary', [
|
||||||
'MeasurementTools',
|
'MeasurementTools',
|
||||||
'Zoom',
|
'Zoom',
|
||||||
'WindowLevel',
|
'WindowLevelGroup',
|
||||||
'Pan',
|
'Pan',
|
||||||
'Capture',
|
'Capture',
|
||||||
'Layout',
|
'Layout',
|
||||||
@ -102,6 +99,48 @@ function modeFactory() {
|
|||||||
'MoreTools',
|
'MoreTools',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
toolbarService.createButtonSection('windowLevelSection', [
|
||||||
|
'WindowLevel',
|
||||||
|
'Soft tissue',
|
||||||
|
'Lung',
|
||||||
|
'Liver',
|
||||||
|
'Bone',
|
||||||
|
'Brain',
|
||||||
|
]);
|
||||||
|
|
||||||
|
toolbarService.createButtonSection('measurementSection', [
|
||||||
|
'Length',
|
||||||
|
'Bidirectional',
|
||||||
|
'ArrowAnnotate',
|
||||||
|
'EllipticalROI',
|
||||||
|
'CircleROI',
|
||||||
|
'PlanarFreehandROI',
|
||||||
|
'SplineROI',
|
||||||
|
'LivewireContour',
|
||||||
|
]);
|
||||||
|
|
||||||
|
toolbarService.createButtonSection('moreToolsSection', [
|
||||||
|
'Reset',
|
||||||
|
'rotate-right',
|
||||||
|
'flipHorizontal',
|
||||||
|
'ImageSliceSync',
|
||||||
|
'ReferenceLines',
|
||||||
|
'ImageOverlayViewer',
|
||||||
|
'StackScroll',
|
||||||
|
'invert',
|
||||||
|
'Probe',
|
||||||
|
'Cine',
|
||||||
|
'Angle',
|
||||||
|
'CobbAngle',
|
||||||
|
'Magnify',
|
||||||
|
'RectangleROI',
|
||||||
|
'CalibrationLine',
|
||||||
|
'TagBrowser',
|
||||||
|
'AdvancedMagnify',
|
||||||
|
'UltrasoundDirectionalTool',
|
||||||
|
'WindowLevelRegion',
|
||||||
|
]);
|
||||||
|
|
||||||
customizationService.setCustomizations(
|
customizationService.setCustomizations(
|
||||||
{
|
{
|
||||||
'ohif.hotkeyBindings': {
|
'ohif.hotkeyBindings': {
|
||||||
@ -154,22 +193,14 @@ function modeFactory() {
|
|||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: 'basic-test',
|
path: 'basic-test',
|
||||||
/*init: ({ servicesManager, extensionManager }) => {
|
|
||||||
//defaultViewerRouteInit
|
|
||||||
},*/
|
|
||||||
layoutTemplate: () => {
|
layoutTemplate: () => {
|
||||||
return {
|
return {
|
||||||
id: ohif.layout,
|
id: ohif.layout,
|
||||||
props: {
|
props: {
|
||||||
// Use the first two for an untracked view
|
|
||||||
// leftPanels: [ohif.thumbnailList],
|
|
||||||
// rightPanels: [dicomSeg.panel, ohif.measurements],
|
|
||||||
leftPanels: [tracked.thumbnailList],
|
leftPanels: [tracked.thumbnailList],
|
||||||
leftPanelResizable: true,
|
leftPanelResizable: true,
|
||||||
// Can use cornerstone.measurements for all measurements
|
|
||||||
rightPanels: [cornerstone.panel, tracked.measurements, cornerstone.measurements],
|
rightPanels: [cornerstone.panel, tracked.measurements, cornerstone.measurements],
|
||||||
rightPanelResizable: true,
|
rightPanelResizable: true,
|
||||||
// rightPanelClosed: true, // optional prop to start with collapse panels
|
|
||||||
viewports: [
|
viewports: [
|
||||||
{
|
{
|
||||||
namespace: tracked.viewport,
|
namespace: tracked.viewport,
|
||||||
@ -206,12 +237,7 @@ function modeFactory() {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
extensions: extensionDependencies,
|
extensions: extensionDependencies,
|
||||||
// Default protocol gets self-registered by default in the init
|
|
||||||
hangingProtocol: 'default',
|
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: [
|
sopClassHandlers: [
|
||||||
dicomvideo.sopClassHandler,
|
dicomvideo.sopClassHandler,
|
||||||
dicomSeg.sopClassHandler,
|
dicomSeg.sopClassHandler,
|
||||||
@ -221,8 +247,6 @@ function modeFactory() {
|
|||||||
dicomsr.sopClassHandler,
|
dicomsr.sopClassHandler,
|
||||||
],
|
],
|
||||||
hotkeys: {
|
hotkeys: {
|
||||||
// Don't store the hotkeys for basic-test-mode under the same key
|
|
||||||
// because they get customized by tests
|
|
||||||
name: 'basic-test-hotkeys',
|
name: 'basic-test-hotkeys',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,212 +0,0 @@
|
|||||||
import type { RunCommand } from '@ohif/core/types';
|
|
||||||
import { EVENTS } from '@cornerstonejs/core';
|
|
||||||
import { ToolbarService, ViewportGridService } from '@ohif/core';
|
|
||||||
import { setToolActiveToolbar } from './toolbarButtons';
|
|
||||||
const { createButton } = ToolbarService;
|
|
||||||
|
|
||||||
const ReferenceLinesListeners: RunCommand = [
|
|
||||||
{
|
|
||||||
commandName: 'setSourceViewportForReferenceLinesTool',
|
|
||||||
context: 'CORNERSTONE',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const moreTools = [
|
|
||||||
{
|
|
||||||
id: 'MoreTools',
|
|
||||||
uiType: 'ohif.toolButtonList',
|
|
||||||
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',
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'ImageSliceSync',
|
|
||||||
icon: 'link',
|
|
||||||
label: 'Image Slice Sync',
|
|
||||||
tooltip: 'Enable position synchronization on stack viewports',
|
|
||||||
commands: {
|
|
||||||
commandName: 'toggleSynchronizer',
|
|
||||||
commandOptions: {
|
|
||||||
type: 'imageSlice',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
listeners: {
|
|
||||||
[EVENTS.VIEWPORT_NEW_IMAGE_SET]: {
|
|
||||||
commandName: 'toggleImageSliceSync',
|
|
||||||
commandOptions: { toggledState: true },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
evaluate: 'evaluate.cornerstone.synchronizer',
|
|
||||||
}),
|
|
||||||
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',
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'Angle',
|
|
||||||
icon: 'tool-angle',
|
|
||||||
label: 'Angle',
|
|
||||||
tooltip: 'Angle',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'CobbAngle',
|
|
||||||
icon: 'icon-tool-cobb-angle',
|
|
||||||
label: 'Cobb Angle',
|
|
||||||
tooltip: 'Cobb 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 moreTools;
|
|
||||||
@ -1,14 +1,11 @@
|
|||||||
// TODO: torn, can either bake this here; or have to create a whole new button type
|
// 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
|
// Only ways that you can pass in a custom React component for render :l
|
||||||
import {
|
|
||||||
// ListMenu,
|
|
||||||
WindowLevelMenuItem,
|
|
||||||
} from '@ohif/ui';
|
|
||||||
import { defaults, ToolbarService } from '@ohif/core';
|
|
||||||
import type { Button } from '@ohif/core/types';
|
import type { Button } from '@ohif/core/types';
|
||||||
|
import { EVENTS } from '@cornerstonejs/core';
|
||||||
|
import { ViewportGridService } from '@ohif/core';
|
||||||
|
|
||||||
|
import { defaults } from '@ohif/core';
|
||||||
const { windowLevelPresets } = defaults;
|
const { windowLevelPresets } = defaults;
|
||||||
const { createButton } = ToolbarService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -18,18 +15,21 @@ const { createButton } = ToolbarService;
|
|||||||
*/
|
*/
|
||||||
function _createWwwcPreset(preset, title, subtitle) {
|
function _createWwwcPreset(preset, title, subtitle) {
|
||||||
return {
|
return {
|
||||||
id: preset.toString(),
|
id: title,
|
||||||
title,
|
uiType: 'ohif.toolButton',
|
||||||
subtitle,
|
props: {
|
||||||
commands: [
|
title,
|
||||||
{
|
subtitle,
|
||||||
commandName: 'setWindowLevel',
|
commands: [
|
||||||
commandOptions: {
|
{
|
||||||
...windowLevelPresets[preset],
|
commandName: 'setWindowLevel',
|
||||||
|
commandOptions: {
|
||||||
|
...windowLevelPresets[preset],
|
||||||
|
},
|
||||||
|
context: 'CORNERSTONE',
|
||||||
},
|
},
|
||||||
context: 'CORNERSTONE',
|
],
|
||||||
},
|
},
|
||||||
],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,92 +40,142 @@ export const setToolActiveToolbar = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ReferenceLinesListeners = [
|
||||||
|
{
|
||||||
|
commandName: 'setSourceViewportForReferenceLinesTool',
|
||||||
|
context: 'CORNERSTONE',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const toolbarButtons: Button[] = [
|
const toolbarButtons: Button[] = [
|
||||||
{
|
{
|
||||||
id: 'MeasurementTools',
|
id: 'MeasurementTools',
|
||||||
uiType: 'ohif.toolButtonList',
|
uiType: 'ohif.toolButtonList',
|
||||||
props: {
|
props: {
|
||||||
|
buttonSection: 'measurementSection',
|
||||||
groupId: 'MeasurementTools',
|
groupId: 'MeasurementTools',
|
||||||
// group evaluate to determine which item should move to the top
|
},
|
||||||
evaluate: 'evaluate.group.promoteToPrimaryIfCornerstoneToolNotActiveInTheList',
|
},
|
||||||
primary: createButton({
|
{
|
||||||
id: 'Length',
|
id: 'MoreTools',
|
||||||
icon: 'tool-length',
|
uiType: 'ohif.toolButtonList',
|
||||||
label: 'Length',
|
props: {
|
||||||
tooltip: 'Length Tool',
|
buttonSection: 'moreToolsSection',
|
||||||
commands: setToolActiveToolbar,
|
groupId: 'MoreTools',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
},
|
||||||
}),
|
},
|
||||||
secondary: {
|
{
|
||||||
icon: 'chevron-down',
|
id: 'WindowLevelGroup',
|
||||||
tooltip: 'More Measure Tools',
|
uiType: 'ohif.toolButtonList',
|
||||||
},
|
props: {
|
||||||
items: [
|
groupId: 'WindowLevelGroup',
|
||||||
createButton({
|
buttonSection: 'windowLevelSection',
|
||||||
id: 'Length',
|
},
|
||||||
icon: 'tool-length',
|
},
|
||||||
label: 'Length',
|
|
||||||
tooltip: 'Length Tool',
|
// tool defs
|
||||||
commands: setToolActiveToolbar,
|
_createWwwcPreset(1, 'Soft tissue', '400 / 40'),
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
_createWwwcPreset(2, 'Lung', '1500 / -600'),
|
||||||
}),
|
_createWwwcPreset(3, 'Liver', '150 / 90'),
|
||||||
createButton({
|
_createWwwcPreset(4, 'Bone', '2500 / 480'),
|
||||||
id: 'Bidirectional',
|
_createWwwcPreset(5, 'Brain', '80 / 40'),
|
||||||
icon: 'tool-bidirectional',
|
{
|
||||||
label: 'Bidirectional',
|
id: 'WindowLevel',
|
||||||
tooltip: 'Bidirectional Tool',
|
uiType: 'ohif.toolButton',
|
||||||
commands: setToolActiveToolbar,
|
props: {
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
icon: 'tool-window-level',
|
||||||
}),
|
label: 'Window Level',
|
||||||
createButton({
|
tooltip: 'Window Level',
|
||||||
id: 'ArrowAnnotate',
|
commands: setToolActiveToolbar,
|
||||||
icon: 'tool-annotate',
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
label: 'Annotation',
|
},
|
||||||
tooltip: 'Arrow Annotate',
|
},
|
||||||
commands: setToolActiveToolbar,
|
{
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
id: 'Length',
|
||||||
}),
|
uiType: 'ohif.toolButton',
|
||||||
createButton({
|
props: {
|
||||||
id: 'EllipticalROI',
|
icon: 'tool-length',
|
||||||
icon: 'tool-ellipse',
|
label: 'Length',
|
||||||
label: 'Ellipse',
|
tooltip: 'Length Tool',
|
||||||
tooltip: 'Ellipse ROI',
|
commands: setToolActiveToolbar,
|
||||||
commands: setToolActiveToolbar,
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
},
|
||||||
}),
|
},
|
||||||
createButton({
|
{
|
||||||
id: 'CircleROI',
|
id: 'Bidirectional',
|
||||||
icon: 'tool-circle',
|
uiType: 'ohif.toolButton',
|
||||||
label: 'Circle',
|
props: {
|
||||||
tooltip: 'Circle Tool',
|
icon: 'tool-bidirectional',
|
||||||
commands: setToolActiveToolbar,
|
label: 'Bidirectional',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
tooltip: 'Bidirectional Tool',
|
||||||
}),
|
commands: setToolActiveToolbar,
|
||||||
createButton({
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
id: 'PlanarFreehandROI',
|
},
|
||||||
icon: 'icon-tool-freehand-roi',
|
},
|
||||||
label: 'Freehand ROI',
|
{
|
||||||
tooltip: 'Freehand ROI',
|
id: 'ArrowAnnotate',
|
||||||
commands: setToolActiveToolbar,
|
uiType: 'ohif.toolButton',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
props: {
|
||||||
}),
|
icon: 'tool-annotate',
|
||||||
createButton({
|
label: 'Annotation',
|
||||||
id: 'SplineROI',
|
tooltip: 'Arrow Annotate',
|
||||||
icon: 'icon-tool-spline-roi',
|
commands: setToolActiveToolbar,
|
||||||
label: 'Spline ROI',
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
tooltip: 'Spline ROI',
|
},
|
||||||
commands: setToolActiveToolbar,
|
},
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
{
|
||||||
}),
|
id: 'EllipticalROI',
|
||||||
createButton({
|
uiType: 'ohif.toolButton',
|
||||||
id: 'LivewireContour',
|
props: {
|
||||||
icon: 'icon-tool-livewire',
|
icon: 'tool-ellipse',
|
||||||
label: 'Livewire tool',
|
label: 'Ellipse',
|
||||||
tooltip: 'Livewire tool',
|
tooltip: 'Ellipse ROI',
|
||||||
commands: setToolActiveToolbar,
|
commands: setToolActiveToolbar,
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
}),
|
},
|
||||||
],
|
},
|
||||||
|
{
|
||||||
|
id: 'CircleROI',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-circle',
|
||||||
|
label: 'Circle',
|
||||||
|
tooltip: 'Circle Tool',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'PlanarFreehandROI',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-freehand-roi',
|
||||||
|
label: 'Freehand ROI',
|
||||||
|
tooltip: 'Freehand ROI',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'SplineROI',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-spline-roi',
|
||||||
|
label: 'Spline ROI',
|
||||||
|
tooltip: 'Spline ROI',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'LivewireContour',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-livewire',
|
||||||
|
label: 'Livewire tool',
|
||||||
|
tooltip: 'Livewire tool',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -134,40 +184,11 @@ const toolbarButtons: Button[] = [
|
|||||||
props: {
|
props: {
|
||||||
icon: 'tool-zoom',
|
icon: 'tool-zoom',
|
||||||
label: 'Zoom',
|
label: 'Zoom',
|
||||||
|
tooltip: 'Zoom',
|
||||||
commands: setToolActiveToolbar,
|
commands: setToolActiveToolbar,
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Window Level
|
|
||||||
{
|
|
||||||
id: 'WindowLevel',
|
|
||||||
uiType: 'ohif.toolButtonList',
|
|
||||||
props: {
|
|
||||||
groupId: 'WindowLevel',
|
|
||||||
primary: createButton({
|
|
||||||
id: 'WindowLevel',
|
|
||||||
icon: 'tool-window-level',
|
|
||||||
label: 'Window Level',
|
|
||||||
tooltip: 'Window Level',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
secondary: {
|
|
||||||
icon: 'chevron-down',
|
|
||||||
label: 'W/L Manual',
|
|
||||||
tooltip: 'W/L Presets',
|
|
||||||
},
|
|
||||||
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',
|
id: 'Pan',
|
||||||
uiType: 'ohif.toolButton',
|
uiType: 'ohif.toolButton',
|
||||||
@ -175,6 +196,7 @@ const toolbarButtons: Button[] = [
|
|||||||
type: 'tool',
|
type: 'tool',
|
||||||
icon: 'tool-move',
|
icon: 'tool-move',
|
||||||
label: 'Pan',
|
label: 'Pan',
|
||||||
|
tooltip: 'Pan',
|
||||||
commands: setToolActiveToolbar,
|
commands: setToolActiveToolbar,
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
},
|
},
|
||||||
@ -185,24 +207,24 @@ const toolbarButtons: Button[] = [
|
|||||||
props: {
|
props: {
|
||||||
icon: 'icon-mpr',
|
icon: 'icon-mpr',
|
||||||
label: 'MPR',
|
label: 'MPR',
|
||||||
commands: [
|
tooltip: 'MPR',
|
||||||
{
|
commands: {
|
||||||
commandName: 'toggleHangingProtocol',
|
commandName: 'toggleHangingProtocol',
|
||||||
commandOptions: {
|
commandOptions: {
|
||||||
protocolId: 'mpr',
|
protocolId: 'mpr',
|
||||||
},
|
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
evaluate: 'evaluate.mpr',
|
evaluate: 'evaluate.mpr',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'TrackBallRotate',
|
id: 'TrackBallRotate',
|
||||||
type: 'ohif.toolButton',
|
uiType: 'ohif.toolButton',
|
||||||
props: {
|
props: {
|
||||||
type: 'tool',
|
type: 'tool',
|
||||||
icon: 'tool-3d-rotate',
|
icon: 'tool-3d-rotate',
|
||||||
label: '3D Rotate',
|
label: '3D Rotate',
|
||||||
|
tooltip: '3D Rotate',
|
||||||
commands: setToolActiveToolbar,
|
commands: setToolActiveToolbar,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -212,6 +234,7 @@ const toolbarButtons: Button[] = [
|
|||||||
props: {
|
props: {
|
||||||
icon: 'tool-capture',
|
icon: 'tool-capture',
|
||||||
label: 'Capture',
|
label: 'Capture',
|
||||||
|
tooltip: 'Capture',
|
||||||
commands: 'showDownloadViewportModal',
|
commands: 'showDownloadViewportModal',
|
||||||
evaluate: [
|
evaluate: [
|
||||||
'evaluate.action',
|
'evaluate.action',
|
||||||
@ -239,6 +262,7 @@ const toolbarButtons: Button[] = [
|
|||||||
type: 'tool',
|
type: 'tool',
|
||||||
icon: 'tool-crosshair',
|
icon: 'tool-crosshair',
|
||||||
label: 'Crosshairs',
|
label: 'Crosshairs',
|
||||||
|
tooltip: 'Crosshairs',
|
||||||
commands: {
|
commands: {
|
||||||
commandName: 'setToolActiveToolbar',
|
commandName: 'setToolActiveToolbar',
|
||||||
commandOptions: {
|
commandOptions: {
|
||||||
@ -248,6 +272,236 @@ const toolbarButtons: Button[] = [
|
|||||||
evaluate: 'evaluate.cornerstoneTool',
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ImageSliceSync',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'link',
|
||||||
|
label: 'Image Slice Sync',
|
||||||
|
tooltip: 'Enable position synchronization on stack viewports',
|
||||||
|
commands: {
|
||||||
|
commandName: 'toggleSynchronizer',
|
||||||
|
commandOptions: {
|
||||||
|
type: 'imageSlice',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
listeners: {
|
||||||
|
[EVENTS.VIEWPORT_NEW_IMAGE_SET]: {
|
||||||
|
commandName: 'toggleImageSliceSync',
|
||||||
|
commandOptions: { toggledState: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
evaluate: 'evaluate.cornerstone.synchronizer',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ReferenceLines',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Angle',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-angle',
|
||||||
|
label: 'Angle',
|
||||||
|
tooltip: 'Angle',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'CobbAngle',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-cobb-angle',
|
||||||
|
label: 'Cobb Angle',
|
||||||
|
tooltip: 'Cobb 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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default toolbarButtons;
|
export default toolbarButtons;
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
import { hotkeys } from '@ohif/core';
|
|
||||||
import i18n from 'i18next';
|
import i18n from 'i18next';
|
||||||
import { id } from './id';
|
import { id } from './id';
|
||||||
import initToolGroups from './initToolGroups';
|
import initToolGroups from './initToolGroups';
|
||||||
import toolbarButtons from './toolbarButtons';
|
import toolbarButtons from './toolbarButtons';
|
||||||
import moreTools from './moreTools';
|
|
||||||
|
|
||||||
// Allow this mode by excluding non-imaging modalities such as SR, SEG
|
// Allow this mode by excluding non-imaging modalities such as SR, SEG
|
||||||
// Also, SM is not a simple imaging modalities, so exclude it.
|
// Also, SM is not a simple imaging modalities, so exclude it.
|
||||||
@ -84,15 +82,14 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
* Lifecycle hooks
|
* Lifecycle hooks
|
||||||
*/
|
*/
|
||||||
onModeEnter: function ({ servicesManager, extensionManager, commandsManager }: withAppTypes) {
|
onModeEnter: function ({ servicesManager, extensionManager, commandsManager }: withAppTypes) {
|
||||||
const { measurementService, toolbarService, toolGroupService, customizationService } =
|
const { measurementService, toolbarService, toolGroupService } = servicesManager.services;
|
||||||
servicesManager.services;
|
|
||||||
|
|
||||||
measurementService.clearMeasurements();
|
measurementService.clearMeasurements();
|
||||||
|
|
||||||
// Init Default and SR ToolGroups
|
// Init Default and SR ToolGroups
|
||||||
initToolGroups(extensionManager, toolGroupService, commandsManager);
|
initToolGroups(extensionManager, toolGroupService, commandsManager);
|
||||||
|
|
||||||
toolbarService.addButtons([...toolbarButtons, ...moreTools]);
|
toolbarService.addButtons(toolbarButtons);
|
||||||
toolbarService.createButtonSection('primary', [
|
toolbarService.createButtonSection('primary', [
|
||||||
'MeasurementTools',
|
'MeasurementTools',
|
||||||
'Zoom',
|
'Zoom',
|
||||||
@ -105,6 +102,39 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
'MoreTools',
|
'MoreTools',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
toolbarService.createButtonSection('measurementSection', [
|
||||||
|
'Length',
|
||||||
|
'Bidirectional',
|
||||||
|
'ArrowAnnotate',
|
||||||
|
'EllipticalROI',
|
||||||
|
'RectangleROI',
|
||||||
|
'CircleROI',
|
||||||
|
'PlanarFreehandROI',
|
||||||
|
'SplineROI',
|
||||||
|
'LivewireContour',
|
||||||
|
]);
|
||||||
|
|
||||||
|
toolbarService.createButtonSection('moreToolsSection', [
|
||||||
|
'Reset',
|
||||||
|
'rotate-right',
|
||||||
|
'flipHorizontal',
|
||||||
|
'ImageSliceSync',
|
||||||
|
'ReferenceLines',
|
||||||
|
'ImageOverlayViewer',
|
||||||
|
'StackScroll',
|
||||||
|
'invert',
|
||||||
|
'Probe',
|
||||||
|
'Cine',
|
||||||
|
'Angle',
|
||||||
|
'CobbAngle',
|
||||||
|
'Magnify',
|
||||||
|
'CalibrationLine',
|
||||||
|
'TagBrowser',
|
||||||
|
'AdvancedMagnify',
|
||||||
|
'UltrasoundDirectionalTool',
|
||||||
|
'WindowLevelRegion',
|
||||||
|
]);
|
||||||
|
|
||||||
// // ActivatePanel event trigger for when a segmentation or measurement is added.
|
// // 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.
|
// // Do not force activation so as to respect the state the user may have left the UI in.
|
||||||
// _activatePanelTriggersSubscriptions = [
|
// _activatePanelTriggersSubscriptions = [
|
||||||
@ -250,4 +280,4 @@ const mode = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default mode;
|
export default mode;
|
||||||
export { initToolGroups, moreTools, toolbarButtons };
|
export { initToolGroups, toolbarButtons };
|
||||||
|
|||||||
@ -1,270 +0,0 @@
|
|||||||
import type { RunCommand } from '@ohif/core/types';
|
|
||||||
import { EVENTS } from '@cornerstonejs/core';
|
|
||||||
import { ToolbarService, ViewportGridService } from '@ohif/core';
|
|
||||||
import { setToolActiveToolbar } from './toolbarButtons';
|
|
||||||
const { createButton } = ToolbarService;
|
|
||||||
|
|
||||||
const ReferenceLinesListeners: RunCommand = [
|
|
||||||
{
|
|
||||||
commandName: 'setSourceViewportForReferenceLinesTool',
|
|
||||||
context: 'CORNERSTONE',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const moreTools = [
|
|
||||||
{
|
|
||||||
id: 'MoreTools',
|
|
||||||
uiType: 'ohif.toolButtonList',
|
|
||||||
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',
|
|
||||||
{
|
|
||||||
name: 'evaluate.viewport.supported',
|
|
||||||
unsupportedViewportTypes: ['video'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'flipHorizontal',
|
|
||||||
icon: 'tool-flip-horizontal',
|
|
||||||
label: 'Flip Horizontal',
|
|
||||||
tooltip: 'Flip Horizontally',
|
|
||||||
commands: 'flipViewportHorizontal',
|
|
||||||
evaluate: [
|
|
||||||
'evaluate.viewportProperties.toggle',
|
|
||||||
{
|
|
||||||
name: 'evaluate.viewport.supported',
|
|
||||||
unsupportedViewportTypes: ['video', 'volume3d'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'ImageSliceSync',
|
|
||||||
icon: 'link',
|
|
||||||
label: 'Image Slice Sync',
|
|
||||||
tooltip: 'Enable position synchronization on stack viewports',
|
|
||||||
commands: {
|
|
||||||
commandName: 'toggleSynchronizer',
|
|
||||||
commandOptions: {
|
|
||||||
type: 'imageSlice',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
listeners: {
|
|
||||||
[EVENTS.VIEWPORT_NEW_IMAGE_SET]: {
|
|
||||||
commandName: 'toggleImageSliceSync',
|
|
||||||
commandOptions: { toggledState: true },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
evaluate: [
|
|
||||||
'evaluate.cornerstone.synchronizer',
|
|
||||||
{
|
|
||||||
name: 'evaluate.viewport.supported',
|
|
||||||
unsupportedViewportTypes: ['video', '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',
|
|
||||||
{
|
|
||||||
name: 'evaluate.viewport.supported',
|
|
||||||
unsupportedViewportTypes: ['video'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'ImageOverlayViewer',
|
|
||||||
icon: 'toggle-dicom-overlay',
|
|
||||||
label: 'Image Overlay',
|
|
||||||
tooltip: 'Toggle Image Overlay',
|
|
||||||
commands: 'toggleEnabledDisabledToolbar',
|
|
||||||
evaluate: [
|
|
||||||
'evaluate.cornerstoneTool.toggle',
|
|
||||||
{
|
|
||||||
name: 'evaluate.viewport.supported',
|
|
||||||
unsupportedViewportTypes: ['video'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
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',
|
|
||||||
{
|
|
||||||
name: 'evaluate.viewport.supported',
|
|
||||||
unsupportedViewportTypes: ['video'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
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: 'CobbAngle',
|
|
||||||
icon: 'icon-tool-cobb-angle',
|
|
||||||
label: 'Cobb Angle',
|
|
||||||
tooltip: 'Cobb Angle',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'Magnify',
|
|
||||||
icon: 'tool-magnify',
|
|
||||||
label: 'Zoom-in',
|
|
||||||
tooltip: 'Zoom-in',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: [
|
|
||||||
'evaluate.cornerstoneTool',
|
|
||||||
{
|
|
||||||
name: 'evaluate.viewport.supported',
|
|
||||||
unsupportedViewportTypes: ['video'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'CalibrationLine',
|
|
||||||
icon: 'tool-calibration',
|
|
||||||
label: 'Calibration',
|
|
||||||
tooltip: 'Calibration Line',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: [
|
|
||||||
'evaluate.cornerstoneTool',
|
|
||||||
{
|
|
||||||
name: 'evaluate.viewport.supported',
|
|
||||||
unsupportedViewportTypes: ['video'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
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',
|
|
||||||
{
|
|
||||||
name: 'evaluate.viewport.supported',
|
|
||||||
unsupportedViewportTypes: ['video'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
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',
|
|
||||||
{
|
|
||||||
name: 'evaluate.viewport.supported',
|
|
||||||
unsupportedViewportTypes: ['video'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default moreTools;
|
|
||||||
@ -1,9 +1,14 @@
|
|||||||
// 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 { ToolbarService } from '@ohif/core';
|
|
||||||
import type { Button } from '@ohif/core/types';
|
import type { Button } from '@ohif/core/types';
|
||||||
|
|
||||||
const { createButton } = ToolbarService;
|
import { EVENTS } from '@cornerstonejs/core';
|
||||||
|
import { ViewportGridService } from '@ohif/core';
|
||||||
|
|
||||||
|
const ReferenceLinesListeners = [
|
||||||
|
{
|
||||||
|
commandName: 'setSourceViewportForReferenceLinesTool',
|
||||||
|
context: 'CORNERSTONE',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const setToolActiveToolbar = {
|
export const setToolActiveToolbar = {
|
||||||
commandName: 'setToolActiveToolbar',
|
commandName: 'setToolActiveToolbar',
|
||||||
@ -13,107 +18,403 @@ export const setToolActiveToolbar = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toolbarButtons: Button[] = [
|
const toolbarButtons: Button[] = [
|
||||||
|
// sections
|
||||||
{
|
{
|
||||||
id: 'MeasurementTools',
|
id: 'MeasurementTools',
|
||||||
uiType: 'ohif.toolButtonList',
|
uiType: 'ohif.toolButtonList',
|
||||||
props: {
|
props: {
|
||||||
|
buttonSection: 'measurementSection',
|
||||||
groupId: 'MeasurementTools',
|
groupId: 'MeasurementTools',
|
||||||
// group evaluate to determine which item should move to the top
|
},
|
||||||
evaluate: 'evaluate.group.promoteToPrimaryIfCornerstoneToolNotActiveInTheList',
|
},
|
||||||
primary: createButton({
|
{
|
||||||
id: 'Length',
|
id: 'MoreTools',
|
||||||
icon: 'tool-length',
|
uiType: 'ohif.toolButtonList',
|
||||||
label: 'Length',
|
props: {
|
||||||
tooltip: 'Length Tool',
|
buttonSection: 'moreToolsSection',
|
||||||
commands: setToolActiveToolbar,
|
groupId: 'MoreTools',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
},
|
||||||
}),
|
},
|
||||||
secondary: {
|
// tool defs
|
||||||
icon: 'chevron-down',
|
{
|
||||||
tooltip: 'More Measure Tools',
|
id: 'Reset',
|
||||||
},
|
uiType: 'ohif.toolButton',
|
||||||
items: [
|
props: {
|
||||||
createButton({
|
icon: 'tool-reset',
|
||||||
id: 'Length',
|
label: 'Reset View',
|
||||||
icon: 'tool-length',
|
tooltip: 'Reset View',
|
||||||
label: 'Length',
|
commands: 'resetViewport',
|
||||||
tooltip: 'Length Tool',
|
evaluate: 'evaluate.action',
|
||||||
commands: setToolActiveToolbar,
|
},
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
},
|
||||||
}),
|
{
|
||||||
createButton({
|
id: 'rotate-right',
|
||||||
id: 'Bidirectional',
|
uiType: 'ohif.toolButton',
|
||||||
icon: 'tool-bidirectional',
|
props: {
|
||||||
label: 'Bidirectional',
|
icon: 'tool-rotate-right',
|
||||||
tooltip: 'Bidirectional Tool',
|
label: 'Rotate Right',
|
||||||
commands: setToolActiveToolbar,
|
tooltip: 'Rotate +90',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
commands: 'rotateViewportCW',
|
||||||
}),
|
evaluate: [
|
||||||
createButton({
|
'evaluate.action',
|
||||||
id: 'ArrowAnnotate',
|
{
|
||||||
icon: 'tool-annotate',
|
name: 'evaluate.viewport.supported',
|
||||||
label: 'Annotation',
|
unsupportedViewportTypes: ['video'],
|
||||||
tooltip: 'Arrow Annotate',
|
},
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'EllipticalROI',
|
|
||||||
icon: 'tool-ellipse',
|
|
||||||
label: 'Ellipse',
|
|
||||||
tooltip: 'Ellipse ROI',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'RectangleROI',
|
|
||||||
icon: 'tool-rectangle',
|
|
||||||
label: 'Rectangle',
|
|
||||||
tooltip: 'Rectangle ROI',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'CircleROI',
|
|
||||||
icon: 'tool-circle',
|
|
||||||
label: 'Circle',
|
|
||||||
tooltip: 'Circle Tool',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'PlanarFreehandROI',
|
|
||||||
icon: 'icon-tool-freehand-roi',
|
|
||||||
label: 'Freehand ROI',
|
|
||||||
tooltip: 'Freehand ROI',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'SplineROI',
|
|
||||||
icon: 'icon-tool-spline-roi',
|
|
||||||
label: 'Spline ROI',
|
|
||||||
tooltip: 'Spline ROI',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
createButton({
|
|
||||||
id: 'LivewireContour',
|
|
||||||
icon: 'icon-tool-livewire',
|
|
||||||
label: 'Livewire tool',
|
|
||||||
tooltip: 'Livewire tool',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'Zoom',
|
id: 'flipHorizontal',
|
||||||
uiType: 'ohif.toolButton',
|
uiType: 'ohif.toolButton',
|
||||||
props: {
|
props: {
|
||||||
icon: 'tool-zoom',
|
icon: 'tool-flip-horizontal',
|
||||||
label: 'Zoom',
|
label: 'Flip Horizontal',
|
||||||
|
tooltip: 'Flip Horizontally',
|
||||||
|
commands: 'flipViewportHorizontal',
|
||||||
|
evaluate: [
|
||||||
|
'evaluate.viewportProperties.toggle',
|
||||||
|
{
|
||||||
|
name: 'evaluate.viewport.supported',
|
||||||
|
unsupportedViewportTypes: ['video', 'volume3d'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ImageSliceSync',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'link',
|
||||||
|
label: 'Image Slice Sync',
|
||||||
|
tooltip: 'Enable position synchronization on stack viewports',
|
||||||
|
commands: {
|
||||||
|
commandName: 'toggleSynchronizer',
|
||||||
|
commandOptions: {
|
||||||
|
type: 'imageSlice',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
listeners: {
|
||||||
|
[EVENTS.VIEWPORT_NEW_IMAGE_SET]: {
|
||||||
|
commandName: 'toggleImageSliceSync',
|
||||||
|
commandOptions: { toggledState: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
evaluate: [
|
||||||
|
'evaluate.cornerstone.synchronizer',
|
||||||
|
{
|
||||||
|
name: 'evaluate.viewport.supported',
|
||||||
|
unsupportedViewportTypes: ['video', 'volume3d'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ReferenceLines',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
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',
|
||||||
|
{
|
||||||
|
name: 'evaluate.viewport.supported',
|
||||||
|
unsupportedViewportTypes: ['video'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ImageOverlayViewer',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'toggle-dicom-overlay',
|
||||||
|
label: 'Image Overlay',
|
||||||
|
tooltip: 'Toggle Image Overlay',
|
||||||
|
commands: 'toggleEnabledDisabledToolbar',
|
||||||
|
evaluate: [
|
||||||
|
'evaluate.cornerstoneTool.toggle',
|
||||||
|
{
|
||||||
|
name: 'evaluate.viewport.supported',
|
||||||
|
unsupportedViewportTypes: ['video'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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',
|
||||||
|
{
|
||||||
|
name: 'evaluate.viewport.supported',
|
||||||
|
unsupportedViewportTypes: ['video'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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: 'CobbAngle',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-cobb-angle',
|
||||||
|
label: 'Cobb Angle',
|
||||||
|
tooltip: 'Cobb 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',
|
||||||
|
{
|
||||||
|
name: 'evaluate.viewport.supported',
|
||||||
|
unsupportedViewportTypes: ['video'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Length',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-length',
|
||||||
|
label: 'Length',
|
||||||
|
tooltip: 'Length Tool',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Bidirectional',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-bidirectional',
|
||||||
|
label: 'Bidirectional',
|
||||||
|
tooltip: 'Bidirectional Tool',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ArrowAnnotate',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-annotate',
|
||||||
|
label: 'Annotation',
|
||||||
|
tooltip: 'Arrow Annotate',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'EllipticalROI',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-ellipse',
|
||||||
|
label: 'Ellipse',
|
||||||
|
tooltip: 'Ellipse ROI',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'RectangleROI',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-rectangle',
|
||||||
|
label: 'Rectangle',
|
||||||
|
tooltip: 'Rectangle ROI',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'CircleROI',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-circle',
|
||||||
|
label: 'Circle',
|
||||||
|
tooltip: 'Circle Tool',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'PlanarFreehandROI',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-freehand-roi',
|
||||||
|
label: 'Freehand ROI',
|
||||||
|
tooltip: 'Freehand ROI',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'SplineROI',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-spline-roi',
|
||||||
|
label: 'Spline ROI',
|
||||||
|
tooltip: 'Spline ROI',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'LivewireContour',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-livewire',
|
||||||
|
label: 'Livewire tool',
|
||||||
|
tooltip: 'Livewire tool',
|
||||||
commands: setToolActiveToolbar,
|
commands: setToolActiveToolbar,
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
},
|
},
|
||||||
@ -135,7 +436,6 @@ const toolbarButtons: Button[] = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Pan...
|
|
||||||
{
|
{
|
||||||
id: 'Pan',
|
id: 'Pan',
|
||||||
uiType: 'ohif.toolButton',
|
uiType: 'ohif.toolButton',
|
||||||
@ -147,6 +447,17 @@ const toolbarButtons: Button[] = [
|
|||||||
evaluate: 'evaluate.cornerstoneTool',
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'Zoom',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
type: 'tool',
|
||||||
|
icon: 'tool-zoom',
|
||||||
|
label: 'Zoom',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'TrackballRotate',
|
id: 'TrackballRotate',
|
||||||
uiType: 'ohif.toolButton',
|
uiType: 'ohif.toolButton',
|
||||||
|
|||||||
@ -38,8 +38,6 @@ const extensionDependencies = {
|
|||||||
|
|
||||||
function modeFactory({ modeConfiguration }) {
|
function modeFactory({ modeConfiguration }) {
|
||||||
return {
|
return {
|
||||||
// TODO: We're using this as a route segment
|
|
||||||
// We should not be.
|
|
||||||
id,
|
id,
|
||||||
routeName: 'microscopy',
|
routeName: 'microscopy',
|
||||||
displayName: i18n.t('Modes:Microscopy'),
|
displayName: i18n.t('Modes:Microscopy'),
|
||||||
@ -47,11 +45,21 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
/**
|
/**
|
||||||
* Lifecycle hooks
|
* Lifecycle hooks
|
||||||
*/
|
*/
|
||||||
onModeEnter: ({ servicesManager, extensionManager, commandsManager }: withAppTypes) => {
|
onModeEnter: ({ servicesManager }: withAppTypes) => {
|
||||||
const { toolbarService } = servicesManager.services;
|
const { toolbarService } = servicesManager.services;
|
||||||
|
|
||||||
toolbarService.addButtons(toolbarButtons);
|
toolbarService.addButtons(toolbarButtons);
|
||||||
toolbarService.createButtonSection('primary', ['MeasurementTools', 'dragPan', 'TagBrowser']);
|
toolbarService.createButtonSection('primary', ['MeasurementTools', 'dragPan', 'TagBrowser']);
|
||||||
|
|
||||||
|
toolbarService.createButtonSection('measurementSection', [
|
||||||
|
'line',
|
||||||
|
'point',
|
||||||
|
'polygon',
|
||||||
|
'circle',
|
||||||
|
'box',
|
||||||
|
'freehandpolygon',
|
||||||
|
'freehandline',
|
||||||
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
onModeExit: ({ servicesManager }: withAppTypes) => {
|
onModeExit: ({ servicesManager }: withAppTypes) => {
|
||||||
@ -79,9 +87,6 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: 'microscopy',
|
path: 'microscopy',
|
||||||
/*init: ({ servicesManager, extensionManager }) => {
|
|
||||||
//defaultViewerRouteInit
|
|
||||||
},*/
|
|
||||||
layoutTemplate: ({ location, servicesManager }) => {
|
layoutTemplate: ({ location, servicesManager }) => {
|
||||||
return {
|
return {
|
||||||
id: ohif.layout,
|
id: ohif.layout,
|
||||||
|
|||||||
@ -1,164 +0,0 @@
|
|||||||
import { ToolbarService } from '@ohif/core';
|
|
||||||
|
|
||||||
const toolbarButtons = [
|
|
||||||
{
|
|
||||||
id: 'MeasurementTools',
|
|
||||||
uiType: 'ohif.toolButtonList',
|
|
||||||
props: {
|
|
||||||
groupId: 'MeasurementTools',
|
|
||||||
// group evaluate to determine which item should move to the top
|
|
||||||
evaluate: 'evaluate.group.promoteToPrimary',
|
|
||||||
primary: ToolbarService.createButton({
|
|
||||||
id: 'line',
|
|
||||||
icon: 'tool-length',
|
|
||||||
label: 'Line',
|
|
||||||
tooltip: 'Line',
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'line' },
|
|
||||||
context: 'MICROSCOPY',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: 'evaluate.microscopyTool',
|
|
||||||
}),
|
|
||||||
secondary: {
|
|
||||||
icon: 'chevron-down',
|
|
||||||
tooltip: 'More Measure Tools',
|
|
||||||
},
|
|
||||||
items: [
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'line',
|
|
||||||
icon: 'tool-length',
|
|
||||||
label: 'Line',
|
|
||||||
tooltip: 'Line',
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'line' },
|
|
||||||
context: 'MICROSCOPY',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: 'evaluate.microscopyTool',
|
|
||||||
}),
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'point',
|
|
||||||
icon: 'tool-point',
|
|
||||||
label: 'Point',
|
|
||||||
tooltip: 'Point Tool',
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'point' },
|
|
||||||
context: 'MICROSCOPY',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: 'evaluate.microscopyTool',
|
|
||||||
}),
|
|
||||||
// Point Tool was previously defined
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'polygon',
|
|
||||||
icon: 'tool-polygon',
|
|
||||||
label: 'Polygon',
|
|
||||||
tooltip: 'Polygon Tool',
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'polygon' },
|
|
||||||
context: 'MICROSCOPY',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: 'evaluate.microscopyTool',
|
|
||||||
}),
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'circle',
|
|
||||||
icon: 'tool-circle',
|
|
||||||
label: 'Circle',
|
|
||||||
tooltip: 'Circle Tool',
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'circle' },
|
|
||||||
context: 'MICROSCOPY',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: 'evaluate.microscopyTool',
|
|
||||||
}),
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'box',
|
|
||||||
icon: 'tool-rectangle',
|
|
||||||
label: 'Box',
|
|
||||||
tooltip: 'Box Tool',
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'box' },
|
|
||||||
context: 'MICROSCOPY',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: 'evaluate.microscopyTool',
|
|
||||||
}),
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'freehandpolygon',
|
|
||||||
icon: 'tool-freehand-polygon',
|
|
||||||
label: 'Freehand Polygon',
|
|
||||||
tooltip: 'Freehand Polygon Tool',
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'freehandpolygon' },
|
|
||||||
context: 'MICROSCOPY',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: 'evaluate.microscopyTool',
|
|
||||||
}),
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'freehandline',
|
|
||||||
icon: 'tool-freehand-line',
|
|
||||||
label: 'Freehand Line',
|
|
||||||
tooltip: 'Freehand Line Tool',
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'freehandline' },
|
|
||||||
context: 'MICROSCOPY',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: 'evaluate.microscopyTool',
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'dragPan',
|
|
||||||
uiType: 'ohif.toolButton',
|
|
||||||
props: {
|
|
||||||
icon: 'tool-move',
|
|
||||||
label: 'Pan',
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
commandName: 'setToolActive',
|
|
||||||
commandOptions: { toolName: 'dragPan' },
|
|
||||||
context: 'MICROSCOPY',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: 'evaluate.microscopyTool',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'TagBrowser',
|
|
||||||
uiType: 'ohif.toolButton',
|
|
||||||
props: {
|
|
||||||
icon: 'dicom-tag-browser',
|
|
||||||
label: 'Dicom Tag Browser',
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
commandName: 'openDICOMTagViewer',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
evaluate: 'evaluate.action',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default toolbarButtons;
|
|
||||||
141
modes/microscopy/src/toolbarButtons.ts
Normal file
141
modes/microscopy/src/toolbarButtons.ts
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
import type { Button } from '@ohif/core/types';
|
||||||
|
|
||||||
|
export const setToolActiveToolbar = {
|
||||||
|
commandName: 'setToolActive',
|
||||||
|
commandOptions: {
|
||||||
|
toolName: 'line',
|
||||||
|
},
|
||||||
|
context: 'MICROSCOPY',
|
||||||
|
};
|
||||||
|
|
||||||
|
const toolbarButtons: Button[] = [
|
||||||
|
{
|
||||||
|
id: 'MeasurementTools',
|
||||||
|
uiType: 'ohif.toolButtonList',
|
||||||
|
props: {
|
||||||
|
buttonSection: 'measurementSection',
|
||||||
|
groupId: 'MeasurementTools',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'line',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-length',
|
||||||
|
label: 'Line',
|
||||||
|
tooltip: 'Line',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.microscopyTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'point',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-point',
|
||||||
|
label: 'Point',
|
||||||
|
tooltip: 'Point Tool',
|
||||||
|
commands: {
|
||||||
|
...setToolActiveToolbar,
|
||||||
|
commandOptions: { toolName: 'point' },
|
||||||
|
},
|
||||||
|
evaluate: 'evaluate.microscopyTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'polygon',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-polygon',
|
||||||
|
label: 'Polygon',
|
||||||
|
tooltip: 'Polygon Tool',
|
||||||
|
commands: {
|
||||||
|
...setToolActiveToolbar,
|
||||||
|
commandOptions: { toolName: 'polygon' },
|
||||||
|
},
|
||||||
|
evaluate: 'evaluate.microscopyTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'circle',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-circle',
|
||||||
|
label: 'Circle',
|
||||||
|
tooltip: 'Circle Tool',
|
||||||
|
commands: {
|
||||||
|
...setToolActiveToolbar,
|
||||||
|
commandOptions: { toolName: 'circle' },
|
||||||
|
},
|
||||||
|
evaluate: 'evaluate.microscopyTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'box',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-rectangle',
|
||||||
|
label: 'Box',
|
||||||
|
tooltip: 'Box Tool',
|
||||||
|
commands: {
|
||||||
|
...setToolActiveToolbar,
|
||||||
|
commandOptions: { toolName: 'box' },
|
||||||
|
},
|
||||||
|
evaluate: 'evaluate.microscopyTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'freehandpolygon',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-freehand-polygon',
|
||||||
|
label: 'Freehand Polygon',
|
||||||
|
tooltip: 'Freehand Polygon Tool',
|
||||||
|
commands: {
|
||||||
|
...setToolActiveToolbar,
|
||||||
|
commandOptions: { toolName: 'freehandpolygon' },
|
||||||
|
},
|
||||||
|
evaluate: 'evaluate.microscopyTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'freehandline',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-freehand-line',
|
||||||
|
label: 'Freehand Line',
|
||||||
|
tooltip: 'Freehand Line Tool',
|
||||||
|
commands: {
|
||||||
|
...setToolActiveToolbar,
|
||||||
|
commandOptions: { toolName: 'freehandline' },
|
||||||
|
},
|
||||||
|
evaluate: 'evaluate.microscopyTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'dragPan',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-move',
|
||||||
|
label: 'Pan',
|
||||||
|
commands: {
|
||||||
|
...setToolActiveToolbar,
|
||||||
|
commandOptions: { toolName: 'dragPan' },
|
||||||
|
},
|
||||||
|
evaluate: 'evaluate.microscopyTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'TagBrowser',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'dicom-tag-browser',
|
||||||
|
label: 'Dicom Tag Browser',
|
||||||
|
tooltip: 'Dicom Tag Browser',
|
||||||
|
commands: 'openDICOMTagViewer',
|
||||||
|
evaluate: 'evaluate.action',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default toolbarButtons;
|
||||||
@ -10,10 +10,31 @@ const cornerstone = {
|
|||||||
activeViewportWindowLevel: '@ohif/extension-cornerstone.panelModule.activeViewportWindowLevel',
|
activeViewportWindowLevel: '@ohif/extension-cornerstone.panelModule.activeViewportWindowLevel',
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultButtons = {
|
const defaultButtons = [
|
||||||
buttonSection: 'primary',
|
{
|
||||||
buttons: ['MeasurementTools', 'Zoom', 'WindowLevel', 'Crosshairs', 'Pan'],
|
buttonSection: 'primary',
|
||||||
};
|
buttons: ['MeasurementTools', 'Zoom', 'WindowLevel', 'Crosshairs', 'Pan'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
buttonSection: 'measurementSection',
|
||||||
|
buttons: ['Length', 'Bidirectional', 'ArrowAnnotate', 'EllipticalROI'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const ROIThresholdToolbox = [
|
||||||
|
{
|
||||||
|
buttonSection: 'dynamic-toolbox',
|
||||||
|
buttons: ['SegmentationTools'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
buttonSection: 'segmentationToolboxToolsSection',
|
||||||
|
buttons: ['BrushTools', 'RectangleROIStartEndThreshold'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
buttonSection: 'brushToolsSection',
|
||||||
|
buttons: ['Brush', 'Eraser', 'Threshold'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const defaultLeftPanel = [[dynamicVolume.leftPanel, cornerstone.activeViewportWindowLevel]];
|
const defaultLeftPanel = [[dynamicVolume.leftPanel, cornerstone.activeViewportWindowLevel]];
|
||||||
|
|
||||||
@ -66,13 +87,7 @@ function getWorkflowSettings({ servicesManager }) {
|
|||||||
rightPanelClosed: false,
|
rightPanelClosed: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
toolbarButtons: [
|
toolbarButtons: [...defaultButtons, ...ROIThresholdToolbox],
|
||||||
defaultButtons,
|
|
||||||
{
|
|
||||||
buttonSection: 'dynamic-toolbox',
|
|
||||||
buttons: ['BrushTools', 'RectangleROIStartEndThreshold'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
hangingProtocol: {
|
hangingProtocol: {
|
||||||
protocolId: 'default4D',
|
protocolId: 'default4D',
|
||||||
stageId: 'roiQuantification',
|
stageId: 'roiQuantification',
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
import { id } from './id';
|
import { id } from './id';
|
||||||
import { hotkeys } from '@ohif/core';
|
|
||||||
import initWorkflowSteps from './initWorkflowSteps';
|
import initWorkflowSteps from './initWorkflowSteps';
|
||||||
import initToolGroups from './initToolGroups';
|
import initToolGroups from './initToolGroups';
|
||||||
import toolbarButtons from './toolbarButtons';
|
import toolbarButtons from './toolbarButtons';
|
||||||
import segmentationButtons from './segmentationButtons';
|
|
||||||
|
|
||||||
const extensionDependencies = {
|
const extensionDependencies = {
|
||||||
'@ohif/extension-default': '3.7.0-beta.76',
|
'@ohif/extension-default': '3.7.0-beta.76',
|
||||||
@ -56,7 +54,8 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
measurementService.clearMeasurements();
|
measurementService.clearMeasurements();
|
||||||
initToolGroups({ toolNames, Enums, toolGroupService, commandsManager, servicesManager });
|
initToolGroups({ toolNames, Enums, toolGroupService, commandsManager, servicesManager });
|
||||||
|
|
||||||
toolbarService.addButtons([...toolbarButtons, ...segmentationButtons]);
|
toolbarService.addButtons(toolbarButtons);
|
||||||
|
|
||||||
toolbarService.createButtonSection('secondary', ['ProgressDropdown']);
|
toolbarService.createButtonSection('secondary', ['ProgressDropdown']);
|
||||||
|
|
||||||
// the primary button section is created in the workflow steps
|
// the primary button section is created in the workflow steps
|
||||||
|
|||||||
@ -1,164 +0,0 @@
|
|||||||
import type { Button } from '@ohif/core/types';
|
|
||||||
|
|
||||||
const toolbarButtons: Button[] = [
|
|
||||||
{
|
|
||||||
id: 'BrushTools',
|
|
||||||
uiType: 'ohif.toolBoxButtonGroup',
|
|
||||||
props: {
|
|
||||||
groupId: 'BrushTools',
|
|
||||||
evaluate: 'evaluate.cornerstone.hasSegmentation',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
id: 'Brush',
|
|
||||||
icon: 'icon-tool-brush',
|
|
||||||
label: 'Brush',
|
|
||||||
evaluate: {
|
|
||||||
name: 'evaluate.cornerstone.segmentation',
|
|
||||||
toolNames: ['CircularBrush', 'SphereBrush'],
|
|
||||||
},
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Size (mm)',
|
|
||||||
id: 'brush-radius',
|
|
||||||
type: 'range',
|
|
||||||
min: 0.5,
|
|
||||||
max: 99.5,
|
|
||||||
step: 0.5,
|
|
||||||
value: 7,
|
|
||||||
commands: {
|
|
||||||
commandName: 'setBrushSize',
|
|
||||||
commandOptions: { toolNames: ['CircularBrush', 'SphereBrush'] },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Shape',
|
|
||||||
type: 'radio',
|
|
||||||
id: 'brush-mode',
|
|
||||||
value: 'CircularBrush',
|
|
||||||
values: [
|
|
||||||
{ value: 'CircularBrush', label: 'Circle' },
|
|
||||||
{ value: 'SphereBrush', label: 'Sphere' },
|
|
||||||
],
|
|
||||||
commands: 'setToolActiveToolbar',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Eraser',
|
|
||||||
icon: 'icon-tool-eraser',
|
|
||||||
label: 'Eraser',
|
|
||||||
evaluate: {
|
|
||||||
name: 'evaluate.cornerstone.segmentation',
|
|
||||||
toolNames: ['CircularEraser', 'SphereEraser'],
|
|
||||||
},
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Radius (mm)',
|
|
||||||
id: 'eraser-radius',
|
|
||||||
type: 'range',
|
|
||||||
min: 0.5,
|
|
||||||
max: 99.5,
|
|
||||||
step: 0.5,
|
|
||||||
value: 7,
|
|
||||||
commands: {
|
|
||||||
commandName: 'setBrushSize',
|
|
||||||
commandOptions: { toolNames: ['CircularEraser', 'SphereEraser'] },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Shape',
|
|
||||||
type: 'radio',
|
|
||||||
id: 'eraser-mode',
|
|
||||||
value: 'CircularEraser',
|
|
||||||
values: [
|
|
||||||
{ value: 'CircularEraser', label: 'Circle' },
|
|
||||||
{ value: 'SphereEraser', label: 'Sphere' },
|
|
||||||
],
|
|
||||||
commands: 'setToolActiveToolbar',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Threshold',
|
|
||||||
icon: 'icon-tool-threshold',
|
|
||||||
label: 'Eraser',
|
|
||||||
evaluate: {
|
|
||||||
name: 'evaluate.cornerstone.segmentation',
|
|
||||||
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
|
||||||
},
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Radius (mm)',
|
|
||||||
id: 'threshold-radius',
|
|
||||||
type: 'range',
|
|
||||||
min: 0.5,
|
|
||||||
max: 99.5,
|
|
||||||
step: 0.5,
|
|
||||||
value: 7,
|
|
||||||
commands: {
|
|
||||||
commandName: 'setBrushSize',
|
|
||||||
commandOptions: {
|
|
||||||
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Shape',
|
|
||||||
type: 'radio',
|
|
||||||
id: 'eraser-mode',
|
|
||||||
value: 'ThresholdCircularBrush',
|
|
||||||
values: [
|
|
||||||
{ value: 'ThresholdCircularBrush', label: 'Circle' },
|
|
||||||
{ value: 'ThresholdSphereBrush', label: 'Sphere' },
|
|
||||||
],
|
|
||||||
commands: 'setToolActiveToolbar',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'ThresholdRange',
|
|
||||||
type: 'double-range',
|
|
||||||
id: 'threshold-range',
|
|
||||||
min: 0,
|
|
||||||
max: 100,
|
|
||||||
step: 0.5,
|
|
||||||
value: [2, 50],
|
|
||||||
commands: {
|
|
||||||
commandName: 'setThresholdRange',
|
|
||||||
commandOptions: {
|
|
||||||
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Shapes',
|
|
||||||
uiType: 'ohif.toolBoxButton',
|
|
||||||
props: {
|
|
||||||
label: 'Shapes',
|
|
||||||
evaluate: {
|
|
||||||
name: 'evaluate.cornerstone.segmentation',
|
|
||||||
toolNames: ['CircleScissor', 'SphereScissor', 'RectangleScissor'],
|
|
||||||
},
|
|
||||||
icon: 'icon-tool-shape',
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Shape',
|
|
||||||
type: 'radio',
|
|
||||||
value: 'CircleScissor',
|
|
||||||
id: 'shape-mode',
|
|
||||||
values: [
|
|
||||||
{ value: 'CircleScissor', label: 'Circle' },
|
|
||||||
{ value: 'SphereScissor', label: 'Sphere' },
|
|
||||||
{ value: 'RectangleScissor', label: 'Rectangle' },
|
|
||||||
],
|
|
||||||
commands: 'setToolActiveToolbar',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default toolbarButtons;
|
|
||||||
@ -1,8 +1,5 @@
|
|||||||
import { defaults, ToolbarService } from '@ohif/core';
|
|
||||||
import { toolGroupIds } from './initToolGroups';
|
import { toolGroupIds } from './initToolGroups';
|
||||||
|
|
||||||
const { createButton } = ToolbarService;
|
|
||||||
|
|
||||||
const setToolActiveToolbar = {
|
const setToolActiveToolbar = {
|
||||||
commandName: 'setToolActiveToolbar',
|
commandName: 'setToolActiveToolbar',
|
||||||
commandOptions: {
|
commandOptions: {
|
||||||
@ -16,53 +13,67 @@ const toolbarButtons = [
|
|||||||
uiType: 'ohif.toolButtonList',
|
uiType: 'ohif.toolButtonList',
|
||||||
props: {
|
props: {
|
||||||
groupId: 'MeasurementTools',
|
groupId: 'MeasurementTools',
|
||||||
evaluate: 'evaluate.group.promoteToPrimaryIfCornerstoneToolNotActiveInTheList',
|
buttonSection: 'measurementSection',
|
||||||
primary: createButton({
|
},
|
||||||
id: 'Length',
|
},
|
||||||
icon: 'tool-length',
|
{
|
||||||
label: 'Length',
|
id: 'BrushTools',
|
||||||
tooltip: 'Length Tool',
|
uiType: 'ohif.toolBoxButtonGroup',
|
||||||
commands: setToolActiveToolbar,
|
props: {
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
groupId: 'BrushTools',
|
||||||
}),
|
buttonSection: 'brushToolsSection',
|
||||||
secondary: {
|
},
|
||||||
icon: 'chevron-down',
|
},
|
||||||
tooltip: 'More Measure Tools',
|
{
|
||||||
},
|
id: 'SegmentationTools',
|
||||||
items: [
|
uiType: 'ohif.toolBoxButton',
|
||||||
{
|
props: {
|
||||||
id: 'Length',
|
groupId: 'SegmentationTools',
|
||||||
icon: 'tool-length',
|
buttonSection: 'segmentationToolboxToolsSection',
|
||||||
label: 'Length',
|
},
|
||||||
tooltip: 'Length Tool',
|
},
|
||||||
commands: setToolActiveToolbar,
|
{
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
id: 'Length',
|
||||||
},
|
uiType: 'ohif.toolButton',
|
||||||
{
|
props: {
|
||||||
id: 'Bidirectional',
|
icon: 'tool-length',
|
||||||
icon: 'tool-bidirectional',
|
label: 'Length',
|
||||||
label: 'Bidirectional',
|
tooltip: 'Length Tool',
|
||||||
tooltip: 'Bidirectional Tool',
|
commands: setToolActiveToolbar,
|
||||||
commands: setToolActiveToolbar,
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ArrowAnnotate',
|
id: 'Bidirectional',
|
||||||
icon: 'tool-annotate',
|
uiType: 'ohif.toolButton',
|
||||||
label: 'Annotation',
|
props: {
|
||||||
tooltip: 'Arrow Annotate',
|
icon: 'tool-bidirectional',
|
||||||
commands: setToolActiveToolbar,
|
label: 'Bidirectional',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
tooltip: 'Bidirectional Tool',
|
||||||
},
|
commands: setToolActiveToolbar,
|
||||||
{
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
id: 'EllipticalROI',
|
},
|
||||||
icon: 'tool-ellipse',
|
},
|
||||||
label: 'Ellipse',
|
{
|
||||||
tooltip: 'Ellipse ROI',
|
id: 'ArrowAnnotate',
|
||||||
commands: setToolActiveToolbar,
|
uiType: 'ohif.toolButton',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
props: {
|
||||||
},
|
icon: 'tool-annotate',
|
||||||
],
|
label: 'Annotation',
|
||||||
|
tooltip: 'Arrow Annotate',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'EllipticalROI',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-ellipse',
|
||||||
|
label: 'Ellipse',
|
||||||
|
tooltip: 'Ellipse ROI',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -109,7 +120,7 @@ const toolbarButtons = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'Capture',
|
id: 'Capture',
|
||||||
uiType: 'ohif.radioGroup',
|
uiType: 'ohif.toolButton',
|
||||||
props: {
|
props: {
|
||||||
icon: 'tool-capture',
|
icon: 'tool-capture',
|
||||||
label: 'Capture',
|
label: 'Capture',
|
||||||
@ -130,6 +141,7 @@ const toolbarButtons = [
|
|||||||
rows: 3,
|
rows: 3,
|
||||||
columns: 4,
|
columns: 4,
|
||||||
evaluate: 'evaluate.action',
|
evaluate: 'evaluate.action',
|
||||||
|
commands: 'setViewportGridLayout',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -149,7 +161,7 @@ const toolbarButtons = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'RectangleROIStartEndThreshold',
|
id: 'RectangleROIStartEndThreshold',
|
||||||
uiType: 'ohif.radioGroup',
|
uiType: 'ohif.toolBoxButton',
|
||||||
props: {
|
props: {
|
||||||
icon: 'tool-create-threshold',
|
icon: 'tool-create-threshold',
|
||||||
label: 'Rectangle ROI Threshold',
|
label: 'Rectangle ROI Threshold',
|
||||||
@ -161,6 +173,163 @@ const toolbarButtons = [
|
|||||||
options: 'tmtv.RectangleROIThresholdOptions',
|
options: 'tmtv.RectangleROIThresholdOptions',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'Brush',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-brush',
|
||||||
|
label: 'Brush',
|
||||||
|
evaluate: {
|
||||||
|
name: 'evaluate.cornerstone.segmentation',
|
||||||
|
toolNames: ['CircularBrush', 'SphereBrush'],
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Size (mm)',
|
||||||
|
id: 'brush-radius',
|
||||||
|
type: 'range',
|
||||||
|
min: 0.5,
|
||||||
|
max: 99.5,
|
||||||
|
step: 0.5,
|
||||||
|
value: 7,
|
||||||
|
commands: {
|
||||||
|
commandName: 'setBrushSize',
|
||||||
|
commandOptions: { toolNames: ['CircularBrush', 'SphereBrush'] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Shape',
|
||||||
|
type: 'radio',
|
||||||
|
id: 'brush-mode',
|
||||||
|
value: 'CircularBrush',
|
||||||
|
values: [
|
||||||
|
{ value: 'CircularBrush', label: 'Circle' },
|
||||||
|
{ value: 'SphereBrush', label: 'Sphere' },
|
||||||
|
],
|
||||||
|
commands: 'setToolActiveToolbar',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Eraser',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-eraser',
|
||||||
|
label: 'Eraser',
|
||||||
|
evaluate: {
|
||||||
|
name: 'evaluate.cornerstone.segmentation',
|
||||||
|
toolNames: ['CircularEraser', 'SphereEraser'],
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Radius (mm)',
|
||||||
|
id: 'eraser-radius',
|
||||||
|
type: 'range',
|
||||||
|
min: 0.5,
|
||||||
|
max: 99.5,
|
||||||
|
step: 0.5,
|
||||||
|
value: 7,
|
||||||
|
commands: {
|
||||||
|
commandName: 'setBrushSize',
|
||||||
|
commandOptions: { toolNames: ['CircularEraser', 'SphereEraser'] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Shape',
|
||||||
|
type: 'radio',
|
||||||
|
id: 'eraser-mode',
|
||||||
|
value: 'CircularEraser',
|
||||||
|
values: [
|
||||||
|
{ value: 'CircularEraser', label: 'Circle' },
|
||||||
|
{ value: 'SphereEraser', label: 'Sphere' },
|
||||||
|
],
|
||||||
|
commands: 'setToolActiveToolbar',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Threshold',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-threshold',
|
||||||
|
label: 'Threshold',
|
||||||
|
evaluate: {
|
||||||
|
name: 'evaluate.cornerstone.segmentation',
|
||||||
|
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Radius (mm)',
|
||||||
|
id: 'threshold-radius',
|
||||||
|
type: 'range',
|
||||||
|
min: 0.5,
|
||||||
|
max: 99.5,
|
||||||
|
step: 0.5,
|
||||||
|
value: 7,
|
||||||
|
commands: {
|
||||||
|
commandName: 'setBrushSize',
|
||||||
|
commandOptions: {
|
||||||
|
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Shape',
|
||||||
|
type: 'radio',
|
||||||
|
id: 'eraser-mode',
|
||||||
|
value: 'ThresholdCircularBrush',
|
||||||
|
values: [
|
||||||
|
{ value: 'ThresholdCircularBrush', label: 'Circle' },
|
||||||
|
{ value: 'ThresholdSphereBrush', label: 'Sphere' },
|
||||||
|
],
|
||||||
|
commands: 'setToolActiveToolbar',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ThresholdRange',
|
||||||
|
type: 'double-range',
|
||||||
|
id: 'threshold-range',
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
step: 0.5,
|
||||||
|
value: [2, 50],
|
||||||
|
commands: {
|
||||||
|
commandName: 'setThresholdRange',
|
||||||
|
commandOptions: {
|
||||||
|
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Shapes',
|
||||||
|
uiType: 'ohif.toolBoxButton',
|
||||||
|
props: {
|
||||||
|
label: 'Shapes',
|
||||||
|
evaluate: {
|
||||||
|
name: 'evaluate.cornerstone.segmentation',
|
||||||
|
toolNames: ['CircleScissor', 'SphereScissor', 'RectangleScissor'],
|
||||||
|
},
|
||||||
|
icon: 'icon-tool-shape',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Shape',
|
||||||
|
type: 'radio',
|
||||||
|
value: 'CircleScissor',
|
||||||
|
id: 'shape-mode',
|
||||||
|
values: [
|
||||||
|
{ value: 'CircleScissor', label: 'Circle' },
|
||||||
|
{ value: 'SphereScissor', label: 'Sphere' },
|
||||||
|
{ value: 'RectangleScissor', label: 'Rectangle' },
|
||||||
|
],
|
||||||
|
commands: 'setToolActiveToolbar',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default toolbarButtons;
|
export default toolbarButtons;
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { id } from './id';
|
import { id } from './id';
|
||||||
import toolbarButtons from './toolbarButtons';
|
import toolbarButtons from './toolbarButtons';
|
||||||
import segmentationButtons from './segmentationButtons';
|
|
||||||
import initToolGroups from './initToolGroups';
|
import initToolGroups from './initToolGroups';
|
||||||
|
|
||||||
const ohif = {
|
const ohif = {
|
||||||
@ -57,7 +56,6 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
initToolGroups(extensionManager, toolGroupService, commandsManager);
|
initToolGroups(extensionManager, toolGroupService, commandsManager);
|
||||||
|
|
||||||
toolbarService.addButtons(toolbarButtons);
|
toolbarService.addButtons(toolbarButtons);
|
||||||
toolbarService.addButtons(segmentationButtons);
|
|
||||||
|
|
||||||
toolbarService.createButtonSection('primary', [
|
toolbarService.createButtonSection('primary', [
|
||||||
'WindowLevel',
|
'WindowLevel',
|
||||||
@ -69,7 +67,26 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
'Crosshairs',
|
'Crosshairs',
|
||||||
'MoreTools',
|
'MoreTools',
|
||||||
]);
|
]);
|
||||||
toolbarService.createButtonSection('segmentationToolbox', ['BrushTools', 'Shapes']);
|
|
||||||
|
toolbarService.createButtonSection('moreToolsSection', [
|
||||||
|
'Reset',
|
||||||
|
'rotate-right',
|
||||||
|
'flipHorizontal',
|
||||||
|
'ReferenceLines',
|
||||||
|
'ImageOverlayViewer',
|
||||||
|
'StackScroll',
|
||||||
|
'invert',
|
||||||
|
'Cine',
|
||||||
|
'Magnify',
|
||||||
|
'TagBrowser',
|
||||||
|
]);
|
||||||
|
|
||||||
|
toolbarService.createButtonSection('segmentationToolbox', ['SegmentationTools']);
|
||||||
|
toolbarService.createButtonSection('segmentationToolboxToolsSection', [
|
||||||
|
'BrushTools',
|
||||||
|
'Shapes',
|
||||||
|
]);
|
||||||
|
toolbarService.createButtonSection('brushToolsSection', ['Brush', 'Eraser', 'Threshold']);
|
||||||
},
|
},
|
||||||
onModeExit: ({ servicesManager }: withAppTypes) => {
|
onModeExit: ({ servicesManager }: withAppTypes) => {
|
||||||
const {
|
const {
|
||||||
|
|||||||
@ -76,6 +76,20 @@ function createTools(utilityModule) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
toolName: 'ThresholdSphereBrushDynamic',
|
||||||
|
parentTool: 'Brush',
|
||||||
|
configuration: {
|
||||||
|
activeStrategy: 'THRESHOLD_INSIDE_SPHERE',
|
||||||
|
// preview: {
|
||||||
|
// enabled: true,
|
||||||
|
// },
|
||||||
|
threshold: {
|
||||||
|
isDynamic: true,
|
||||||
|
dynamicRadius: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{ toolName: toolNames.CircleScissors },
|
{ toolName: toolNames.CircleScissors },
|
||||||
{ toolName: toolNames.RectangleScissors },
|
{ toolName: toolNames.RectangleScissors },
|
||||||
{ toolName: toolNames.SphereScissors },
|
{ toolName: toolNames.SphereScissors },
|
||||||
|
|||||||
@ -1,204 +0,0 @@
|
|||||||
import type { Button } from '@ohif/core/types';
|
|
||||||
|
|
||||||
const toolbarButtons: Button[] = [
|
|
||||||
{
|
|
||||||
id: 'BrushTools',
|
|
||||||
uiType: 'ohif.toolBoxButtonGroup',
|
|
||||||
props: {
|
|
||||||
groupId: 'BrushTools',
|
|
||||||
evaluate: 'evaluate.cornerstone.hasSegmentation',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
id: 'Brush',
|
|
||||||
icon: 'icon-tool-brush',
|
|
||||||
label: 'Brush',
|
|
||||||
evaluate: {
|
|
||||||
name: 'evaluate.cornerstone.segmentation',
|
|
||||||
toolNames: ['CircularBrush', 'SphereBrush'],
|
|
||||||
disabledText: 'Create new segmentation to enable this tool.',
|
|
||||||
},
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Radius (mm)',
|
|
||||||
id: 'brush-radius',
|
|
||||||
type: 'range',
|
|
||||||
min: 0.5,
|
|
||||||
max: 99.5,
|
|
||||||
step: 0.5,
|
|
||||||
value: 25,
|
|
||||||
commands: {
|
|
||||||
commandName: 'setBrushSize',
|
|
||||||
commandOptions: { toolNames: ['CircularBrush', 'SphereBrush'] },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Shape',
|
|
||||||
type: 'radio',
|
|
||||||
id: 'brush-mode',
|
|
||||||
value: 'CircularBrush',
|
|
||||||
values: [
|
|
||||||
{ value: 'CircularBrush', label: 'Circle' },
|
|
||||||
{ value: 'SphereBrush', label: 'Sphere' },
|
|
||||||
],
|
|
||||||
commands: 'setToolActiveToolbar',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Eraser',
|
|
||||||
icon: 'icon-tool-eraser',
|
|
||||||
label: 'Eraser',
|
|
||||||
evaluate: {
|
|
||||||
name: 'evaluate.cornerstone.segmentation',
|
|
||||||
toolNames: ['CircularEraser', 'SphereEraser'],
|
|
||||||
},
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Radius (mm)',
|
|
||||||
id: 'eraser-radius',
|
|
||||||
type: 'range',
|
|
||||||
min: 0.5,
|
|
||||||
max: 99.5,
|
|
||||||
step: 0.5,
|
|
||||||
value: 25,
|
|
||||||
commands: {
|
|
||||||
commandName: 'setBrushSize',
|
|
||||||
commandOptions: { toolNames: ['CircularEraser', 'SphereEraser'] },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Shape',
|
|
||||||
type: 'radio',
|
|
||||||
id: 'eraser-mode',
|
|
||||||
value: 'CircularEraser',
|
|
||||||
values: [
|
|
||||||
{ value: 'CircularEraser', label: 'Circle' },
|
|
||||||
{ value: 'SphereEraser', label: 'Sphere' },
|
|
||||||
],
|
|
||||||
commands: 'setToolActiveToolbar',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Threshold',
|
|
||||||
icon: 'icon-tool-threshold',
|
|
||||||
label: 'Threshold Tool',
|
|
||||||
evaluate: {
|
|
||||||
name: 'evaluate.cornerstone.segmentation',
|
|
||||||
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
|
||||||
},
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Radius (mm)',
|
|
||||||
id: 'threshold-radius',
|
|
||||||
type: 'range',
|
|
||||||
min: 0.5,
|
|
||||||
max: 99.5,
|
|
||||||
step: 0.5,
|
|
||||||
value: 25,
|
|
||||||
commands: {
|
|
||||||
commandName: 'setBrushSize',
|
|
||||||
commandOptions: {
|
|
||||||
toolNames: [
|
|
||||||
'ThresholdCircularBrush',
|
|
||||||
'ThresholdSphereBrush',
|
|
||||||
'ThresholdCircularBrushDynamic',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: 'Threshold',
|
|
||||||
type: 'radio',
|
|
||||||
id: 'dynamic-mode',
|
|
||||||
value: 'ThresholdRange',
|
|
||||||
values: [
|
|
||||||
{ value: 'ThresholdDynamic', label: 'Dynamic' },
|
|
||||||
{ value: 'ThresholdRange', label: 'Range' },
|
|
||||||
],
|
|
||||||
commands: ({ value, commandsManager, options }) => {
|
|
||||||
if (value === 'ThresholdDynamic') {
|
|
||||||
commandsManager.run('setToolActive', {
|
|
||||||
toolName: 'ThresholdCircularBrushDynamic',
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the condition of the threshold-range option
|
|
||||||
const thresholdRangeOption = options.find(
|
|
||||||
option => option.id === 'threshold-shape'
|
|
||||||
);
|
|
||||||
|
|
||||||
commandsManager.run('setToolActiveToolbar', {
|
|
||||||
toolName: thresholdRangeOption.value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Shape',
|
|
||||||
type: 'radio',
|
|
||||||
id: 'threshold-shape',
|
|
||||||
value: 'ThresholdCircularBrush',
|
|
||||||
values: [
|
|
||||||
{ value: 'ThresholdCircularBrush', label: 'Circle' },
|
|
||||||
{ value: 'ThresholdSphereBrush', label: 'Sphere' },
|
|
||||||
],
|
|
||||||
condition: ({ options }) =>
|
|
||||||
options.find(option => option.id === 'dynamic-mode').value === 'ThresholdRange',
|
|
||||||
commands: 'setToolActiveToolbar',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'ThresholdRange',
|
|
||||||
type: 'double-range',
|
|
||||||
id: 'threshold-range',
|
|
||||||
min: -1000,
|
|
||||||
max: 1000,
|
|
||||||
step: 1,
|
|
||||||
value: [100, 600],
|
|
||||||
condition: ({ options }) =>
|
|
||||||
options.find(option => option.id === 'dynamic-mode').value === 'ThresholdRange',
|
|
||||||
commands: {
|
|
||||||
commandName: 'setThresholdRange',
|
|
||||||
commandOptions: {
|
|
||||||
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Shapes',
|
|
||||||
uiType: 'ohif.toolBoxButton',
|
|
||||||
props: {
|
|
||||||
id: 'Shapes',
|
|
||||||
icon: 'icon-tool-shape',
|
|
||||||
label: 'Shapes',
|
|
||||||
evaluate: {
|
|
||||||
name: 'evaluate.cornerstone.segmentation',
|
|
||||||
toolNames: ['CircleScissor', 'SphereScissor', 'RectangleScissor'],
|
|
||||||
disabledText: 'Create new segmentation to enable shapes tool.',
|
|
||||||
},
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Shape',
|
|
||||||
type: 'radio',
|
|
||||||
value: 'CircleScissor',
|
|
||||||
id: 'shape-mode',
|
|
||||||
values: [
|
|
||||||
{ value: 'CircleScissor', label: 'Circle' },
|
|
||||||
{ value: 'SphereScissor', label: 'Sphere' },
|
|
||||||
{ value: 'RectangleScissor', label: 'Rectangle' },
|
|
||||||
],
|
|
||||||
commands: 'setToolActiveToolbar',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default toolbarButtons;
|
|
||||||
@ -1,16 +1,6 @@
|
|||||||
import type { Button } from '@ohif/core/types';
|
import type { Button } from '@ohif/core/types';
|
||||||
import { ToolbarService, ViewportGridService } from '@ohif/core';
|
|
||||||
|
|
||||||
const { createButton } = ToolbarService;
|
const setToolActiveToolbar = {
|
||||||
|
|
||||||
const ReferenceLinesListeners: RunCommand = [
|
|
||||||
{
|
|
||||||
commandName: 'setSourceViewportForReferenceLinesTool',
|
|
||||||
context: 'CORNERSTONE',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const setToolActiveToolbar = {
|
|
||||||
commandName: 'setToolActiveToolbar',
|
commandName: 'setToolActiveToolbar',
|
||||||
commandOptions: {
|
commandOptions: {
|
||||||
toolGroupIds: ['default', 'mpr', 'SRToolGroup', 'volume3d'],
|
toolGroupIds: ['default', 'mpr', 'SRToolGroup', 'volume3d'],
|
||||||
@ -18,6 +8,41 @@ export const setToolActiveToolbar = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toolbarButtons: Button[] = [
|
const toolbarButtons: Button[] = [
|
||||||
|
// sections
|
||||||
|
{
|
||||||
|
id: 'MoreTools',
|
||||||
|
uiType: 'ohif.toolButtonList',
|
||||||
|
props: {
|
||||||
|
buttonSection: 'moreToolsSection',
|
||||||
|
groupId: 'MoreTools',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'BrushTools',
|
||||||
|
uiType: 'ohif.toolBoxButtonGroup',
|
||||||
|
props: {
|
||||||
|
groupId: 'BrushTools',
|
||||||
|
buttonSection: 'brushToolsSection',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Section containers for the nested toolbox
|
||||||
|
{
|
||||||
|
id: 'SegmentationUtilities',
|
||||||
|
uiType: 'ohif.toolBoxButton',
|
||||||
|
props: {
|
||||||
|
groupId: 'SegmentationUtilities',
|
||||||
|
buttonSection: 'segmentationToolboxUtilitySection',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'SegmentationTools',
|
||||||
|
uiType: 'ohif.toolBoxButton',
|
||||||
|
props: {
|
||||||
|
groupId: 'SegmentationTools',
|
||||||
|
buttonSection: 'segmentationToolboxToolsSection',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// tool defs
|
||||||
{
|
{
|
||||||
id: 'Zoom',
|
id: 'Zoom',
|
||||||
uiType: 'ohif.toolButton',
|
uiType: 'ohif.toolButton',
|
||||||
@ -107,150 +132,345 @@ const toolbarButtons: Button[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'MoreTools',
|
id: 'Reset',
|
||||||
uiType: 'ohif.toolButtonList',
|
uiType: 'ohif.toolButton',
|
||||||
props: {
|
props: {
|
||||||
groupId: 'MoreTools',
|
icon: 'tool-reset',
|
||||||
evaluate: 'evaluate.group.promoteToPrimaryIfCornerstoneToolNotActiveInTheList',
|
label: 'Reset View',
|
||||||
primary: createButton({
|
tooltip: 'Reset View',
|
||||||
id: 'Reset',
|
commands: 'resetViewport',
|
||||||
icon: 'tool-reset',
|
evaluate: 'evaluate.action',
|
||||||
tooltip: 'Reset View',
|
},
|
||||||
label: 'Reset',
|
},
|
||||||
commands: 'resetViewport',
|
{
|
||||||
evaluate: 'evaluate.action',
|
id: 'rotate-right',
|
||||||
}),
|
uiType: 'ohif.toolButton',
|
||||||
secondary: {
|
props: {
|
||||||
icon: 'chevron-down',
|
icon: 'tool-rotate-right',
|
||||||
label: '',
|
label: 'Rotate Right',
|
||||||
tooltip: 'More Tools',
|
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: 'Cine',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-cine',
|
||||||
|
label: 'Cine',
|
||||||
|
tooltip: 'Cine',
|
||||||
|
commands: 'toggleCine',
|
||||||
|
evaluate: [
|
||||||
|
'evaluate.cine',
|
||||||
|
{
|
||||||
|
name: 'evaluate.viewport.supported',
|
||||||
|
unsupportedViewportTypes: ['volume3d'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Magnify',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-magnify',
|
||||||
|
label: 'Zoom-in',
|
||||||
|
tooltip: 'Zoom-in',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'TagBrowser',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'dicom-tag-browser',
|
||||||
|
label: 'Dicom Tag Browser',
|
||||||
|
tooltip: 'Dicom Tag Browser',
|
||||||
|
commands: 'openDICOMTagViewer',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'Brush',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-brush',
|
||||||
|
label: 'Brush',
|
||||||
|
evaluate: {
|
||||||
|
name: 'evaluate.cornerstone.segmentation',
|
||||||
|
toolNames: ['CircularBrush', 'SphereBrush'],
|
||||||
|
disabledText: 'Create new segmentation to enable this tool.',
|
||||||
},
|
},
|
||||||
items: [
|
options: [
|
||||||
createButton({
|
{
|
||||||
id: 'Reset',
|
name: 'Radius (mm)',
|
||||||
icon: 'tool-reset',
|
id: 'brush-radius',
|
||||||
label: 'Reset View',
|
type: 'range',
|
||||||
tooltip: 'Reset View',
|
min: 0.5,
|
||||||
commands: 'resetViewport',
|
max: 99.5,
|
||||||
evaluate: 'evaluate.action',
|
step: 0.5,
|
||||||
}),
|
value: 25,
|
||||||
createButton({
|
commands: {
|
||||||
id: 'rotate-right',
|
commandName: 'setBrushSize',
|
||||||
icon: 'tool-rotate-right',
|
commandOptions: { toolNames: ['CircularBrush', 'SphereBrush'] },
|
||||||
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({
|
name: 'Shape',
|
||||||
id: 'ImageOverlayViewer',
|
type: 'radio',
|
||||||
icon: 'toggle-dicom-overlay',
|
id: 'brush-mode',
|
||||||
label: 'Image Overlay',
|
value: 'CircularBrush',
|
||||||
tooltip: 'Toggle Image Overlay',
|
values: [
|
||||||
commands: 'toggleEnabledDisabledToolbar',
|
{ value: 'CircularBrush', label: 'Circle' },
|
||||||
evaluate: 'evaluate.cornerstoneTool.toggle',
|
{ value: 'SphereBrush', label: 'Sphere' },
|
||||||
}),
|
|
||||||
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: 'Cine',
|
|
||||||
icon: 'tool-cine',
|
|
||||||
label: 'Cine',
|
|
||||||
tooltip: 'Cine',
|
|
||||||
commands: 'toggleCine',
|
|
||||||
evaluate: [
|
|
||||||
'evaluate.cine',
|
|
||||||
{
|
|
||||||
name: 'evaluate.viewport.supported',
|
|
||||||
unsupportedViewportTypes: ['volume3d'],
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
}),
|
commands: 'setToolActiveToolbar',
|
||||||
createButton({
|
},
|
||||||
id: 'Magnify',
|
],
|
||||||
icon: 'tool-magnify',
|
},
|
||||||
label: 'Zoom-in',
|
},
|
||||||
tooltip: 'Zoom-in',
|
{
|
||||||
commands: setToolActiveToolbar,
|
id: 'Eraser',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
uiType: 'ohif.toolButton',
|
||||||
}),
|
props: {
|
||||||
createButton({
|
icon: 'icon-tool-eraser',
|
||||||
id: 'TagBrowser',
|
label: 'Eraser',
|
||||||
icon: 'dicom-tag-browser',
|
evaluate: {
|
||||||
label: 'Dicom Tag Browser',
|
name: 'evaluate.cornerstone.segmentation',
|
||||||
tooltip: 'Dicom Tag Browser',
|
toolNames: ['CircularEraser', 'SphereEraser'],
|
||||||
commands: 'openDICOMTagViewer',
|
},
|
||||||
}),
|
options: [
|
||||||
createButton({
|
{
|
||||||
id: 'AdvancedMagnify',
|
name: 'Radius (mm)',
|
||||||
icon: 'icon-tool-loupe',
|
id: 'eraser-radius',
|
||||||
label: 'Magnify Probe',
|
type: 'range',
|
||||||
tooltip: 'Magnify Probe',
|
min: 0.5,
|
||||||
commands: 'toggleActiveDisabledToolbar',
|
max: 99.5,
|
||||||
evaluate: 'evaluate.cornerstoneTool.toggle.ifStrictlyDisabled',
|
step: 0.5,
|
||||||
}),
|
value: 25,
|
||||||
createButton({
|
commands: {
|
||||||
id: 'UltrasoundDirectionalTool',
|
commandName: 'setBrushSize',
|
||||||
icon: 'icon-tool-ultrasound-bidirectional',
|
commandOptions: { toolNames: ['CircularEraser', 'SphereEraser'] },
|
||||||
label: 'Ultrasound Directional',
|
},
|
||||||
tooltip: 'Ultrasound Directional',
|
},
|
||||||
commands: setToolActiveToolbar,
|
{
|
||||||
evaluate: [
|
name: 'Shape',
|
||||||
'evaluate.cornerstoneTool',
|
type: 'radio',
|
||||||
{
|
id: 'eraser-mode',
|
||||||
name: 'evaluate.modality.supported',
|
value: 'CircularEraser',
|
||||||
supportedModalities: ['US'],
|
values: [
|
||||||
},
|
{ value: 'CircularEraser', label: 'Circle' },
|
||||||
|
{ value: 'SphereEraser', label: 'Sphere' },
|
||||||
],
|
],
|
||||||
}),
|
commands: 'setToolActiveToolbar',
|
||||||
createButton({
|
},
|
||||||
id: 'WindowLevelRegion',
|
],
|
||||||
icon: 'icon-tool-window-region',
|
},
|
||||||
label: 'Window Level Region',
|
},
|
||||||
tooltip: 'Window Level Region',
|
{
|
||||||
commands: setToolActiveToolbar,
|
id: 'Threshold',
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
uiType: 'ohif.toolButton',
|
||||||
}),
|
props: {
|
||||||
|
icon: 'icon-tool-threshold',
|
||||||
|
label: 'Threshold Tool',
|
||||||
|
evaluate: {
|
||||||
|
name: 'evaluate.cornerstone.segmentation',
|
||||||
|
toolNames: [
|
||||||
|
'ThresholdCircularBrush',
|
||||||
|
'ThresholdSphereBrush',
|
||||||
|
'ThresholdCircularBrushDynamic',
|
||||||
|
'ThresholdSphereBrushDynamic',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Radius (mm)',
|
||||||
|
id: 'threshold-radius',
|
||||||
|
type: 'range',
|
||||||
|
min: 0.5,
|
||||||
|
max: 99.5,
|
||||||
|
step: 0.5,
|
||||||
|
value: 25,
|
||||||
|
commands: {
|
||||||
|
commandName: 'setBrushSize',
|
||||||
|
commandOptions: {
|
||||||
|
toolNames: [
|
||||||
|
'ThresholdCircularBrush',
|
||||||
|
'ThresholdSphereBrush',
|
||||||
|
'ThresholdCircularBrushDynamic',
|
||||||
|
'ThresholdSphereBrushDynamic',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Shape',
|
||||||
|
type: 'radio',
|
||||||
|
id: 'threshold-shape',
|
||||||
|
value: 'ThresholdCircularBrush',
|
||||||
|
values: [
|
||||||
|
{ value: 'ThresholdCircularBrush', label: 'Circle' },
|
||||||
|
{ value: 'ThresholdSphereBrush', label: 'Sphere' },
|
||||||
|
],
|
||||||
|
commands: ({ value, commandsManager, options }) => {
|
||||||
|
const optionsDynamic = options.find(option => option.id === 'dynamic-mode');
|
||||||
|
|
||||||
|
if (optionsDynamic.value === 'ThresholdDynamic') {
|
||||||
|
commandsManager.run('setToolActive', {
|
||||||
|
toolName:
|
||||||
|
value === 'ThresholdCircularBrush'
|
||||||
|
? 'ThresholdCircularBrushDynamic'
|
||||||
|
: 'ThresholdSphereBrushDynamic',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
commandsManager.run('setToolActive', {
|
||||||
|
toolName: value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Threshold',
|
||||||
|
type: 'radio',
|
||||||
|
id: 'dynamic-mode',
|
||||||
|
value: 'ThresholdDynamic',
|
||||||
|
values: [
|
||||||
|
{ value: 'ThresholdDynamic', label: 'Dynamic' },
|
||||||
|
{ value: 'ThresholdRange', label: 'Range' },
|
||||||
|
],
|
||||||
|
commands: ({ value, commandsManager, options }) => {
|
||||||
|
const thresholdRangeOption = options.find(option => option.id === 'threshold-shape');
|
||||||
|
|
||||||
|
if (value === 'ThresholdDynamic') {
|
||||||
|
commandsManager.run('setToolActiveToolbar', {
|
||||||
|
toolName:
|
||||||
|
thresholdRangeOption.value === 'ThresholdCircularBrush'
|
||||||
|
? 'ThresholdCircularBrushDynamic'
|
||||||
|
: 'ThresholdSphereBrushDynamic',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
commandsManager.run('setToolActiveToolbar', {
|
||||||
|
toolName: thresholdRangeOption.value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const thresholdRangeValue = options.find(
|
||||||
|
option => option.id === 'threshold-range'
|
||||||
|
).value;
|
||||||
|
|
||||||
|
commandsManager.run('setThresholdRange', {
|
||||||
|
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
||||||
|
value: thresholdRangeValue,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ThresholdRange',
|
||||||
|
type: 'double-range',
|
||||||
|
id: 'threshold-range',
|
||||||
|
min: -1000,
|
||||||
|
max: 1000,
|
||||||
|
step: 1,
|
||||||
|
value: [50, 600],
|
||||||
|
condition: ({ options }) =>
|
||||||
|
options.find(option => option.id === 'dynamic-mode').value === 'ThresholdRange',
|
||||||
|
commands: {
|
||||||
|
commandName: 'setThresholdRange',
|
||||||
|
commandOptions: {
|
||||||
|
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Shapes',
|
||||||
|
uiType: 'ohif.toolBoxButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-shape',
|
||||||
|
label: 'Shapes',
|
||||||
|
evaluate: {
|
||||||
|
name: 'evaluate.cornerstone.segmentation',
|
||||||
|
toolNames: ['CircleScissor', 'SphereScissor', 'RectangleScissor'],
|
||||||
|
disabledText: 'Create new segmentation to enable shapes tool.',
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Shape',
|
||||||
|
type: 'radio',
|
||||||
|
value: 'CircleScissor',
|
||||||
|
id: 'shape-mode',
|
||||||
|
values: [
|
||||||
|
{ value: 'CircleScissor', label: 'Circle' },
|
||||||
|
{ value: 'SphereScissor', label: 'Sphere' },
|
||||||
|
{ value: 'RectangleScissor', label: 'Rectangle' },
|
||||||
|
],
|
||||||
|
commands: 'setToolActiveToolbar',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { hotkeys, classes } from '@ohif/core';
|
import { classes } from '@ohif/core';
|
||||||
import toolbarButtons from './toolbarButtons.js';
|
import toolbarButtons from './toolbarButtons';
|
||||||
import { id } from './id.js';
|
import { id } from './id.js';
|
||||||
import initToolGroups from './initToolGroups.js';
|
import initToolGroups from './initToolGroups.js';
|
||||||
import setCrosshairsConfiguration from './utils/setCrosshairsConfiguration.js';
|
import setCrosshairsConfiguration from './utils/setCrosshairsConfiguration.js';
|
||||||
@ -96,11 +96,21 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
'Crosshairs',
|
'Crosshairs',
|
||||||
'Pan',
|
'Pan',
|
||||||
]);
|
]);
|
||||||
toolbarService.createButtonSection('ROIThresholdToolbox', [
|
toolbarService.createButtonSection('measurementSection', [
|
||||||
|
'Length',
|
||||||
|
'Bidirectional',
|
||||||
|
'ArrowAnnotate',
|
||||||
|
'EllipticalROI',
|
||||||
|
]);
|
||||||
|
|
||||||
|
toolbarService.createButtonSection('ROIThresholdToolbox', ['SegmentationTools']);
|
||||||
|
toolbarService.createButtonSection('segmentationToolboxToolsSection', [
|
||||||
'RectangleROIStartEndThreshold',
|
'RectangleROIStartEndThreshold',
|
||||||
'BrushTools',
|
'BrushTools',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
toolbarService.createButtonSection('brushToolsSection', ['Brush', 'Eraser', 'Threshold']);
|
||||||
|
|
||||||
customizationService.setCustomizations({
|
customizationService.setCustomizations({
|
||||||
'panelSegmentation.tableMode': {
|
'panelSegmentation.tableMode': {
|
||||||
$set: 'expanded',
|
$set: 'expanded',
|
||||||
|
|||||||
@ -1,285 +0,0 @@
|
|||||||
import { ToolbarService } from '@ohif/core';
|
|
||||||
import { toolGroupIds } from './initToolGroups';
|
|
||||||
|
|
||||||
const setToolActiveToolbar = {
|
|
||||||
commandName: 'setToolActiveToolbar',
|
|
||||||
commandOptions: {
|
|
||||||
toolGroupIds: [toolGroupIds.CT, toolGroupIds.PT, toolGroupIds.Fusion],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const toolbarButtons = [
|
|
||||||
{
|
|
||||||
id: 'MeasurementTools',
|
|
||||||
uiType: 'ohif.toolButtonList',
|
|
||||||
props: {
|
|
||||||
groupId: 'MeasurementTools',
|
|
||||||
primary: ToolbarService.createButton({
|
|
||||||
id: 'Length',
|
|
||||||
icon: 'tool-length',
|
|
||||||
label: 'Length',
|
|
||||||
tooltip: 'Length Tool',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
secondary: {
|
|
||||||
icon: 'chevron-down',
|
|
||||||
tooltip: 'More Measure Tools',
|
|
||||||
},
|
|
||||||
items: [
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'Bidirectional',
|
|
||||||
icon: 'tool-bidirectional',
|
|
||||||
label: 'Bidirectional',
|
|
||||||
tooltip: 'Bidirectional Tool',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'ArrowAnnotate',
|
|
||||||
icon: 'tool-annotate',
|
|
||||||
label: 'Arrow Annotate',
|
|
||||||
tooltip: 'Arrow Annotate Tool',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
ToolbarService.createButton({
|
|
||||||
id: 'EllipticalROI',
|
|
||||||
icon: 'tool-ellipse',
|
|
||||||
label: 'Ellipse',
|
|
||||||
tooltip: 'Ellipse Tool',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Zoom',
|
|
||||||
uiType: 'ohif.toolButton',
|
|
||||||
props: {
|
|
||||||
icon: 'tool-zoom',
|
|
||||||
label: 'Zoom',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Window Level + Presets
|
|
||||||
{
|
|
||||||
id: 'WindowLevel',
|
|
||||||
uiType: 'ohif.toolButton',
|
|
||||||
props: {
|
|
||||||
icon: 'tool-window-level',
|
|
||||||
label: 'Window Level',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Crosshairs Button
|
|
||||||
{
|
|
||||||
id: 'Crosshairs',
|
|
||||||
uiType: 'ohif.toolButton',
|
|
||||||
props: {
|
|
||||||
icon: 'tool-crosshair',
|
|
||||||
label: 'Crosshairs',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Pan Button
|
|
||||||
{
|
|
||||||
id: 'Pan',
|
|
||||||
uiType: 'ohif.toolButton',
|
|
||||||
props: {
|
|
||||||
icon: 'tool-move',
|
|
||||||
label: 'Pan',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: 'evaluate.cornerstoneTool',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Rectangle ROI Start End Threshold Button
|
|
||||||
{
|
|
||||||
id: 'RectangleROIStartEndThreshold',
|
|
||||||
uiType: 'ohif.toolBoxButton',
|
|
||||||
props: {
|
|
||||||
icon: 'tool-create-threshold',
|
|
||||||
label: 'Rectangle ROI Threshold',
|
|
||||||
commands: setToolActiveToolbar,
|
|
||||||
evaluate: [
|
|
||||||
'evaluate.cornerstone.segmentation',
|
|
||||||
// need to put the disabled text last, since each evaluator will
|
|
||||||
// merge the result text into the final result
|
|
||||||
{
|
|
||||||
name: 'evaluate.cornerstoneTool',
|
|
||||||
disabledText: 'Select the PT Axial to enable this tool',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
options: 'tmtv.RectangleROIThresholdOptions',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'BrushTools',
|
|
||||||
uiType: 'ohif.toolBoxButtonGroup',
|
|
||||||
props: {
|
|
||||||
groupId: 'BrushTools',
|
|
||||||
evaluate: 'evaluate.cornerstone.hasSegmentation',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
id: 'Brush',
|
|
||||||
icon: 'icon-tool-brush',
|
|
||||||
label: 'Brush',
|
|
||||||
evaluate: {
|
|
||||||
name: 'evaluate.cornerstone.segmentation',
|
|
||||||
toolNames: ['CircularBrush', 'SphereBrush'],
|
|
||||||
disabledText: 'Create new segmentation to enable this tool.',
|
|
||||||
},
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Radius (mm)',
|
|
||||||
id: 'brush-radius',
|
|
||||||
type: 'range',
|
|
||||||
min: 0.5,
|
|
||||||
max: 99.5,
|
|
||||||
step: 0.5,
|
|
||||||
value: 25,
|
|
||||||
commands: {
|
|
||||||
commandName: 'setBrushSize',
|
|
||||||
commandOptions: { toolNames: ['CircularBrush', 'SphereBrush'] },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Shape',
|
|
||||||
type: 'radio',
|
|
||||||
id: 'brush-mode',
|
|
||||||
value: 'CircularBrush',
|
|
||||||
values: [
|
|
||||||
{ value: 'CircularBrush', label: 'Circle' },
|
|
||||||
{ value: 'SphereBrush', label: 'Sphere' },
|
|
||||||
],
|
|
||||||
commands: 'setToolActiveToolbar',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Eraser',
|
|
||||||
icon: 'icon-tool-eraser',
|
|
||||||
label: 'Eraser',
|
|
||||||
evaluate: {
|
|
||||||
name: 'evaluate.cornerstone.segmentation',
|
|
||||||
toolNames: ['CircularEraser', 'SphereEraser'],
|
|
||||||
},
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Radius (mm)',
|
|
||||||
id: 'eraser-radius',
|
|
||||||
type: 'range',
|
|
||||||
min: 0.5,
|
|
||||||
max: 99.5,
|
|
||||||
step: 0.5,
|
|
||||||
value: 25,
|
|
||||||
commands: {
|
|
||||||
commandName: 'setBrushSize',
|
|
||||||
commandOptions: { toolNames: ['CircularEraser', 'SphereEraser'] },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Shape',
|
|
||||||
type: 'radio',
|
|
||||||
id: 'eraser-mode',
|
|
||||||
value: 'CircularEraser',
|
|
||||||
values: [
|
|
||||||
{ value: 'CircularEraser', label: 'Circle' },
|
|
||||||
{ value: 'SphereEraser', label: 'Sphere' },
|
|
||||||
],
|
|
||||||
commands: 'setToolActiveToolbar',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'Threshold',
|
|
||||||
icon: 'icon-tool-threshold',
|
|
||||||
label: 'Threshold Tool',
|
|
||||||
evaluate: {
|
|
||||||
name: 'evaluate.cornerstone.segmentation',
|
|
||||||
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
|
||||||
},
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: 'Radius (mm)',
|
|
||||||
id: 'threshold-radius',
|
|
||||||
type: 'range',
|
|
||||||
min: 0.5,
|
|
||||||
max: 99.5,
|
|
||||||
step: 0.5,
|
|
||||||
value: 25,
|
|
||||||
commands: {
|
|
||||||
commandName: 'setBrushSize',
|
|
||||||
commandOptions: {
|
|
||||||
toolNames: [
|
|
||||||
'ThresholdCircularBrush',
|
|
||||||
'ThresholdSphereBrush',
|
|
||||||
'ThresholdCircularBrushDynamic',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: 'Threshold',
|
|
||||||
type: 'radio',
|
|
||||||
id: 'dynamic-mode',
|
|
||||||
value: 'ThresholdRange',
|
|
||||||
values: [
|
|
||||||
{ value: 'ThresholdDynamic', label: 'Dynamic' },
|
|
||||||
{ value: 'ThresholdRange', label: 'Range' },
|
|
||||||
],
|
|
||||||
commands: ({ value, commandsManager }) => {
|
|
||||||
if (value === 'ThresholdDynamic') {
|
|
||||||
commandsManager.run('setToolActive', {
|
|
||||||
toolName: 'ThresholdCircularBrushDynamic',
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
commandsManager.run('setToolActive', {
|
|
||||||
toolName: 'ThresholdCircularBrush',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Shape',
|
|
||||||
type: 'radio',
|
|
||||||
id: 'eraser-mode',
|
|
||||||
value: 'ThresholdCircularBrush',
|
|
||||||
values: [
|
|
||||||
{ value: 'ThresholdCircularBrush', label: 'Circle' },
|
|
||||||
{ value: 'ThresholdSphereBrush', label: 'Sphere' },
|
|
||||||
],
|
|
||||||
condition: ({ options }) =>
|
|
||||||
options.find(option => option.id === 'dynamic-mode').value === 'ThresholdRange',
|
|
||||||
commands: 'setToolActiveToolbar',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'ThresholdRange',
|
|
||||||
type: 'double-range',
|
|
||||||
id: 'threshold-range',
|
|
||||||
min: 0,
|
|
||||||
max: 50,
|
|
||||||
step: 0.5,
|
|
||||||
value: [2.5, 50],
|
|
||||||
condition: ({ options }) =>
|
|
||||||
options.find(option => option.id === 'dynamic-mode').value === 'ThresholdRange',
|
|
||||||
commands: {
|
|
||||||
commandName: 'setThresholdRange',
|
|
||||||
commandOptions: {
|
|
||||||
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default toolbarButtons;
|
|
||||||
300
modes/tmtv/src/toolbarButtons.ts
Normal file
300
modes/tmtv/src/toolbarButtons.ts
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
import { toolGroupIds } from './initToolGroups';
|
||||||
|
|
||||||
|
const setToolActiveToolbar = {
|
||||||
|
commandName: 'setToolActiveToolbar',
|
||||||
|
commandOptions: {
|
||||||
|
toolGroupIds: [toolGroupIds.CT, toolGroupIds.PT, toolGroupIds.Fusion],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const toolbarButtons = [
|
||||||
|
{
|
||||||
|
id: 'MeasurementTools',
|
||||||
|
uiType: 'ohif.toolButtonList',
|
||||||
|
props: {
|
||||||
|
buttonSection: 'measurementSection',
|
||||||
|
groupId: 'MeasurementTools',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'SegmentationTools',
|
||||||
|
uiType: 'ohif.toolBoxButton',
|
||||||
|
props: {
|
||||||
|
groupId: 'SegmentationTools',
|
||||||
|
buttonSection: 'segmentationToolboxToolsSection',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'BrushTools',
|
||||||
|
uiType: 'ohif.toolBoxButtonGroup',
|
||||||
|
props: {
|
||||||
|
buttonSection: 'brushToolsSection',
|
||||||
|
groupId: 'BrushTools',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Length',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-length',
|
||||||
|
label: 'Length',
|
||||||
|
tooltip: 'Length Tool',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Bidirectional',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-bidirectional',
|
||||||
|
label: 'Bidirectional',
|
||||||
|
tooltip: 'Bidirectional Tool',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ArrowAnnotate',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-annotate',
|
||||||
|
label: 'Arrow Annotate',
|
||||||
|
tooltip: 'Arrow Annotate Tool',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'EllipticalROI',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-ellipse',
|
||||||
|
label: 'Ellipse',
|
||||||
|
tooltip: 'Ellipse Tool',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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: 'Crosshairs',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-crosshair',
|
||||||
|
label: 'Crosshairs',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Pan',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-move',
|
||||||
|
label: 'Pan',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'RectangleROIStartEndThreshold',
|
||||||
|
uiType: 'ohif.toolBoxButton',
|
||||||
|
props: {
|
||||||
|
icon: 'tool-create-threshold',
|
||||||
|
label: 'Rectangle ROI Threshold',
|
||||||
|
commands: setToolActiveToolbar,
|
||||||
|
evaluate: [
|
||||||
|
'evaluate.cornerstone.segmentation',
|
||||||
|
{
|
||||||
|
name: 'evaluate.cornerstoneTool',
|
||||||
|
disabledText: 'Select the PT Axial to enable this tool',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options: 'tmtv.RectangleROIThresholdOptions',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'Brush',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-brush',
|
||||||
|
label: 'Brush',
|
||||||
|
evaluate: {
|
||||||
|
name: 'evaluate.cornerstone.segmentation',
|
||||||
|
toolNames: ['CircularBrush', 'SphereBrush'],
|
||||||
|
disabledText: 'Create new segmentation to enable this tool.',
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Radius (mm)',
|
||||||
|
id: 'brush-radius',
|
||||||
|
type: 'range',
|
||||||
|
min: 0.5,
|
||||||
|
max: 99.5,
|
||||||
|
step: 0.5,
|
||||||
|
value: 25,
|
||||||
|
commands: {
|
||||||
|
commandName: 'setBrushSize',
|
||||||
|
commandOptions: { toolNames: ['CircularBrush', 'SphereBrush'] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Shape',
|
||||||
|
type: 'radio',
|
||||||
|
id: 'brush-mode',
|
||||||
|
value: 'CircularBrush',
|
||||||
|
values: [
|
||||||
|
{ value: 'CircularBrush', label: 'Circle' },
|
||||||
|
{ value: 'SphereBrush', label: 'Sphere' },
|
||||||
|
],
|
||||||
|
commands: 'setToolActiveToolbar',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Eraser',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-eraser',
|
||||||
|
label: 'Eraser',
|
||||||
|
evaluate: {
|
||||||
|
name: 'evaluate.cornerstone.segmentation',
|
||||||
|
toolNames: ['CircularEraser', 'SphereEraser'],
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Radius (mm)',
|
||||||
|
id: 'eraser-radius',
|
||||||
|
type: 'range',
|
||||||
|
min: 0.5,
|
||||||
|
max: 99.5,
|
||||||
|
step: 0.5,
|
||||||
|
value: 25,
|
||||||
|
commands: {
|
||||||
|
commandName: 'setBrushSize',
|
||||||
|
commandOptions: { toolNames: ['CircularEraser', 'SphereEraser'] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Shape',
|
||||||
|
type: 'radio',
|
||||||
|
id: 'eraser-mode',
|
||||||
|
value: 'CircularEraser',
|
||||||
|
values: [
|
||||||
|
{ value: 'CircularEraser', label: 'Circle' },
|
||||||
|
{ value: 'SphereEraser', label: 'Sphere' },
|
||||||
|
],
|
||||||
|
commands: 'setToolActiveToolbar',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Threshold',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-threshold',
|
||||||
|
label: 'Threshold Tool',
|
||||||
|
evaluate: {
|
||||||
|
name: 'evaluate.cornerstone.segmentation',
|
||||||
|
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Radius (mm)',
|
||||||
|
id: 'threshold-radius',
|
||||||
|
type: 'range',
|
||||||
|
min: 0.5,
|
||||||
|
max: 99.5,
|
||||||
|
step: 0.5,
|
||||||
|
value: 25,
|
||||||
|
commands: {
|
||||||
|
commandName: 'setBrushSize',
|
||||||
|
commandOptions: {
|
||||||
|
toolNames: [
|
||||||
|
'ThresholdCircularBrush',
|
||||||
|
'ThresholdSphereBrush',
|
||||||
|
'ThresholdCircularBrushDynamic',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Threshold',
|
||||||
|
type: 'radio',
|
||||||
|
id: 'dynamic-mode',
|
||||||
|
value: 'ThresholdRange',
|
||||||
|
values: [
|
||||||
|
{ value: 'ThresholdDynamic', label: 'Dynamic' },
|
||||||
|
{ value: 'ThresholdRange', label: 'Range' },
|
||||||
|
],
|
||||||
|
commands: ({ value, commandsManager }) => {
|
||||||
|
if (value === 'ThresholdDynamic') {
|
||||||
|
commandsManager.run('setToolActive', {
|
||||||
|
toolName: 'ThresholdCircularBrushDynamic',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
commandsManager.run('setToolActive', {
|
||||||
|
toolName: 'ThresholdCircularBrush',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Shape',
|
||||||
|
type: 'radio',
|
||||||
|
id: 'eraser-mode',
|
||||||
|
value: 'ThresholdCircularBrush',
|
||||||
|
values: [
|
||||||
|
{ value: 'ThresholdCircularBrush', label: 'Circle' },
|
||||||
|
{ value: 'ThresholdSphereBrush', label: 'Sphere' },
|
||||||
|
],
|
||||||
|
condition: ({ options }) =>
|
||||||
|
options.find(option => option.id === 'dynamic-mode').value === 'ThresholdRange',
|
||||||
|
commands: 'setToolActiveToolbar',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ThresholdRange',
|
||||||
|
type: 'double-range',
|
||||||
|
id: 'threshold-range',
|
||||||
|
min: 0,
|
||||||
|
max: 50,
|
||||||
|
step: 0.5,
|
||||||
|
value: [2.5, 50],
|
||||||
|
condition: ({ options }) =>
|
||||||
|
options.find(option => option.id === 'dynamic-mode').value === 'ThresholdRange',
|
||||||
|
commands: {
|
||||||
|
commandName: 'setThresholdRange',
|
||||||
|
commandOptions: {
|
||||||
|
toolNames: ['ThresholdCircularBrush', 'ThresholdSphereBrush'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default toolbarButtons;
|
||||||
@ -76,7 +76,7 @@
|
|||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@percy/cypress": "^3.1.1",
|
"@percy/cypress": "^3.1.1",
|
||||||
"@playwright/test": "^1.48.0",
|
"@playwright/test": "^1.48.0",
|
||||||
"cypress": "^14.0.0",
|
"cypress": "^14.1.0",
|
||||||
"cypress-file-upload": "^5.0.8"
|
"cypress-file-upload": "^5.0.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@ -1,108 +1,95 @@
|
|||||||
describe('OHIF Download Snapshot File', () => {
|
// describe('OHIF Download Snapshot File', () => {
|
||||||
beforeEach(() => {
|
// beforeEach(() => {
|
||||||
cy.checkStudyRouteInViewer('1.2.840.113619.2.5.1762583153.215519.978957063.78');
|
// cy.checkStudyRouteInViewer('1.2.840.113619.2.5.1762583153.215519.978957063.78');
|
||||||
cy.expectMinimumThumbnails(3);
|
// cy.expectMinimumThumbnails(3);
|
||||||
cy.openDownloadImageModal();
|
// cy.openDownloadImageModal();
|
||||||
});
|
// });
|
||||||
|
|
||||||
it('checks displayed information for Desktop experience', function () {
|
// it('checks displayed information for Desktop experience', function () {
|
||||||
// Set Desktop resolution
|
// // Set Desktop resolution
|
||||||
// cy.viewport(1750, 720);
|
// // cy.viewport(1750, 720);
|
||||||
// Visual comparison
|
// // Visual comparison
|
||||||
// cy.screenshot('Download Image Modal - Desktop experience');
|
// // cy.screenshot('Download Image Modal - Desktop experience');
|
||||||
//Check if all elements are displayed
|
// //Check if all elements are displayed
|
||||||
|
|
||||||
// TODO: need to add this attribute to the modal
|
// // Check image preview
|
||||||
cy.get('[data-cy=modal-header]')
|
// cy.get('[data-cy="image-preview"]').should('contain.text', 'Image preview');
|
||||||
.as('downloadImageModal')
|
|
||||||
.should('contain.text', 'Download High Quality Image');
|
|
||||||
|
|
||||||
// Check input fields
|
// //TODO: This is a canvas now, not an img with src
|
||||||
// TODO: select2
|
// // cy.get('[data-cy="viewport-preview-img"]')
|
||||||
// cy.get('[data-cy="file-type"]')
|
// // .should('have.attr', 'src')
|
||||||
// .select('png')
|
// // .and('include', 'data:image');
|
||||||
// .should('have.value', 'png')
|
|
||||||
// .select('jpg')
|
|
||||||
// .should('have.value', 'jpg');
|
|
||||||
|
|
||||||
// Check image preview
|
// // Check buttons
|
||||||
cy.get('[data-cy="image-preview"]').should('contain.text', 'Image preview');
|
// cy.get('[data-cy="cancel-btn"]').scrollIntoView().should('be.visible');
|
||||||
|
// cy.get('[data-cy="download-btn"]').scrollIntoView().should('be.visible');
|
||||||
|
|
||||||
//TODO: This is a canvas now, not an img with src
|
// cy.get('[data-cy="cancel-btn"]').click();
|
||||||
// cy.get('[data-cy="viewport-preview-img"]')
|
// });
|
||||||
// .should('have.attr', 'src')
|
|
||||||
// .and('include', 'data:image');
|
|
||||||
|
|
||||||
// Check buttons
|
// /*it('cancel changes on download modal', function() {
|
||||||
cy.get('[data-cy="cancel-btn"]').scrollIntoView().should('be.visible');
|
// //Change Image Width, Filename and File Type
|
||||||
cy.get('[data-cy="download-btn"]').scrollIntoView().should('be.visible');
|
// cy.get('[data-cy="image-width"]')
|
||||||
|
// .clear()
|
||||||
|
// .type('300');
|
||||||
|
// cy.get('[data-cy="image-height"]') //Image Height should be the same as width
|
||||||
|
// .should('have.value', '300');
|
||||||
|
// cy.get('[data-cy="file-name"]')
|
||||||
|
// .clear()
|
||||||
|
// .type('new-filename');
|
||||||
|
// cy.get('[data-cy="file-type"]').select('png');
|
||||||
|
// //Click on Cancel button
|
||||||
|
// cy.get('[data-cy="cancel-btn"]')
|
||||||
|
// .scrollIntoView()
|
||||||
|
// .click();
|
||||||
|
// //Check modal is closed
|
||||||
|
// cy.get('[data-cy="modal"]').should('not.exist');
|
||||||
|
// //Open Modal
|
||||||
|
// cy.openDownloadImageModal();
|
||||||
|
// //Verify default values was restored
|
||||||
|
// cy.get('[data-cy="image-width"]').should('have.value', '512');
|
||||||
|
// cy.get('[data-cy="file-name"]').should('have.value', 'image');
|
||||||
|
// cy.get('[data-cy=file-type]').should('have.value', 'jpg');
|
||||||
|
// });*/
|
||||||
|
|
||||||
cy.get('[data-cy="cancel-btn"]').click();
|
// // TO-DO once issue is fixed: https://github.com/OHIF/Viewers/issues/1217
|
||||||
});
|
// // it('checks error messages for empty fields', function() {
|
||||||
|
// // //Clear fields Image Width and Filename
|
||||||
|
// // cy.get('[data-cy="image-width"]').clear();
|
||||||
|
// // cy.get('[data-cy="file-name"]').clear();
|
||||||
|
|
||||||
/*it('cancel changes on download modal', function() {
|
// // //Click on Download button
|
||||||
//Change Image Width, Filename and File Type
|
// // cy.get('[data-cy="download-btn"]')
|
||||||
cy.get('[data-cy="image-width"]')
|
// // .scrollIntoView()
|
||||||
.clear()
|
// // .click();
|
||||||
.type('300');
|
// // //Check error message
|
||||||
cy.get('[data-cy="image-height"]') //Image Height should be the same as width
|
// // });
|
||||||
.should('have.value', '300');
|
|
||||||
cy.get('[data-cy="file-name"]')
|
|
||||||
.clear()
|
|
||||||
.type('new-filename');
|
|
||||||
cy.get('[data-cy="file-type"]').select('png');
|
|
||||||
//Click on Cancel button
|
|
||||||
cy.get('[data-cy="cancel-btn"]')
|
|
||||||
.scrollIntoView()
|
|
||||||
.click();
|
|
||||||
//Check modal is closed
|
|
||||||
cy.get('[data-cy="modal"]').should('not.exist');
|
|
||||||
//Open Modal
|
|
||||||
cy.openDownloadImageModal();
|
|
||||||
//Verify default values was restored
|
|
||||||
cy.get('[data-cy="image-width"]').should('have.value', '512');
|
|
||||||
cy.get('[data-cy="file-name"]').should('have.value', 'image');
|
|
||||||
cy.get('[data-cy=file-type]').should('have.value', 'jpg');
|
|
||||||
});*/
|
|
||||||
|
|
||||||
// TO-DO once issue is fixed: https://github.com/OHIF/Viewers/issues/1217
|
// /*it('checks if "Show Annotations" checkbox will display annotations', function() {
|
||||||
// it('checks error messages for empty fields', function() {
|
// // Close modal that is initially opened
|
||||||
// //Clear fields Image Width and Filename
|
// cy.get('[data-cy="close-button"]').click();
|
||||||
// cy.get('[data-cy="image-width"]').clear();
|
|
||||||
// cy.get('[data-cy="file-name"]').clear();
|
|
||||||
|
|
||||||
// //Click on Download button
|
// // Add measurements in the viewport
|
||||||
// cy.get('[data-cy="download-btn"]')
|
// cy.addLengthMeasurement();
|
||||||
// .scrollIntoView()
|
// cy.addAngleMeasurement();
|
||||||
// .click();
|
|
||||||
// //Check error message
|
|
||||||
// });
|
|
||||||
|
|
||||||
/*it('checks if "Show Annotations" checkbox will display annotations', function() {
|
// // Open Modal
|
||||||
// Close modal that is initially opened
|
// cy.openDownloadImageModal();
|
||||||
cy.get('[data-cy="close-button"]').click();
|
// // Select "Show Annotations" option
|
||||||
|
// cy.get('[data-cy="show-annotations"]').check();
|
||||||
// Add measurements in the viewport
|
// // Check image preview
|
||||||
cy.addLengthMeasurement();
|
// cy.get('[data-cy="image-preview"]').scrollIntoView();
|
||||||
cy.addAngleMeasurement();
|
// //Compare classes that exists on Image Preview with Annotations and Without Annotation
|
||||||
|
// cy.get('[data-cy="modal-content"]')
|
||||||
// Open Modal
|
// .find('canvas')
|
||||||
cy.openDownloadImageModal();
|
// .should('have.class', 'magnifyTool'); //Class "MagnifyTool" exists with annotations displayed on Image preview
|
||||||
// Select "Show Annotations" option
|
// // Uncheck "Show Annotations" option
|
||||||
cy.get('[data-cy="show-annotations"]').check();
|
// cy.get('[data-cy="show-annotations"]')
|
||||||
// Check image preview
|
// .uncheck()
|
||||||
cy.get('[data-cy="image-preview"]').scrollIntoView();
|
// .wait(300);
|
||||||
//Compare classes that exists on Image Preview with Annotations and Without Annotation
|
// // Check that class "MagnifyTool" should not exist
|
||||||
cy.get('[data-cy="modal-content"]')
|
// cy.get('[data-cy="modal-content"]')
|
||||||
.find('canvas')
|
// .find('canvas')
|
||||||
.should('have.class', 'magnifyTool'); //Class "MagnifyTool" exists with annotations displayed on Image preview
|
// .should('not.have.class', 'magnifyTool');
|
||||||
// Uncheck "Show Annotations" option
|
// });*/
|
||||||
cy.get('[data-cy="show-annotations"]')
|
// });
|
||||||
.uncheck()
|
|
||||||
.wait(300);
|
|
||||||
// Check that class "MagnifyTool" should not exist
|
|
||||||
cy.get('[data-cy="modal-content"]')
|
|
||||||
.find('canvas')
|
|
||||||
.should('not.have.class', 'magnifyTool');
|
|
||||||
});*/
|
|
||||||
});
|
|
||||||
|
|||||||
@ -4,8 +4,8 @@ export function initCornerstoneToolsAliases() {
|
|||||||
// cy.get('[data-cy="StackScroll"]').as('stackScrollBtn');
|
// cy.get('[data-cy="StackScroll"]').as('stackScrollBtn');
|
||||||
|
|
||||||
cy.get('[data-cy="Zoom"]').as('zoomBtn');
|
cy.get('[data-cy="Zoom"]').as('zoomBtn');
|
||||||
cy.get('[data-cy="WindowLevel-split-button-primary"]').as('wwwcBtnPrimary');
|
cy.get('[data-cy="WindowLevelGroup-split-button-primary"]').as('wwwcBtnPrimary');
|
||||||
cy.get('[data-cy="WindowLevel-split-button-secondary"]').as('wwwcBtnSecondary');
|
cy.get('[data-cy="WindowLevelGroup-split-button-secondary"]').as('wwwcBtnSecondary');
|
||||||
cy.get('[data-cy="Pan"]').as('panBtn');
|
cy.get('[data-cy="Pan"]').as('panBtn');
|
||||||
cy.get('[data-cy="MeasurementTools-split-button-primary"]').as('measurementToolsBtnPrimary');
|
cy.get('[data-cy="MeasurementTools-split-button-primary"]').as('measurementToolsBtnPrimary');
|
||||||
cy.get('[data-cy="MeasurementTools-split-button-secondary"]').as('measurementToolsBtnSecondary');
|
cy.get('[data-cy="MeasurementTools-split-button-secondary"]').as('measurementToolsBtnSecondary');
|
||||||
|
|||||||
@ -54,7 +54,7 @@
|
|||||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||||
"@cornerstonejs/dicom-image-loader": "^3.0.1",
|
"@cornerstonejs/dicom-image-loader": "^3.0.4",
|
||||||
"@emotion/serialize": "^1.1.3",
|
"@emotion/serialize": "^1.1.3",
|
||||||
"@ohif/core": "3.10.0-beta.116",
|
"@ohif/core": "3.10.0-beta.116",
|
||||||
"@ohif/extension-cornerstone": "3.10.0-beta.116",
|
"@ohif/extension-cornerstone": "3.10.0-beta.116",
|
||||||
|
|||||||
@ -6,13 +6,7 @@ window.config = {
|
|||||||
// whiteLabeling: {},
|
// whiteLabeling: {},
|
||||||
extensions: [],
|
extensions: [],
|
||||||
modes: [],
|
modes: [],
|
||||||
customizationService: {
|
customizationService: {},
|
||||||
'viewportActionMenu.windowLevelActionMenu': {
|
|
||||||
$merge: {
|
|
||||||
location: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
showStudyList: true,
|
showStudyList: true,
|
||||||
// some windows systems have issues with more than 3 web workers
|
// some windows systems have issues with more than 3 web workers
|
||||||
maxNumberOfWebWorkers: 3,
|
maxNumberOfWebWorkers: 3,
|
||||||
|
|||||||
@ -26,7 +26,6 @@ import {
|
|||||||
ViewportGridProvider,
|
ViewportGridProvider,
|
||||||
DialogProvider,
|
DialogProvider,
|
||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
ToolboxProvider,
|
|
||||||
Modal as ModalNext,
|
Modal as ModalNext,
|
||||||
ManagedDialog,
|
ManagedDialog,
|
||||||
ModalProvider,
|
ModalProvider,
|
||||||
@ -117,7 +116,6 @@ function App({
|
|||||||
[ThemeWrapperNext],
|
[ThemeWrapperNext],
|
||||||
[ThemeWrapper],
|
[ThemeWrapper],
|
||||||
[SystemContextProvider, { commandsManager, extensionManager, hotkeysManager, servicesManager }],
|
[SystemContextProvider, { commandsManager, extensionManager, hotkeysManager, servicesManager }],
|
||||||
[ToolboxProvider],
|
|
||||||
[ViewportGridProvider, { service: viewportGridService }],
|
[ViewportGridProvider, { service: viewportGridService }],
|
||||||
[ViewportDialogProvider, { service: uiViewportDialogService }],
|
[ViewportDialogProvider, { service: uiViewportDialogService }],
|
||||||
[CineProvider, { service: cineService }],
|
[CineProvider, { service: cineService }],
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { hotkeys } from '@ohif/core';
|
|
||||||
import { initToolGroups, toolbarButtons } from '@ohif/mode-longitudinal';
|
import { initToolGroups, toolbarButtons } from '@ohif/mode-longitudinal';
|
||||||
import { id } from './id';
|
import { id } from './id';
|
||||||
|
|
||||||
@ -50,14 +49,47 @@ function modeFactory({ modeConfiguration }) {
|
|||||||
|
|
||||||
toolbarService.addButtons(toolbarButtons);
|
toolbarService.addButtons(toolbarButtons);
|
||||||
toolbarService.createButtonSection('primary', [
|
toolbarService.createButtonSection('primary', [
|
||||||
'MeasurementTools',
|
'measurementSection',
|
||||||
'Zoom',
|
'Zoom',
|
||||||
'WindowLevel',
|
'WindowLevel',
|
||||||
'Pan',
|
'Pan',
|
||||||
'Capture',
|
'Capture',
|
||||||
'Layout',
|
'Layout',
|
||||||
'Crosshairs',
|
'Crosshairs',
|
||||||
'MoreTools',
|
'moreToolsSection',
|
||||||
|
]);
|
||||||
|
|
||||||
|
toolbarService.createButtonSection('measurementSection', [
|
||||||
|
'Length',
|
||||||
|
'Bidirectional',
|
||||||
|
'ArrowAnnotate',
|
||||||
|
'EllipticalROI',
|
||||||
|
'RectangleROI',
|
||||||
|
'CircleROI',
|
||||||
|
'PlanarFreehandROI',
|
||||||
|
'SplineROI',
|
||||||
|
'LivewireContour',
|
||||||
|
]);
|
||||||
|
|
||||||
|
toolbarService.createButtonSection('moreToolsSection', [
|
||||||
|
'Reset',
|
||||||
|
'rotate-right',
|
||||||
|
'flipHorizontal',
|
||||||
|
'ImageSliceSync',
|
||||||
|
'ReferenceLines',
|
||||||
|
'ImageOverlayViewer',
|
||||||
|
'StackScroll',
|
||||||
|
'invert',
|
||||||
|
'Probe',
|
||||||
|
'Cine',
|
||||||
|
'Angle',
|
||||||
|
'CobbAngle',
|
||||||
|
'Magnify',
|
||||||
|
'CalibrationLine',
|
||||||
|
'TagBrowser',
|
||||||
|
'AdvancedMagnify',
|
||||||
|
'UltrasoundDirectionalTool',
|
||||||
|
'WindowLevelRegion',
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
onModeExit: ({ servicesManager }: withAppTypes) => {
|
onModeExit: ({ servicesManager }: withAppTypes) => {
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
|
||||||
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
"@cornerstonejs/codec-openjpeg": "^1.2.4",
|
||||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||||
"@cornerstonejs/dicom-image-loader": "^3.0.1",
|
"@cornerstonejs/dicom-image-loader": "^3.0.4",
|
||||||
"@ohif/ui": "3.10.0-beta.116",
|
"@ohif/ui": "3.10.0-beta.116",
|
||||||
"cornerstone-math": "0.1.9",
|
"cornerstone-math": "0.1.9",
|
||||||
"dicom-parser": "^1.8.21"
|
"dicom-parser": "^1.8.21"
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { useSystem } from '../contextProviders/SystemProvider';
|
||||||
|
|
||||||
export function useToolbar({ servicesManager, buttonSection = 'primary' }: withAppTypes) {
|
export function useToolbar({ buttonSection = 'primary' }: withAppTypes) {
|
||||||
|
const { commandsManager, servicesManager } = useSystem();
|
||||||
const { toolbarService, viewportGridService } = servicesManager.services;
|
const { toolbarService, viewportGridService } = servicesManager.services;
|
||||||
const { EVENTS } = toolbarService;
|
const { EVENTS } = toolbarService;
|
||||||
|
|
||||||
@ -11,15 +13,54 @@ export function useToolbar({ servicesManager, buttonSection = 'primary' }: withA
|
|||||||
// Callback function for handling toolbar interactions
|
// Callback function for handling toolbar interactions
|
||||||
const onInteraction = useCallback(
|
const onInteraction = useCallback(
|
||||||
args => {
|
args => {
|
||||||
|
args.event?.stopPropagation?.();
|
||||||
const viewportId = viewportGridService.getActiveViewportId();
|
const viewportId = viewportGridService.getActiveViewportId();
|
||||||
const refreshProps = {
|
const refreshProps = { viewportId };
|
||||||
viewportId,
|
|
||||||
};
|
const buttonProps = toolbarService.getButtonProps(args.itemId);
|
||||||
toolbarService.recordInteraction(args, {
|
|
||||||
refreshProps,
|
if (buttonProps.commands || buttonProps.options) {
|
||||||
});
|
const allCommands = [];
|
||||||
|
const options = buttonProps.options || [];
|
||||||
|
const itemCommands = buttonProps.commands || [];
|
||||||
|
|
||||||
|
// Process item commands
|
||||||
|
if (itemCommands) {
|
||||||
|
Array.isArray(itemCommands)
|
||||||
|
? allCommands.push(...itemCommands)
|
||||||
|
: allCommands.push(itemCommands);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process commands from options
|
||||||
|
if (options.length > 0) {
|
||||||
|
options.forEach(option => {
|
||||||
|
if (!option.commands) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const valueToUse = option.value;
|
||||||
|
const commands = Array.isArray(option.commands) ? option.commands : [option.commands];
|
||||||
|
|
||||||
|
commands.forEach(command => {
|
||||||
|
const commandOptions = {
|
||||||
|
...option,
|
||||||
|
value: valueToUse,
|
||||||
|
options: buttonProps.options,
|
||||||
|
servicesManager: servicesManager,
|
||||||
|
commandsManager: commandsManager,
|
||||||
|
};
|
||||||
|
|
||||||
|
const processedCommand = () => commandsManager.run(command, commandOptions);
|
||||||
|
allCommands.push(processedCommand);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonProps.commands = allCommands;
|
||||||
|
}
|
||||||
|
toolbarService.recordInteraction({ ...args, ...buttonProps }, { refreshProps });
|
||||||
},
|
},
|
||||||
[toolbarService, viewportGridService]
|
[toolbarService, viewportGridService, toolbarButtons]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Effect to handle toolbar modification events
|
// Effect to handle toolbar modification events
|
||||||
|
|||||||
@ -134,7 +134,7 @@ export default class ToolbarService extends PubSubService {
|
|||||||
buttons.forEach(button => {
|
buttons.forEach(button => {
|
||||||
if (replace || !this.state.buttons[button.id]) {
|
if (replace || !this.state.buttons[button.id]) {
|
||||||
if (!button.props) {
|
if (!button.props) {
|
||||||
button.props = {};
|
button.props = {} as ButtonProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.state.buttons[button.id] = button;
|
this.state.buttons[button.id] = button;
|
||||||
@ -173,12 +173,16 @@ export default class ToolbarService extends PubSubService {
|
|||||||
? interaction.commands
|
? interaction.commands
|
||||||
: [interaction.commands];
|
: [interaction.commands];
|
||||||
|
|
||||||
|
commands = commands.filter(Boolean);
|
||||||
|
|
||||||
if (!commands?.length) {
|
if (!commands?.length) {
|
||||||
this.refreshToolbarState({
|
this.refreshToolbarState({
|
||||||
...options?.refreshProps,
|
...options?.refreshProps,
|
||||||
itemId,
|
itemId,
|
||||||
interaction,
|
interaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const commandOptions = { ...options, ...interaction };
|
const commandOptions = { ...options, ...interaction };
|
||||||
@ -228,10 +232,6 @@ export default class ToolbarService extends PubSubService {
|
|||||||
*/
|
*/
|
||||||
public refreshToolbarState(refreshProps) {
|
public refreshToolbarState(refreshProps) {
|
||||||
const buttons = this.state.buttons;
|
const buttons = this.state.buttons;
|
||||||
|
|
||||||
// Tracks evaluated buttons to avoid re-evaluating them (this will
|
|
||||||
// cause issue for toggles where if the button is in primary
|
|
||||||
// and secondary it will be evaluated twice)
|
|
||||||
const evaluationResults = new Map();
|
const evaluationResults = new Map();
|
||||||
|
|
||||||
const evaluateButtonProps = (button, props, refreshProps) => {
|
const evaluateButtonProps = (button, props, refreshProps) => {
|
||||||
@ -252,59 +252,50 @@ export default class ToolbarService extends PubSubService {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshedButtons = Object.values(buttons).reduce((acc, button: Button) => {
|
Object.values(buttons).forEach(button => {
|
||||||
const isNested = (button.props as NestedButtonProps)?.groupId;
|
const hasSection = (button.props as NestedButtonProps)?.buttonSection;
|
||||||
|
|
||||||
if (!isNested) {
|
if (!hasSection) {
|
||||||
this.handleEvaluate(button.props);
|
this.handleEvaluate(button.props);
|
||||||
const buttonProps = button.props as ButtonProps;
|
const buttonProps = button.props as ButtonProps;
|
||||||
|
|
||||||
const updatedProps = evaluateButtonProps(button, buttonProps, refreshProps);
|
const updatedProps = evaluateButtonProps(button, buttonProps, refreshProps);
|
||||||
acc[button.id] = {
|
buttons[button.id] = {
|
||||||
...button,
|
...button,
|
||||||
props: updatedProps,
|
props: updatedProps,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
let buttonProps = button.props as NestedButtonProps;
|
let buttonProps = button.props as NestedButtonProps;
|
||||||
// if it is nested we should perform evaluate on each item in the group
|
|
||||||
this.handleEvaluateNested(buttonProps);
|
|
||||||
|
|
||||||
const { evaluate: groupEvaluate } = buttonProps;
|
const { evaluate: groupEvaluate } = buttonProps;
|
||||||
|
const groupEvaluated =
|
||||||
|
typeof groupEvaluate === 'function'
|
||||||
|
? groupEvaluate({ ...refreshProps, button })
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const groupEvaluated = groupEvaluate?.({ ...refreshProps, button });
|
|
||||||
// handle group evaluate function which might switch the primary
|
|
||||||
// item in the group
|
|
||||||
buttonProps = {
|
buttonProps = {
|
||||||
...buttonProps,
|
...buttonProps,
|
||||||
primary: groupEvaluated?.primary ?? buttonProps.primary,
|
|
||||||
disabled: groupEvaluated?.disabled ?? buttonProps.disabled,
|
disabled: groupEvaluated?.disabled ?? buttonProps.disabled,
|
||||||
disabledText: groupEvaluated?.disabledText ?? buttonProps.disabledText,
|
disabledText: groupEvaluated?.disabledText ?? buttonProps.disabledText,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { primary, items } = buttonProps;
|
const toolButtonIds = this.state.buttonSections[buttonProps.buttonSection];
|
||||||
|
|
||||||
// primary and items evaluate functions
|
if (!toolButtonIds) {
|
||||||
let updatedPrimary;
|
return;
|
||||||
if (primary) {
|
|
||||||
updatedPrimary = evaluateButtonProps(primary, primary, refreshProps);
|
|
||||||
}
|
}
|
||||||
const updatedItems = items.map(item => evaluateButtonProps(item, item, refreshProps));
|
|
||||||
buttonProps = {
|
|
||||||
...buttonProps,
|
|
||||||
primary: updatedPrimary,
|
|
||||||
items: updatedItems,
|
|
||||||
};
|
|
||||||
|
|
||||||
acc[button.id] = {
|
toolButtonIds.forEach(buttonId => {
|
||||||
...button,
|
const button = buttons[buttonId];
|
||||||
props: buttonProps,
|
const updatedProps = evaluateButtonProps(button, button.props, refreshProps);
|
||||||
};
|
buttons[buttonId] = {
|
||||||
|
...button,
|
||||||
|
props: updatedProps,
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return acc;
|
this.setButtons(buttons);
|
||||||
}, {});
|
|
||||||
|
|
||||||
this.setButtons(refreshedButtons);
|
|
||||||
return this.state;
|
return this.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,17 +340,6 @@ export default class ToolbarService extends PubSubService {
|
|||||||
* @returns The button properties.
|
* @returns The button properties.
|
||||||
*/
|
*/
|
||||||
public getButtonProps(id: string): ButtonProps {
|
public getButtonProps(id: string): ButtonProps {
|
||||||
for (const buttonId of Object.keys(this.state.buttons)) {
|
|
||||||
const { primary, items } = (this.state.buttons[buttonId].props as NestedButtonProps) || {};
|
|
||||||
if (primary?.id === id) {
|
|
||||||
return primary;
|
|
||||||
}
|
|
||||||
const found = items?.find(childButton => childButton.id === id);
|
|
||||||
if (found) {
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This should be checked after we checked the nested buttons, since
|
// This should be checked after we checked the nested buttons, since
|
||||||
// we are checking based on the ids, the nested objects are higher priority
|
// we are checking based on the ids, the nested objects are higher priority
|
||||||
// and more specific
|
// and more specific
|
||||||
@ -421,6 +401,12 @@ export default class ToolbarService extends PubSubService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getButtonPropsInButtonSection(sectionId: string) {
|
||||||
|
const buttonSectionIds = this.state.buttonSections[sectionId];
|
||||||
|
|
||||||
|
return buttonSectionIds?.map(btnId => this.getButtonProps(btnId)) || [];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the tool name for a given button.
|
* Retrieves the tool name for a given button.
|
||||||
* @param button - The button object.
|
* @param button - The button object.
|
||||||
@ -448,41 +434,119 @@ export default class ToolbarService extends PubSubService {
|
|||||||
* @param {*} metadata
|
* @param {*} metadata
|
||||||
* @param {*} props - Props set by the Viewer layer
|
* @param {*} props - Props set by the Viewer layer
|
||||||
*/
|
*/
|
||||||
_mapButtonToDisplay(btn, props) {
|
_mapButtonToDisplay(btn: Button, props: Record<string, unknown>) {
|
||||||
if (!btn) {
|
if (!btn) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id, uiType, component } = btn;
|
const { id, uiType } = btn;
|
||||||
const { groupId } = btn.props;
|
const { groupId } = btn.props as NestedButtonProps;
|
||||||
|
|
||||||
const buttonTypes = this._getButtonUITypes();
|
const buttonTypes = this._getButtonUITypes();
|
||||||
|
|
||||||
const buttonType = buttonTypes[uiType];
|
const buttonType = buttonTypes[uiType];
|
||||||
|
|
||||||
if (!buttonType && !component) {
|
if (!btn.component) {
|
||||||
|
btn.component = buttonType.defaultComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buttonType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
!groupId ? this.handleEvaluate(btn.props) : this.handleEvaluateNested(btn.props);
|
!groupId ? this.handleEvaluate(btn.props) : this.handleEvaluateNested(btn.props);
|
||||||
|
|
||||||
|
const { id: buttonId, props: componentProps } = btn;
|
||||||
|
|
||||||
|
const createEnhancedOptions = (options, itemId) => {
|
||||||
|
const optionsToUse = Array.isArray(options) ? options : [options];
|
||||||
|
const toolProps = this.getButtonProps(itemId);
|
||||||
|
|
||||||
|
return optionsToUse.map(option => {
|
||||||
|
if (typeof option.optionComponent === 'function') {
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...option,
|
||||||
|
onChange: value => {
|
||||||
|
// Update the option's value for UI
|
||||||
|
option.value = value;
|
||||||
|
|
||||||
|
const cmds = Array.isArray(option.commands) ? option.commands : [option.commands];
|
||||||
|
|
||||||
|
// Find the parent button and update its options
|
||||||
|
if (toolProps && toolProps.options) {
|
||||||
|
// Find the option in the button's options array and update its value
|
||||||
|
const optionIndex = toolProps.options.findIndex(opt => opt.id === option.id);
|
||||||
|
if (optionIndex !== -1) {
|
||||||
|
toolProps.options[optionIndex].value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmds.forEach(command => {
|
||||||
|
const commandOptions = {
|
||||||
|
...option,
|
||||||
|
value,
|
||||||
|
options: toolProps.options,
|
||||||
|
servicesManager: this._servicesManager,
|
||||||
|
commandsManager: this._commandsManager,
|
||||||
|
};
|
||||||
|
|
||||||
|
this._commandsManager.run(command, commandOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Notify that toolbar state has been modified
|
||||||
|
this._broadcastEvent(EVENTS.TOOL_BAR_STATE_MODIFIED, {
|
||||||
|
buttons: this.state.buttons,
|
||||||
|
buttonSections: this.state.buttonSections,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((componentProps as NestedButtonProps)?.items?.length) {
|
||||||
|
const { items = [] } = componentProps as NestedButtonProps;
|
||||||
|
|
||||||
|
items.forEach(item => {
|
||||||
|
if (!item.options) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item.options = createEnhancedOptions(item.options, item.id);
|
||||||
|
});
|
||||||
|
} else if ((componentProps as ButtonProps).options?.length) {
|
||||||
|
(componentProps as ButtonProps).options = createEnhancedOptions(
|
||||||
|
(componentProps as ButtonProps).options,
|
||||||
|
buttonId
|
||||||
|
);
|
||||||
|
} else if ((componentProps as ButtonProps).optionComponent) {
|
||||||
|
(componentProps as ButtonProps).optionComponent = options.optionComponent;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
Component: component || buttonType.defaultComponent,
|
Component: btn.component,
|
||||||
componentProps: Object.assign({}, btn.props, props),
|
componentProps: Object.assign({ id }, btn.props, props),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEvaluateNested = props => {
|
handleEvaluateNested = props => {
|
||||||
const { primary, items } = props;
|
const { buttonSection } = props;
|
||||||
// handle group evaluate function
|
|
||||||
this.handleEvaluate(props);
|
|
||||||
|
|
||||||
// primary and items evaluate functions
|
if (!buttonSection) {
|
||||||
if (primary) {
|
return;
|
||||||
this.handleEvaluate(primary);
|
|
||||||
}
|
}
|
||||||
items.forEach(item => this.handleEvaluate(item));
|
|
||||||
|
const toolbarButtons = this.getButtonSection(buttonSection);
|
||||||
|
|
||||||
|
if (!toolbarButtons?.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toolbarButtons.forEach(button => {
|
||||||
|
this.handleEvaluate(button.componentProps);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleEvaluate = props => {
|
handleEvaluate = props => {
|
||||||
@ -492,9 +556,7 @@ export default class ToolbarService extends PubSubService {
|
|||||||
// get the custom option component from the extension manager and set it as the optionComponent
|
// get the custom option component from the extension manager and set it as the optionComponent
|
||||||
const buttonTypes = this._getButtonUITypes();
|
const buttonTypes = this._getButtonUITypes();
|
||||||
const optionComponent = buttonTypes[options]?.defaultComponent;
|
const optionComponent = buttonTypes[options]?.defaultComponent;
|
||||||
props.options = {
|
props.options = optionComponent;
|
||||||
optionComponent,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof evaluate === 'function') {
|
if (typeof evaluate === 'function') {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import type { RunCommand } from '../../types/Command';
|
import type { RunCommand } from '../../types/Command';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
export type EvaluatePublic =
|
export type EvaluatePublic =
|
||||||
| string
|
| string
|
||||||
@ -17,6 +18,20 @@ export type EvaluateObject = {
|
|||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ButtonOptions = {
|
||||||
|
id: string;
|
||||||
|
type: 'range' | 'radio' | 'double-range' | 'custom';
|
||||||
|
name?: string;
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
step?: number;
|
||||||
|
value?: number | number[] | string;
|
||||||
|
commands?: (value: unknown) => void;
|
||||||
|
condition?: (props: Record<string, unknown>) => boolean;
|
||||||
|
children?: React.ReactNode | (() => React.ReactNode);
|
||||||
|
options?: Array<{ value: string; label: string }>;
|
||||||
|
};
|
||||||
|
|
||||||
export type ButtonProps = {
|
export type ButtonProps = {
|
||||||
id: string;
|
id: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
@ -27,27 +42,15 @@ export type ButtonProps = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
evaluate?: EvaluatePublic;
|
evaluate?: EvaluatePublic;
|
||||||
listeners?: Record<string, RunCommand>;
|
listeners?: Record<string, RunCommand>;
|
||||||
};
|
options?: ButtonOptions[];
|
||||||
|
buttonSection?: string;
|
||||||
export type NestedButtonProps = {
|
|
||||||
groupId: string;
|
|
||||||
// group evaluate which is different
|
|
||||||
// from the evaluate function for the primary and items
|
|
||||||
evaluate?: EvaluatePublic;
|
|
||||||
items: ButtonProps[];
|
|
||||||
primary: ButtonProps & {
|
|
||||||
// Todo: this is really ugly but really we don't have any other option
|
|
||||||
// the ui design requires this since the button should be rounded if
|
|
||||||
// active otherwise it should not be rounded
|
|
||||||
isActive?: boolean;
|
|
||||||
};
|
|
||||||
secondary: ButtonProps;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Button = {
|
export type Button = {
|
||||||
id: string;
|
id: string;
|
||||||
props: ButtonProps | NestedButtonProps;
|
props: ButtonProps;
|
||||||
// button ui type (e.g. 'ohif.splitButton', 'ohif.radioGroup')
|
// button ui type (e.g. 'ohif.splitButton', 'ohif.radioGroup')
|
||||||
// extensions can provide custom components for these types
|
// extensions can provide custom components for these types
|
||||||
uiType: string;
|
uiType: string;
|
||||||
|
component?: React.ComponentType<any>;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -27,7 +27,7 @@ export const EVENTS = {
|
|||||||
sections: [
|
sections: [
|
||||||
{
|
{
|
||||||
key: 'primary',
|
key: 'primary',
|
||||||
buttons: [ 'MeasurementTools', 'Zoom', ... ],
|
buttons: [ 'measurementSection', 'Zoom', ... ],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -72,11 +72,114 @@ The `ohif.buttonGroup` and `ohif.radioGroup` types used in the Toolbox have been
|
|||||||
The `getToolbarModule` function previously returned `disabled`, `disabledText`, and `className` as part of its evaluation process for the button state. These properties will still be returned, but common class names are now handled internally by the new UI button components, including `ToolButton`, `ToolButtonList`, `Toolbox`, and `ToolBoxGroup`. You can override the `className` if you need to.
|
The `getToolbarModule` function previously returned `disabled`, `disabledText`, and `className` as part of its evaluation process for the button state. These properties will still be returned, but common class names are now handled internally by the new UI button components, including `ToolButton`, `ToolButtonList`, `Toolbox`, and `ToolBoxGroup`. You can override the `className` if you need to.
|
||||||
|
|
||||||
|
|
||||||
|
## Tool Definitions: Moving to Section-Based Definitions
|
||||||
|
|
||||||
|
This migration represents a significant step toward a more extension-based toolbar system. We've moved away from the nested primary/items structure in favor of a flatter, more composable section-based approach.
|
||||||
|
|
||||||
|
### Deprecated: Nested Toolbar Structures
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- {
|
||||||
|
- id: 'MeasurementTools',
|
||||||
|
- uiType: 'ohif.toolButtonList',
|
||||||
|
- props: {
|
||||||
|
- groupId: 'MeasurementTools',
|
||||||
|
- evaluate: 'evaluate.group.promoteToPrimaryIfCornerstoneToolNotActiveInTheList',
|
||||||
|
- primary: createButton({
|
||||||
|
- id: 'Length',
|
||||||
|
- icon: 'tool-length',
|
||||||
|
- label: 'Length',
|
||||||
|
- tooltip: 'Length Tool',
|
||||||
|
- commands: setToolActiveToolbar,
|
||||||
|
- evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
- }),
|
||||||
|
- secondary: {
|
||||||
|
- icon: 'chevron-down',
|
||||||
|
- tooltip: 'More Measure Tools',
|
||||||
|
- },
|
||||||
|
- items: [
|
||||||
|
- createButton({ ... }),
|
||||||
|
- createButton({ ... }),
|
||||||
|
- // More nested buttons
|
||||||
|
- ],
|
||||||
|
- },
|
||||||
|
- }
|
||||||
|
```
|
||||||
|
|
||||||
|
### New Approach: Section-Based Definitions
|
||||||
|
|
||||||
|
```diff
|
||||||
|
+ // 1. Define the toolbar section container
|
||||||
|
+ {
|
||||||
|
+ id: 'MeasurementTools',
|
||||||
|
+ uiType: 'ohif.toolButtonList',
|
||||||
|
+ props: {
|
||||||
|
+ buttonSection: 'measurementSection',
|
||||||
|
+ groupId: 'MeasurementTools',
|
||||||
|
+ },
|
||||||
|
+ },
|
||||||
|
+ // 2. Register individual buttons separately
|
||||||
|
+ {
|
||||||
|
+ id: 'Length',
|
||||||
|
+ uiType: 'ohif.toolButton',
|
||||||
|
+ props: {
|
||||||
|
+ icon: 'tool-length',
|
||||||
|
+ label: 'Length',
|
||||||
|
+ tooltip: 'Length Tool',
|
||||||
|
+ commands: setToolActiveToolbar,
|
||||||
|
+ evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
+ },
|
||||||
|
+ },
|
||||||
|
+ {
|
||||||
|
+ id: 'Bidirectional',
|
||||||
|
+ uiType: 'ohif.toolButton',
|
||||||
|
+ props: {
|
||||||
|
+ icon: 'tool-bidirectional',
|
||||||
|
+ label: 'Bidirectional',
|
||||||
|
+ tooltip: 'Bidirectional Tool',
|
||||||
|
+ commands: setToolActiveToolbar,
|
||||||
|
+ evaluate: 'evaluate.cornerstoneTool',
|
||||||
|
+ },
|
||||||
|
+ },
|
||||||
|
```
|
||||||
|
|
||||||
|
and then in your mode you can compose the section and associate buttons
|
||||||
|
|
||||||
|
```diff
|
||||||
|
+ // 3. In your mode, create the section and associate buttons
|
||||||
|
+ toolbarService.createButtonSection('primary', [
|
||||||
|
+ 'MeasurementTools',
|
||||||
|
+ 'Pan',
|
||||||
|
+ 'Zoom',
|
||||||
|
+ ]);
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ toolbarService.createButtonSection('measurementSection', [
|
||||||
|
+ 'Length',
|
||||||
|
+ 'Bidirectional',
|
||||||
|
+ 'ArrowAnnotate',
|
||||||
|
+ 'EllipticalROI',
|
||||||
|
+ ]);
|
||||||
|
```
|
||||||
|
|
||||||
|
:::note
|
||||||
|
The `measurementSection` is defined in the tool button configuration of the `MeasurementTools` button.
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
### Group Evaluators Deprecated
|
||||||
|
|
||||||
|
Group evaluator functions like `evaluate.group.promoteToPrimaryIfCornerstoneToolNotActiveInTheList` are now deprecated. Instead, the `uiType` component itself is responsible for grouping and displaying the buttons from a section as needed. This allows for more flexible UI implementations that aren't tied to specific evaluation logic.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## ToolBox
|
## ToolBox
|
||||||
|
|
||||||
Previously, the segmentation toolbox was not using an `evaluator` property. This is now taken into account
|
Previously, the segmentation toolbox was not using an `evaluator` property. This is now taken into account
|
||||||
|
|
||||||
|
|
||||||
|
### evaluators in Toolbox
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// old
|
// old
|
||||||
{
|
{
|
||||||
@ -84,7 +187,6 @@ Previously, the segmentation toolbox was not using an `evaluator` property. This
|
|||||||
uiType: 'ohif.buttonGroup',
|
uiType: 'ohif.buttonGroup',
|
||||||
props: {
|
props: {
|
||||||
groupId: 'BrushTools',
|
groupId: 'BrushTools',
|
||||||
items: []
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +197,237 @@ Previously, the segmentation toolbox was not using an `evaluator` property. This
|
|||||||
props: {
|
props: {
|
||||||
groupId: 'BrushTools',
|
groupId: 'BrushTools',
|
||||||
evaluate: 'evaluate.cornerstone.hasSegmentation',
|
evaluate: 'evaluate.cornerstone.hasSegmentation',
|
||||||
items: []
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Replace Toolbox imports from ui-next with extension-default
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- import { Toolbox } from '@ohif/ui-next';
|
||||||
|
+ import { Toolbox } from '@ohif/extension-default';
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Ensure you're importing the Toolbox component from the correct location:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// New import pattern
|
||||||
|
import { Toolbox } from '@ohif/extension-default';
|
||||||
|
|
||||||
|
// Usage remains similar
|
||||||
|
<Toolbox
|
||||||
|
servicesManager={servicesManager}
|
||||||
|
buttonSectionId="segmentation"
|
||||||
|
title="Segmentation Tools"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stacked Sections in Toolbox
|
||||||
|
|
||||||
|
The new Toolbox component supports stacked sections, which allows for more complex UI organization. Instead of flat button groups, you can now create deep hierarchies of tool sections and subsections.
|
||||||
|
|
||||||
|
|
||||||
|
Previously you were able to have something like this
|
||||||
|
|
||||||
|
```js
|
||||||
|
// old
|
||||||
|
// buttons for BrushTools were a giant group of buttons
|
||||||
|
const buttons = {
|
||||||
|
id: 'BrushTools',
|
||||||
|
uiType: 'ohif.toolBoxButtonGroup',
|
||||||
|
props: {
|
||||||
|
groupId: 'BrushTools',
|
||||||
|
evaluate: 'evaluate.cornerstone.hasSegmentation',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'Brush',
|
||||||
|
icon: 'icon-tool-brush',
|
||||||
|
label: 'Brush',
|
||||||
|
evaluate: {
|
||||||
|
// ...
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
// ...
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Eraser',
|
||||||
|
icon: 'icon-tool-eraser',
|
||||||
|
label: 'Eraser',
|
||||||
|
evaluate: {
|
||||||
|
// ...
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
// ...
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Threshold',
|
||||||
|
icon: 'icon-tool-threshold',
|
||||||
|
label: 'Threshold Tool',
|
||||||
|
evaluate: {
|
||||||
|
// ...
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
// ...
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Shapes',
|
||||||
|
uiType: 'ohif.toolBoxButton',
|
||||||
|
props: {
|
||||||
|
id: 'Shapes',
|
||||||
|
icon: 'icon-tool-shape',
|
||||||
|
label: 'Shapes',
|
||||||
|
evaluate: {
|
||||||
|
// ...
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
// ...
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
toolbarService.addButtons(buttons);
|
||||||
|
|
||||||
|
toolbarService.createButtonSection('segmentationToolbox', ['BrushTools', 'Shapes']);
|
||||||
|
```
|
||||||
|
|
||||||
|
But now you should have at least one section defined in your toolbar buttons
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
// separate flat definitions for each button and each section
|
||||||
|
const buttons = [
|
||||||
|
{
|
||||||
|
id: 'Brush',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-brush',
|
||||||
|
label: 'Brush',
|
||||||
|
evaluate: {
|
||||||
|
// ...
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
// ...
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Eraser',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-eraser',
|
||||||
|
label: 'Eraser',
|
||||||
|
evaluate: {
|
||||||
|
// ...
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
// ...
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Threshold',
|
||||||
|
uiType: 'ohif.toolButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-threshold',
|
||||||
|
label: 'Threshold Tool',
|
||||||
|
evaluate: {
|
||||||
|
// ...
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
// ...
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Shapes',
|
||||||
|
uiType: 'ohif.toolBoxButton',
|
||||||
|
props: {
|
||||||
|
icon: 'icon-tool-shape',
|
||||||
|
label: 'Shapes',
|
||||||
|
evaluate: {
|
||||||
|
name: 'evaluate.cornerstone.segmentation',
|
||||||
|
toolNames: ['CircleScissor', 'SphereScissor', 'RectangleScissor'],
|
||||||
|
disabledText: 'Create new segmentation to enable shapes tool.',
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
// ...
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Sections
|
||||||
|
{
|
||||||
|
id: 'SegmentationTools',
|
||||||
|
uiType: 'ohif.toolBoxButton',
|
||||||
|
props: {
|
||||||
|
groupId: 'SegmentationTools',
|
||||||
|
buttonSection: 'segmentationToolboxToolsSection',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'BrushTools',
|
||||||
|
uiType: 'ohif.toolBoxButtonGroup',
|
||||||
|
props: {
|
||||||
|
groupId: 'BrushTools',
|
||||||
|
buttonSection: 'brushToolsSection',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
toolbarService.addButtons(buttons);
|
||||||
|
```
|
||||||
|
|
||||||
|
and then
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Step 2: Create the section hierarchy
|
||||||
|
// Top level toolbox section
|
||||||
|
toolbarService.createButtonSection('segmentationToolbox', ['SegmentationTools']);
|
||||||
|
|
||||||
|
// Next level - subsections within the toolbox
|
||||||
|
toolbarService.createButtonSection('segmentationToolboxToolsSection', ['BrushTools', 'Shapes']);
|
||||||
|
|
||||||
|
// Lowest level - buttons within a subsection
|
||||||
|
toolbarService.createButtonSection('brushToolsSection', ['Brush', 'Eraser', 'Threshold']);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Remove ToolboxProvider from composition root
|
||||||
|
|
||||||
|
If you have the ToolboxProvider in your application composition, remove it:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
// In App.tsx or similar
|
||||||
|
const appComposition = [
|
||||||
|
[ThemeWrapperNext],
|
||||||
|
[ThemeWrapper],
|
||||||
|
[SystemContextProvider, { commandsManager, extensionManager, hotkeysManager, servicesManager }],
|
||||||
|
- [ToolboxProvider],
|
||||||
|
[ViewportGridProvider, { service: viewportGridService }],
|
||||||
|
// Other providers...
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
we now keep the state for toolbar inside the ToolbarService itself
|
||||||
|
|
||||||
|
### 3. Update tool option handlers to use onChange instead of commands
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- <RowSegmentedControl
|
||||||
|
- key={option.id}
|
||||||
|
- option={option}
|
||||||
|
- />
|
||||||
|
|
||||||
|
+ <RowSegmentedControl
|
||||||
|
+ key={option.id}
|
||||||
|
+ option={option}
|
||||||
|
+ onChange={option.onChange}
|
||||||
|
+ />
|
||||||
|
```
|
||||||
|
|||||||
@ -13,18 +13,23 @@ interface RadioOption {
|
|||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: string;
|
||||||
values: RadioValue[];
|
values: RadioValue[];
|
||||||
commands?: (val: string) => void;
|
onChange?: (val: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RowSegmentedControlProps {
|
interface RowSegmentedControlProps {
|
||||||
option: RadioOption;
|
option: RadioOption;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
onChange?: (val: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RowSegmentedControl: React.FC<RowSegmentedControlProps> = ({ option, className }) => {
|
export const RowSegmentedControl: React.FC<RowSegmentedControlProps> = ({
|
||||||
|
option,
|
||||||
|
className,
|
||||||
|
onChange,
|
||||||
|
}) => {
|
||||||
const handleValueChange = (newVal: string) => {
|
const handleValueChange = (newVal: string) => {
|
||||||
if (option.commands) {
|
if (onChange) {
|
||||||
option.commands(newVal);
|
onChange(newVal);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -56,7 +56,7 @@ const renderRangeSetting = option => {
|
|||||||
maxValue={option.max}
|
maxValue={option.max}
|
||||||
step={option.step}
|
step={option.step}
|
||||||
value={option.value}
|
value={option.value}
|
||||||
onChange={value => option.commands?.(value)}
|
onChange={value => option.onChange?.(value)}
|
||||||
allowNumberEdit={true}
|
allowNumberEdit={true}
|
||||||
inputClassName="ml-1 w-4/5 cursor-pointer"
|
inputClassName="ml-1 w-4/5 cursor-pointer"
|
||||||
/>
|
/>
|
||||||
@ -70,6 +70,7 @@ const renderRadioSetting = option => {
|
|||||||
<RowSegmentedControl
|
<RowSegmentedControl
|
||||||
key={option.id}
|
key={option.id}
|
||||||
option={option}
|
option={option}
|
||||||
|
onChange={option.onChange}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -79,7 +80,7 @@ function renderDoubleRangeSetting(option) {
|
|||||||
<RowDoubleRange
|
<RowDoubleRange
|
||||||
key={option.id}
|
key={option.id}
|
||||||
values={option.value}
|
values={option.value}
|
||||||
onChange={option.commands}
|
onChange={option.onChange}
|
||||||
minValue={option.min}
|
minValue={option.min}
|
||||||
maxValue={option.max}
|
maxValue={option.max}
|
||||||
step={option.step}
|
step={option.step}
|
||||||
|
|||||||
@ -1,162 +0,0 @@
|
|||||||
import React, { useEffect, useRef } from 'react';
|
|
||||||
import { ToolboxUI, useToolbox } from '../../';
|
|
||||||
import { useToolbar } from '@ohif/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A toolbox is a collection of buttons and commands that they invoke, used to provide
|
|
||||||
* custom control panels to users. This component is a generic UI component that
|
|
||||||
* interacts with services and commands in a generic fashion. While it might
|
|
||||||
* seem unconventional to import it from the UI and integrate it into the JSX,
|
|
||||||
* it belongs in the UI components as there isn't anything in this component that
|
|
||||||
* couldn't be used for a completely different type of app. It plays a crucial
|
|
||||||
* role in enhancing the app with a toolbox by providing a way to integrate
|
|
||||||
* and display various tools and their corresponding options
|
|
||||||
*/
|
|
||||||
function Toolbox({
|
|
||||||
servicesManager,
|
|
||||||
buttonSectionId,
|
|
||||||
commandsManager,
|
|
||||||
title,
|
|
||||||
...props
|
|
||||||
}: withAppTypes) {
|
|
||||||
// We should move these outside of the platform/ui-next, no file here
|
|
||||||
// should rely on the managers and services
|
|
||||||
const { state: toolboxState, api } = useToolbox(buttonSectionId);
|
|
||||||
const { onInteraction, toolbarButtons } = useToolbar({
|
|
||||||
servicesManager,
|
|
||||||
buttonSection: buttonSectionId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const prevButtonIdsRef = useRef('');
|
|
||||||
const prevToolboxStateRef = useRef('');
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const currentButtonIdsStr = JSON.stringify(
|
|
||||||
toolbarButtons.map(button => {
|
|
||||||
const { id, componentProps } = button;
|
|
||||||
if (componentProps.items?.length) {
|
|
||||||
return componentProps.items.map(item => `${item.id}-${item.disabled}`);
|
|
||||||
}
|
|
||||||
return `${id}-${componentProps.disabled}`;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentToolBoxStateStr = JSON.stringify(
|
|
||||||
Object.keys(toolboxState.toolOptions).map(tool => {
|
|
||||||
const options = toolboxState.toolOptions[tool];
|
|
||||||
if (Array.isArray(options)) {
|
|
||||||
return options?.map(option => `${option.id}-${option.value}`);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
prevButtonIdsRef.current === currentButtonIdsStr &&
|
|
||||||
prevToolboxStateRef.current === currentToolBoxStateStr
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
prevButtonIdsRef.current = currentButtonIdsStr;
|
|
||||||
prevToolboxStateRef.current = currentToolBoxStateStr;
|
|
||||||
|
|
||||||
const initializeOptionsWithEnhancements = toolbarButtons.reduce(
|
|
||||||
(accumulator, toolbarButton) => {
|
|
||||||
const { id: buttonId, componentProps } = toolbarButton;
|
|
||||||
|
|
||||||
const createEnhancedOptions = (options, parentId) => {
|
|
||||||
const optionsToUse = Array.isArray(options) ? options : [options];
|
|
||||||
|
|
||||||
return optionsToUse.map(option => {
|
|
||||||
if (typeof option.optionComponent === 'function') {
|
|
||||||
return option;
|
|
||||||
}
|
|
||||||
|
|
||||||
const value =
|
|
||||||
toolboxState.toolOptions?.[parentId]?.find(prop => prop.id === option.id)?.value ??
|
|
||||||
option.value;
|
|
||||||
|
|
||||||
const updatedOptions = toolboxState.toolOptions?.[parentId];
|
|
||||||
|
|
||||||
return {
|
|
||||||
...option,
|
|
||||||
value,
|
|
||||||
commands: value => {
|
|
||||||
api.handleToolOptionChange(parentId, option.id, value);
|
|
||||||
|
|
||||||
const { isArray } = Array;
|
|
||||||
const cmds = isArray(option.commands) ? option.commands : [option.commands];
|
|
||||||
|
|
||||||
cmds.forEach(command => {
|
|
||||||
const isString = typeof command === 'string';
|
|
||||||
const isObject = typeof command === 'object';
|
|
||||||
const isFunction = typeof command === 'function';
|
|
||||||
|
|
||||||
if (isString) {
|
|
||||||
commandsManager.run(command, { value });
|
|
||||||
} else if (isObject) {
|
|
||||||
commandsManager.run({
|
|
||||||
...command,
|
|
||||||
commandOptions: {
|
|
||||||
...command.commandOptions,
|
|
||||||
...option,
|
|
||||||
value,
|
|
||||||
options: updatedOptions,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else if (isFunction) {
|
|
||||||
command({ value, commandsManager, servicesManager, options: updatedOptions });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const { items, options } = componentProps;
|
|
||||||
|
|
||||||
if (items?.length) {
|
|
||||||
items.forEach(({ options, id }) => {
|
|
||||||
if (!options) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
accumulator[id] = createEnhancedOptions(options, id);
|
|
||||||
});
|
|
||||||
} else if (options?.length) {
|
|
||||||
accumulator[buttonId] = createEnhancedOptions(options, buttonId);
|
|
||||||
} else if (options?.optionComponent) {
|
|
||||||
accumulator[buttonId] = options.optionComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return accumulator;
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
|
|
||||||
api.initializeToolOptions(initializeOptionsWithEnhancements);
|
|
||||||
}, [toolbarButtons, api, toolboxState, commandsManager, servicesManager]);
|
|
||||||
|
|
||||||
const handleToolOptionChange = (toolName, optionName, newValue) => {
|
|
||||||
api.handleToolOptionChange(toolName, optionName, newValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
|
||||||
api.handleToolSelect(null);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ToolboxUI
|
|
||||||
{...props}
|
|
||||||
title={title}
|
|
||||||
toolbarButtons={toolbarButtons}
|
|
||||||
toolboxState={toolboxState}
|
|
||||||
handleToolSelect={id => api.handleToolSelect(id)}
|
|
||||||
handleToolOptionChange={handleToolOptionChange}
|
|
||||||
onInteraction={onInteraction}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Toolbox;
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef } from 'react';
|
import React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
import { PanelSection } from '../../components';
|
import { PanelSection } from '../../components';
|
||||||
@ -6,52 +6,39 @@ import { ToolSettings } from '../OHIFToolSettings';
|
|||||||
|
|
||||||
const ItemsPerRow = 4;
|
const ItemsPerRow = 4;
|
||||||
|
|
||||||
function usePrevious(value) {
|
interface ToolbarButton {
|
||||||
const ref = useRef();
|
id: string;
|
||||||
useEffect(() => {
|
Component: React.ComponentType<{
|
||||||
ref.current = value;
|
id: string;
|
||||||
});
|
onInteraction: (details: { itemId: string }) => void;
|
||||||
return ref.current;
|
size: string;
|
||||||
|
}>;
|
||||||
|
componentProps: {
|
||||||
|
isActive?: boolean;
|
||||||
|
buttonSection?: string;
|
||||||
|
options?: unknown;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
interface ToolboxProps {
|
||||||
* Just refactoring from the toolbox component to make it more readable
|
toolbarButtons: ToolbarButton[];
|
||||||
*/
|
numRows: number;
|
||||||
function ToolboxUI(props: withAppTypes) {
|
title?: string;
|
||||||
|
useCollapsedPanel?: boolean;
|
||||||
|
onInteraction?: (details: { itemId: string }) => void;
|
||||||
|
activeToolOptions?: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ToolboxUI(props: ToolboxProps) {
|
||||||
const {
|
const {
|
||||||
toolbarButtons,
|
toolbarButtons = [],
|
||||||
handleToolSelect,
|
|
||||||
toolboxState,
|
|
||||||
numRows,
|
numRows,
|
||||||
servicesManager,
|
|
||||||
title,
|
title,
|
||||||
useCollapsedPanel = true,
|
useCollapsedPanel = true,
|
||||||
|
onInteraction,
|
||||||
|
activeToolOptions,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const { activeTool, toolOptions, selectedEvent } = toolboxState;
|
|
||||||
const activeToolOptions = toolOptions?.[activeTool];
|
|
||||||
|
|
||||||
const prevToolOptions = usePrevious(activeToolOptions);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!activeToolOptions || Array.isArray(activeToolOptions) === false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
activeToolOptions.forEach((option, index) => {
|
|
||||||
const prevOption = prevToolOptions ? prevToolOptions[index] : undefined;
|
|
||||||
if (!prevOption || option.value !== prevOption.value || selectedEvent) {
|
|
||||||
const isOptionValid = option.condition
|
|
||||||
? option.condition({ options: activeToolOptions })
|
|
||||||
: true;
|
|
||||||
if (isOptionValid) {
|
|
||||||
const { commands } = option;
|
|
||||||
commands(option.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [activeToolOptions, selectedEvent]);
|
|
||||||
|
|
||||||
const render = () => {
|
const render = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -67,12 +54,9 @@ function ToolboxUI(props: withAppTypes) {
|
|||||||
|
|
||||||
const toolClasses = `ml-1 ${isLastRow ? '' : 'mb-2'}`;
|
const toolClasses = `ml-1 ${isLastRow ? '' : 'mb-2'}`;
|
||||||
|
|
||||||
const onInteraction = ({ itemId, id, commands }) => {
|
const handleInteraction = ({ itemId }: { itemId: string }) => {
|
||||||
const idToUse = itemId || id;
|
onInteraction?.({
|
||||||
handleToolSelect(idToUse);
|
|
||||||
props.onInteraction({
|
|
||||||
itemId,
|
itemId,
|
||||||
commands,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,10 +69,8 @@ function ToolboxUI(props: withAppTypes) {
|
|||||||
>
|
>
|
||||||
<Component
|
<Component
|
||||||
{...componentProps}
|
{...componentProps}
|
||||||
{...props}
|
|
||||||
id={id}
|
id={id}
|
||||||
servicesManager={servicesManager}
|
onInteraction={handleInteraction}
|
||||||
onInteraction={onInteraction}
|
|
||||||
size="toolbox"
|
size="toolbox"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,3 +1 @@
|
|||||||
import { ToolboxUI } from './ToolboxUI';
|
export * from './ToolboxUI';
|
||||||
import Toolbox from './Toolbox';
|
|
||||||
export { ToolboxUI, Toolbox };
|
|
||||||
|
|||||||
@ -41,7 +41,10 @@ const StudyItem = ({
|
|||||||
<div className="flex min-w-0 flex-col items-start text-[13px]">
|
<div className="flex min-w-0 flex-col items-start text-[13px]">
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipContent>{date}</TooltipContent>
|
<TooltipContent>{date}</TooltipContent>
|
||||||
<TooltipTrigger className="w-full">
|
<TooltipTrigger
|
||||||
|
className="w-full"
|
||||||
|
asChild
|
||||||
|
>
|
||||||
<div className="h-[18px] w-full max-w-[160px] overflow-hidden truncate whitespace-nowrap text-left text-white">
|
<div className="h-[18px] w-full max-w-[160px] overflow-hidden truncate whitespace-nowrap text-left text-white">
|
||||||
{date}
|
{date}
|
||||||
</div>
|
</div>
|
||||||
@ -49,7 +52,10 @@ const StudyItem = ({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipContent>{description}</TooltipContent>
|
<TooltipContent>{description}</TooltipContent>
|
||||||
<TooltipTrigger className="w-full">
|
<TooltipTrigger
|
||||||
|
className="w-full"
|
||||||
|
asChild
|
||||||
|
>
|
||||||
<div className="text-muted-foreground h-[18px] w-full overflow-hidden truncate whitespace-nowrap text-left">
|
<div className="text-muted-foreground h-[18px] w-full overflow-hidden truncate whitespace-nowrap text-left">
|
||||||
{description}
|
{description}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -50,7 +50,7 @@ function ToolButton(props: ToolButtonProps) {
|
|||||||
className,
|
className,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const { buttonSizeClass, iconSizeClass } = sizeClasses[size];
|
const { buttonSizeClass, iconSizeClass } = sizeClasses[size] || sizeClasses.default;
|
||||||
|
|
||||||
const buttonClasses = cn(
|
const buttonClasses = cn(
|
||||||
baseClasses,
|
baseClasses,
|
||||||
|
|||||||
@ -52,7 +52,7 @@ import { ThumbnailList } from './ThumbnailList';
|
|||||||
import { PanelSection } from './PanelSection';
|
import { PanelSection } from './PanelSection';
|
||||||
import { DisplaySetMessageListTooltip } from './DisplaySetMessageListTooltip';
|
import { DisplaySetMessageListTooltip } from './DisplaySetMessageListTooltip';
|
||||||
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './Tooltip';
|
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './Tooltip';
|
||||||
import { ToolboxUI, Toolbox } from './OHIFToolbox';
|
import { ToolboxUI } from './OHIFToolbox';
|
||||||
import Numeric from './Numeric';
|
import Numeric from './Numeric';
|
||||||
import { InputDialog, PresetDialog } from './OHIFDialogs';
|
import { InputDialog, PresetDialog } from './OHIFDialogs';
|
||||||
import { AboutModal, ImageModal, UserPreferencesModal } from './OHIFModals';
|
import { AboutModal, ImageModal, UserPreferencesModal } from './OHIFModals';
|
||||||
@ -105,6 +105,7 @@ import {
|
|||||||
ToolButtonListItem,
|
ToolButtonListItem,
|
||||||
ToolButtonListDivider,
|
ToolButtonListDivider,
|
||||||
} from './ToolButton';
|
} from './ToolButton';
|
||||||
|
import { ToolSettings } from './OHIFToolSettings';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Numeric,
|
Numeric,
|
||||||
@ -173,7 +174,6 @@ export {
|
|||||||
PanelSection,
|
PanelSection,
|
||||||
DisplaySetMessageListTooltip,
|
DisplaySetMessageListTooltip,
|
||||||
ToolboxUI,
|
ToolboxUI,
|
||||||
Toolbox,
|
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@ -236,4 +236,5 @@ export {
|
|||||||
ImageModal,
|
ImageModal,
|
||||||
UserPreferencesModal,
|
UserPreferencesModal,
|
||||||
FooterAction,
|
FooterAction,
|
||||||
|
ToolSettings,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,109 +0,0 @@
|
|||||||
import React, { createContext, useContext, useReducer } from 'react';
|
|
||||||
|
|
||||||
export const initialState = {};
|
|
||||||
|
|
||||||
export const toolboxReducer = (state, action) => {
|
|
||||||
const { toolbarSectionId } = action.payload;
|
|
||||||
|
|
||||||
if (!state[toolbarSectionId]) {
|
|
||||||
state[toolbarSectionId] = { activeTool: null, toolOptions: {}, selectedEvent: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (action.type) {
|
|
||||||
case 'SET_ACTIVE_TOOL':
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
[toolbarSectionId]: {
|
|
||||||
...state[toolbarSectionId],
|
|
||||||
activeTool: action.payload.activeTool,
|
|
||||||
selectedEvent: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
case 'UPDATE_TOOL_OPTION':
|
|
||||||
const { toolName, optionName, value } = action.payload;
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
[toolbarSectionId]: {
|
|
||||||
...state[toolbarSectionId],
|
|
||||||
selectedEvent: false,
|
|
||||||
toolOptions: {
|
|
||||||
...state[toolbarSectionId].toolOptions,
|
|
||||||
[toolName]: state[toolbarSectionId].toolOptions[toolName].map(option =>
|
|
||||||
option.id === optionName ? { ...option, value } : option
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
case 'INITIALIZE_TOOL_OPTIONS':
|
|
||||||
// Initialize tool options for each toolbarSectionId
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
selectedEvent: false,
|
|
||||||
[action.toolbarSectionId]: {
|
|
||||||
...state[action.toolbarSectionId],
|
|
||||||
toolOptions: action.payload,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ToolboxContext = createContext();
|
|
||||||
|
|
||||||
export const ToolboxProvider = ({ children }) => {
|
|
||||||
const [state, dispatch] = useReducer(toolboxReducer, initialState);
|
|
||||||
|
|
||||||
const handleToolSelect = (toolbarSectionId, toolName) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'SET_ACTIVE_TOOL',
|
|
||||||
payload: { toolbarSectionId, activeTool: toolName },
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleToolOptionChange = (toolbarSectionId, toolName, optionName, newValue) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'UPDATE_TOOL_OPTION',
|
|
||||||
payload: { toolbarSectionId, toolName, optionName, value: newValue },
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const initializeToolOptions = (toolbarSectionId, toolOptions) => {
|
|
||||||
dispatch({
|
|
||||||
type: 'INITIALIZE_TOOL_OPTIONS',
|
|
||||||
toolbarSectionId,
|
|
||||||
payload: toolOptions,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const api = { handleToolSelect, handleToolOptionChange, initializeToolOptions };
|
|
||||||
|
|
||||||
const value = { state, api };
|
|
||||||
|
|
||||||
return <ToolboxContext.Provider value={value}>{children}</ToolboxContext.Provider>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom hook for accessing toolbox state and actions for a specific toolbar section.
|
|
||||||
* You can use this hook to access the state and actions for a specific toolbar section (
|
|
||||||
* defined by the toolbarSectionId) in your custom toolbar components. This hook
|
|
||||||
* helps to manage the state and actions for the tools and their options in the toolbar.
|
|
||||||
*/
|
|
||||||
export const useToolbox = toolbarSectionId => {
|
|
||||||
const context = useContext(ToolboxContext);
|
|
||||||
if (context === undefined) {
|
|
||||||
throw new Error('useToolbox must be used within a ToolboxProvider');
|
|
||||||
}
|
|
||||||
const { state, api } = context;
|
|
||||||
|
|
||||||
return {
|
|
||||||
state: state[toolbarSectionId] || { activeTool: null, toolOptions: {} },
|
|
||||||
api: {
|
|
||||||
handleToolSelect: toolName => api.handleToolSelect(toolbarSectionId, toolName),
|
|
||||||
handleToolOptionChange: (toolName, optionName, value) =>
|
|
||||||
api.handleToolOptionChange(toolbarSectionId, toolName, optionName, value),
|
|
||||||
initializeToolOptions: toolOptions =>
|
|
||||||
api.initializeToolOptions(toolbarSectionId, toolOptions),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,13 +1,11 @@
|
|||||||
import NotificationProvider, { useNotification } from './NotificationProvider';
|
import NotificationProvider, { useNotification } from './NotificationProvider';
|
||||||
import { ViewportGridContext, ViewportGridProvider, useViewportGrid } from './ViewportGridProvider';
|
import { ViewportGridContext, ViewportGridProvider, useViewportGrid } from './ViewportGridProvider';
|
||||||
import { ToolboxProvider, useToolbox } from './ToolboxContext';
|
|
||||||
import { ModalProvider, useModal } from './ModalProvider';
|
import { ModalProvider, useModal } from './ModalProvider';
|
||||||
import { DialogProvider, useDialog } from './DialogProvider';
|
import { DialogProvider, useDialog } from './DialogProvider';
|
||||||
import ManagedDialog from './ManagedDialog';
|
import ManagedDialog from './ManagedDialog';
|
||||||
|
|
||||||
export { useNotification, NotificationProvider };
|
export { useNotification, NotificationProvider };
|
||||||
export { ViewportGridContext, ViewportGridProvider, useViewportGrid };
|
export { ViewportGridContext, ViewportGridProvider, useViewportGrid };
|
||||||
export { ToolboxProvider, useToolbox };
|
|
||||||
export { ModalProvider, useModal };
|
export { ModalProvider, useModal };
|
||||||
export { DialogProvider, useDialog };
|
export { DialogProvider, useDialog };
|
||||||
export { ManagedDialog };
|
export { ManagedDialog };
|
||||||
|
|||||||
@ -33,6 +33,7 @@ import {
|
|||||||
PanelSection,
|
PanelSection,
|
||||||
DisplaySetMessageListTooltip,
|
DisplaySetMessageListTooltip,
|
||||||
ToolboxUI,
|
ToolboxUI,
|
||||||
|
ToolSettings,
|
||||||
DoubleSlider,
|
DoubleSlider,
|
||||||
Label,
|
Label,
|
||||||
Slider,
|
Slider,
|
||||||
@ -98,7 +99,6 @@ import {
|
|||||||
ToolButtonListDropDown,
|
ToolButtonListDropDown,
|
||||||
ToolButtonListItem,
|
ToolButtonListItem,
|
||||||
ToolButtonListDivider,
|
ToolButtonListDivider,
|
||||||
Toolbox,
|
|
||||||
Numeric,
|
Numeric,
|
||||||
InputDialog,
|
InputDialog,
|
||||||
PresetDialog,
|
PresetDialog,
|
||||||
@ -113,8 +113,6 @@ import { DataRow } from './components/DataRow';
|
|||||||
import {
|
import {
|
||||||
useNotification,
|
useNotification,
|
||||||
NotificationProvider,
|
NotificationProvider,
|
||||||
useToolbox,
|
|
||||||
ToolboxProvider,
|
|
||||||
useModal,
|
useModal,
|
||||||
ModalProvider,
|
ModalProvider,
|
||||||
DialogProvider,
|
DialogProvider,
|
||||||
@ -232,9 +230,6 @@ export {
|
|||||||
ToolButtonListDropDown,
|
ToolButtonListDropDown,
|
||||||
ToolButtonListItem,
|
ToolButtonListItem,
|
||||||
ToolButtonListDivider,
|
ToolButtonListDivider,
|
||||||
ToolboxProvider,
|
|
||||||
Toolbox,
|
|
||||||
useToolbox,
|
|
||||||
utils,
|
utils,
|
||||||
Numeric,
|
Numeric,
|
||||||
AboutModal,
|
AboutModal,
|
||||||
@ -249,4 +244,5 @@ export {
|
|||||||
DialogProvider,
|
DialogProvider,
|
||||||
useDialog,
|
useDialog,
|
||||||
ManagedDialog,
|
ManagedDialog,
|
||||||
|
ToolSettings,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -13,6 +13,6 @@ test('should reset the image to its original state', async ({ page }) => {
|
|||||||
await page.getByTestId('MoreTools-split-button-secondary').click();
|
await page.getByTestId('MoreTools-split-button-secondary').click();
|
||||||
await page.getByTestId('invert').click();
|
await page.getByTestId('invert').click();
|
||||||
await page.getByTestId('MoreTools-split-button-secondary').click();
|
await page.getByTestId('MoreTools-split-button-secondary').click();
|
||||||
await page.getByTestId('Reset').click();
|
await page.getByText('Reset View').click();
|
||||||
await checkForScreenshot(page, page, screenShotPaths.reset.resetDisplayedCorrectly);
|
await checkForScreenshot(page, page, screenShotPaths.reset.resetDisplayedCorrectly);
|
||||||
});
|
});
|
||||||
|
|||||||
187
yarn.lock
187
yarn.lock
@ -1393,10 +1393,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
|
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
|
||||||
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
|
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
|
||||||
|
|
||||||
"@cornerstonejs/adapters@^3.0.1":
|
"@cornerstonejs/adapters@^3.0.4":
|
||||||
version "3.0.1"
|
version "3.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-3.0.1.tgz#596e302d7155ee64b7c20bcfedc57ce6ca10d5fb"
|
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-3.0.4.tgz#3aea5f65e95fbb067885eb51ebcae2cacd673465"
|
||||||
integrity sha512-Ym6s4cTpMkojap5QZ8MXZ8hDbs2TMMN/ypqU7wKMwAY2LGoltoeGw0Z/7LL+iostbaSw3fVs+TZzJSKhKw8Bug==
|
integrity sha512-TJtW0biDf0wgi+XxQFqvKXT/Cf8ueyUruohH9n/RJsWiyE8z1/LOBxOqCZNkToGGs1EbO51T/PMPIUWordW43w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime-corejs2" "^7.17.8"
|
"@babel/runtime-corejs2" "^7.17.8"
|
||||||
buffer "^6.0.3"
|
buffer "^6.0.3"
|
||||||
@ -1429,19 +1429,19 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0"
|
resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0"
|
||||||
integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg==
|
integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg==
|
||||||
|
|
||||||
"@cornerstonejs/core@^3.0.1":
|
"@cornerstonejs/core@^3.0.4":
|
||||||
version "3.0.1"
|
version "3.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-3.0.1.tgz#8a938013c148d752d2c4f4eba7bd63048a6c814a"
|
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-3.0.4.tgz#a75e0e86cc3ac4cd19355c30f8f531ebe279ae36"
|
||||||
integrity sha512-K+cOoN/TzJIPRRoaWWNkhJ+2CdkBBX8BA64DG0aBVOthlwJPRqK2YQE6PTTVRx18mjMA4to/m3de0emFNKrTzQ==
|
integrity sha512-6rMiqhBjyz3wsalPOAFjThfPUJnWVOs7Xqe3xLFvqd1qIFW1q42bqlQ7ak2DRMUMtC1nLURk6YIMhkWxK+t+7A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@kitware/vtk.js" "32.9.0"
|
"@kitware/vtk.js" "32.9.0"
|
||||||
comlink "^4.4.1"
|
comlink "^4.4.1"
|
||||||
gl-matrix "^3.4.3"
|
gl-matrix "^3.4.3"
|
||||||
|
|
||||||
"@cornerstonejs/dicom-image-loader@^3.0.1":
|
"@cornerstonejs/dicom-image-loader@^3.0.4":
|
||||||
version "3.0.1"
|
version "3.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-3.0.1.tgz#e18f716620ab176d88c25b9efd25fc0983bce180"
|
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-3.0.4.tgz#0c553e1b01fc90d956d216d72686f6dcda9400f7"
|
||||||
integrity sha512-t4bI6rVOt4J8YOHRR9Mh9ClInajc98qqI6fwsByiXmtc2Y4INrZ1uaRspFnOJBosbr+EwsJBV7iT2yt6Jk6CjA==
|
integrity sha512-w0NoutE7+/C2FeT1YHo0cnMJpZ17ARH0qwyGwWockFwuJkUVjRcU5ZW1sT0ABNOPUHqZse/K/YmH2IX+ppaScQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cornerstonejs/codec-charls" "^1.2.3"
|
"@cornerstonejs/codec-charls" "^1.2.3"
|
||||||
"@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2"
|
"@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2"
|
||||||
@ -1459,10 +1459,10 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@icr/polyseg-wasm" "0.4.0"
|
"@icr/polyseg-wasm" "0.4.0"
|
||||||
|
|
||||||
"@cornerstonejs/tools@^3.0.1":
|
"@cornerstonejs/tools@^3.0.4":
|
||||||
version "3.0.1"
|
version "3.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-3.0.1.tgz#4d707992283235d79532f35e60e8c763b174ccef"
|
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-3.0.4.tgz#413031f55dd7aca30168bfd13fe52911ba81f795"
|
||||||
integrity sha512-fRjoXJ46mdpYc5JZ/FUn0g1vCK4LohnNjgZl+O72HK2reMdc5/dQeCueJCT+tBMay04sJMUHm0tAke2DN10FBQ==
|
integrity sha512-gkenXhOS6lYYmQhKDwayojeObTU/KiG9k+JEC/hoOBhRdoFZljyXfQtnljKFHL+G9rkdbNKxXq/a3+C9Bn7EVg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/offscreencanvas" "2019.7.3"
|
"@types/offscreencanvas" "2019.7.3"
|
||||||
comlink "^4.4.1"
|
comlink "^4.4.1"
|
||||||
@ -1574,10 +1574,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz#2cbcf822bf3764c9658c4d2e568bd0c0cb748016"
|
resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz#2cbcf822bf3764c9658c4d2e568bd0c0cb748016"
|
||||||
integrity sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==
|
integrity sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==
|
||||||
|
|
||||||
"@cypress/request@^3.0.6":
|
"@cypress/request@^3.0.7":
|
||||||
version "3.0.7"
|
version "3.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.7.tgz#6a74a4da98d9e5ae9121d6e2d9c14780c9b5cf1a"
|
resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.8.tgz#992f1f42ba03ebb14fa5d97290abe9d015ed0815"
|
||||||
integrity sha512-LzxlLEMbBOPYB85uXrDqvD4MgcenjRBLIns3zyhx7vTPj/0u2eQhzXvPiGcaJrV38Q9dbkExWp6cOHPJ+EtFYg==
|
integrity sha512-h0NFgh1mJmm1nr4jCwkGHwKneVYKghUyWe6TMNrk0B9zsjAJxpg8C4/+BAcmLgCPa1vj1V8rNUaILl+zYRUWBQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
aws-sign2 "~0.7.0"
|
aws-sign2 "~0.7.0"
|
||||||
aws4 "^1.8.0"
|
aws4 "^1.8.0"
|
||||||
@ -1592,7 +1592,7 @@
|
|||||||
json-stringify-safe "~5.0.1"
|
json-stringify-safe "~5.0.1"
|
||||||
mime-types "~2.1.19"
|
mime-types "~2.1.19"
|
||||||
performance-now "^2.1.0"
|
performance-now "^2.1.0"
|
||||||
qs "6.13.1"
|
qs "6.14.0"
|
||||||
safe-buffer "^5.1.2"
|
safe-buffer "^5.1.2"
|
||||||
tough-cookie "^5.0.0"
|
tough-cookie "^5.0.0"
|
||||||
tunnel-agent "^0.6.0"
|
tunnel-agent "^0.6.0"
|
||||||
@ -7322,6 +7322,14 @@ cachedir@^2.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.4.0.tgz#7fef9cf7367233d7c88068fe6e34ed0d355a610d"
|
resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.4.0.tgz#7fef9cf7367233d7c88068fe6e34ed0d355a610d"
|
||||||
integrity sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==
|
integrity sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==
|
||||||
|
|
||||||
|
call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6"
|
||||||
|
integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==
|
||||||
|
dependencies:
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
function-bind "^1.1.2"
|
||||||
|
|
||||||
call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
|
call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
|
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
|
||||||
@ -7333,6 +7341,14 @@ call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bin
|
|||||||
get-intrinsic "^1.2.4"
|
get-intrinsic "^1.2.4"
|
||||||
set-function-length "^1.2.1"
|
set-function-length "^1.2.1"
|
||||||
|
|
||||||
|
call-bound@^1.0.2:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a"
|
||||||
|
integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==
|
||||||
|
dependencies:
|
||||||
|
call-bind-apply-helpers "^1.0.2"
|
||||||
|
get-intrinsic "^1.3.0"
|
||||||
|
|
||||||
caller-callsite@^2.0.0:
|
caller-callsite@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134"
|
resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134"
|
||||||
@ -7571,7 +7587,7 @@ ci-info@^3.2.0, ci-info@^3.6.1:
|
|||||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4"
|
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4"
|
||||||
integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==
|
integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==
|
||||||
|
|
||||||
ci-info@^4.0.0:
|
ci-info@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.1.0.tgz#92319d2fa29d2620180ea5afed31f589bc98cf83"
|
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.1.0.tgz#92319d2fa29d2620180ea5afed31f589bc98cf83"
|
||||||
integrity sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==
|
integrity sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==
|
||||||
@ -8513,12 +8529,12 @@ cypress-file-upload@^5.0.8:
|
|||||||
resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-5.0.8.tgz#d8824cbeaab798e44be8009769f9a6c9daa1b4a1"
|
resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-5.0.8.tgz#d8824cbeaab798e44be8009769f9a6c9daa1b4a1"
|
||||||
integrity sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g==
|
integrity sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g==
|
||||||
|
|
||||||
cypress@^14.0.0:
|
cypress@^14.1.0:
|
||||||
version "14.0.0"
|
version "14.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/cypress/-/cypress-14.0.0.tgz#a71cb0a243a0bfeb97b6973ab9c5291ca5288e93"
|
resolved "https://registry.yarnpkg.com/cypress/-/cypress-14.1.0.tgz#b2dbe7bbc529dc0c93ffd4e0e9fa59763afba0b8"
|
||||||
integrity sha512-kEGqQr23so5IpKeg/dp6GVi7RlHx1NmW66o2a2Q4wk9gRaAblLZQSiZJuDI8UMC4LlG5OJ7Q6joAiqTrfRNbTw==
|
integrity sha512-pPPj8Uu9NwjaaiXAEcjYZZmgsq6v9Zs1Nw6a+zRF+ANgYSNhH4S32SjFRsvMcuOHR/8dp4GBJhBPqIPSs+TxaA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cypress/request" "^3.0.6"
|
"@cypress/request" "^3.0.7"
|
||||||
"@cypress/xvfb" "^1.2.4"
|
"@cypress/xvfb" "^1.2.4"
|
||||||
"@types/sinonjs__fake-timers" "8.1.1"
|
"@types/sinonjs__fake-timers" "8.1.1"
|
||||||
"@types/sizzle" "^2.3.2"
|
"@types/sizzle" "^2.3.2"
|
||||||
@ -8529,7 +8545,7 @@ cypress@^14.0.0:
|
|||||||
cachedir "^2.3.0"
|
cachedir "^2.3.0"
|
||||||
chalk "^4.1.0"
|
chalk "^4.1.0"
|
||||||
check-more-types "^2.24.0"
|
check-more-types "^2.24.0"
|
||||||
ci-info "^4.0.0"
|
ci-info "^4.1.0"
|
||||||
cli-cursor "^3.1.0"
|
cli-cursor "^3.1.0"
|
||||||
cli-table3 "~0.6.1"
|
cli-table3 "~0.6.1"
|
||||||
commander "^6.2.1"
|
commander "^6.2.1"
|
||||||
@ -9507,6 +9523,15 @@ dotenv@~16.3.1:
|
|||||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.2.tgz#3cb611ce5a63002dbabf7c281bc331f69d28f03f"
|
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.2.tgz#3cb611ce5a63002dbabf7c281bc331f69d28f03f"
|
||||||
integrity sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ==
|
integrity sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ==
|
||||||
|
|
||||||
|
dunder-proto@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
|
||||||
|
integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
|
||||||
|
dependencies:
|
||||||
|
call-bind-apply-helpers "^1.0.1"
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
gopd "^1.2.0"
|
||||||
|
|
||||||
duplexer@^0.1.1, duplexer@^0.1.2, duplexer@~0.1.1:
|
duplexer@^0.1.1, duplexer@^0.1.2, duplexer@~0.1.1:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
|
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
|
||||||
@ -9762,6 +9787,11 @@ es-define-property@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
get-intrinsic "^1.2.4"
|
get-intrinsic "^1.2.4"
|
||||||
|
|
||||||
|
es-define-property@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
|
||||||
|
integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
|
||||||
|
|
||||||
es-errors@^1.2.1, es-errors@^1.3.0:
|
es-errors@^1.2.1, es-errors@^1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
|
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
|
||||||
@ -9814,6 +9844,13 @@ es-object-atoms@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
es-errors "^1.3.0"
|
es-errors "^1.3.0"
|
||||||
|
|
||||||
|
es-object-atoms@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1"
|
||||||
|
integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==
|
||||||
|
dependencies:
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
|
||||||
es-set-tostringtag@^2.0.1, es-set-tostringtag@^2.0.3:
|
es-set-tostringtag@^2.0.1, es-set-tostringtag@^2.0.3:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777"
|
resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777"
|
||||||
@ -11103,6 +11140,22 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@
|
|||||||
has-symbols "^1.0.3"
|
has-symbols "^1.0.3"
|
||||||
hasown "^2.0.0"
|
hasown "^2.0.0"
|
||||||
|
|
||||||
|
get-intrinsic@^1.2.5, get-intrinsic@^1.3.0:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
|
||||||
|
integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==
|
||||||
|
dependencies:
|
||||||
|
call-bind-apply-helpers "^1.0.2"
|
||||||
|
es-define-property "^1.0.1"
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
es-object-atoms "^1.1.1"
|
||||||
|
function-bind "^1.1.2"
|
||||||
|
get-proto "^1.0.1"
|
||||||
|
gopd "^1.2.0"
|
||||||
|
has-symbols "^1.1.0"
|
||||||
|
hasown "^2.0.2"
|
||||||
|
math-intrinsics "^1.1.0"
|
||||||
|
|
||||||
get-nonce@^1.0.0:
|
get-nonce@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3"
|
resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3"
|
||||||
@ -11138,6 +11191,14 @@ get-port@5.1.1, get-port@^5.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193"
|
resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193"
|
||||||
integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==
|
integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==
|
||||||
|
|
||||||
|
get-proto@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1"
|
||||||
|
integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==
|
||||||
|
dependencies:
|
||||||
|
dunder-proto "^1.0.1"
|
||||||
|
es-object-atoms "^1.0.0"
|
||||||
|
|
||||||
get-stdin@^7.0.0:
|
get-stdin@^7.0.0:
|
||||||
version "7.0.0"
|
version "7.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6"
|
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6"
|
||||||
@ -11451,6 +11512,11 @@ gopd@^1.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
get-intrinsic "^1.1.3"
|
get-intrinsic "^1.1.3"
|
||||||
|
|
||||||
|
gopd@^1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
|
||||||
|
integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
|
||||||
|
|
||||||
got@^12.1.0:
|
got@^12.1.0:
|
||||||
version "12.6.1"
|
version "12.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/got/-/got-12.6.1.tgz#8869560d1383353204b5a9435f782df9c091f549"
|
resolved "https://registry.yarnpkg.com/got/-/got-12.6.1.tgz#8869560d1383353204b5a9435f782df9c091f549"
|
||||||
@ -11581,6 +11647,11 @@ has-symbols@^1.0.2, has-symbols@^1.0.3:
|
|||||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
|
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
|
||||||
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
|
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
|
||||||
|
|
||||||
|
has-symbols@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
|
||||||
|
integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
|
||||||
|
|
||||||
has-tostringtag@^1.0.0, has-tostringtag@^1.0.2:
|
has-tostringtag@^1.0.0, has-tostringtag@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
|
resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
|
||||||
@ -14289,6 +14360,11 @@ material-colors@^1.2.1:
|
|||||||
resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
|
resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
|
||||||
integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==
|
integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==
|
||||||
|
|
||||||
|
math-intrinsics@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
|
||||||
|
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
|
||||||
|
|
||||||
mathjs@^11.2:
|
mathjs@^11.2:
|
||||||
version "11.12.0"
|
version "11.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-11.12.0.tgz#e933e5941930d44763ddfc5bfb08b90059449b2c"
|
resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-11.12.0.tgz#e933e5941930d44763ddfc5bfb08b90059449b2c"
|
||||||
@ -15651,6 +15727,11 @@ object-inspect@^1.13.1:
|
|||||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff"
|
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff"
|
||||||
integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==
|
integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==
|
||||||
|
|
||||||
|
object-inspect@^1.13.3:
|
||||||
|
version "1.13.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213"
|
||||||
|
integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==
|
||||||
|
|
||||||
object-is@^1.1.2, object-is@^1.1.5:
|
object-is@^1.1.2, object-is@^1.1.5:
|
||||||
version "1.1.6"
|
version "1.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07"
|
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07"
|
||||||
@ -17353,12 +17434,12 @@ qs@6.13.0, qs@^6.10.0, qs@^6.12.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
side-channel "^1.0.6"
|
side-channel "^1.0.6"
|
||||||
|
|
||||||
qs@6.13.1:
|
qs@6.14.0:
|
||||||
version "6.13.1"
|
version "6.14.0"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.1.tgz#3ce5fc72bd3a8171b85c99b93c65dd20b7d1b16e"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930"
|
||||||
integrity sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==
|
integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==
|
||||||
dependencies:
|
dependencies:
|
||||||
side-channel "^1.0.6"
|
side-channel "^1.1.0"
|
||||||
|
|
||||||
query-string@^4.1.0:
|
query-string@^4.1.0:
|
||||||
version "4.3.4"
|
version "4.3.4"
|
||||||
@ -18790,6 +18871,35 @@ shx@^0.3.3:
|
|||||||
minimist "^1.2.3"
|
minimist "^1.2.3"
|
||||||
shelljs "^0.8.5"
|
shelljs "^0.8.5"
|
||||||
|
|
||||||
|
side-channel-list@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad"
|
||||||
|
integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==
|
||||||
|
dependencies:
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
object-inspect "^1.13.3"
|
||||||
|
|
||||||
|
side-channel-map@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42"
|
||||||
|
integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==
|
||||||
|
dependencies:
|
||||||
|
call-bound "^1.0.2"
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
get-intrinsic "^1.2.5"
|
||||||
|
object-inspect "^1.13.3"
|
||||||
|
|
||||||
|
side-channel-weakmap@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea"
|
||||||
|
integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==
|
||||||
|
dependencies:
|
||||||
|
call-bound "^1.0.2"
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
get-intrinsic "^1.2.5"
|
||||||
|
object-inspect "^1.13.3"
|
||||||
|
side-channel-map "^1.0.1"
|
||||||
|
|
||||||
side-channel@^1.0.4, side-channel@^1.0.6:
|
side-channel@^1.0.4, side-channel@^1.0.6:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
|
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
|
||||||
@ -18800,6 +18910,17 @@ side-channel@^1.0.4, side-channel@^1.0.6:
|
|||||||
get-intrinsic "^1.2.4"
|
get-intrinsic "^1.2.4"
|
||||||
object-inspect "^1.13.1"
|
object-inspect "^1.13.1"
|
||||||
|
|
||||||
|
side-channel@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9"
|
||||||
|
integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==
|
||||||
|
dependencies:
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
object-inspect "^1.13.3"
|
||||||
|
side-channel-list "^1.0.0"
|
||||||
|
side-channel-map "^1.0.1"
|
||||||
|
side-channel-weakmap "^1.0.2"
|
||||||
|
|
||||||
signal-exit@3.0.7, signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
|
signal-exit@3.0.7, signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
|
||||||
version "3.0.7"
|
version "3.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
|
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user