Adding inputs to define hotkeys

This commit is contained in:
Bruno Alves de Faria 2017-04-28 08:50:41 -03:00 committed by Erik Ziegler
parent bbb1cf0789
commit 20f274962b
8 changed files with 160 additions and 74 deletions

View File

@ -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;
});
}

View File

@ -1,5 +1,5 @@
<template name="hotkeysDialog">
{{#dialogSimple title='Keyboard Shortcuts'}}
{{>hotkeysForm}}
{{#dialogSimple (extend this dialogClass='dialog-hotkeys' title='Keyboard Shortcuts')}}
{{>hotkeysForm this}}
{{/dialogSimple}}
</template>

View File

@ -0,0 +1,3 @@
.dialog-hotkeys .modal-body
max-height: 80vh
overflow-y: auto

View File

@ -1,5 +1,7 @@
<template name="hotkeysForm">
{{#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}}
</template>

View File

@ -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;
}
});

View File

@ -1,4 +1,5 @@
import './dialog.html';
import './dialog.styl';
import './form.html';
import './form.js';

View File

@ -15,6 +15,7 @@ Package.onUse(function(api) {
api.use([
'ecmascript',
'templating',
'stylus',
'reactive-var',
'session',
'iron:router',

View File

@ -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
}