Skip to content
Snippets Groups Projects
Commit b0cdf22c authored by Alexander Rose's avatar Alexander Rose
Browse files

various interaction behaviors improvements

parent a61ba71f
No related branches found
No related tags found
No related merge requests found
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
import { Structure, StructureElement } from '../../../../mol-model/structure'; import { Structure, StructureElement, Link } from '../../../../mol-model/structure';
import { PluginBehavior } from '../../../../mol-plugin/behavior'; import { PluginBehavior } from '../../../../mol-plugin/behavior';
import { PluginCommands } from '../../../../mol-plugin/command'; import { PluginCommands } from '../../../../mol-plugin/command';
import { PluginStateObject } from '../../../../mol-plugin/state/objects'; import { PluginStateObject } from '../../../../mol-plugin/state/objects';
...@@ -17,10 +17,9 @@ import { StateObjectCell, StateSelection, StateTransform } from '../../../../mol ...@@ -17,10 +17,9 @@ import { StateObjectCell, StateSelection, StateTransform } from '../../../../mol
import { BuiltInColorThemes } from '../../../../mol-theme/color'; import { BuiltInColorThemes } from '../../../../mol-theme/color';
import { BuiltInSizeThemes } from '../../../../mol-theme/size'; import { BuiltInSizeThemes } from '../../../../mol-theme/size';
import { ButtonsType, ModifiersKeys } from '../../../../mol-util/input/input-observer'; import { ButtonsType, ModifiersKeys } from '../../../../mol-util/input/input-observer';
import { Representation } from '../../../../mol-repr/representation';
import { Binding } from '../../../../mol-util/binding'; import { Binding } from '../../../../mol-util/binding';
import { ParamDefinition as PD } from '../../../../mol-util/param-definition'; import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
import { isEmptyLoci } from '../../../../mol-model/loci'; import { isEmptyLoci, Loci, EmptyLoci } from '../../../../mol-model/loci';
const B = ButtonsType const B = ButtonsType
const M = ModifiersKeys const M = ModifiersKeys
...@@ -117,19 +116,19 @@ export class StructureRepresentationInteractionBehavior extends PluginBehavior.W ...@@ -117,19 +116,19 @@ export class StructureRepresentationInteractionBehavior extends PluginBehavior.W
} }
register(ref: string): void { register(ref: string): void {
let lastLoci: Representation.Loci = Representation.Loci.Empty; let lastLoci: Loci = EmptyLoci;
this.subscribeObservable(this.plugin.events.state.object.removed, o => { this.subscribeObservable(this.plugin.events.state.object.removed, o => {
if (!PluginStateObject.Molecule.Structure.is(o.obj) || lastLoci.loci.kind !== 'element-loci') return; if (!PluginStateObject.Molecule.Structure.is(o.obj) || !StructureElement.Loci.is(lastLoci)) return;
if (lastLoci.loci.structure === o.obj.data) { if (lastLoci.structure === o.obj.data) {
lastLoci = Representation.Loci.Empty; lastLoci = EmptyLoci;
} }
}); });
this.subscribeObservable(this.plugin.events.state.object.updated, o => { this.subscribeObservable(this.plugin.events.state.object.updated, o => {
if (!PluginStateObject.Molecule.Structure.is(o.oldObj) || lastLoci.loci.kind !== 'element-loci') return; if (!PluginStateObject.Molecule.Structure.is(o.oldObj) || !StructureElement.Loci.is(lastLoci)) return;
if (lastLoci.loci.structure === o.oldObj.data) { if (lastLoci.structure === o.oldObj.data) {
lastLoci = Representation.Loci.Empty; lastLoci = EmptyLoci;
} }
}); });
...@@ -139,26 +138,36 @@ export class StructureRepresentationInteractionBehavior extends PluginBehavior.W ...@@ -139,26 +138,36 @@ export class StructureRepresentationInteractionBehavior extends PluginBehavior.W
if (Binding.match(clickInteractionAroundOnly, buttons, modifiers)) { if (Binding.match(clickInteractionAroundOnly, buttons, modifiers)) {
if (isEmptyLoci(current.loci)) { if (isEmptyLoci(current.loci)) {
this.clear(StateTransform.RootRef); this.clear(StateTransform.RootRef);
lastLoci = current; lastLoci = current.loci;
return; return;
} }
// TODO: support link and structure loci as well? let loci: StructureElement.Loci;
if (!StructureElement.Loci.is(current.loci)) return; if (StructureElement.Loci.is(current.loci)) {
loci = current.loci;
} else if (Link.isLoci(current.loci)) {
loci = Link.toStructureElementLoci(current.loci);
} else if (Structure.isLoci(current.loci)) {
loci = Structure.toStructureElementLoci(current.loci);
} else {
return;
}
if (StructureElement.Loci.isEmpty(loci)) return;
const parent = this.plugin.helpers.substructureParent.get(current.loci.structure); const parent = this.plugin.helpers.substructureParent.get(loci.structure);
if (!parent || !parent.obj) return; if (!parent || !parent.obj) return;
if (Representation.Loci.areEqual(lastLoci, current)) { if (Loci.areEqual(lastLoci, loci)) {
lastLoci = Representation.Loci.Empty; lastLoci = EmptyLoci;
this.clear(parent.transform.ref); this.clear(parent.transform.ref);
return; return;
} }
lastLoci = current; lastLoci = loci;
const core = MS.struct.modifier.wholeResidues([ const core = MS.struct.modifier.wholeResidues([
StructureElement.Loci.toExpression(current.loci) StructureElement.Loci.toExpression(loci)
]); ]);
const surroundings = MS.struct.modifier.includeSurroundings({ const surroundings = MS.struct.modifier.includeSurroundings({
......
...@@ -22,9 +22,10 @@ import { PluginCommands } from '../../../command'; ...@@ -22,9 +22,10 @@ import { PluginCommands } from '../../../command';
import { StateSelection } from '../../../../mol-state'; import { StateSelection } from '../../../../mol-state';
import { Representation } from '../../../../mol-repr/representation'; import { Representation } from '../../../../mol-repr/representation';
import { ButtonsType, ModifiersKeys } from '../../../../mol-util/input/input-observer'; import { ButtonsType, ModifiersKeys } from '../../../../mol-util/input/input-observer';
import { StructureElement, Link } from '../../../../mol-model/structure'; import { StructureElement, Link, Structure } from '../../../../mol-model/structure';
import { PluginContext } from '../../../context'; import { PluginContext } from '../../../context';
import { Binding } from '../../../../mol-util/binding'; import { Binding } from '../../../../mol-util/binding';
import { EmptyLoci, Loci, isEmptyLoci } from '../../../../mol-model/loci';
const B = ButtonsType const B = ButtonsType
const M = ModifiersKeys const M = ModifiersKeys
...@@ -115,7 +116,7 @@ export namespace VolumeStreaming { ...@@ -115,7 +116,7 @@ export namespace VolumeStreaming {
export class Behavior extends PluginBehavior.WithSubscribers<Params> { export class Behavior extends PluginBehavior.WithSubscribers<Params> {
private cache = LRUCache.create<ChannelsData>(25); private cache = LRUCache.create<ChannelsData>(25);
public params: Params = {} as any; public params: Params = {} as any;
private lastLoci: Representation.Loci = Representation.Loci.Empty; private lastLoci: StructureElement.Loci | EmptyLoci = EmptyLoci;
private ref: string = ''; private ref: string = '';
channels: Channels = {} channels: Channels = {}
...@@ -198,67 +199,70 @@ export namespace VolumeStreaming { ...@@ -198,67 +199,70 @@ export namespace VolumeStreaming {
this.ref = ref; this.ref = ref;
this.subscribeObservable(this.plugin.events.state.object.removed, o => { this.subscribeObservable(this.plugin.events.state.object.removed, o => {
if (!PluginStateObject.Molecule.Structure.is(o.obj) || this.lastLoci.loci.kind !== 'element-loci') return; if (!PluginStateObject.Molecule.Structure.is(o.obj) || !StructureElement.Loci.is(this.lastLoci)) return;
if (this.lastLoci.loci.structure === o.obj.data) { if (this.lastLoci.structure === o.obj.data) {
this.lastLoci = Representation.Loci.Empty; this.lastLoci = EmptyLoci;
} }
}); });
this.subscribeObservable(this.plugin.events.state.object.updated, o => { this.subscribeObservable(this.plugin.events.state.object.updated, o => {
if (!PluginStateObject.Molecule.Structure.is(o.oldObj) || this.lastLoci.loci.kind !== 'element-loci') return; if (!PluginStateObject.Molecule.Structure.is(o.oldObj) || !StructureElement.Loci.is(this.lastLoci)) return;
if (this.lastLoci.loci.structure === o.oldObj.data) { if (this.lastLoci.structure === o.oldObj.data) {
this.lastLoci = Representation.Loci.Empty; this.lastLoci = EmptyLoci;
} }
}); });
this.subscribeObservable(this.plugin.behaviors.interaction.click, ({ current, buttons, modifiers }) => { this.subscribeObservable(this.plugin.behaviors.interaction.click, ({ current, buttons, modifiers }) => {
if (!Binding.match(this.params.bindings.clickVolumeAroundOnly || DefaultBindings.clickVolumeAroundOnly, buttons, modifiers)) return; if (!Binding.match(this.params.bindings.clickVolumeAroundOnly || DefaultBindings.clickVolumeAroundOnly, buttons, modifiers)) return;
if (this.params.view.name !== 'selection-box') { if (this.params.view.name !== 'selection-box') {
this.lastLoci = current; this.lastLoci = this.getNormalizedLoci(current.loci);
} else { } else {
this.updateInteraction(current); this.updateInteraction(current);
} }
}); });
} }
private getBoxFromLoci(current: Representation.Loci) { private getNormalizedLoci(loci: Loci): StructureElement.Loci | EmptyLoci {
if (current.loci.kind === 'empty-loci') { if (StructureElement.Loci.is(loci)) {
return; return loci;
} else if (Link.isLoci(loci)) {
return Link.toStructureElementLoci(loci);
} else if (Structure.isLoci(loci)) {
return Structure.toStructureElementLoci(loci);
} else {
return EmptyLoci;
}
} }
let loci: StructureElement.Loci; private getBoxFromLoci(loci: StructureElement.Loci | EmptyLoci): Box3D {
if (isEmptyLoci(loci) || StructureElement.Loci.isEmpty(loci)) {
// TODO: support structure loci as well? return Box3D.empty();
if (StructureElement.Loci.is(current.loci)) {
loci = current.loci;
} else if (Link.isLoci(current.loci) && current.loci.links.length !== 0) {
loci = Link.toStructureElementLoci(current.loci);
} else {
return;
} }
const parent = this.plugin.helpers.substructureParent.get(loci.structure); const parent = this.plugin.helpers.substructureParent.get(loci.structure);
if (!parent) return; if (!parent) return Box3D.empty();
const root = this.getStructureRoot(); const root = this.getStructureRoot();
if (!root || !root.obj || root.obj !== parent.obj) return; if (!root || !root.obj || root.obj !== parent.obj) return Box3D.empty();
return StructureElement.Loci.getBoundary(StructureElement.Loci.extendToWholeResidues(loci)).box; return StructureElement.Loci.getBoundary(StructureElement.Loci.extendToWholeResidues(loci)).box;
} }
private updateInteraction(current: Representation.Loci) { private updateInteraction(current: Representation.Loci) {
if (Representation.Loci.areEqual(this.lastLoci, current)) { const loci = this.getNormalizedLoci(current.loci)
this.lastLoci = Representation.Loci.Empty; if (Loci.areEqual(this.lastLoci, loci)) {
this.lastLoci = EmptyLoci;
this.updateDynamicBox(Box3D.empty()); this.updateDynamicBox(Box3D.empty());
return; return;
} }
if (current.loci.kind === 'empty-loci') { this.lastLoci = loci;
if (isEmptyLoci(loci)) {
this.updateDynamicBox(Box3D.empty()); this.updateDynamicBox(Box3D.empty());
this.lastLoci = current;
return; return;
} }
const box = this.getBoxFromLoci(current); const box = this.getBoxFromLoci(loci);
if (!box) return; if (!box) return;
this.updateDynamicBox(box); this.updateDynamicBox(box);
} }
......
...@@ -148,7 +148,8 @@ const CreateVolumeStreamingBehavior = PluginStateTransform.BuiltIn({ ...@@ -148,7 +148,8 @@ const CreateVolumeStreamingBehavior = PluginStateTransform.BuiltIn({
})({ })({
canAutoUpdate: ({ oldParams, newParams }) => { canAutoUpdate: ({ oldParams, newParams }) => {
return oldParams.view === newParams.view return oldParams.view === newParams.view
|| (oldParams.view.name === newParams.view.name && oldParams.view.name === 'selection-box'); || newParams.view.name === 'selection-box'
|| newParams.view.name === 'off';
}, },
apply: ({ a, params }, plugin: PluginContext) => Task.create('Volume streaming', async _ => { apply: ({ a, params }, plugin: PluginContext) => Task.create('Volume streaming', async _ => {
const behavior = new VolumeStreaming.Behavior(plugin, a.data); const behavior = new VolumeStreaming.Behavior(plugin, a.data);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment