Browse Source

tweak bindings to work better with one-button mouse

Alexander Rose 5 years ago
parent
commit
a26d03205a

+ 7 - 7
src/mol-canvas3d/controls/trackball.ts

@@ -21,15 +21,15 @@ const M = ModifiersKeys
 const Trigger = Binding.Trigger
 
 export const DefaultTrackballBindings = {
-    dragRotate: Binding(Trigger(B.Flag.Primary, M.create()), 'Rotate the 3D scene by dragging using ${trigger}'),
-    dragRotateZ: Binding(Trigger(B.Flag.Primary, M.create({ shift: true })), 'Rotate the 3D scene around the z-axis by dragging using ${trigger}'),
-    dragPan: Binding(Trigger(B.Flag.Secondary, M.create()), 'Pan the 3D scene by dragging using ${trigger}'),
+    dragRotate: Binding([Trigger(B.Flag.Primary, M.create())], 'Rotate the 3D scene by dragging using ${triggers}'),
+    dragRotateZ: Binding([Trigger(B.Flag.Primary, M.create({ shift: true }))], 'Rotate the 3D scene around the z-axis by dragging using ${triggers}'),
+    dragPan: Binding([Trigger(B.Flag.Secondary, M.create()), Trigger(B.Flag.Primary, M.create({ control: true }))], 'Pan the 3D scene by dragging using ${triggers}'),
     dragZoom: Binding.Empty,
-    dragFocus: Binding(Trigger(B.Flag.Forth, M.create()), 'Focus the 3D scene by dragging using ${trigger}'),
-    dragFocusZoom: Binding(Trigger(B.Flag.Auxilary, M.create()), 'Focus and zoom the 3D scene by dragging using ${trigger}'),
+    dragFocus: Binding([Trigger(B.Flag.Forth, M.create())], 'Focus the 3D scene by dragging using ${triggers}'),
+    dragFocusZoom: Binding([Trigger(B.Flag.Auxilary, M.create())], 'Focus and zoom the 3D scene by dragging using ${triggers}'),
 
-    scrollZoom: Binding(Trigger(B.Flag.Auxilary, M.create()), 'Zoom the 3D scene by scrolling using ${trigger}'),
-    scrollFocus: Binding(Trigger(B.Flag.Auxilary, M.create({ shift: true })), 'Focus the 3D scene by scrolling using ${trigger}'),
+    scrollZoom: Binding([Trigger(B.Flag.Auxilary, M.create())], 'Zoom the 3D scene by scrolling using ${triggers}'),
+    scrollFocus: Binding([Trigger(B.Flag.Auxilary, M.create({ shift: true }))], 'Focus the 3D scene by scrolling using ${triggers}'),
     scrollFocusZoom: Binding.Empty,
 }
 

+ 1 - 1
src/mol-plugin/behavior/dynamic/camera.ts

@@ -16,7 +16,7 @@ const M = ModifiersKeys
 const Trigger = Binding.Trigger
 
 const DefaultFocusLociBindings = {
-    clickCenterFocus: Binding(Trigger(B.Flag.Primary, M.create()), 'Center and focus the clicked element using ${trigger}.'),
+    clickCenterFocus: Binding([Trigger(B.Flag.Primary, M.create())], 'Center and focus the clicked element using ${triggers}.'),
 }
 const FocusLociParams = {
     minRadius: PD.Numeric(8, { min: 1, max: 50, step: 1 }),

+ 11 - 6
src/mol-plugin/behavior/dynamic/representation.ts

@@ -16,7 +16,7 @@ import { StateSelection } from '../../../mol-state';
 import { ButtonsType, ModifiersKeys } from '../../../mol-util/input/input-observer';
 import { Binding } from '../../../mol-util/binding';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
-import { EmptyLoci } from '../../../mol-model/loci';
+import { EmptyLoci, Loci } from '../../../mol-model/loci';
 
 const B = ButtonsType
 const M = ModifiersKeys
@@ -25,8 +25,8 @@ const Trigger = Binding.Trigger
 //
 
 const DefaultHighlightLociBindings = {
-    hoverHighlightOnly: Binding(Trigger(B.Flag.None), 'Highlight hovered element using ${trigger}'),
-    hoverHighlightOnlyExtend: Binding(Trigger(B.Flag.None, M.create({ shift: true })), 'Extend highlight from selected to hovered element along polymer using ${trigger}'),
+    hoverHighlightOnly: Binding([Trigger(B.Flag.None)], 'Highlight hovered element using ${triggers}'),
+    hoverHighlightOnlyExtend: Binding([Trigger(B.Flag.None, M.create({ shift: true }))], 'Extend highlight from selected to hovered element along polymer using ${triggers}'),
 }
 const HighlightLociParams = {
     bindings: PD.Value(DefaultHighlightLociBindings, { isHidden: true }),
@@ -74,10 +74,11 @@ export const HighlightLoci = PluginBehavior.create({
 
 const DefaultSelectLociBindings = {
     clickSelect: Binding.Empty,
-    clickSelectExtend: Binding(Trigger(B.Flag.Primary, M.create({ shift: true })), 'Extend selection to clicked element along polymer using ${trigger}.'),
-    clickSelectOnly: Binding(Trigger(B.Flag.Secondary, M.create({ control: true })), 'Select only the clicked element using ${trigger}.'),
-    clickSelectToggle: Binding(Trigger(B.Flag.Primary, M.create({ control: true })), 'Toggle selection of clicked element using ${trigger}.'),
+    clickSelectExtend: Binding([Trigger(B.Flag.Primary, M.create({ shift: true }))], 'Extend selection to clicked element along polymer using ${triggers}.'),
+    clickSelectOnly: Binding([Trigger(B.Flag.Primary, M.create({ alt: true, shift: true }))], 'Select only the clicked element using ${triggers}.'),
+    clickSelectToggle: Binding([Trigger(B.Flag.Primary, M.create({ alt: true }))], 'Toggle selection of clicked element using ${triggers}.'),
     clickDeselect: Binding.Empty,
+    clickDeselectAllOnEmpty: Binding.Empty,
 }
 const SelectLociParams = {
     bindings: PD.Value(DefaultSelectLociBindings, { isHidden: true }),
@@ -127,6 +128,10 @@ export const SelectLoci = PluginBehavior.create({
                 if (Binding.match(this.params.bindings.clickDeselect, buttons, modifiers)) {
                     this.ctx.interactivity.lociSelects.deselect(current)
                 }
+
+                if (Binding.match(this.params.bindings.clickDeselectAllOnEmpty, buttons, modifiers)) {
+                    if (Loci.isEmpty(current.loci)) this.ctx.interactivity.lociSelects.deselect(current)
+                }
             });
             this.ctx.interactivity.lociSelects.addProvider(this.lociMarkProvider)
 

+ 1 - 1
src/mol-plugin/behavior/dynamic/selection/structure-representation-interaction.ts

@@ -26,7 +26,7 @@ const M = ModifiersKeys
 const Trigger = Binding.Trigger
 
 const DefaultStructureRepresentationInteractionBindings = {
-    clickInteractionAroundOnly: Binding(Trigger(B.Flag.Secondary, M.create()), 'Show the structure interaction around only the clicked element using ${trigger}.'),
+    clickInteractionAroundOnly: Binding([Trigger(B.Flag.Secondary, M.create()), Trigger(B.Flag.Primary, M.create({ control: true }))], 'Show the structure interaction around only the clicked element using ${triggers}.'),
 }
 const StructureRepresentationInteractionParams = {
     bindings: PD.Value(DefaultStructureRepresentationInteractionBindings, { isHidden: true }),

+ 1 - 1
src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts

@@ -51,7 +51,7 @@ export namespace VolumeStreaming {
     };
 
     export const DefaultBindings = {
-        clickVolumeAroundOnly: Binding(Trigger(B.Flag.Secondary, M.create()), 'Show the volume around only the clicked element using ${trigger}.'),
+        clickVolumeAroundOnly: Binding([Trigger(B.Flag.Secondary, M.create()), Trigger(B.Flag.Primary, M.create({ control: true }))], 'Show the volume around only the clicked element using ${triggers}.'),
     }
 
     export function createParams(data?: VolumeServerInfo.Data, defaultView?: ViewTypes, binding?: typeof DefaultBindings) {

+ 10 - 9
src/mol-util/binding.ts

@@ -10,31 +10,32 @@ import { interpolate, stringToWords } from './string';
 export { Binding }
 
 interface Binding {
-    trigger: Binding.Trigger
+    triggers: Binding.Trigger[]
     description: string
 }
 
-function Binding(trigger: Binding.Trigger, description = '') {
-    return Binding.create(trigger, description)
+function Binding(triggers: Binding.Trigger[], description = '') {
+    return Binding.create(triggers, description)
 }
 
 namespace Binding {
-    export function create(trigger: Trigger, description = ''): Binding {
-        return { trigger, description }
+    export function create(triggers: Trigger[], description = ''): Binding {
+        return { triggers, description }
     }
 
-    export const Empty: Binding = { trigger: {}, description: '' }
+    export const Empty: Binding = { triggers: [], description: '' }
     export function isEmpty(binding: Binding) {
-        return binding.trigger.buttons === undefined && binding.trigger.modifiers === undefined
+        return binding.triggers.length === 0 ||
+            binding.triggers.every(t => t.buttons === undefined && t.modifiers === undefined)
     }
 
     export function match(binding: Binding, buttons: ButtonsType, modifiers: ModifiersKeys) {
-        return Trigger.match(binding.trigger, buttons, modifiers)
+        return binding.triggers.some(t => Trigger.match(t, buttons, modifiers))
     }
 
     export function format(binding: Binding, name = '') {
         const help = binding.description || stringToWords(name)
-        return interpolate(help, { trigger: Trigger.format(binding.trigger) })
+        return interpolate(help, { triggers: binding.triggers.map(t => Trigger.format(t)).join(' or ') })
     }
 
     export interface Trigger {