From 3d4f40f680a6b6faba6767404fa0f1cb48d5644b Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Sat, 2 Mar 2019 16:08:07 +0100 Subject: [PATCH] mol-plugin: SubstructureParentHelper --- .../behavior/dynamic/representation.ts | 4 +- src/mol-plugin/context.ts | 6 +- .../util/structure-element-selection.ts | 61 +++++------------- .../util/substructure-parent-helper.ts | 63 +++++++++++++++++++ 4 files changed, 83 insertions(+), 51 deletions(-) create mode 100644 src/mol-plugin/util/substructure-parent-helper.ts diff --git a/src/mol-plugin/behavior/dynamic/representation.ts b/src/mol-plugin/behavior/dynamic/representation.ts index bb1987dbf..c3df52b80 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 63f8891d5..5f953100a 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 b5f7d7b99..8ebe9d12d 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 000000000..322f43f73 --- /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 -- GitLab