diff --git a/extensions/cornerstone/package.json b/extensions/cornerstone/package.json index 6a9ec771b..98d24669c 100644 --- a/extensions/cornerstone/package.json +++ b/extensions/cornerstone/package.json @@ -33,7 +33,7 @@ "@ohif/ui": "^0.50.0", "cornerstone-core": "^2.3.0", "cornerstone-math": "^0.1.8", - "cornerstone-tools": "4.17.0", + "cornerstone-tools": "4.18.0", "cornerstone-wado-image-loader": "^3.1.2", "dcmjs": "0.14.2", "dicom-parser": "^1.8.3", diff --git a/extensions/cornerstone/src/init.js b/extensions/cornerstone/src/init.js index 7dffe4ab6..edfdf4b8b 100644 --- a/extensions/cornerstone/src/init.js +++ b/extensions/cornerstone/src/init.js @@ -38,12 +38,13 @@ export default function init({ servicesManager, configuration }) { ], onSubmit: ({ action, value }) => { switch (action.id) { - case 'save': callback(value.label); + case 'save': + callback(value.label); } UIDialogService.dismiss({ id: dialogId }); }, body: ({ value, setValue }) => { - const onChangeHandler = (event) => { + const onChangeHandler = event => { event.persist(); setValue(value => ({ ...value, label: event.target.value })); }; @@ -93,7 +94,7 @@ export default function init({ servicesManager, configuration }) { // THIS // is a way for extensions that "depend" on this extension to notify it of // new cornerstone enabled elements so it's commands continue to work. - const handleOhifCornerstoneEnabledElementEvent = function (evt) { + const handleOhifCornerstoneEnabledElementEvent = function(evt) { const { viewportIndex, enabledElement } = evt.detail; setEnabledElement(viewportIndex, enabledElement); @@ -271,7 +272,10 @@ const _connectToolsToMeasurementService = measurementService => { const csToolsVer4MeasurementSource = _initMeasurementService( measurementService ); - _connectMeasurementServiceToTools(measurementService, csToolsVer4MeasurementSource); + _connectMeasurementServiceToTools( + measurementService, + csToolsVer4MeasurementSource + ); const { addOrUpdate, remove } = csToolsVer4MeasurementSource; const elementEnabledEvt = cornerstone.EVENTS.ELEMENT_ENABLED; @@ -336,14 +340,18 @@ const _connectToolsToMeasurementService = measurementService => { }); }; -const _connectMeasurementServiceToTools = (measurementService, measurementSource) => { - const { MEASUREMENTS_CLEARED, MEASUREMENT_REMOVED } = measurementService.EVENTS; +const _connectMeasurementServiceToTools = ( + measurementService, + measurementSource +) => { + const { + MEASUREMENTS_CLEARED, + MEASUREMENT_REMOVED, + } = measurementService.EVENTS; const sourceId = measurementSource.id; measurementService.subscribe(MEASUREMENTS_CLEARED, () => { - cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState( - {} - ); + cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState({}); cornerstone.getEnabledElements().forEach(enabledElement => { cornerstone.updateImage(enabledElement.element); }); diff --git a/extensions/dicom-rt/package.json b/extensions/dicom-rt/package.json index 4ac7c2ede..69f4a2e6e 100644 --- a/extensions/dicom-rt/package.json +++ b/extensions/dicom-rt/package.json @@ -30,7 +30,7 @@ "peerDependencies": { "@ohif/core": "^0.50.0", "cornerstone-core": "^2.2.8", - "cornerstone-tools": "4.17.0", + "cornerstone-tools": "4.18.0", "dcmjs": "0.14.2", "prop-types": "^15.6.2", "react": "^16.8.6", diff --git a/extensions/dicom-segmentation/package.json b/extensions/dicom-segmentation/package.json index 2700290d8..330377c24 100644 --- a/extensions/dicom-segmentation/package.json +++ b/extensions/dicom-segmentation/package.json @@ -30,7 +30,7 @@ "peerDependencies": { "@ohif/core": "^0.50.0", "cornerstone-core": "^2.2.8", - "cornerstone-tools": "4.17.0", + "cornerstone-tools": "4.18.0", "dcmjs": "0.14.2", "prop-types": "^15.6.2", "react": "^16.8.6", diff --git a/extensions/dicom-sr/package.json b/extensions/dicom-sr/package.json index 948bddccf..a4406bfad 100644 --- a/extensions/dicom-sr/package.json +++ b/extensions/dicom-sr/package.json @@ -33,7 +33,7 @@ "@ohif/ui": "^0.50.0", "cornerstone-core": "^2.3.0", "cornerstone-math": "^0.1.8", - "cornerstone-tools": "4.17.0", + "cornerstone-tools": "4.18.0", "cornerstone-wado-image-loader": "^3.1.2", "dcmjs": "0.14.2", "dicom-parser": "^1.8.3", diff --git a/extensions/dicom-sr/src/OHIFCornerstoneSRViewport.js b/extensions/dicom-sr/src/OHIFCornerstoneSRViewport.js index d936f87bb..5415e2078 100644 --- a/extensions/dicom-sr/src/OHIFCornerstoneSRViewport.js +++ b/extensions/dicom-sr/src/OHIFCornerstoneSRViewport.js @@ -399,14 +399,23 @@ function OHIFCornerstoneSRViewport({ }); } + const label = + viewports.length > 1 + ? _viewportLabels[firstViewportIndexWithMatchingDisplaySetUid] + : ''; + return ( <> { + evt.stopPropagation(); + evt.preventDefault(); + }} onSeriesChange={onMeasurementChange} onHydrationClick={hydrateMeasurementService} showNavArrows={viewportIndex === activeViewportIndex} studyData={{ - label: _viewportLabels[firstViewportIndexWithMatchingDisplaySetUid], + label, isTracked: false, isLocked: displaySet.isLocked, isHydrated, @@ -432,18 +441,23 @@ function OHIFCornerstoneSRViewport({ }, }} /> - +
+ +
{childrenWithProps} ); @@ -573,4 +587,14 @@ function _addToolDataToCornerstoneTools(data, toolType, imageId) { toolData.data.push(data); } +function _onDoubleClick() { + const cancelActiveManipulatorsForElement = cornerstoneTools.getModule( + 'manipulatorState' + ).setters.cancelActiveManipulatorsForElement; + const enabledElements = cornerstoneTools.store.state.enabledElements; + enabledElements.forEach(element => { + cancelActiveManipulatorsForElement(element); + }); +} + export default OHIFCornerstoneSRViewport; diff --git a/extensions/measurement-tracking/package.json b/extensions/measurement-tracking/package.json index 4d3a1ea76..2f03c02f6 100644 --- a/extensions/measurement-tracking/package.json +++ b/extensions/measurement-tracking/package.json @@ -28,7 +28,7 @@ }, "peerDependencies": { "@ohif/core": "^0.50.0", - "cornerstone-tools": "4.17.0", + "cornerstone-tools": "4.18.0", "dcmjs": "0.14.2", "prop-types": "^15.6.2", "react": "^16.13.1", diff --git a/extensions/measurement-tracking/src/viewports/TrackedCornerstoneViewport.js b/extensions/measurement-tracking/src/viewports/TrackedCornerstoneViewport.js index 8c4a2d61b..941da322c 100644 --- a/extensions/measurement-tracking/src/viewports/TrackedCornerstoneViewport.js +++ b/extensions/measurement-tracking/src/viewports/TrackedCornerstoneViewport.js @@ -295,6 +295,10 @@ function TrackedCornerstoneViewport({ return ( <> { + evt.stopPropagation(); + evt.preventDefault(); + }} onSeriesChange={direction => switchMeasurement(direction)} showNavArrows={showNavArrows} studyData={{ @@ -324,7 +328,10 @@ function TrackedCornerstoneViewport({ }} /> {/* TODO: Viewport interface to accept stack or layers of content like this? */} -
+
{ + cancelActiveManipulatorsForElement(element); + }); +} + + /** * Builds the viewport data from a datasource and a displayset. * @@ -413,6 +432,7 @@ function _getCornerstoneStack(displaySet, dataSource) { * @param {Object} displaySet * @return {Object} viewport data */ + async function _getViewportData(dataSource, displaySet) { const stack = _getCornerstoneStack(displaySet, dataSource); diff --git a/extensions/vtk/package.json b/extensions/vtk/package.json index ee59ce0ff..46972b4a1 100644 --- a/extensions/vtk/package.json +++ b/extensions/vtk/package.json @@ -57,7 +57,7 @@ "@ohif/core": "^2.9.6", "@ohif/ui": "^2.0.0", "cornerstone-core": "^2.3.0", - "cornerstone-tools": "4.17.0", + "cornerstone-tools": "4.18.0", "cornerstone-wado-image-loader": "^3.1.2", "dicom-parser": "^1.8.3", "gh-pages": "^2.0.1", diff --git a/lerna-debug.log b/lerna-debug.log new file mode 100644 index 000000000..e1724452f --- /dev/null +++ b/lerna-debug.log @@ -0,0 +1,12 @@ +0 silly argv { _: [ 'run' ], +0 silly argv stream: true, +0 silly argv lernaVersion: '3.22.0', +0 silly argv '$0': +0 silly argv '/Users/jamesapetts/cornerstonejs/Viewers/node_modules/.bin/lerna', +0 silly argv script: 'dev:viewer' } +1 notice cli v3.22.0 +2 verbose rootPath /Users/jamesapetts/cornerstonejs/Viewers +3 info versioning independent +4 error JSONError: Unexpected token < in JSON at position 871 while parsing near '...ne-core": "^2.3.0",<<<<<<< HEAD "co...' in platform/core/package.json +4 error at module.exports (/Users/jamesapetts/cornerstonejs/Viewers/node_modules/parse-json/index.js:26:19) +4 error at parse (/Users/jamesapetts/cornerstonejs/Viewers/node_modules/load-json-file/index.js:15:9) diff --git a/platform/core/package.json b/platform/core/package.json index 24123a934..a0ed83e29 100644 --- a/platform/core/package.json +++ b/platform/core/package.json @@ -31,7 +31,7 @@ }, "peerDependencies": { "cornerstone-core": "^2.3.0", - "cornerstone-tools": "4.17.0", + "cornerstone-tools": "4.18.0", "cornerstone-wado-image-loader": "^3.1.2", "dicom-parser": "^1.8.3" }, diff --git a/platform/core/src/services/ViewportGridService/ViewportGridService.js b/platform/core/src/services/ViewportGridService/ViewportGridService.js index 662d543b9..23c984668 100644 --- a/platform/core/src/services/ViewportGridService/ViewportGridService.js +++ b/platform/core/src/services/ViewportGridService/ViewportGridService.js @@ -6,14 +6,18 @@ const publicAPI = { setActiveViewportIndex: _setActiveViewportIndex, setDisplaysetForViewport: _setDisplaysetForViewport, setLayout: _setLayout, + setCachedLayout: _setCachedLayout, setServiceImplementation, }; const serviceImplementation = { _getState: () => console.warn('getState() NOT IMPLEMENTED'), - _setActiveViewportIndex: () => console.warn('setActiveViewportIndex() NOT IMPLEMENTED'), - _setDisplaysetForViewport: () => console.warn('setDisplaysetForViewport() NOT IMPLEMENTED'), + _setActiveViewportIndex: () => + console.warn('setActiveViewportIndex() NOT IMPLEMENTED'), + _setDisplaysetForViewport: () => + console.warn('setDisplaysetForViewport() NOT IMPLEMENTED'), _setLayout: () => console.warn('setLayout() NOT IMPLEMENTED'), + _setCachedLayout: () => console.warn('setCachedLayout() NOT IMPLEMENTED'), }; function _getState() { @@ -35,10 +39,15 @@ function _setLayout({ numCols, numRows }) { return serviceImplementation._setLayout({ numCols, numRows }); } +function _setCachedLayout({ numCols, numRows, viewports }) { + return serviceImplementation._setLayout({ numCols, numRows, viewports }); +} + function setServiceImplementation({ getState: getStateImplementation, setActiveViewportIndex: setActiveViewportIndexImplementation, setDisplaysetForViewport: setDisplaysetForViewportImplementation, + setCachedLayout: setCachedLayoutImplementation, setLayout: setLayoutImplementation, }) { if (getStateImplementation) { @@ -53,6 +62,9 @@ function setServiceImplementation({ if (setLayoutImplementation) { serviceImplementation._setLayout = setLayoutImplementation; } + if (setCachedLayoutImplementation) { + serviceImplementation._setCachedLayout = setCachedLayoutImplementation; + } } export default { diff --git a/platform/ui/src/components/ViewportActionBar/ViewportActionBar.jsx b/platform/ui/src/components/ViewportActionBar/ViewportActionBar.jsx index 00c24ef22..cf1adddef 100644 --- a/platform/ui/src/components/ViewportActionBar/ViewportActionBar.jsx +++ b/platform/ui/src/components/ViewportActionBar/ViewportActionBar.jsx @@ -16,6 +16,7 @@ const ViewportActionBar = ({ showPatientInfo: patientInfoVisibility, onSeriesChange, onHydrationClick, + onDoubleClick, }) => { const [showPatientInfo, setShowPatientInfo] = useState(patientInfoVisibility); @@ -135,7 +136,10 @@ const ViewportActionBar = ({ }; return ( -
+
{renderIconStatus()} diff --git a/platform/ui/src/components/ViewportPane/ViewportPane.jsx b/platform/ui/src/components/ViewportPane/ViewportPane.jsx index 0b08135de..61864dcfc 100644 --- a/platform/ui/src/components/ViewportPane/ViewportPane.jsx +++ b/platform/ui/src/components/ViewportPane/ViewportPane.jsx @@ -11,6 +11,7 @@ function ViewportPane({ className, isActive, onDrop, + onDoubleClick, onInteraction, acceptDropsFor, }) { @@ -57,6 +58,7 @@ function ViewportPane({ // https://reactjs.org/docs/events.html#mouse-events // https://stackoverflow.com/questions/8378243/catch-scrolling-event-on-overflowhidden-element onMouseDown={onInteractionHandler} + onDoubleClick={onDoubleClick} onClick={onInteractionHandler} onScroll={onInteractionHandler} onWheel={onInteractionHandler} @@ -95,6 +97,8 @@ ViewportPane.propTypes = { onDrop: PropTypes.func.isRequired, /** Called when the viewportPane is interacted with by the user */ onInteraction: PropTypes.func.isRequired, + /** Executed when the pane is double clicked */ + onDoubleClick: PropTypes.func, }; const noop = () => {}; diff --git a/platform/ui/src/contextProviders/ViewportGridProvider.jsx b/platform/ui/src/contextProviders/ViewportGridProvider.jsx index 6c5c1120e..bfc9b3d51 100644 --- a/platform/ui/src/contextProviders/ViewportGridProvider.jsx +++ b/platform/ui/src/contextProviders/ViewportGridProvider.jsx @@ -32,7 +32,7 @@ export function ViewportGridProvider({ children, service }) { viewports[viewportIndex] = { displaySetInstanceUID, imageIndex }; - return { ...state, ...{ viewports } }; + return { ...state, ...{ viewports }, cachedLayout: undefined }; } case 'SET_LAYOUT': { const { numCols, numRows } = action.payload; @@ -51,8 +51,12 @@ export function ViewportGridProvider({ children, service }) { return { ...state, ...{ activeViewportIndex, numCols, numRows, viewports }, + cachedLayout: undefined, }; } + case 'SET_CACHED_LAYOUT': { + return { ...state, cachedLayout: action.payload }; + } default: return action.payload; } @@ -93,6 +97,15 @@ export function ViewportGridProvider({ children, service }) { [dispatch] ); + const setCachedLayout = useCallback( + payload => + dispatch({ + type: 'SET_CACHED_LAYOUT', + payload, + }), + [dispatch] + ); + /** * Sets the implementation of a modal service that can be used by extensions. * @@ -105,6 +118,7 @@ export function ViewportGridProvider({ children, service }) { setActiveViewportIndex, setDisplaysetForViewport, setLayout, + setCachedLayout, }); } }, [ @@ -113,6 +127,7 @@ export function ViewportGridProvider({ children, service }) { setActiveViewportIndex, setDisplaysetForViewport, setLayout, + setCachedLayout, ]); const api = { @@ -120,6 +135,7 @@ export function ViewportGridProvider({ children, service }) { setActiveViewportIndex, setDisplaysetForViewport, setLayout, + setCachedLayout, }; return ( diff --git a/platform/viewer/package.json b/platform/viewer/package.json index 333dd0c09..c7e66fb32 100644 --- a/platform/viewer/package.json +++ b/platform/viewer/package.json @@ -67,7 +67,7 @@ "classnames": "^2.2.6", "core-js": "^3.2.1", "cornerstone-math": "^0.1.8", - "cornerstone-tools": "4.17.0", + "cornerstone-tools": "4.18.0", "cornerstone-wado-image-loader": "^3.1.2", "dcmjs": "0.14.2", "dicom-parser": "^1.8.3", diff --git a/platform/viewer/src/components/ViewportGrid.jsx b/platform/viewer/src/components/ViewportGrid.jsx index 8617ce03a..652124fec 100644 --- a/platform/viewer/src/components/ViewportGrid.jsx +++ b/platform/viewer/src/components/ViewportGrid.jsx @@ -11,7 +11,7 @@ const { ImageSet } = classes; function ViewerViewportGrid(props) { const { servicesManager, viewportComponents, dataSource } = props; const [ - { numCols, numRows, activeViewportIndex, viewports }, + { numCols, numRows, activeViewportIndex, viewports, cachedLayout }, viewportGridService, ] = useViewportGrid(); @@ -67,6 +67,43 @@ function ViewerViewportGrid(props) { }; }; + const onDoubleClick = viewportIndex => { + if (cachedLayout) { + viewportGridService.setLayout({ + numCols: cachedLayout.numCols, + numRows: cachedLayout.numRows, + }); + + cachedLayout.viewports.forEach((viewport, viewportIndex) => { + viewportGridService.setDisplaysetForViewport({ + viewportIndex, + displaySetInstanceUID: viewport.displaySetInstanceUID, + }); + }); + + return; + } + + const cachedViewports = viewports.map(viewport => { + return { + displaySetInstanceUID: viewport.displaySetInstanceUID, + }; + }); + + viewportGridService.setDisplaysetForViewport({ + viewportIndex: 0, + displaySetInstanceUID: viewports[viewportIndex].displaySetInstanceUID, + }); + + viewportGridService.setLayout({ numCols: 1, numRows: 1 }); + + viewportGridService.setCachedLayout({ + numCols, + numRows, + viewports: cachedViewports, + }); + }; + // TODO: // Hmm... Should a "displaySet" being added update the viewport based on HP? // I guess it might. @@ -127,6 +164,7 @@ function ViewerViewportGrid(props) { acceptDropsFor="displayset" onDrop={onDropHandler.bind(null, viewportIndex)} onInteraction={onInterationHandler} + onDoubleClick={() => onDoubleClick(viewportIndex)} isActive={activeViewportIndex === viewportIndex} >