diff --git a/extensions/cornerstone/src/commandsModule.js b/extensions/cornerstone/src/commandsModule.js index c7cc9b817..05371161e 100644 --- a/extensions/cornerstone/src/commandsModule.js +++ b/extensions/cornerstone/src/commandsModule.js @@ -121,6 +121,7 @@ const commandsModule = ({ servicesManager }) => { lesionNamingNumber, measurementNumber, } = measurementData; + if (!_id) { return; } diff --git a/extensions/cornerstone/src/init.js b/extensions/cornerstone/src/init.js index 0910a5407..7dffe4ab6 100644 --- a/extensions/cornerstone/src/init.js +++ b/extensions/cornerstone/src/init.js @@ -271,6 +271,7 @@ const _connectToolsToMeasurementService = measurementService => { const csToolsVer4MeasurementSource = _initMeasurementService( measurementService ); + _connectMeasurementServiceToTools(measurementService, csToolsVer4MeasurementSource); const { addOrUpdate, remove } = csToolsVer4MeasurementSource; const elementEnabledEvt = cornerstone.EVENTS.ELEMENT_ENABLED; @@ -335,6 +336,30 @@ const _connectToolsToMeasurementService = measurementService => { }); }; +const _connectMeasurementServiceToTools = (measurementService, measurementSource) => { + const { MEASUREMENTS_CLEARED, MEASUREMENT_REMOVED } = measurementService.EVENTS; + const sourceId = measurementSource.id; + + measurementService.subscribe(MEASUREMENTS_CLEARED, () => { + cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState( + {} + ); + cornerstone.getEnabledElements().forEach(enabledElement => { + cornerstone.updateImage(enabledElement.element); + }); + }); + + /* TODO: Remove per measurement + measurementService.subscribe(MEASUREMENT_REMOVED, + ({ source, measurement }) => { + if ([sourceId].includes(source.id)) { + // const annotation = getAnnotation('Length', measurement.id); + // iterate tool state + } + } + ); */ +}; + // const { // MEASUREMENT_ADDED, // MEASUREMENT_UPDATED, diff --git a/extensions/default/src/PanelMeasurementTable.js b/extensions/default/src/PanelMeasurementTable.js index 1cf8cd183..90acd31aa 100644 --- a/extensions/default/src/PanelMeasurementTable.js +++ b/extensions/default/src/PanelMeasurementTable.js @@ -23,9 +23,10 @@ export default function PanelMeasurementTable({ const added = MeasurementService.EVENTS.MEASUREMENT_ADDED; const updated = MeasurementService.EVENTS.MEASUREMENT_UPDATED; const removed = MeasurementService.EVENTS.MEASUREMENT_REMOVED; + const cleared = MeasurementService.EVENTS.MEASUREMENTS_CLEARED; const subscriptions = []; - [added, updated, removed].forEach(evt => { + [added, updated, removed, cleared].forEach(evt => { subscriptions.push( MeasurementService.subscribe(evt, () => { debouncedSetDisplayMeasurements( diff --git a/extensions/default/src/commandsModule.js b/extensions/default/src/commandsModule.js new file mode 100644 index 000000000..0066c0302 --- /dev/null +++ b/extensions/default/src/commandsModule.js @@ -0,0 +1,25 @@ +const commandsModule = ({ servicesManager }) => { + const { MeasurementService } = servicesManager.services; + + const actions = { + clearMeasurements: () => { + MeasurementService.clear(); + }, + }; + + const definitions = { + clearMeasurements: { + commandFn: actions.clearMeasurements, + storeContexts: [], + options: {}, + }, + }; + + return { + actions, + definitions, + defaultContext: 'DEFAULT', + }; +}; + +export default commandsModule; diff --git a/extensions/default/src/getContextModule.js b/extensions/default/src/getContextModule.js index ddca1fcfd..4411fb788 100644 --- a/extensions/default/src/getContextModule.js +++ b/extensions/default/src/getContextModule.js @@ -3,7 +3,7 @@ import { ViewModelContext } from '@ohif/core'; const HelloWorldContext = React.createContext({ message: 'HelloWorldContextTesting', - setMessage: () => {}, + setMessage: () => { }, }); HelloWorldContext.displayName = 'HelloWorldContext'; diff --git a/extensions/default/src/index.js b/extensions/default/src/index.js index a426be014..a87410ecc 100644 --- a/extensions/default/src/index.js +++ b/extensions/default/src/index.js @@ -4,6 +4,7 @@ import getLayoutTemplateModule from './getLayoutTemplateModule.js'; import getPanelModule from './getPanelModule.js'; import getSopClassHandlerModule from './getSopClassHandlerModule.js'; import getToolbarModule from './getToolbarModule.js'; +import commandsModule from './commandsModule'; import id from './id'; export default { @@ -17,4 +18,7 @@ export default { getPanelModule, getSopClassHandlerModule, getToolbarModule, + getCommandsModule({ servicesManager }) { + return commandsModule({ servicesManager }); + }, }; diff --git a/extensions/measurement-tracking/src/panels/PanelMeasurementTableTracking/index.js b/extensions/measurement-tracking/src/panels/PanelMeasurementTableTracking/index.js index 263eca1f3..9260c26b9 100644 --- a/extensions/measurement-tracking/src/panels/PanelMeasurementTableTracking/index.js +++ b/extensions/measurement-tracking/src/panels/PanelMeasurementTableTracking/index.js @@ -101,9 +101,10 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) { const added = MeasurementService.EVENTS.MEASUREMENT_ADDED; const updated = MeasurementService.EVENTS.MEASUREMENT_UPDATED; const removed = MeasurementService.EVENTS.MEASUREMENT_REMOVED; + const cleared = MeasurementService.EVENTS.MEASUREMENTS_CLEARED; const subscriptions = []; - [added, updated, removed].forEach(evt => { + [added, updated, removed, cleared].forEach(evt => { subscriptions.push( MeasurementService.subscribe(evt, () => { setMeasurementsUpdated(Date.now().toString()); diff --git a/modes/longitudinal/src/index.js b/modes/longitudinal/src/index.js index db09204ba..ca7dad86a 100644 --- a/modes/longitudinal/src/index.js +++ b/modes/longitudinal/src/index.js @@ -62,6 +62,7 @@ export default function mode({ modeConfiguration }) { 'Bidirectional', 'Ellipse', 'Length', + 'Clear', ]); // Could import layout selector here from org.ohif.default (when it exists!) diff --git a/modes/longitudinal/src/toolbarButtons.js b/modes/longitudinal/src/toolbarButtons.js index b0a271638..9fec54e93 100644 --- a/modes/longitudinal/src/toolbarButtons.js +++ b/modes/longitudinal/src/toolbarButtons.js @@ -307,4 +307,19 @@ export default [ type: 'secondary', }, }, + { + id: 'Clear', + type: 'ohif.action', + config: { + groupName: 'primaryTool', + }, + props: { + isActive: false, + icon: 'old-trash', + label: 'Clear', + commandName: 'clearMeasurements', + commandOptions: {}, + type: 'secondary', + }, + }, ]; diff --git a/platform/core/src/services/MeasurementService/MeasurementService.js b/platform/core/src/services/MeasurementService/MeasurementService.js index 5972a9877..34f1a398c 100644 --- a/platform/core/src/services/MeasurementService/MeasurementService.js +++ b/platform/core/src/services/MeasurementService/MeasurementService.js @@ -52,6 +52,7 @@ const EVENTS = { MEASUREMENT_UPDATED: 'event::measurement_updated', MEASUREMENT_ADDED: 'event::measurement_added', MEASUREMENT_REMOVED: 'event::measurement_removed', + MEASUREMENTS_CLEARED: 'event::measurements_cleared', }; const VALUE_TYPES = { @@ -500,6 +501,14 @@ class MeasurementService { } } + /** + * Clear all measurements and broadcasts cleared event. + */ + clear() { + this.measurements = {}; + this._broadcastChange(this.EVENTS.MEASUREMENTS_CLEARED); + } + /** * Get measurement mapping function if matching criteria. * @@ -559,15 +568,27 @@ class MeasurementService { /** * Broadcasts measurement changes. * - * @param {string} measurementId The measurement id - * @param {MeasurementSource} source The measurement source * @param {string} eventName The event name + * @param {MeasurementSource} source The measurement source + * @param {string} measurement The measurement id * @return void */ _broadcastChange(eventName, source, measurement) { const hasListeners = Object.keys(this.listeners).length > 0; const hasCallbacks = Array.isArray(this.listeners[eventName]); + if (!source) { + /* Broadcast to all sources */ + /* Object.keys(this.sources).forEach(source => { + if (hasListeners && hasCallbacks) { + this.listeners[eventName].forEach(listener => { + listener.callback({ source, measurement }); + }); + } + }); + return; */ + } + if (hasListeners && hasCallbacks) { this.listeners[eventName].forEach(listener => { listener.callback({ source, measurement }); diff --git a/platform/ui/src/assets/icons/old-trash.svg b/platform/ui/src/assets/icons/old-trash.svg new file mode 100644 index 000000000..f3033a083 --- /dev/null +++ b/platform/ui/src/assets/icons/old-trash.svg @@ -0,0 +1,9 @@ + + Trash + + diff --git a/platform/ui/src/components/Icon/getIcon.jsx b/platform/ui/src/components/Icon/getIcon.jsx index f421f579a..bda2d02bf 100644 --- a/platform/ui/src/components/Icon/getIcon.jsx +++ b/platform/ui/src/components/Icon/getIcon.jsx @@ -57,6 +57,7 @@ import oldDotCircle from './../../assets/icons/old-dot-circle.svg'; import oldAngleLeft from './../../assets/icons/old-angle-left.svg'; import oldReset from './../../assets/icons/old-reset.svg'; import oldCircleO from './../../assets/icons/old-circle-o.svg'; +import oldTrash from './../../assets/icons/old-trash.svg'; const ICONS = { 'arrow-down': arrowDown, @@ -114,7 +115,8 @@ const ICONS = { 'old-dot-circle': oldDotCircle, 'old-angle-left': oldAngleLeft, 'old-reset': oldReset, - 'old-circle-o': oldCircleO + 'old-circle-o': oldCircleO, + 'old-trash': oldTrash }; /** diff --git a/platform/viewer/src/appInit.js b/platform/viewer/src/appInit.js index 3c35dd487..fa424036b 100644 --- a/platform/viewer/src/appInit.js +++ b/platform/viewer/src/appInit.js @@ -33,7 +33,7 @@ function appInit(appConfigOrFunc, defaultExtensions) { /** Used by commands to inject `viewports` from "redux" */ getAppState: () => { }, /** Used by commands to determine active context */ - getActiveContexts: () => ['VIEWER', 'ACTIVE_VIEWPORT::CORNERSTONE'], + getActiveContexts: () => ['VIEWER', 'DEFAULT', 'ACTIVE_VIEWPORT::CORNERSTONE'], }; const servicesManager = new ServicesManager();