feat!: Ability to configure cornerstone tools via extension configuration (#1229)

* Fix ExtensionManager bug and add test to bandaid

* Add tools configuration to extension manager preinit

* Fix reducing of configs

* Merge internal with external configs

* Merge internal with external configs

* Remove dialog from init in measurementstable

* Testing injected configuration

* New way to set config

* Add new prop to dialog provider to allow disabling last position

* Remove code from preinit in cornerstone

* Add new prop to dialog provider to allow disabling last position

* Add centralize to dialogs

* Reorder dialogs when adding them

* Fix draggable styles (cursor)

* Remove repositioning methods from labelling flow and remove overlay from labelling manager

* Fix empty array being set in bringToFront

* Add new command to update table and pass commands manager to modules/preinit hook

* Ad UIContextMenu service / factory

* Use new contextmenu service in measurementspanel extension

* Use dialogs for arrow annotate in default

* Remove positioning funcionality from tool context menu

* Add context menu service

* Pass commandsModule to extension

* Update edit description dialog and simple dialog to position relative

* Remove style code from labelling flow and manager

* Remove eventdata from labelling

* Remove labelling code from measurement init

* Add commandsmanager to provider

* Update contextmenu provider and service

* Add touchstart and mouseclick to hide contextmenu

* Hide labelling if click/touch

* Remove labelling and context menu dead code

* Fix undefined bug if ViewerMain grid has no children

* Fix broken prop on context menu

* Update commandsmodule based on master

* Fix broken configuration

* Update script tag config

* Remove cornerstone from toolcontextmenu

* Remove cornerstone from toolcontextmenu

* Split labelling and context menu providers

* Split labelling and context menu providers

* Update test

* Destructure extensions into new array

* CR Update: Move default arrow config to cornerstone instead of default

* CR Update: Fix app configuration props structure

* CR Update: Fix app configuration prop in script tag and extract commands manager from providers

* CR Update: Create custom providers to use commandsManager

* CR Update: Use services directly in measurementspanel

* CR Update: Pass components to providers

* CR Update: Remove position from dialog

* CR Update: fix dialog prop check

* CR Update: Fix comments

* CR Update: Update documentation

* CR Update: Add test default configuration

* CR Update: Add default empy array to extensions

* CR Update: Update i18n configuration all ot match current function configuration

* CR Update: Add defaults to injected dependencies in configuration and extension configuration

* CR Update: Add defaults to configuration with no args

* Update documentation

* CR Update: Add default for tools

* CR Update: Update config object to i18n

* CR Update: spread defaults

* CR Update: Add tool configuration example to cornerstone extension

* CR Update: Add tool configuration to netlify (testing)

* CR Update: Remove netlify config for tools

* CR Update: Rollback changes to i18n to be fixed later

* CR Update: Update documentation and pass whole cornerstone config object instead of tools key

SEE: https://www.conventionalcommits.org/en/v1.0.0/#commit-message-with-both-and-breaking-change-footer

BREAKING CHANGE: modifies the exposed react <App /> components props. The contract for providing configuration for the app has changed. Please reference updated documentation for guidance.
This commit is contained in:
Igor Octaviano authored and Danny Brown committed 2019-12-09 12:47:23 -05:00
1 parent fd7620ced9
commit 55a580659e
66 files changed
+1464 -1223

No files matched your search

@@ -1,19 +1,7 @@
import OHIF from '@ohif/core';
import cornerstone from 'cornerstone-core';
import csTools from 'cornerstone-tools';
import {
getToolLabellingFlowCallback,
getOnRightClickCallback,
getOnTouchPressCallback,
getResetLabellingAndContextMenu,
} from './labelingFlowCallbacks.js';
import throttle from 'lodash.throttle';
import { SimpleDialog } from '@ohif/ui';
// TODO: This only works because we have a hard dependency on this extension
// We need to decouple and make stuff like this possible w/o bundling this at
// build time
import store from './../../store';
const {
onAdded,
@@ -33,92 +21,18 @@ const MEASUREMENT_ACTION_MAP = {
*
*
* @export
* @param {*} configuration
* @param {Object} servicesManager
* @param {Object} configuration
*/
export default function init({ servicesManager, configuration = {} }) {
const { UIDialogService } = servicesManager.services;
const callInputDialog = (data, event, callback) => {
let dialogId = UIDialogService.create({
content: SimpleDialog.InputDialog,
defaultPosition: {
x: (event && event.currentPoints.canvas.x) || 0,
y: (event && event.currentPoints.canvas.y) || 0,
},
showOverlay: true,
contentProps: {
title: 'Enter your annotation',
label: 'New label',
defaultValue: data ? data.text : '',
onClose: () => UIDialogService.dismiss({ id: dialogId }),
onSubmit: value => {
callback(value);
UIDialogService.dismiss({ id: dialogId });
},
},
});
};
// If these tools were already added by a different extension, we want to replace
// them with the same tools that have an alternative configuration. By passing in
// our custom `getMeasurementLocationCallback`, we can...
const toolLabellingFlowCallback = getToolLabellingFlowCallback(store);
// Removes all tools from all enabled elements w/ provided name
// Not commonly used API, so :eyes: for unknown side-effects
csTools.removeTool('Bidirectional');
csTools.removeTool('Length');
csTools.removeTool('Angle');
csTools.removeTool('FreehandRoi');
csTools.removeTool('EllipticalRoi');
csTools.removeTool('CircleRoi');
csTools.removeTool('RectangleRoi');
csTools.removeTool('ArrowAnnotate');
// Re-add each tool w/ our custom configuration
csTools.addTool(csTools.BidirectionalTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.LengthTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.AngleTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.FreehandRoiTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.EllipticalRoiTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.CircleRoiTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.RectangleRoiTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
},
});
csTools.addTool(csTools.ArrowAnnotateTool, {
configuration: {
getMeasurementLocationCallback: toolLabellingFlowCallback,
getTextCallback: (callback, eventDetails) =>
callInputDialog(null, eventDetails, callback),
changeTextCallback: (data, eventDetails, callback) =>
callInputDialog(data, eventDetails, callback),
},
});
export default function init({
servicesManager,
commandsManager,
configuration,
}) {
const {
UIContextMenuService,
UILabellingFlowService,
} = servicesManager.services;
// TODO: MEASUREMENT_COMPLETED (not present in initial implementation)
const onMeasurementsChanged = (action, event) => {
@@ -131,15 +45,43 @@ export default function init({ servicesManager, configuration = {} }) {
this,
'labelmapModified'
);
//
const onRightClick = getOnRightClickCallback(store);
const onTouchPress = getOnTouchPressCallback(store);
const onNewImage = getResetLabellingAndContextMenu(store);
const onMouseClick = getResetLabellingAndContextMenu(store);
const onTouchStart = getResetLabellingAndContextMenu(store);
// Because click gives us the native "mouse up", buttons will always be `0`
// Need to fallback to event.which;
const onRightClick = event => {
if (UIContextMenuService) {
UIContextMenuService.show({ event: event.detail });
}
};
const onTouchPress = event => {
if (UIContextMenuService) {
UIContextMenuService.show({
event: event.detail,
props: {
isTouchEvent: true,
},
});
}
};
const onTouchStart = () => resetLabelligAndContextMenu();
const onMouseClick = () => resetLabelligAndContextMenu();
const resetLabelligAndContextMenu = () => {
if (UILabellingFlowService && UIContextMenuService) {
UILabellingFlowService.hide();
UIContextMenuService.hide();
}
};
// TODO: This makes scrolling painfully slow
// const onNewImage = ...
/*
* Because click gives us the native "mouse up", buttons will always be `0`
* Need to fallback to event.which;
*
*/
const handleClick = cornerstoneMouseClickEvent => {
const mouseUpEvent = cornerstoneMouseClickEvent.detail.event;
const isRightClick = mouseUpEvent.which === 3;
@@ -170,10 +112,11 @@ export default function init({ servicesManager, configuration = {} }) {
csTools.EVENTS.LABELMAP_MODIFIED,
onLabelmapModified
);
//
element.addEventListener(csTools.EVENTS.TOUCH_PRESS, onTouchPress);
element.addEventListener(csTools.EVENTS.MOUSE_CLICK, handleClick);
element.addEventListener(csTools.EVENTS.TOUCH_START, onTouchStart);
// TODO: This makes scrolling painfully slow
// element.addEventListener(cornerstone.EVENTS.NEW_IMAGE, onNewImage);
}
@@ -197,10 +140,12 @@ export default function init({ servicesManager, configuration = {} }) {
csTools.EVENTS.LABELMAP_MODIFIED,
onLabelmapModified
);
//
element.removeEventListener(csTools.EVENTS.TOUCH_PRESS, onTouchPress);
element.removeEventListener(csTools.EVENTS.MOUSE_CLICK, handleClick);
element.removeEventListener(csTools.EVENTS.TOUCH_START, onTouchStart);
// TODO: This makes scrolling painfully slow
// element.removeEventListener(cornerstone.EVENTS.NEW_IMAGE, onNewImage);
}