Browse Source

StructureHierarchy now relies less on tags

David Sehnal 5 years ago
parent
commit
af5ddf6950

+ 1 - 1
package.json

@@ -21,7 +21,7 @@
     "watch-viewer": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer\"",
     "watch-tsc": "tsc --watch --incremental",
     "watch-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html,ico}\" lib/ --watch",
-    "watch-webpack": "webpack -w --mode development --display errors-only --info-verbosity verbose",
+    "watch-webpack": "webpack -w --mode development --display minimal",
     "watch-webpack-viewer": "webpack -w --mode development --display errors-only --info-verbosity verbose --config ./webpack.config.viewer.js",
     "serve": "http-server -p 1338",
     "model-server": "node lib/servers/model/server.js",

+ 20 - 23
src/mol-plugin-state/builder/structure/representation.ts

@@ -6,7 +6,7 @@
 
 import { arrayFind } from '../../../mol-data/util';
 import { PluginContext } from '../../../mol-plugin/context';
-import { StateBuilder, StateObjectRef, StateObjectSelector } from '../../../mol-state';
+import { StateBuilder, StateObjectRef, StateObjectSelector, StateTransform } from '../../../mol-state';
 import { Task } from '../../../mol-task';
 import { isProductionMode } from '../../../mol-util/debug';
 import { objectForEach } from '../../../mol-util/object';
@@ -18,10 +18,6 @@ import { PresetStructureReprentations, StructureRepresentationPresetProvider } f
 
 export type StructureRepresentationPresetProviderRef = keyof PresetStructureReprentations | StructureRepresentationPresetProvider | string
 
-export const enum StructureRepresentationBuilderTags {
-    Representation = 'structure-representation'
-}
-
 export class StructureRepresentationBuilder {
     private _providers: StructureRepresentationPresetProvider[] = [];
     private providerMap: Map<string, StructureRepresentationPresetProvider> = new Map();
@@ -107,36 +103,37 @@ export class StructureRepresentationBuilder {
         return this.plugin.runTask(task);
     }
 
-    async addRepresentation<P extends StructureRepresentationBuiltInProps>(structure: StateObjectRef<PluginStateObject.Molecule.Structure>, props?: P): Promise<StateObjectSelector<PluginStateObject.Molecule.Structure.Representation3D>>
-    async addRepresentation<P extends StructureRepresentationProps>(structure: StateObjectRef<PluginStateObject.Molecule.Structure>, props?: P): Promise<StateObjectSelector<PluginStateObject.Molecule.Structure.Representation3D>>
-    async addRepresentation(structure: StateObjectRef<PluginStateObject.Molecule.Structure>, props?: any) {
-        const data = StateObjectRef.resolveAndCheck(this.dataState, structure)?.obj?.data;
-        if (!data) return;
-
-        const params = createStructureRepresentationParams(this.plugin, data, props);
-        const repr = this.dataState.build()
-            .to(structure)
-            .apply(StructureRepresentation3D, params, { tags: StructureRepresentationBuilderTags.Representation });
+    async addRepresentation<P extends StructureRepresentationBuiltInProps>(structure: StateObjectRef<PluginStateObject.Molecule.Structure>, props: P, options?: Partial<StructureRepresentationBuilder.AddRepresentationOptions>): Promise<StateObjectSelector<PluginStateObject.Molecule.Structure.Representation3D>>
+    async addRepresentation<P extends StructureRepresentationProps>(structure: StateObjectRef<PluginStateObject.Molecule.Structure>, props: P, options?: Partial<StructureRepresentationBuilder.AddRepresentationOptions>): Promise<StateObjectSelector<PluginStateObject.Molecule.Structure.Representation3D>>
+    async addRepresentation(structure: StateObjectRef<PluginStateObject.Molecule.Structure>, props: any, options?: Partial<StructureRepresentationBuilder.AddRepresentationOptions>) {
+        const repr = this.dataState.build();
+        const selector = this.buildRepresentation(repr, structure, props, options);
+        if (!selector) return;
 
         await this.plugin.updateDataState(repr);
-        return  repr.selector;
+        return selector;
     }
 
-    async buildRepresentation<P extends StructureRepresentationBuiltInProps>(builder: StateBuilder.Root, structure: StateObjectRef<PluginStateObject.Molecule.Structure> | undefined, props?: P): Promise<StateObjectSelector<PluginStateObject.Molecule.Structure.Representation3D>>
-    async buildRepresentation<P extends StructureRepresentationProps>(builder: StateBuilder.Root, structure: StateObjectRef<PluginStateObject.Molecule.Structure> | undefined, props?: P): Promise<StateObjectSelector<PluginStateObject.Molecule.Structure.Representation3D>>
-    async buildRepresentation(builder: StateBuilder.Root, structure: StateObjectRef<PluginStateObject.Molecule.Structure> | undefined, props?: any) {
+    async buildRepresentation<P extends StructureRepresentationBuiltInProps>(builder: StateBuilder.Root, structure: StateObjectRef<PluginStateObject.Molecule.Structure> | undefined, props: P, options?: Partial<StructureRepresentationBuilder.AddRepresentationOptions>): Promise<StateObjectSelector<PluginStateObject.Molecule.Structure.Representation3D>>
+    async buildRepresentation<P extends StructureRepresentationProps>(builder: StateBuilder.Root, structure: StateObjectRef<PluginStateObject.Molecule.Structure> | undefined, props: P, options?: Partial<StructureRepresentationBuilder.AddRepresentationOptions>): Promise<StateObjectSelector<PluginStateObject.Molecule.Structure.Representation3D>>
+    async buildRepresentation(builder: StateBuilder.Root, structure: StateObjectRef<PluginStateObject.Molecule.Structure> | undefined, props: any, options?: Partial<StructureRepresentationBuilder.AddRepresentationOptions>) {
         if (!structure) return;
         const data = StateObjectRef.resolveAndCheck(this.dataState, structure)?.obj?.data;
         if (!data) return;
 
         const params = createStructureRepresentationParams(this.plugin, data, props);
-        return builder
-            .to(structure)
-            .apply(StructureRepresentation3D, params, { tags: StructureRepresentationBuilderTags.Representation })
-            .selector;
+        return builder.to(structure)
+            .apply(StructureRepresentation3D, params, { tags: options?.tag, state: options?.initialState }).selector;
     }
 
     constructor(public plugin: PluginContext) {
         objectForEach(PresetStructureReprentations, r => this.registerPreset(r));
     }
+}
+
+export namespace StructureRepresentationBuilder {
+    export interface AddRepresentationOptions {
+        initialState?: Partial<StateTransform.State>,
+        tag?: string
+    }
 }

+ 52 - 15
src/mol-plugin-state/manager/structure/hierarchy-state.ts

@@ -7,7 +7,6 @@
 import { PluginStateObject as SO } from '../../objects';
 import { StateObject, StateTransform, State, StateObjectCell, StateTree, StateTransformer } from '../../../mol-state';
 import { StructureBuilderTags } from '../../builder/structure';
-import { StructureRepresentationBuilderTags } from '../../builder/structure/representation';
 import { StructureRepresentationInteractionTags } from '../../../mol-plugin/behavior/dynamic/selection/structure-representation-interaction';
 import { StateTransforms } from '../../transforms';
 import { VolumeStreaming } from '../../../mol-plugin/behavior/dynamic/volume-streaming/behavior';
@@ -189,11 +188,34 @@ function createOrUpdateRef<R extends HierarchyRef, C extends any[]>(state: Build
     return ref;
 }
 
-const tagMap: [string, (state: BuildState, cell: StateObjectCell) => boolean | void, (state: BuildState) => any][] = [
-    [StructureBuilderTags.Trajectory, (state, cell) => {
+type TestCell = (cell: StateObjectCell, state: BuildState) => boolean
+type ApplyRef = (state: BuildState, cell: StateObjectCell) => boolean | void
+type LeaveRef = (state: BuildState) => any
+
+function isTag(t: string): TestCell {
+    return (cell) => StateObject.hasTag(cell.obj!, t);
+}
+
+function isType(t: StateObject.Ctor): TestCell {
+    return (cell) => t.is(cell.obj);
+}
+
+function isTypeRoot(t: StateObject.Ctor, target: (state: BuildState) => any): TestCell {
+    return (cell, state) => !target(state) && t.is(cell.obj);
+}
+
+function isTransformer(t: StateTransformer): TestCell {
+    return cell => cell.transform.transformer === t;
+}
+
+const tagMap: [TestCell, ApplyRef, LeaveRef][] = [
+    // Trajectory
+    [isType(SO.Molecule.Trajectory), (state, cell) => {
         state.currentTrajectory = createOrUpdateRefList(state, cell, state.hierarchy.trajectories, TrajectoryRef, cell);
     }, state => state.currentTrajectory = void 0],
-    [StructureBuilderTags.Model, (state, cell) => {
+
+    // Model
+    [isTypeRoot(SO.Molecule.Model, s => s.currentModel), (state, cell) => {
         if (state.currentTrajectory) {
             state.currentModel = createOrUpdateRefList(state, cell, state.currentTrajectory.models, ModelRef, cell, state.currentTrajectory);
         } else {
@@ -201,20 +223,22 @@ const tagMap: [string, (state: BuildState, cell: StateObjectCell) => boolean | v
         }
         state.hierarchy.models.push(state.currentModel);
     }, state => state.currentModel = void 0],
-    [StructureBuilderTags.ModelProperties, (state, cell) => {
+    [isTransformer(StateTransforms.Model.CustomModelProperties), (state, cell) => {
         if (!state.currentModel) return false;
         state.currentModel.properties = createOrUpdateRef(state, cell, ModelPropertiesRef, cell, state.currentModel);
     }, state => { }],
-    [StructureBuilderTags.ModelUnitcell, (state, cell) => {
+    [isTag(StructureBuilderTags.ModelUnitcell), (state, cell) => {
         if (!state.currentModel) return false;
         state.currentModel.unitcell = createOrUpdateRef(state, cell, ModelUnitcellRef, cell, state.currentModel);
     }, state => { }],
-    [StructureBuilderTags.ModelGenericRepresentation, (state, cell) => {
+    [isTag(StructureBuilderTags.ModelGenericRepresentation), (state, cell) => {
         if (!state.currentModel) return false;
         if (!state.currentModel.genericRepresentations) state.currentModel.genericRepresentations = []
         createOrUpdateRefList(state, cell, state.currentModel.genericRepresentations, GenericRepresentationRef, cell, state.currentModel);
     }, state => { }],
-    [StructureBuilderTags.Structure, (state, cell) => {
+
+    // Structure
+    [isTypeRoot(SO.Molecule.Structure, s => s.currentStructure), (state, cell) => {
         if (state.currentModel) {
             state.currentStructure = createOrUpdateRefList(state, cell, state.currentModel.structures, StructureRef, cell, state.currentModel);
         } else {
@@ -222,25 +246,38 @@ const tagMap: [string, (state: BuildState, cell: StateObjectCell) => boolean | v
         }
         state.hierarchy.structures.push(state.currentStructure);
     }, state => state.currentStructure = void 0],
-    [StructureBuilderTags.StructureProperties, (state, cell) => {
+    [isTransformer(StateTransforms.Model.CustomStructureProperties), (state, cell) => {
         if (!state.currentStructure) return false;
         state.currentStructure.properties = createOrUpdateRef(state, cell, StructurePropertiesRef, cell, state.currentStructure);
     }, state => { }],
-    [StructureBuilderTags.Component, (state, cell) => {
+
+    // Component
+    [(cell, state) => {
+        if (!state.currentStructure || !SO.Molecule.Structure.is(cell.obj) || cell.transform.transformer.definition.isDecorator) return false;
+        if (StateObject.hasTag(cell.obj!, StructureBuilderTags.Component)) return true;
+        const parent = state.state.cells.get(cell.transform.parent);
+        return SO.Molecule.Structure.is(parent?.obj) && SO.Molecule.Structure.is(cell.obj);
+    }, (state, cell) => {
         if (!state.currentStructure) return false;
         state.currentComponent = createOrUpdateRefList(state, cell, state.currentStructure.components, StructureComponentRef, cell, state.currentStructure);
     }, state => state.currentComponent = void 0],
-    [StructureRepresentationBuilderTags.Representation, (state, cell) => {
+
+    // Component Rpresentation
+    [(cell, state) => {
+        return !cell.state.isGhost && !!state.currentComponent && SO.Molecule.Structure.Representation3D.is(cell.obj)
+    }, (state, cell) => {
         if (!state.currentComponent) return false;
         createOrUpdateRefList(state, cell, state.currentComponent.representations, StructureRepresentationRef, cell, state.currentComponent);
     }, state => { }],
-    [StructureRepresentationInteractionTags.ResidueSel, (state, cell) => {
+
+    // Current interaction
+    [isTag(StructureRepresentationInteractionTags.ResidueSel), (state, cell) => {
         if (!state.currentStructure) return false;
         if (!state.currentStructure.currentFocus) state.currentStructure.currentFocus = { };
         state.currentStructure.currentFocus.focus = createOrUpdateRef(state, cell, StructureComponentRef, cell, state.currentStructure);
         state.currentComponent = state.currentStructure.currentFocus.focus;
     }, state => state.currentComponent = void 0],
-    [StructureRepresentationInteractionTags.SurrSel, (state, cell) => {
+    [isTag(StructureRepresentationInteractionTags.SurrSel), (state, cell) => {
         if (!state.currentStructure) return false;
         if (!state.currentStructure.currentFocus) state.currentStructure.currentFocus = { };
         state.currentStructure.currentFocus.surroundings = createOrUpdateRef(state, cell, StructureComponentRef, cell, state.currentStructure);
@@ -270,8 +307,8 @@ function _doPreOrder(ctx: VisitorCtx, root: StateTransform) {
     if (!isValidCell(cell)) return;
 
     let onLeave: undefined | ((state: BuildState) => any) = void 0;
-    for (const [t, f, l] of tagMap) {
-        if (StateObject.hasTag(cell.obj!, t)) {
+    for (const [test, f, l] of tagMap) {
+        if (test(cell, state)) {
             const stop = f(state, cell);
             if (stop === false) {
                 return;

+ 1 - 1
src/mol-state/object.ts

@@ -29,7 +29,7 @@ namespace StateObject {
     }
 
     export type Type<Cls extends string = string> = { name: string, typeClass: Cls }
-    export type Ctor<T extends StateObject = StateObject> = { new(...args: any[]): T, type: any }
+    export type Ctor<T extends StateObject = StateObject> = { new(...args: any[]): T, is(obj?: StateObject): boolean, type: any }
     export type From<C extends Ctor> = C extends Ctor<infer T> ? T : never
 
     export function create<Data, T extends Type>(type: T) {