diff --git a/Packages/ohif-hotkeys/client/classes/HotkeysContext.js b/Packages/ohif-hotkeys/client/classes/HotkeysContext.js
index d65b32622..ebbc7a2c8 100644
--- a/Packages/ohif-hotkeys/client/classes/HotkeysContext.js
+++ b/Packages/ohif-hotkeys/client/classes/HotkeysContext.js
@@ -12,7 +12,10 @@ export class HotkeysContext {
Object.keys(definitions).forEach(command => {
const hotkey = definitions[command];
this.unregister(command);
- this.register(command, hotkey);
+ if (hotkey) {
+ this.register(command, hotkey);
+ }
+
this.definitions[command] = hotkey;
});
}
diff --git a/Packages/ohif-hotkeys/client/components/dialog.html b/Packages/ohif-hotkeys/client/components/dialog.html
index 18fb11fca..9df5d5ed8 100644
--- a/Packages/ohif-hotkeys/client/components/dialog.html
+++ b/Packages/ohif-hotkeys/client/components/dialog.html
@@ -1,5 +1,5 @@
- {{#dialogSimple title='Keyboard Shortcuts'}}
- {{>hotkeysForm}}
+ {{#dialogSimple (extend this dialogClass='dialog-hotkeys' title='Keyboard Shortcuts')}}
+ {{>hotkeysForm this}}
{{/dialogSimple}}
diff --git a/Packages/ohif-hotkeys/client/components/dialog.styl b/Packages/ohif-hotkeys/client/components/dialog.styl
new file mode 100644
index 000000000..9142edc82
--- /dev/null
+++ b/Packages/ohif-hotkeys/client/components/dialog.styl
@@ -0,0 +1,3 @@
+.dialog-hotkeys .modal-body
+ max-height: 80vh
+ overflow-y: auto
diff --git a/Packages/ohif-hotkeys/client/components/form.html b/Packages/ohif-hotkeys/client/components/form.html
index ab2fa2de6..e201f730a 100644
--- a/Packages/ohif-hotkeys/client/components/form.html
+++ b/Packages/ohif-hotkeys/client/components/form.html
@@ -1,5 +1,7 @@
- {{#form class='form-themed'}}
- {{>inputText class='hotkey' label='Window W/L'}}
+ {{#form (extend this class='form-themed')}}
+ {{#each hotkeyInputInformation in getHotkeyInputInformationList}}
+ {{>inputText (extend hotkeyInputInformation class='hotkey')}}
+ {{/each}}
{{/form}}
diff --git a/Packages/ohif-hotkeys/client/components/form.js b/Packages/ohif-hotkeys/client/components/form.js
index 2c1141220..251a64095 100644
--- a/Packages/ohif-hotkeys/client/components/form.js
+++ b/Packages/ohif-hotkeys/client/components/form.js
@@ -1,6 +1,8 @@
+import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { $ } from 'meteor/jquery';
import { _ } from 'meteor/underscore';
+import { OHIF } from 'meteor/ohif:core';
Template.hotkeysForm.onCreated(() => {
const instance = Template.instance();
@@ -38,6 +40,19 @@ Template.hotkeysForm.onCreated(() => {
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({
@@ -52,7 +67,47 @@ Template.hotkeysForm.events({
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) {
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;
+ }
+});
diff --git a/Packages/ohif-hotkeys/client/components/index.js b/Packages/ohif-hotkeys/client/components/index.js
index 28804bee3..90bf0451b 100644
--- a/Packages/ohif-hotkeys/client/components/index.js
+++ b/Packages/ohif-hotkeys/client/components/index.js
@@ -1,4 +1,5 @@
import './dialog.html';
+import './dialog.styl';
import './form.html';
import './form.js';
diff --git a/Packages/ohif-hotkeys/package.js b/Packages/ohif-hotkeys/package.js
index 0985263a7..746d6b686 100644
--- a/Packages/ohif-hotkeys/package.js
+++ b/Packages/ohif-hotkeys/package.js
@@ -15,6 +15,7 @@ Package.onUse(function(api) {
api.use([
'ecmascript',
'templating',
+ 'stylus',
'reactive-var',
'session',
'iron:router',
diff --git a/Packages/ohif-viewerbase/client/lib/hotkeyUtils.js b/Packages/ohif-viewerbase/client/lib/hotkeyUtils.js
index 1f3910fc1..f00f1b877 100644
--- a/Packages/ohif-viewerbase/client/lib/hotkeyUtils.js
+++ b/Packages/ohif-viewerbase/client/lib/hotkeyUtils.js
@@ -22,31 +22,54 @@ Meteor.startup(function() {
};
OHIF.viewer.defaultHotkeys = {
+ // Tool hotkeys
defaultTool: 'ESC',
+ zoom: 'Z',
+ wwwc: 'W',
+ pan: 'P',
angle: 'A',
stackScroll: 'S',
- pan: 'P',
magnify: 'M',
- scrollDown: 'DOWN',
- scrollUp: 'UP',
- nextDisplaySet: 'PAGEDOWN',
- previousDisplaySet: 'PAGEUP',
- nextPanel: 'RIGHT',
- previousPanel: 'LEFT',
- invert: 'I',
- flipV: 'V',
+ length: '',
+ annotate: '',
+ dragProbe: '',
+ ellipticalRoi: '',
+ rectangleRoi: '',
+ spine: '',
+
+ // Viewport hotkeys
flipH: 'H',
- wwwc: 'W',
- zoom: 'Z',
- toggleCinePlay: 'SPACE',
+ flipV: 'V',
rotateR: 'R',
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',
- WLPresetSoftTissue: ['NUMPAD1', '1'],
- WLPresetLung: ['NUMPAD2', '2'],
- WLPresetLiver: ['NUMPAD3', '3'],
- WLPresetBone: ['NUMPAD4', '4'],
- WLPresetBrain: ['NUMPAD5', '5']
+ toggleCinePlay: 'SPACE',
+ toggleCineDialog: '',
+
+ // Preset hotkeys
+ WLPresetSoftTissue: '1',
+ WLPresetLung: '2',
+ WLPresetLiver: '3',
+ WLPresetBone: '4',
+ WLPresetBrain: '5'
};
// 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
registerToolCommands({
- wwwc: 'Levels',
+ wwwc: 'Window W/L',
zoom: 'Zoom',
- angle: 'Angle',
- dragProbe: 'Probe',
- ellipticalRoi: 'Ellipse',
+ angle: 'Angle Measurement',
+ dragProbe: 'Pixel Probe',
+ ellipticalRoi: 'Elliptical Probe',
rectangleRoi: 'Rectangle',
magnify: 'Magnify',
annotate: 'Annotate',
- stackScroll: 'Stack Scroll',
+ stackScroll: 'Scroll Stack',
pan: 'Pan',
- length: 'Length',
- spine: 'Spine',
- wwwcRegion: 'ROI Window'
+ length: 'Length Measurement',
+ spine: 'Spine Labels',
+ wwwcRegion: 'W/L by Region'
});
// Functions to register the viewport commands
@@ -99,16 +128,16 @@ Meteor.startup(function() {
// Register the viewport commands
registerViewportCommands({
- zoomIn: 'Zoom in',
- zoomOut: 'Zoom out',
- zoomToFit: 'Zoom to fit',
+ zoomIn: 'Zoom In',
+ zoomOut: 'Zoom Out',
+ zoomToFit: 'Zoom to Fit',
invert: 'Invert',
- flipH: 'Flip horizontally',
- flipV: 'Flip vertically',
- rotateR: 'Rotate right',
- rotateL: 'Rotate left',
+ flipH: 'Flip Horizontally',
+ flipV: 'Flip Vertically',
+ rotateR: 'Rotate Right',
+ rotateL: 'Rotate Left',
resetViewport: 'Reset',
- clearTools: 'Clear'
+ clearTools: 'Clear Tools'
});
// Functions to register the preset switching commands
@@ -122,75 +151,67 @@ Meteor.startup(function() {
// Register the preset switching commands
registerWLPresetCommands({
- WLPresetSoftTissue: 'SoftTissue',
- WLPresetLung: 'Lung',
- WLPresetLiver: 'Liver',
- WLPresetBone: 'Bone',
- WLPresetBrain: 'Brain'
+ WLPresetSoftTissue: 'W/L Preset: Soft Tissue',
+ WLPresetLung: 'W/L Preset: Lung',
+ WLPresetLiver: 'W/L Preset: Liver',
+ WLPresetBone: 'W/L Preset: Bone',
+ 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
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: {
- name: 'Previous display set',
+ name: 'Previous Series',
action: () => OHIF.viewerbase.layoutManager.moveDisplaySets(false),
disabled: () => !OHIF.viewerbase.layoutManager.canMoveDisplaySets(false)
},
nextDisplaySet: {
- name: 'Next display set',
+ name: 'Next Series',
action: () => OHIF.viewerbase.layoutManager.moveDisplaySets(true),
disabled: () => !OHIF.viewerbase.layoutManager.canMoveDisplaySets(true)
},
nextPanel: {
- name: 'Next panel',
+ name: 'Next Panel',
action: () => panelNavigation.loadNextActivePanel()
},
previousPanel: {
- name: 'Previous panel',
+ name: 'Previous Panel',
action: () => panelNavigation.loadPreviousActivePanel()
}
}, true);
// Register miscellaneous commands
OHIF.commands.set(contextName, {
- defaultTool: {
- name: 'Default tool',
- action: () => toolManager.setActiveTool(toolManager.getDefaultTool())
- },
toggleOverlayTags: {
- name: 'Toggle overlay tags',
+ name: 'Toggle Image Annotations',
action() {
const $dicomTags = $('.imageViewerViewportOverlay .dicomTag');
$dicomTags.toggle($dicomTags.eq(0).css('display') === 'none');
}
},
toggleCinePlay: {
- name: 'Play/Pause',
+ name: 'Play/Pause Cine',
action: viewportUtils.toggleCinePlay,
disabled: OHIF.viewerbase.viewportUtils.hasMultipleFrames
},
toggleCineDialog: {
- name: 'CINE dialog',
+ name: 'Show/Hide Cine Controls',
action: viewportUtils.toggleCineDialog,
disabled: OHIF.viewerbase.viewportUtils.hasMultipleFrames
}