Adding inputs to define hotkeys
This commit is contained in:
parent
bbb1cf0789
commit
20f274962b
@ -12,7 +12,10 @@ export class HotkeysContext {
|
|||||||
Object.keys(definitions).forEach(command => {
|
Object.keys(definitions).forEach(command => {
|
||||||
const hotkey = definitions[command];
|
const hotkey = definitions[command];
|
||||||
this.unregister(command);
|
this.unregister(command);
|
||||||
this.register(command, hotkey);
|
if (hotkey) {
|
||||||
|
this.register(command, hotkey);
|
||||||
|
}
|
||||||
|
|
||||||
this.definitions[command] = hotkey;
|
this.definitions[command] = hotkey;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template name="hotkeysDialog">
|
<template name="hotkeysDialog">
|
||||||
{{#dialogSimple title='Keyboard Shortcuts'}}
|
{{#dialogSimple (extend this dialogClass='dialog-hotkeys' title='Keyboard Shortcuts')}}
|
||||||
{{>hotkeysForm}}
|
{{>hotkeysForm this}}
|
||||||
{{/dialogSimple}}
|
{{/dialogSimple}}
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
3
Packages/ohif-hotkeys/client/components/dialog.styl
Normal file
3
Packages/ohif-hotkeys/client/components/dialog.styl
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.dialog-hotkeys .modal-body
|
||||||
|
max-height: 80vh
|
||||||
|
overflow-y: auto
|
||||||
@ -1,5 +1,7 @@
|
|||||||
<template name="hotkeysForm">
|
<template name="hotkeysForm">
|
||||||
{{#form class='form-themed'}}
|
{{#form (extend this class='form-themed')}}
|
||||||
{{>inputText class='hotkey' label='Window W/L'}}
|
{{#each hotkeyInputInformation in getHotkeyInputInformationList}}
|
||||||
|
{{>inputText (extend hotkeyInputInformation class='hotkey')}}
|
||||||
|
{{/each}}
|
||||||
{{/form}}
|
{{/form}}
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
import { Template } from 'meteor/templating';
|
import { Template } from 'meteor/templating';
|
||||||
import { $ } from 'meteor/jquery';
|
import { $ } from 'meteor/jquery';
|
||||||
import { _ } from 'meteor/underscore';
|
import { _ } from 'meteor/underscore';
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
Template.hotkeysForm.onCreated(() => {
|
Template.hotkeysForm.onCreated(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
@ -38,6 +40,19 @@ Template.hotkeysForm.onCreated(() => {
|
|||||||
|
|
||||||
return keysPressedArray;
|
return keysPressedArray;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
instance.disallowedCombinations = {
|
||||||
|
'': [],
|
||||||
|
ALT: ['SPACE'],
|
||||||
|
SHIFT: [],
|
||||||
|
CTRL: ['F4', 'F5', 'F11', 'W', 'R', 'T', 'O', 'P', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'L', 'Z', 'X', 'C', 'V', 'B', 'N', 'PAGEDOWN', 'PAGEUP'],
|
||||||
|
'CTRL+SHIFT': ['Q', 'W', 'R', 'T', 'P', 'A', 'H', 'V', 'B', 'N']
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// >>>> REMOVE ME
|
||||||
|
Meteor.startup(() => {
|
||||||
|
OHIF.ui.showDialog('hotkeysDialog', { contextName: 'viewer' });
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.hotkeysForm.events({
|
Template.hotkeysForm.events({
|
||||||
@ -52,7 +67,47 @@ Template.hotkeysForm.events({
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'blur .hotkey'(event, instance) {
|
||||||
|
const $target = $(event.currentTarget);
|
||||||
|
const combination = $target.val();
|
||||||
|
const keys = combination.split('+');
|
||||||
|
const lastKey = keys.pop();
|
||||||
|
const modifierCombination = keys.join('+');
|
||||||
|
const isModifier = ['CTRL', 'ALT', 'SHIFT'].indexOf(lastKey) > -1;
|
||||||
|
// Clean the input if left with only a modifier key or browser specific command
|
||||||
|
if (isModifier) {
|
||||||
|
$target.val('');
|
||||||
|
} else if (instance.disallowedCombinations[modifierCombination].indexOf(lastKey) > -1) {
|
||||||
|
$target.val('');
|
||||||
|
// TODO: show warning
|
||||||
|
$target.focus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
'keyup .hotkey'(event, instance) {
|
'keyup .hotkey'(event, instance) {
|
||||||
instance.updateInputText(event);
|
instance.updateInputText(event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Template.hotkeysForm.helpers({
|
||||||
|
getHotkeyInputInformationList() {
|
||||||
|
OHIF.context.dep.depend();
|
||||||
|
const instance = Template.instance();
|
||||||
|
const { contextName } = instance.data;
|
||||||
|
const hotkeysInputInformation = [];
|
||||||
|
const hotkeysContext = OHIF.hotkeys.getContext(contextName);
|
||||||
|
const commandsContext = OHIF.commands.getContext(contextName);
|
||||||
|
if (!hotkeysContext || !commandsContext) return hotkeysInputInformation;
|
||||||
|
const hotkeyDefinitions = hotkeysContext.definitions;
|
||||||
|
_.each(hotkeyDefinitions, (keyCombination, commandName) => {
|
||||||
|
const commandDefinitions = commandsContext[commandName];
|
||||||
|
if (!commandDefinitions) return;
|
||||||
|
hotkeysInputInformation.push({
|
||||||
|
key: commandName,
|
||||||
|
label: commandDefinitions.name,
|
||||||
|
value: keyCombination
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return hotkeysInputInformation;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import './dialog.html';
|
import './dialog.html';
|
||||||
|
import './dialog.styl';
|
||||||
|
|
||||||
import './form.html';
|
import './form.html';
|
||||||
import './form.js';
|
import './form.js';
|
||||||
|
|||||||
@ -15,6 +15,7 @@ Package.onUse(function(api) {
|
|||||||
api.use([
|
api.use([
|
||||||
'ecmascript',
|
'ecmascript',
|
||||||
'templating',
|
'templating',
|
||||||
|
'stylus',
|
||||||
'reactive-var',
|
'reactive-var',
|
||||||
'session',
|
'session',
|
||||||
'iron:router',
|
'iron:router',
|
||||||
|
|||||||
@ -22,31 +22,54 @@ Meteor.startup(function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
OHIF.viewer.defaultHotkeys = {
|
OHIF.viewer.defaultHotkeys = {
|
||||||
|
// Tool hotkeys
|
||||||
defaultTool: 'ESC',
|
defaultTool: 'ESC',
|
||||||
|
zoom: 'Z',
|
||||||
|
wwwc: 'W',
|
||||||
|
pan: 'P',
|
||||||
angle: 'A',
|
angle: 'A',
|
||||||
stackScroll: 'S',
|
stackScroll: 'S',
|
||||||
pan: 'P',
|
|
||||||
magnify: 'M',
|
magnify: 'M',
|
||||||
scrollDown: 'DOWN',
|
length: '',
|
||||||
scrollUp: 'UP',
|
annotate: '',
|
||||||
nextDisplaySet: 'PAGEDOWN',
|
dragProbe: '',
|
||||||
previousDisplaySet: 'PAGEUP',
|
ellipticalRoi: '',
|
||||||
nextPanel: 'RIGHT',
|
rectangleRoi: '',
|
||||||
previousPanel: 'LEFT',
|
spine: '',
|
||||||
invert: 'I',
|
|
||||||
flipV: 'V',
|
// Viewport hotkeys
|
||||||
flipH: 'H',
|
flipH: 'H',
|
||||||
wwwc: 'W',
|
flipV: 'V',
|
||||||
zoom: 'Z',
|
|
||||||
toggleCinePlay: 'SPACE',
|
|
||||||
rotateR: 'R',
|
rotateR: 'R',
|
||||||
rotateL: 'L',
|
rotateL: 'L',
|
||||||
|
invert: 'I',
|
||||||
|
zoomIn: '',
|
||||||
|
zoomOut: '',
|
||||||
|
zoomToFit: '',
|
||||||
|
resetViewport: '',
|
||||||
|
clearTools: '',
|
||||||
|
|
||||||
|
// Viewport navigation hotkeys
|
||||||
|
scrollDown: 'DOWN',
|
||||||
|
scrollUp: 'UP',
|
||||||
|
scrollLastImage: '',
|
||||||
|
scrollFirstImage: '',
|
||||||
|
previousDisplaySet: 'PAGEUP',
|
||||||
|
nextDisplaySet: 'PAGEDOWN',
|
||||||
|
nextPanel: 'RIGHT',
|
||||||
|
previousPanel: 'LEFT',
|
||||||
|
|
||||||
|
// Miscellaneous hotkeys
|
||||||
toggleOverlayTags: 'SHIFT',
|
toggleOverlayTags: 'SHIFT',
|
||||||
WLPresetSoftTissue: ['NUMPAD1', '1'],
|
toggleCinePlay: 'SPACE',
|
||||||
WLPresetLung: ['NUMPAD2', '2'],
|
toggleCineDialog: '',
|
||||||
WLPresetLiver: ['NUMPAD3', '3'],
|
|
||||||
WLPresetBone: ['NUMPAD4', '4'],
|
// Preset hotkeys
|
||||||
WLPresetBrain: ['NUMPAD5', '5']
|
WLPresetSoftTissue: '1',
|
||||||
|
WLPresetLung: '2',
|
||||||
|
WLPresetLiver: '3',
|
||||||
|
WLPresetBone: '4',
|
||||||
|
WLPresetBrain: '5'
|
||||||
};
|
};
|
||||||
|
|
||||||
// For now
|
// For now
|
||||||
@ -71,21 +94,27 @@ Meteor.startup(function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Register the default tool command
|
||||||
|
OHIF.commands.register(contextName, 'defaultTool', {
|
||||||
|
name: 'Default Tool',
|
||||||
|
action: () => toolManager.setActiveTool(toolManager.getDefaultTool())
|
||||||
|
});
|
||||||
|
|
||||||
// Register the tool switching commands
|
// Register the tool switching commands
|
||||||
registerToolCommands({
|
registerToolCommands({
|
||||||
wwwc: 'Levels',
|
wwwc: 'Window W/L',
|
||||||
zoom: 'Zoom',
|
zoom: 'Zoom',
|
||||||
angle: 'Angle',
|
angle: 'Angle Measurement',
|
||||||
dragProbe: 'Probe',
|
dragProbe: 'Pixel Probe',
|
||||||
ellipticalRoi: 'Ellipse',
|
ellipticalRoi: 'Elliptical Probe',
|
||||||
rectangleRoi: 'Rectangle',
|
rectangleRoi: 'Rectangle',
|
||||||
magnify: 'Magnify',
|
magnify: 'Magnify',
|
||||||
annotate: 'Annotate',
|
annotate: 'Annotate',
|
||||||
stackScroll: 'Stack Scroll',
|
stackScroll: 'Scroll Stack',
|
||||||
pan: 'Pan',
|
pan: 'Pan',
|
||||||
length: 'Length',
|
length: 'Length Measurement',
|
||||||
spine: 'Spine',
|
spine: 'Spine Labels',
|
||||||
wwwcRegion: 'ROI Window'
|
wwwcRegion: 'W/L by Region'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Functions to register the viewport commands
|
// Functions to register the viewport commands
|
||||||
@ -99,16 +128,16 @@ Meteor.startup(function() {
|
|||||||
|
|
||||||
// Register the viewport commands
|
// Register the viewport commands
|
||||||
registerViewportCommands({
|
registerViewportCommands({
|
||||||
zoomIn: 'Zoom in',
|
zoomIn: 'Zoom In',
|
||||||
zoomOut: 'Zoom out',
|
zoomOut: 'Zoom Out',
|
||||||
zoomToFit: 'Zoom to fit',
|
zoomToFit: 'Zoom to Fit',
|
||||||
invert: 'Invert',
|
invert: 'Invert',
|
||||||
flipH: 'Flip horizontally',
|
flipH: 'Flip Horizontally',
|
||||||
flipV: 'Flip vertically',
|
flipV: 'Flip Vertically',
|
||||||
rotateR: 'Rotate right',
|
rotateR: 'Rotate Right',
|
||||||
rotateL: 'Rotate left',
|
rotateL: 'Rotate Left',
|
||||||
resetViewport: 'Reset',
|
resetViewport: 'Reset',
|
||||||
clearTools: 'Clear'
|
clearTools: 'Clear Tools'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Functions to register the preset switching commands
|
// Functions to register the preset switching commands
|
||||||
@ -122,75 +151,67 @@ Meteor.startup(function() {
|
|||||||
|
|
||||||
// Register the preset switching commands
|
// Register the preset switching commands
|
||||||
registerWLPresetCommands({
|
registerWLPresetCommands({
|
||||||
WLPresetSoftTissue: 'SoftTissue',
|
WLPresetSoftTissue: 'W/L Preset: Soft Tissue',
|
||||||
WLPresetLung: 'Lung',
|
WLPresetLung: 'W/L Preset: Lung',
|
||||||
WLPresetLiver: 'Liver',
|
WLPresetLiver: 'W/L Preset: Liver',
|
||||||
WLPresetBone: 'Bone',
|
WLPresetBone: 'W/L Preset: Bone',
|
||||||
WLPresetBrain: 'Brain'
|
WLPresetBrain: 'W/L Preset: Brain'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Register scrolling commands
|
|
||||||
OHIF.commands.set(contextName, {
|
|
||||||
scrollDown: {
|
|
||||||
name: 'Scroll down',
|
|
||||||
action: () => !isActiveViewportEmpty() && switchToImageRelative(1)
|
|
||||||
},
|
|
||||||
scrollUp: {
|
|
||||||
name: 'Scroll up',
|
|
||||||
action: () => !isActiveViewportEmpty() && switchToImageRelative(-1)
|
|
||||||
},
|
|
||||||
scrollFirstImage: {
|
|
||||||
name: 'Scroll to first image',
|
|
||||||
action: () => !isActiveViewportEmpty() && switchToImageByIndex(0)
|
|
||||||
},
|
|
||||||
scrollLastImage: {
|
|
||||||
name: 'Scroll to last image',
|
|
||||||
action: () => !isActiveViewportEmpty() && switchToImageByIndex(-1)
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
// Register viewport navigation commands
|
// Register viewport navigation commands
|
||||||
OHIF.commands.set(contextName, {
|
OHIF.commands.set(contextName, {
|
||||||
|
scrollDown: {
|
||||||
|
name: 'Scroll Down',
|
||||||
|
action: () => !isActiveViewportEmpty() && switchToImageRelative(1)
|
||||||
|
},
|
||||||
|
scrollUp: {
|
||||||
|
name: 'Scroll Up',
|
||||||
|
action: () => !isActiveViewportEmpty() && switchToImageRelative(-1)
|
||||||
|
},
|
||||||
|
scrollFirstImage: {
|
||||||
|
name: 'Scroll to First Image',
|
||||||
|
action: () => !isActiveViewportEmpty() && switchToImageByIndex(0)
|
||||||
|
},
|
||||||
|
scrollLastImage: {
|
||||||
|
name: 'Scroll to Last Image',
|
||||||
|
action: () => !isActiveViewportEmpty() && switchToImageByIndex(-1)
|
||||||
|
},
|
||||||
previousDisplaySet: {
|
previousDisplaySet: {
|
||||||
name: 'Previous display set',
|
name: 'Previous Series',
|
||||||
action: () => OHIF.viewerbase.layoutManager.moveDisplaySets(false),
|
action: () => OHIF.viewerbase.layoutManager.moveDisplaySets(false),
|
||||||
disabled: () => !OHIF.viewerbase.layoutManager.canMoveDisplaySets(false)
|
disabled: () => !OHIF.viewerbase.layoutManager.canMoveDisplaySets(false)
|
||||||
},
|
},
|
||||||
nextDisplaySet: {
|
nextDisplaySet: {
|
||||||
name: 'Next display set',
|
name: 'Next Series',
|
||||||
action: () => OHIF.viewerbase.layoutManager.moveDisplaySets(true),
|
action: () => OHIF.viewerbase.layoutManager.moveDisplaySets(true),
|
||||||
disabled: () => !OHIF.viewerbase.layoutManager.canMoveDisplaySets(true)
|
disabled: () => !OHIF.viewerbase.layoutManager.canMoveDisplaySets(true)
|
||||||
},
|
},
|
||||||
nextPanel: {
|
nextPanel: {
|
||||||
name: 'Next panel',
|
name: 'Next Panel',
|
||||||
action: () => panelNavigation.loadNextActivePanel()
|
action: () => panelNavigation.loadNextActivePanel()
|
||||||
},
|
},
|
||||||
previousPanel: {
|
previousPanel: {
|
||||||
name: 'Previous panel',
|
name: 'Previous Panel',
|
||||||
action: () => panelNavigation.loadPreviousActivePanel()
|
action: () => panelNavigation.loadPreviousActivePanel()
|
||||||
}
|
}
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
// Register miscellaneous commands
|
// Register miscellaneous commands
|
||||||
OHIF.commands.set(contextName, {
|
OHIF.commands.set(contextName, {
|
||||||
defaultTool: {
|
|
||||||
name: 'Default tool',
|
|
||||||
action: () => toolManager.setActiveTool(toolManager.getDefaultTool())
|
|
||||||
},
|
|
||||||
toggleOverlayTags: {
|
toggleOverlayTags: {
|
||||||
name: 'Toggle overlay tags',
|
name: 'Toggle Image Annotations',
|
||||||
action() {
|
action() {
|
||||||
const $dicomTags = $('.imageViewerViewportOverlay .dicomTag');
|
const $dicomTags = $('.imageViewerViewportOverlay .dicomTag');
|
||||||
$dicomTags.toggle($dicomTags.eq(0).css('display') === 'none');
|
$dicomTags.toggle($dicomTags.eq(0).css('display') === 'none');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleCinePlay: {
|
toggleCinePlay: {
|
||||||
name: 'Play/Pause',
|
name: 'Play/Pause Cine',
|
||||||
action: viewportUtils.toggleCinePlay,
|
action: viewportUtils.toggleCinePlay,
|
||||||
disabled: OHIF.viewerbase.viewportUtils.hasMultipleFrames
|
disabled: OHIF.viewerbase.viewportUtils.hasMultipleFrames
|
||||||
},
|
},
|
||||||
toggleCineDialog: {
|
toggleCineDialog: {
|
||||||
name: 'CINE dialog',
|
name: 'Show/Hide Cine Controls',
|
||||||
action: viewportUtils.toggleCineDialog,
|
action: viewportUtils.toggleCineDialog,
|
||||||
disabled: OHIF.viewerbase.viewportUtils.hasMultipleFrames
|
disabled: OHIF.viewerbase.viewportUtils.hasMultipleFrames
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user