Integrate Cornerstone Tools v3 (#235) - WIP

fix(mouse-buttons): Support for assigning tools to mouse buttons (left, right, middle)
fix(tool-naming): Fix tool naming issues
This commit is contained in:
Evren Ozkan 2018-10-26 23:45:19 -04:00
parent 7bf059ad05
commit 3f2968b05f
9 changed files with 170 additions and 121 deletions

View File

@ -288,28 +288,29 @@ Template.toolbarSection.onCreated( function() {
});
Template.toolbarSection.onRendered(function() {
// Set disabled/enabled tool buttons that are set in toolManager
const states = Viewerbase.toolManager.getToolDefaultStates();
const disabledToolButtons = states.disabledToolButtons;
const allToolbarButtons = $('.toolbarSection').find('.toolbarSectionButton:not(.nonAutoDisableState)');
// Additional toolbar buttons whose classes are not toolbarSectionButton
allToolbarButtons.push($('#toolbarSectionEntry')[0]);
allToolbarButtons.push($('#toggleMeasurements')[0]);
if (disabledToolButtons && disabledToolButtons.length > 0) {
for (let i = 0; i < allToolbarButtons.length; i++) {
const toolbarButton = allToolbarButtons[i];
const index = disabledToolButtons.indexOf($(toolbarButton).attr('id'));
if (index !== -1) {
$(toolbarButton).addClass('disabled');
$(toolbarButton).find('*').addClass('disabled');
} else {
$(toolbarButton).removeClass('disabled');
$(toolbarButton).find('*').removeClass('disabled');
}
}
}
// TODO: Figure out a way to disable/enable the buttons with each status from New API
// // Set disabled/enabled tool buttons that are set in toolManager
// const states = Viewerbase.toolManager.getToolDefaultStates();
// const disabledToolButtons = states.disabledToolButtons;
// const allToolbarButtons = $('.toolbarSection').find('.toolbarSectionButton:not(.nonAutoDisableState)');
//
// // Additional toolbar buttons whose classes are not toolbarSectionButton
// allToolbarButtons.push($('#toolbarSectionEntry')[0]);
// allToolbarButtons.push($('#toggleMeasurements')[0]);
//
// if (disabledToolButtons && disabledToolButtons.length > 0) {
// for (let i = 0; i < allToolbarButtons.length; i++) {
// const toolbarButton = allToolbarButtons[i];
// const index = disabledToolButtons.indexOf($(toolbarButton).attr('id'));
// if (index !== -1) {
// $(toolbarButton).addClass('disabled');
// $(toolbarButton).find('*').addClass('disabled');
// } else {
// $(toolbarButton).removeClass('disabled');
// $(toolbarButton).find('*').removeClass('disabled');
// }
// }
// }
});
Template.caseProgress.onDestroyed(() => {

View File

@ -303,20 +303,20 @@ Template.toolbarSection.onRendered(function() {
OHIF.viewerbase.viewportUtils.toggleCineDialog();
}
// Set disabled/enabled tool buttons that are set in toolManager
const states = OHIF.viewerbase.toolManager.getToolDefaultStates();
const disabledToolButtons = states.disabledToolButtons;
const allToolbarButtons = $('#toolbar').find('button');
if (disabledToolButtons && disabledToolButtons.length > 0) {
for (let i = 0; i < allToolbarButtons.length; i++) {
const toolbarButton = allToolbarButtons[i];
$(toolbarButton).prop('disabled', false);
const index = disabledToolButtons.indexOf($(toolbarButton).attr('id'));
if (index !== -1) {
$(toolbarButton).prop('disabled', true);
}
}
}
// TODO: Figure out a way to disable/enable the buttons with each status from New API
// // Set disabled/enabled tool buttons that are set in toolManager
// const states = OHIF.viewerbase.toolManager.getToolDefaultStates();
// const disabledToolButtons = states.disabledToolButtons;
// const allToolbarButtons = $('#toolbar').find('button');
// if (disabledToolButtons && disabledToolButtons.length > 0) {
// for (let i = 0; i < allToolbarButtons.length; i++) {
// const toolbarButton = allToolbarButtons[i];
// $(toolbarButton).prop('disabled', false);
//
// const index = disabledToolButtons.indexOf($(toolbarButton).attr('id'));
// if (index !== -1) {
// $(toolbarButton).prop('disabled', true);
// }
// }
// }
});

View File

@ -48,7 +48,12 @@ Meteor.startup(() => {
Session.setDefault('leftSidebar', false);
Session.setDefault('rightSidebar', false);
OHIF.viewer.defaultTool = 'wwwc';
OHIF.viewer.defaultTool = {
left: 'wwwc',
right: 'zoom',
middle: 'pan'
};
OHIF.viewer.refLinesEnabled = true;
OHIF.viewer.cine = {
framesPerSecond: 24,

View File

@ -6,8 +6,8 @@ Package.describe({
Npm.depends({
hammerjs: '2.0.8',
'cornerstone-core': '2.2.6',
'cornerstone-tools': '3.0.0-b.969',
'cornerstone-core': '2.2.7',
'cornerstone-tools': '3.0.0-b.1020',
'cornerstone-math': '0.1.6',
'dicom-parser': '1.8.0',
'cornerstone-wado-image-loader': '2.1.4',

View File

@ -272,8 +272,7 @@ const loadDisplaySetIntoViewport = (data, templateData) => {
// Use the tool manager to enable the currently active tool for this
// newly rendered element
const activeTool = toolManager.getActiveTool();
toolManager.setActiveTool(activeTool);
toolManager.setActiveTool();
// Define a function to run whenever the Cornerstone viewport is rendered
// (e.g. following a change of window or zoom)
@ -453,6 +452,7 @@ const loadDisplaySetIntoViewport = (data, templateData) => {
// that is used for its synchronized viewport updating.
// This is necessary if this new image shares a frame of reference
// with currently displayed images
const activeTool = toolManager.getActiveTool();
if (activeTool === 'crosshairs') {
updateCrosshairsSynchronizer(imagePlane.frameOfReferenceUID);
}

View File

@ -50,10 +50,10 @@ Template.textMarkerDialogs.events({
cornerstone.updateImage(element);
},
'click .closeTextMarkerDialogs'() {
const defaultTool = toolManager.getDefaultTool();
toolManager.setActiveTool(defaultTool);
toolManager.setActiveTool();
document.getElementById('textMarkerOptionsDialog').close();
$('#spine').removeClass('active');
const defaultTool = toolManager.getDefaultTool();
$('#' + defaultTool).addClass('active');
}

View File

@ -13,7 +13,13 @@ import { WLPresets } from './WLPresets';
// TODO: add this to namespace definitions
Meteor.startup(function() {
OHIF.viewer.loadIndicatorDelay = 200;
OHIF.viewer.defaultTool = 'Wwwc';
OHIF.viewer.defaultTool = {
left: 'wwwc',
right: 'zoom',
middle: 'pan'
};
OHIF.viewer.refLinesEnabled = true;
OHIF.viewer.isPlaying = {};
OHIF.viewer.cine = {
@ -24,17 +30,17 @@ Meteor.startup(function() {
OHIF.viewer.defaultHotkeys = {
// Tool hotkeys
defaultTool: 'ESC',
Zoom: 'Z',
Wwwc: 'W',
Pan: 'P',
Angle: 'A',
StackScroll: 'S',
Magnify: 'M',
Length: '',
Annotate: '',
DragProbe: '',
EllipticalRoi: '',
RectangleRoi: '',
zoom: 'Z',
wwwc: 'W',
pan: 'P',
angle: 'A',
stackScroll: 'S',
magnify: 'M',
length: '',
annotate: '',
dragProbe: '',
ellipticalRoi: '',
rectangleRoi: '',
// Viewport hotkeys
flipH: 'H',
@ -102,25 +108,24 @@ Meteor.startup(function() {
// Register the default tool command
OHIF.commands.register(contextName, 'defaultTool', {
name: 'Default Tool',
action: () => toolManager.setActiveTool(toolManager.getDefaultTool())
action: () => toolManager.setActiveTool()
});
// Register the tool switching commands
registerToolCommands({
Wwwc: 'W/L',
Zoom: 'Zoom',
Angle: 'Angle Measurement',
DragProbe: 'Pixel Probe',
StackScroll: 'Stack Scroll',
EllipticalRoi: 'Elliptical ROI',
RectangleRoi: 'Rectangle ROI',
Magnify: 'Magnify',
ArrowAnnotate: 'Annotate',
stackScrollMouseWheel: 'Scroll Stack Mouse Wheel',
Pan: 'Pan',
Length: 'Length Measurement',
WwwcRegion: 'W/L by Region',
Crosshairs: 'Crosshairs'
wwwc: 'W/L',
zoom: 'Zoom',
angle: 'Angle Measurement',
dragProbe: 'Pixel Probe',
ellipticalRoi: 'Elliptical ROI',
rectangleRoi: 'Rectangle ROI',
magnify: 'Magnify',
annotate: 'Annotate',
stackScroll: 'Scroll Stack',
pan: 'Pan',
length: 'Length Measurement',
wwwcRegion: 'W/L by Region',
crosshairs: 'Crosshairs'
});
// Functions to register the viewport commands

View File

@ -4,17 +4,17 @@ import { OHIF } from 'meteor/ohif:core';
import { cornerstone, cornerstoneTools } from 'meteor/ohif:cornerstone';
let activeTool;
let tools = [];
let tools = {};
let initialized = false;
let defaultTool = {
left: 'Wwwc',
right: 'Zoom',
middle: 'Pan'
left: 'wwwc',
right: 'zoom',
middle: 'pan'
};
const buttonNum = {
'left': 1,
'right': 4,
'middle': 2
'right': 2,
'middle': 4
};
/**
@ -24,29 +24,30 @@ export const toolManager = {
init() {
// if a default tool is globally defined, make it the default tool...
if (OHIF.viewer.defaultTool) {
toolManager.setDefaultTool(OHIF.viewer.defaultTool);
toolManager.setDefaultTool(OHIF.viewer.defaultTool.left);
toolManager.setDefaultTool(OHIF.viewer.defaultTool.right, 'right');
toolManager.setDefaultTool(OHIF.viewer.defaultTool.middle, 'middle');
}
cornerstoneTools.init();
tools = [
'Length',
'Angle',
'ArrowAnnotate',
'Wwwc',
'Zoom',
'Pan',
'DragProbe',
'Magnify',
'Crosshairs',
'StackScroll',
'StackScrollMouseWheel',
'ZoomTouchPinch',
'ZoomMouseWheel',
'EllipticalRoi',
'RectangleRoi',
'WwwcRegion'
];
tools = {
length: 'LengthTool',
angle: 'AngleTool',
annotate: 'ArrowAnnotateTool',
wwwc: 'WwwcTool',
zoom: 'ZoomTool',
pan: 'PanTool',
dragProbe: 'DragProbeTool',
magnify: 'MagnifyTool',
crosshairs: 'CrosshairsTool',
stackScroll: 'StackScrollTool',
zoomTouchPinch: 'ZoomTouchPinchTool',
zoomMouseWheel: 'ZoomMouseWheelTool',
ellipticalRoi: 'EllipticalRoiTool',
rectangleRoi: 'RectangleRoiTool',
wwwcRegion: 'WwwcRegionTool'
};
initialized = true;
},
@ -88,10 +89,18 @@ export const toolManager = {
},
getTools() {
return tools;
return Object.keys(tools);
},
setActiveTool(toolName, button = 'left') {
// Using setActiveTool with no arguments activates the default tools for all buttons
if (!toolName) {
toolManager.setActiveTool(toolManager.getDefaultTool());
toolManager.setActiveTool(toolManager.getDefaultTool('right'), 'right');
toolManager.setActiveTool(toolManager.getDefaultTool('middle'), 'middle');
return;
}
let options = {};
const mouseButtonMask = toolManager.getMouseButtonMask(button);
if (mouseButtonMask) {
@ -101,9 +110,36 @@ export const toolManager = {
}
toolManager.setAllToolsPassive();
cornerstoneTools.setToolActive(toolName, options);
// TODO: add the active tool with the correct button
// Set active tools for the other buttons than this one
switch(button) {
case 'left':
cornerstoneTools.setToolActive(toolManager.getActiveTool('right'), {
mouseButtonMask: toolManager.getMouseButtonMask('right')
});
cornerstoneTools.setToolActive(toolManager.getActiveTool('middle'), {
mouseButtonMask: toolManager.getMouseButtonMask('middle')
});
break;
case 'right':
cornerstoneTools.setToolActive(toolManager.getActiveTool('left'), {
mouseButtonMask: toolManager.getMouseButtonMask('left')
});
cornerstoneTools.setToolActive(toolManager.getActiveTool('middle'), {
mouseButtonMask: toolManager.getMouseButtonMask('middle')
});
break;
case 'middle':
cornerstoneTools.setToolActive(toolManager.getActiveTool('left'), {
mouseButtonMask: toolManager.getMouseButtonMask('left')
});
cornerstoneTools.setToolActive(toolManager.getActiveTool('right'), {
mouseButtonMask: toolManager.getMouseButtonMask('right')
});
break;
}
cornerstoneTools.setToolActive(toolName, options);
activeTool[button] = toolName;
// Enable reactivity
@ -111,22 +147,24 @@ export const toolManager = {
},
setAllToolsPassive() {
cornerstoneTools.store.state.tools.forEach((tool) => {
cornerstoneTools.setToolPassive(tool.name)
});
cornerstoneTools.store.state.tools.forEach((tool) => {
cornerstoneTools.setToolPassive(tool.name)
});
},
instantiateTools() {
Array.from(tools).forEach(toolName => {
const apiTool = cornerstoneTools[`${toolName}Tool`];
Object.keys(tools).forEach(toolName => {
const apiTool = cornerstoneTools[tools[toolName]];
if (apiTool) {
cornerstoneTools.addTool(apiTool);
cornerstoneTools.addTool(apiTool, { name: toolName });
}
});
toolManager.setAllToolsPassive();
},
getNearbyToolData() {
// TODO: Implement this and let the others (e.g. deleteLesionKeyboardTool) use this function
// if it does not exist in cornerstoneTools
return undefined;
},
@ -152,11 +190,11 @@ export const toolManager = {
},
activateCommandButton(button) {
//
// TODO: Do we need this?
},
deactivateCommandButton(button) {
//
// TODO: Do we need this?
}
};

View File

@ -47,42 +47,42 @@ Template.toolbarSection.helpers({
const extraTools = [];
extraTools.push({
id: 'Crosshairs',
id: 'crosshairs',
title: 'Crosshairs',
classes: 'imageViewerTool',
iconClasses: 'fa fa-crosshairs'
});
extraTools.push({
id: 'Magnify',
id: 'magnify',
title: 'Magnify',
classes: 'imageViewerTool toolbarSectionButton',
iconClasses: 'fa fa-circle'
});
extraTools.push({
id: 'WwwcRegion',
id: 'wwwcRegion',
title: 'ROI Window',
classes: 'imageViewerTool',
iconClasses: 'fa fa-square'
});
extraTools.push({
id: 'DragProbe',
id: 'dragProbe',
title: 'Probe',
classes: 'imageViewerTool',
iconClasses: 'fa fa-dot-circle-o'
});
extraTools.push({
id: 'EllipticalRoi',
id: 'ellipticalRoi',
title: 'Ellipse',
classes: 'imageViewerTool',
iconClasses: 'fa fa-circle-o'
});
extraTools.push({
id: 'RectangleRoi',
id: 'rectangleRoi',
title: 'Rectangle',
classes: 'imageViewerTool',
iconClasses: 'fa fa-square-o'
@ -126,49 +126,49 @@ Template.toolbarSection.helpers({
const buttonData = [];
buttonData.push({
id: 'StackScroll',
id: 'stackScroll',
title: 'Stack Scroll',
classes: 'imageViewerTool',
iconClasses: 'fa fa-bars'
});
buttonData.push({
id: 'Zoom',
id: 'zoom',
title: 'Zoom',
classes: 'imageViewerTool',
svgLink: 'packages/ohif_viewerbase/assets/icons.svg#icon-tools-zoom'
});
buttonData.push({
id: 'Wwwc',
id: 'wwwc',
title: 'Levels',
classes: 'imageViewerTool',
svgLink: 'packages/ohif_viewerbase/assets/icons.svg#icon-tools-levels'
});
buttonData.push({
id: 'Pan',
id: 'pan',
title: 'Pan',
classes: 'imageViewerTool',
svgLink: 'packages/ohif_viewerbase/assets/icons.svg#icon-tools-pan'
});
buttonData.push({
id: 'Length',
id: 'length',
title: 'Length',
classes: 'imageViewerTool toolbarSectionButton',
svgLink: 'packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-temp'
});
buttonData.push({
id: 'ArrowAnnotate',
id: 'annotate',
title: 'Annotate',
classes: 'imageViewerTool',
svgLink: 'packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-non-target'
});
buttonData.push({
id: 'Angle',
id: 'angle',
title: 'Angle',
classes: 'imageViewerTool',
iconClasses: 'fa fa-angle-left'