From 62554b522f5d242dcb36051477d8a714bf1e71ed Mon Sep 17 00:00:00 2001 From: Alexander Rose <alexander.rose@weirdbyte.de> Date: Sat, 25 Mar 2023 10:32:02 -0700 Subject: [PATCH] add key bindings for fly mode & reset view --- src/mol-plugin-ui/viewport/help.tsx | 2 +- src/mol-plugin/behavior/dynamic/camera.ts | 113 ++++++++++++++-------- src/mol-plugin/spec.ts | 3 +- 3 files changed, 78 insertions(+), 40 deletions(-) diff --git a/src/mol-plugin-ui/viewport/help.tsx b/src/mol-plugin-ui/viewport/help.tsx index 9146fb6a7..4d5005e8e 100644 --- a/src/mol-plugin-ui/viewport/help.tsx +++ b/src/mol-plugin-ui/viewport/help.tsx @@ -99,7 +99,7 @@ export class ViewportHelpContent extends PluginUIComponent<{ selectOnly?: boolea {(!this.props.selectOnly && this.plugin.canvas3d) && <HelpGroup key='trackball' header='Moving in 3D'> <BindingsHelp bindings={this.plugin.canvas3d.props.trackball.bindings} /> </HelpGroup>} - {!!interactionBindings && <HelpGroup key='interactions' header='Mouse Controls'> + {!!interactionBindings && <HelpGroup key='interactions' header='Mouse & Key Controls'> <BindingsHelp bindings={interactionBindings} /> </HelpGroup>} </>; diff --git a/src/mol-plugin/behavior/dynamic/camera.ts b/src/mol-plugin/behavior/dynamic/camera.ts index b4c43d7a1..e85108007 100644 --- a/src/mol-plugin/behavior/dynamic/camera.ts +++ b/src/mol-plugin/behavior/dynamic/camera.ts @@ -29,8 +29,6 @@ const DefaultFocusLociBindings = { Trigger(B.Flag.Secondary, M.create()), Trigger(B.Flag.Primary, M.create({ control: true })) ], 'Camera center and focus', 'Click element using ${triggers}'), - keySpinAnimation: Binding([Key('KeyI')], 'Spin Animation', 'Press ${triggers}'), - keyRockAnimation: Binding([Key('KeyO')], 'Rock Animation', 'Press ${triggers}'), }; const FocusLociParams = { minRadius: PD.Numeric(8, { min: 1, max: 50, step: 1 }), @@ -63,42 +61,6 @@ export const FocusLoci = PluginBehavior.create<FocusLociProps>({ this.ctx.managers.camera.focusLoci(loci, this.params); } }); - - this.subscribeObservable(this.ctx.behaviors.interaction.key, ({ code, modifiers }) => { - if (!this.ctx.canvas3d) return; - - // include defaults for backwards state compatibility - const b = { ...DefaultFocusLociBindings, ...this.params.bindings }; - const p = this.ctx.canvas3d.props.trackball; - - if (Binding.matchKey(b.keySpinAnimation, code, modifiers)) { - const name = p.animate.name !== 'spin' ? 'spin' : 'off'; - if (name === 'off') { - this.ctx.canvas3d.setProps({ - trackball: { animate: { name, params: {} } } - }); - } else { - this.ctx.canvas3d.setProps({ - trackball: { animate: { - name, params: { speed: 1 } } - } - }); - } - } else if (Binding.matchKey(b.keyRockAnimation, code, modifiers)) { - const name = p.animate.name !== 'rock' ? 'rock' : 'off'; - if (name === 'off') { - this.ctx.canvas3d.setProps({ - trackball: { animate: { name, params: {} } } - }); - } else { - this.ctx.canvas3d.setProps({ - trackball: { animate: { - name, params: { speed: 0.3, angle: 10 } } - } - }); - } - } - }); } }, params: () => FocusLociParams, @@ -166,4 +128,79 @@ export const CameraAxisHelper = PluginBehavior.create<{}>({ }, params: () => ({}), display: { name: 'Camera Axis Helper' } +}); + +const DefaultCameraControlsBindings = { + keySpinAnimation: Binding([Key('KeyI')], 'Spin Animation', 'Press ${triggers}'), + keyRockAnimation: Binding([Key('KeyO')], 'Rock Animation', 'Press ${triggers}'), + keyToggleFlyMode: Binding([Key('Space', M.create({ shift: true }))], 'Toggle Fly Mode', 'Press ${triggers}'), + keyResetView: Binding([Key('KeyT')], 'Reset View', 'Press ${triggers}'), +}; +const CameraControlsParams = { + bindings: PD.Value(DefaultCameraControlsBindings, { isHidden: true }), +}; +type CameraControlsProps = PD.Values<typeof CameraControlsParams> + +export const CameraControls = PluginBehavior.create<CameraControlsProps>({ + name: 'camera-controls', + category: 'interaction', + ctor: class extends PluginBehavior.Handler<CameraControlsProps> { + register(): void { + this.subscribeObservable(this.ctx.behaviors.interaction.key, ({ code, modifiers }) => { + if (!this.ctx.canvas3d) return; + + // include defaults for backwards state compatibility + const b = { ...DefaultCameraControlsBindings, ...this.params.bindings }; + const p = this.ctx.canvas3d.props.trackball; + + if (Binding.matchKey(b.keySpinAnimation, code, modifiers)) { + const name = p.animate.name !== 'spin' ? 'spin' : 'off'; + if (name === 'off') { + this.ctx.canvas3d.setProps({ + trackball: { animate: { name, params: {} } } + }); + } else { + this.ctx.canvas3d.setProps({ + trackball: { animate: { + name, params: { speed: 1 } } + } + }); + } + } + + if (Binding.matchKey(b.keyRockAnimation, code, modifiers)) { + const name = p.animate.name !== 'rock' ? 'rock' : 'off'; + if (name === 'off') { + this.ctx.canvas3d.setProps({ + trackball: { animate: { name, params: {} } } + }); + } else { + this.ctx.canvas3d.setProps({ + trackball: { animate: { + name, params: { speed: 0.3, angle: 10 } } + } + }); + } + } + + if (Binding.matchKey(b.keyToggleFlyMode, code, modifiers)) { + const flyMode = !p.flyMode; + + this.ctx.canvas3d.setProps({ + trackball: { flyMode } + }); + + if (this.ctx.canvas3dContext) { + this.ctx.canvas3dContext.canvas.style.cursor = flyMode ? 'crosshair' : 'unset'; + } + } + + if (Binding.matchKey(b.keyResetView, code, modifiers)) { + PluginCommands.Camera.Reset(this.ctx, {}); + } + }); + } + }, + params: () => CameraControlsParams, + display: { name: 'Camera Controls on Canvas' } }); \ No newline at end of file diff --git a/src/mol-plugin/spec.ts b/src/mol-plugin/spec.ts index e0792376d..bfbc64677 100644 --- a/src/mol-plugin/spec.ts +++ b/src/mol-plugin/spec.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -120,6 +120,7 @@ export const DefaultPluginSpec = (): PluginSpec => ({ PluginSpec.Behavior(PluginBehaviors.Representation.FocusLoci), PluginSpec.Behavior(PluginBehaviors.Camera.FocusLoci), PluginSpec.Behavior(PluginBehaviors.Camera.CameraAxisHelper), + PluginSpec.Behavior(PluginBehaviors.Camera.CameraControls), PluginSpec.Behavior(StructureFocusRepresentation), PluginSpec.Behavior(PluginBehaviors.CustomProps.StructureInfo), -- GitLab