diff --git a/src/mol-plugin/behavior/dynamic/representation.ts b/src/mol-plugin/behavior/dynamic/representation.ts index bb1987dbf780c34f8c6faf62b07fb70876c16c84..c3df52b8061d498f9df819a096add9e8b765293e 100644 --- a/src/mol-plugin/behavior/dynamic/representation.ts +++ b/src/mol-plugin/behavior/dynamic/representation.ts @@ -24,7 +24,7 @@ export const HighlightLoci = PluginBehavior.create({ ctor: class extends PluginBehavior.Handler { register(): void { let prev: Representation.Loci = { loci: EmptyLoci, repr: void 0 }; - const sel = this.ctx.selection.structure; + const sel = this.ctx.helpers.structureSelection; this.subscribeObservable(this.ctx.events.canvas3d.highlight, ({ current, modifiers }) => { if (!this.ctx.canvas3d) return; @@ -58,7 +58,7 @@ export const SelectLoci = PluginBehavior.create({ category: 'interaction', ctor: class extends PluginBehavior.Handler { register(): void { - const sel = this.ctx.selection.structure; + const sel = this.ctx.helpers.structureSelection; const toggleSel = (current: Representation.Loci<StructureElement.Loci>) => { if (sel.has(current.loci)) { diff --git a/src/mol-plugin/context.ts b/src/mol-plugin/context.ts index 63f8891d526821edcd0cb46f9f8144c51f6fd40e..5f953100ae706045ce1a3f694c7f3a3736a02a27 100644 --- a/src/mol-plugin/context.ts +++ b/src/mol-plugin/context.ts @@ -31,6 +31,7 @@ import { LociLabelEntry, LociLabelManager } from './util/loci-label-manager'; 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'; export class PluginContext { private disposed = false; @@ -99,8 +100,9 @@ export class PluginContext { readonly customModelProperties = new CustomPropertyRegistry(); readonly customParamEditors = new Map<string, StateTransformParameters.Class>(); - readonly selection = { - structure: new StructureElementSelectionManager(this) + readonly helpers = { + structureSelection: new StructureElementSelectionManager(this), + substructureParent: new SubstructureParentHelper(this) }; initViewer(canvas: HTMLCanvasElement, container: HTMLDivElement) { diff --git a/src/mol-plugin/util/structure-element-selection.ts b/src/mol-plugin/util/structure-element-selection.ts index b5f7d7b99237d50fa71b3800b082e0b97cb45b4f..8ebe9d12d1bc4c2cda4583f8e62890aa20bf8a72 100644 --- a/src/mol-plugin/util/structure-element-selection.ts +++ b/src/mol-plugin/util/structure-element-selection.ts @@ -4,34 +4,29 @@ * @author David Sehnal <david.sehnal@gmail.com> */ +import { OrderedSet } from 'mol-data/int'; import { EmptyLoci, Loci } from 'mol-model/loci'; import { Structure, StructureElement } from 'mol-model/structure'; -import { State, StateObject, StateSelection } from 'mol-state'; +import { StateObject } from 'mol-state'; import { PluginContext } from '../context'; import { PluginStateObject } from '../state/objects'; -import { OrderedSet } from 'mol-data/int'; export { StructureElementSelectionManager }; class StructureElementSelectionManager { private entries = new Map<string, SelectionEntry>(); - // maps structure to a parent StateObjectCell - private mapping = { - root: new Map<Structure, string>(), - tracked: new Map<string, Structure>() - }; - private getEntry(s: Structure) { - if (!this.mapping.root.has(s)) return; - const key = this.mapping.root.get(s)!; - if (!this.entries.has(key)) { + const cell = this.plugin.helpers.substructureParent.get(s); + if (!cell) return; + const ref = cell.transform.ref; + if (!this.entries.has(ref)) { const entry = SelectionEntry(s); - this.entries.set(key, entry); + this.entries.set(ref, entry); return entry; } - return this.entries.get(key)!; + return this.entries.get(ref)!; } add(loci: StructureElement.Loci): Loci { @@ -112,27 +107,11 @@ class StructureElementSelectionManager { return ret || EmptyLoci; } - private addMapping(state: State, ref: string, obj: StateObject) { - if (!PluginStateObject.Molecule.Structure.is(obj)) return; - const parent = state.select(StateSelection.Generators.byRef(ref).rootOfType([PluginStateObject.Molecule.Structure]))[0]; - this.mapping.tracked.set(ref, obj.data); - if (!parent) { - this.mapping.root.set(obj.data, ref); - } else { - this.mapping.root.set(obj.data, parent.transform.ref); - } - } - - private removeMapping(ref: string) { - if (!this.mapping.tracked.has(ref)) return; - const s = this.mapping.tracked.get(ref)!; - this.mapping.tracked.delete(ref); - const root = this.mapping.root.get(s); - this.mapping.root.delete(s); - if (root === ref) this.entries.delete(ref); + private onRemove(ref: string) { + if (this.entries.has(ref)) this.entries.delete(ref); } - private updateMapping(state: State, ref: string, oldObj: StateObject | undefined, obj: StateObject) { + private onUpdate(ref: string, oldObj: StateObject | undefined, obj: StateObject) { if (!PluginStateObject.Molecule.Structure.is(obj)) return; if (this.entries.has(ref)) { @@ -146,24 +125,12 @@ class StructureElementSelectionManager { // clear the selection this.entries.set(ref, SelectionEntry(obj.data)); - } else { - this.removeMapping(ref); - this.addMapping(state, ref, obj); } } - constructor(plugin: PluginContext) { - plugin.state.dataState.events.object.created.subscribe(e => { - this.addMapping(e.state, e.ref, e.obj); - }); - - plugin.state.dataState.events.object.removed.subscribe(e => { - this.removeMapping(e.ref); - }); - - plugin.state.dataState.events.object.updated.subscribe(e => { - this.updateMapping(e.state, e.ref, e.oldObj, e.obj); - }); + constructor(private plugin: PluginContext) { + plugin.state.dataState.events.object.removed.subscribe(e => this.onRemove(e.ref)); + plugin.state.dataState.events.object.updated.subscribe(e => this.onUpdate(e.ref, e.oldObj, e.obj)); } } diff --git a/src/mol-plugin/util/substructure-parent-helper.ts b/src/mol-plugin/util/substructure-parent-helper.ts new file mode 100644 index 0000000000000000000000000000000000000000..322f43f73fc08805df92ca02e2017e43d5f308de --- /dev/null +++ b/src/mol-plugin/util/substructure-parent-helper.ts @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { Structure } from 'mol-model/structure'; +import { State, StateObject, StateSelection, StateObjectCell } from 'mol-state'; +import { PluginContext } from '../context'; +import { PluginStateObject } from '../state/objects'; + +export { SubstructureParentHelper }; + +class SubstructureParentHelper { + private root = new Map<Structure, string>(); + private tracked = new Map<string, Structure>(); + + get(s: Structure): StateObjectCell<PluginStateObject.Molecule.Structure> | undefined { + const r = this.root.get(s); + if (!r) return; + return this.plugin.state.dataState.cells.get(r); + } + + private addMapping(state: State, ref: string, obj: StateObject) { + if (!PluginStateObject.Molecule.Structure.is(obj)) return; + const parent = state.select(StateSelection.Generators.byRef(ref).rootOfType([PluginStateObject.Molecule.Structure]))[0]; + this.tracked.set(ref, obj.data); + if (!parent) { + this.root.set(obj.data, ref); + } else { + this.root.set(obj.data, parent.transform.ref); + } + } + + private removeMapping(ref: string) { + if (!this.tracked.has(ref)) return; + const s = this.tracked.get(ref)!; + this.tracked.delete(ref); + this.root.get(s); + this.root.delete(s); + } + + private updateMapping(state: State, ref: string, oldObj: StateObject | undefined, obj: StateObject) { + if (!PluginStateObject.Molecule.Structure.is(obj)) return; + + this.removeMapping(ref); + this.addMapping(state, ref, obj); + } + + constructor(private plugin: PluginContext) { + plugin.state.dataState.events.object.created.subscribe(e => { + this.addMapping(e.state, e.ref, e.obj); + }); + + plugin.state.dataState.events.object.removed.subscribe(e => { + this.removeMapping(e.ref); + }); + + plugin.state.dataState.events.object.updated.subscribe(e => { + this.updateMapping(e.state, e.ref, e.oldObj, e.obj); + }); + } +} \ No newline at end of file