Browse Source

mol-plugin: interactivity tweaks

David Sehnal 6 years ago
parent
commit
d9a1a2d204

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

@@ -14,7 +14,7 @@ export const FocusLociOnSelect = PluginBehavior.create<{ minRadius: number, extr
     category: 'interaction',
     ctor: class extends PluginBehavior.Handler<{ minRadius: number, extraRadius: number }> {
         register(): void {
-            this.subscribeObservable(this.ctx.events.canvas3d.click, ({ current, buttons, modifiers }) => {
+            this.subscribeObservable(this.ctx.behaviors.canvas3d.click, ({ current, buttons, modifiers }) => {
                 if (!this.ctx.canvas3d || buttons !== ButtonsType.Flag.Primary || !ModifiersKeys.areEqual(modifiers, ModifiersKeys.None)) return;
 
                 const sphere = Loci.getBoundingSphere(current.loci);

+ 2 - 2
src/mol-plugin/behavior/dynamic/representation.ts

@@ -26,7 +26,7 @@ export const HighlightLoci = PluginBehavior.create({
             let prev: Representation.Loci = { loci: EmptyLoci, repr: void 0 };
             const sel = this.ctx.helpers.structureSelection;
 
-            this.subscribeObservable(this.ctx.events.canvas3d.highlight, ({ current, modifiers }) => {
+            this.subscribeObservable(this.ctx.behaviors.canvas3d.highlight, ({ current, modifiers }) => {
                 if (!this.ctx.canvas3d) return;
 
                 if (StructureElement.isLoci(current.loci)) {
@@ -70,7 +70,7 @@ export const SelectLoci = PluginBehavior.create({
                 }
             }
 
-            this.subscribeObservable(this.ctx.events.canvas3d.click, ({ current, buttons, modifiers }) => {
+            this.subscribeObservable(this.ctx.behaviors.canvas3d.click, ({ current, buttons, modifiers }) => {
                 if (!this.ctx.canvas3d) return;
 
                 if (current.loci.kind === 'empty-loci') {

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

@@ -84,11 +84,30 @@ export class StructureRepresentationInteractionBehavior extends PluginBehavior.W
         return { state, builder, refs };
     }
 
+    private clear() {
+        const state = this.plugin.state.dataState;
+        const groups = state.select(StateSelection.Generators.root.subtree().filter(o => o.transform.props.tag === Tags.Group));
+        if (groups.length === 0) return;
+
+        const update = state.build();
+        for (const g of groups) update.delete(g.transform.ref);
+
+        PluginCommands.State.Update.dispatch(this.plugin, { state, tree: update, options: { doNotLogTiming: true, doNotUpdateCurrent: true } });
+    }
+
     register(ref: string): void {
         // this.ref = ref;
 
-        this.subscribeObservable(this.plugin.events.canvas3d.click, ({ current, buttons }) => {
+        this.subscribeObservable(this.plugin.behaviors.canvas3d.click, ({ current, buttons, modifiers }) => {
             if (buttons !== ButtonsType.Flag.Secondary) return;
+
+            if (current.loci.kind === 'empty-loci') {
+                if (modifiers.control && buttons === ButtonsType.Flag.Secondary) {
+                    this.clear();
+                    return;
+                }
+            }
+
             // TODO: support link loci as well?
             if (!StructureElement.isLoci(current.loci)) return;
 

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

@@ -21,6 +21,8 @@ import { urlCombine } from 'mol-util/url';
 import { VolumeServerHeader, VolumeServerInfo } from './model';
 import { CreateVolumeStreamingBehavior } from './transformers';
 import { ButtonsType } from 'mol-util/input/input-observer';
+import { PluginCommands } from 'mol-plugin/command';
+import { StateSelection } from 'mol-state';
 
 export class VolumeStreaming extends PluginStateObject.CreateBehavior<VolumeStreaming.Behavior>({ name: 'Volume Streaming' }) { }
 
@@ -146,34 +148,55 @@ export namespace VolumeStreaming {
             return ret;
         }
 
+        private updateDynamicBox(ref: string, box: Box3D) {
+            if (this.params.view.name !== 'selection-box') return;
+
+            const eR = this.params.view.params.radius;
+            const state = this.plugin.state.dataState;
+            const update = state.build().to(ref).update(CreateVolumeStreamingBehavior, old => ({
+                ...old,
+                view: {
+                    name: 'selection-box' as 'selection-box',
+                    params: {
+                        radius: eR,
+                        bottomLeft: box.min,
+                        topRight: box.max
+                    }
+                }
+            }));
+
+            PluginCommands.State.Update.dispatch(this.plugin, { state, tree: update, options: { doNotUpdateCurrent: true } });
+        }
+
+        private getStructureRoot(ref: string) {
+            return this.plugin.state.dataState.select(StateSelection.Generators.byRef(ref).rootOfType([PluginStateObject.Molecule.Structure]))[0];
+        }
+
         register(ref: string): void {
             // this.ref = ref;
 
-            this.subscribeObservable(this.plugin.events.canvas3d.click, ({ current, buttons }) => {
+            this.subscribeObservable(this.plugin.behaviors.canvas3d.click, ({ current, buttons, modifiers }) => {
                 if (buttons !== ButtonsType.Flag.Secondary || this.params.view.name !== 'selection-box') return;
+
+                if (current.loci.kind === 'empty-loci') {
+                    if (modifiers.control && buttons === ButtonsType.Flag.Secondary) {
+                        this.updateDynamicBox(ref, Box3D.empty());
+                        return;
+                    }
+                }
+
                 // TODO: support link loci as well?
                 // Perhaps structure loci too?
                 if (!StructureElement.isLoci(current.loci)) return;
 
-                // TODO: check if it's the related structure
-                const loci = StructureElement.Loci.extendToWholeResidues(current.loci);
+                const parent = this.plugin.helpers.substructureParent.get(current.loci.structure);
+                if (!parent) return;
+                const root = this.getStructureRoot(ref);
+                if (!root || !root.obj || root.obj !== parent.obj) return;
 
-                const eR = this.params.view.params.radius;
+                const loci = StructureElement.Loci.extendToWholeResidues(current.loci);
                 const box = StructureElement.Loci.getBoundary(loci).box;
-                const update = this.plugin.state.dataState.build().to(ref).update(CreateVolumeStreamingBehavior, old => ({
-                    ...old,
-                    view: {
-                        name: 'selection-box' as 'selection-box',
-                        params: {
-                            radius: eR,
-                            bottomLeft: box.min,
-                            topRight: box.max
-                        }
-                    }
-                }));
-
-                // TODO: create/use command queue here and cancel any ongoing updates.
-                this.plugin.runTask(this.plugin.state.dataState.updateTree(update));
+                this.updateDynamicBox(ref, box);
             });
         }
 

+ 5 - 3
src/mol-plugin/behavior/dynamic/volume-streaming/transformers.ts

@@ -52,7 +52,9 @@ export const InitVolumeStreaming = StateAction.build({
 
     const infoObj = await state.updateTree(infoTree).runInContext(taskCtx);
 
-    const behTree = state.build().to(infoTree.ref).apply(CreateVolumeStreamingBehavior, PD.getDefaultValues(VolumeStreaming.createParams(infoObj.data)));
+    const behTree = state.build().to(infoTree.ref).apply(CreateVolumeStreamingBehavior,
+        PD.getDefaultValues(VolumeStreaming.createParams(infoObj.data)));
+
     if (params.method === 'em') {
         behTree.apply(VolumeStreamingVisual, { channel: 'em' }, { props: { isGhost: true } });
     } else {
@@ -96,7 +98,7 @@ const CreateVolumeStreamingInfo = PluginStateTransform.BuiltIn({
             emDefaultContourLevel,
             structure: a.data
         };
-        return new VolumeServerInfo(data, { label: `Volume Streaming: ${dataId}` });
+        return new VolumeServerInfo(data, { label: `Volume Server: ${dataId}` });
     })
 });
 
@@ -118,7 +120,7 @@ const CreateVolumeStreamingBehavior = PluginStateTransform.BuiltIn({
     apply: ({ a, params }, plugin: PluginContext) => Task.create('Volume streaming', async _ => {
         const behavior = new VolumeStreaming.Behavior(plugin, a.data);
         await behavior.update(params);
-        return new VolumeStreaming(behavior, { label: 'Streaming Controls' });
+        return new VolumeStreaming(behavior, { label: 'Volume Streaming' });
     }),
     update({ b, newParams }) {
         return Task.create('Update Volume Streaming', async _ => {

+ 3 - 3
src/mol-plugin/behavior/static/state.ts

@@ -105,16 +105,16 @@ export function Highlight(ctx: PluginContext) {
         // const cell = state.select(ref)[0]
         // const repr = cell && SO.isRepresentation3D(cell.obj) ? cell.obj.data : undefined
         // if (cell && cell.obj && cell.obj.type === PluginStateObject.Molecule.Structure.type) {
-        //     ctx.events.canvas3d.highlight.next({ current: { loci: Structure.Loci(cell.obj.data) } });
+        //     ctx.behaviors.canvas3d.highlight.next({ current: { loci: Structure.Loci(cell.obj.data) } });
         // } else if (repr) {
-        //     ctx.events.canvas3d.highlight.next({ current: { loci: EveryLoci, repr } });
+        //     ctx.behaviors.canvas3d.highlight.next({ current: { loci: EveryLoci, repr } });
         // }
     });
 }
 
 export function ClearHighlight(ctx: PluginContext) {
     PluginCommands.State.ClearHighlight.subscribe(ctx, ({ state, ref }) => {
-        // ctx.events.canvas3d.highlight.next({ current: { loci: EmptyLoci } });
+        // ctx.behaviors.canvas3d.highlight.next({ current: { loci: EmptyLoci } });
     });
 }
 

+ 7 - 8
src/mol-plugin/context.ts

@@ -32,6 +32,8 @@ import { TaskManager } from './util/task-manager';
 import { PLUGIN_VERSION, PLUGIN_VERSION_DATE } from './version';
 import { StructureElementSelectionManager } from './util/structure-element-selection';
 import { SubstructureParentHelper } from './util/substructure-parent-helper';
+import { Representation } from 'mol-repr/representation';
+import { ModifiersKeys } from 'mol-util/input/input-observer';
 
 export class PluginContext {
     private disposed = false;
@@ -59,18 +61,15 @@ export class PluginContext {
         log: this.ev<LogEntry>(),
         task: this.tasks.events,
         canvas3d: {
-            settingsUpdated: this.ev(),
-
-            highlight: this.ev<Canvas3D.HighlightEvent>(),
-            click: this.ev<Canvas3D.ClickEvent>()
+            settingsUpdated: this.ev()
         }
     };
 
     readonly behaviors = {
-        // canvas: {
-        //     highlightLoci: this.ev.behavior<{ loci: Loci, repr?: Representation.Any, modifiers?: ModifiersKeys }>({ loci: EmptyLoci }),
-        //     selectLoci: this.ev.behavior<{ loci: Loci, repr?: Representation.Any, modifiers?: ModifiersKeys }>({ loci: EmptyLoci }),
-        // },
+        canvas3d: {
+            highlight: this.ev.behavior<Canvas3D.HighlightEvent>({ current: Representation.Loci.Empty, prev: Representation.Loci.Empty }),
+            click: this.ev.behavior<Canvas3D.ClickEvent>({ current: Representation.Loci.Empty, modifiers: ModifiersKeys.None, buttons: 0 })
+        },
         labels: {
             highlight: this.ev.behavior<{ entries: ReadonlyArray<LociLabelEntry> }>({ entries: [] })
         },

+ 2 - 2
src/mol-plugin/ui/viewport.tsx

@@ -110,8 +110,8 @@ export class Viewport extends PluginUIComponent<{ }, ViewportState> {
         const canvas3d = this.plugin.canvas3d;
         this.subscribe(canvas3d.input.resize, this.handleResize);
 
-        this.subscribe(canvas3d.interaction.click, e => this.plugin.events.canvas3d.click.next(e));
-        this.subscribe(canvas3d.interaction.highlight, e => this.plugin.events.canvas3d.highlight.next(e));
+        this.subscribe(canvas3d.interaction.click, e => this.plugin.behaviors.canvas3d.click.next(e));
+        this.subscribe(canvas3d.interaction.highlight, e => this.plugin.behaviors.canvas3d.highlight.next(e));
         this.subscribe(this.plugin.layout.events.updated, () => {
             setTimeout(this.handleResize, 50);
         });

+ 1 - 1
src/mol-plugin/util/loci-label-manager.ts

@@ -35,6 +35,6 @@ export class LociLabelManager {
     }
 
     constructor(public ctx: PluginContext) {
-        ctx.events.canvas3d.highlight.subscribe(ev => ctx.behaviors.labels.highlight.next({ entries: this.getInfo(ev.current) }));
+        ctx.behaviors.canvas3d.highlight.subscribe(ev => ctx.behaviors.labels.highlight.next({ entries: this.getInfo(ev.current) }));
     }
 }