Browse Source

mol-plugin-state: changing structure "type" recreates the subtree
* different assemblies can have different default components
* i.e. assembly 1 doesn't have carbs and asm 2 does

David Sehnal 5 years ago
parent
commit
f955e6a299

+ 4 - 0
src/mol-plugin-state/helpers/root-structure.ts

@@ -94,6 +94,10 @@ export namespace RootStructureDefinition {
 
     export type Params = PD.Values<ReturnType<typeof getParams>>['type']
 
+    export function isSymmetryType(params: Params) {
+        return params.name.indexOf('symmetry') >= 0;
+    }
+
     async function buildAssembly(plugin: PluginContext, ctx: RuntimeContext, model: Model, id?: string) {
         let asm: Assembly | undefined = void 0;
 

+ 5 - 5
src/mol-plugin-state/manager/structure/component.ts

@@ -7,25 +7,25 @@
 import { VisualQualityOptions } from '../../../mol-geo/geometry/base';
 import { InteractionsProvider } from '../../../mol-model-props/computed/interactions';
 import { Structure, StructureElement } from '../../../mol-model/structure';
-import { structureAreIntersecting, structureSubtract, structureUnion, structureIntersect } from '../../../mol-model/structure/query/utils/structure-set';
+import { structureAreIntersecting, structureIntersect, structureSubtract, structureUnion } from '../../../mol-model/structure/query/utils/structure-set';
 import { setSubtreeVisibility } from '../../../mol-plugin/behavior/static/state';
 import { PluginContext } from '../../../mol-plugin/context';
 import { StateBuilder, StateTransformer } from '../../../mol-state';
 import { Task } from '../../../mol-task';
+import { ColorTheme } from '../../../mol-theme/color';
+import { SizeTheme } from '../../../mol-theme/size';
 import { UUID } from '../../../mol-util';
 import { ColorNames } from '../../../mol-util/color/names';
+import { objectForEach } from '../../../mol-util/object';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { StructureRepresentationPresetProvider } from '../../builder/structure/representation-preset';
 import { StatefulPluginComponent } from '../../component';
 import { StructureComponentParams } from '../../helpers/structure-component';
 import { clearStructureOverpaint, setStructureOverpaint } from '../../helpers/structure-overpaint';
+import { createStructureColorThemeParams, createStructureSizeThemeParams } from '../../helpers/structure-representation-params';
 import { StructureSelectionQueries, StructureSelectionQuery } from '../../helpers/structure-selection-query';
 import { StructureRepresentation3D } from '../../transforms/representation';
 import { HierarchyRef, StructureComponentRef, StructureRef, StructureRepresentationRef } from './hierarchy-state';
-import { createStructureColorThemeParams, createStructureSizeThemeParams } from '../../helpers/structure-representation-params';
-import { ColorTheme } from '../../../mol-theme/color';
-import { SizeTheme } from '../../../mol-theme/size';
-import { objectForEach } from '../../../mol-util/object';
 
 export { StructureComponentManager };
 

+ 39 - 6
src/mol-plugin-state/manager/structure/hierarchy.ts

@@ -5,13 +5,16 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
+import { setSubtreeVisibility } from '../../../mol-plugin/behavior/static/state';
+import { PluginCommands } from '../../../mol-plugin/commands';
 import { PluginContext } from '../../../mol-plugin/context';
-import { StructureHierarchy, buildStructureHierarchy, ModelRef, StructureComponentRef, StructureRef, HierarchyRef, TrajectoryRef } from './hierarchy-state';
-import { PluginComponent } from '../../component';
+import { StateTransform, StateTransformer, StateTree } from '../../../mol-state';
 import { SetUtils } from '../../../mol-util/set';
-import { StateTransform } from '../../../mol-state';
 import { TrajectoryHierarchyPresetProvider } from '../../builder/structure/hierarchy-preset';
-import { setSubtreeVisibility } from '../../../mol-plugin/behavior/static/state';
+import { PluginComponent } from '../../component';
+import { RootStructureDefinition } from '../../helpers/root-structure';
+import { StateTransforms } from '../../transforms';
+import { buildStructureHierarchy, HierarchyRef, ModelRef, StructureComponentRef, StructureHierarchy, StructureRef, TrajectoryRef } from './hierarchy-state';
 
 export class StructureHierarchyManager extends PluginComponent {
     private state = {
@@ -151,10 +154,10 @@ export class StructureHierarchyManager extends PluginComponent {
         this.behaviors.selection.next({ hierarchy, trajectories, models, structures });
     }
 
-    remove(refs: HierarchyRef[], canUndo?: boolean) {
+    remove(refs: (HierarchyRef | string)[], canUndo?: boolean) {
         if (refs.length === 0) return;
         const deletes = this.plugin.state.data.build();
-        for (const r of refs) deletes.delete(r.cell.transform.ref);
+        for (const r of refs) deletes.delete(typeof r === 'string' ? r : r.cell.transform.ref);
         return this.plugin.updateDataState(deletes, { canUndo: canUndo ? 'Remove' : false });
     }
 
@@ -180,6 +183,36 @@ export class StructureHierarchyManager extends PluginComponent {
         });
     }
 
+    private _updateStructure(s: StructureRef, params: any, recreateRepresentation: boolean) {
+        return this.plugin.dataTransaction(async () => {
+            if (recreateRepresentation) {
+                const root = StateTree.getDecoratorRoot(this.dataState.tree, s.cell.transform.ref);
+                const children = this.dataState.tree.children.get(root).toArray();
+                await this.remove(children, false);
+            }
+            await this.plugin.state.updateTransform(this.plugin.state.data, s.cell.transform.ref, params, 'Structure Type');
+            if (recreateRepresentation) {
+                await this.plugin.builders.structure.representation.applyPreset(s.cell.transform.ref, 'auto');
+            }
+        }, { canUndo: 'Structure Type'})
+    }
+
+    async updateStructure(s: StructureRef, newParams: any) {
+        if (s.cell.transform.transformer === StateTransforms.Model.StructureFromModel) {
+            const old = s.cell.transform.params! as StateTransformer.Params<StateTransforms['Model']['StructureFromModel']>;
+            const params = newParams as StateTransformer.Params<StateTransforms['Model']['StructureFromModel']>;
+
+            if (RootStructureDefinition.isSymmetryType(old.type) && RootStructureDefinition.isSymmetryType(params.type)) {
+                await this._updateStructure(s, newParams, false);
+            } else {
+                await this._updateStructure(s, newParams, true);
+            }
+        } else {
+            await this._updateStructure(s, newParams, true);
+        }
+        PluginCommands.Camera.Reset(this.plugin);
+    }
+
     private clearTrajectory(trajectory: TrajectoryRef) {
         const builder = this.dataState.build();
         for (const m of trajectory.models) {

+ 4 - 6
src/mol-plugin-ui/structure/source.tsx

@@ -7,12 +7,11 @@
 
 import * as React from 'react';
 import { HierarchyRef, ModelRef, TrajectoryRef } from '../../mol-plugin-state/manager/structure/hierarchy-state';
+import { StateTransforms } from '../../mol-plugin-state/transforms';
 import { CollapsableControls, CollapsableState } from '../base';
 import { ActionMenu } from '../controls/action-menu';
-import { IconButton, Button } from '../controls/common';
+import { Button, IconButton } from '../controls/common';
 import { ParameterControls } from '../controls/parameters';
-import { PluginCommands } from '../../mol-plugin/commands';
-import { StateTransforms } from '../../mol-plugin-state/transforms';
 import { StructureFocusControls } from './focus';
 
 interface StructureSourceControlState extends CollapsableState {
@@ -229,11 +228,10 @@ export class StructureSourceControls extends CollapsableControls<{}, StructureSo
         return <ParameterControls params={params} values={m.cell.params?.values} onChangeValues={this.updateStructureModel} isDisabled={this.state.isBusy} />
     }
 
-    updateStructure = async (params: any) => {
+    updateStructure = (params: any) => {
         const { selection } = this.plugin.managers.structure.hierarchy;
         const s = selection.structures[0];
-        await this.plugin.state.updateTransform(this.plugin.state.data, s.cell.transform.ref, params, 'Structure Type');
-        PluginCommands.Camera.Reset(this.plugin);
+        this.plugin.managers.structure.hierarchy.updateStructure(s, params);
     }
 
     get structureType() {

+ 2 - 6
src/mol-state/state/builder.ts

@@ -111,12 +111,8 @@ namespace StateBuilder {
 
         readonly ref: StateTransform.Ref;
 
-        private getApplyRoot(ref?: StateTransform.Ref): StateTransform.Ref {
-            const children = this.state.tree.children.get(ref || this.ref);
-            if (children.size !== 1) return ref || this.ref;
-            const child = this.state.tree.transforms.get(children.first());
-            if (child.transformer.definition.isDecorator) return this.getApplyRoot(child.ref);
-            return ref || this.ref;
+        private getApplyRoot(): StateTransform.Ref {
+            return StateTree.getDecoratorRoot(this.state.tree, this.ref);
         }
 
         /**

+ 11 - 1
src/mol-state/tree/immutable.ts

@@ -32,7 +32,9 @@ namespace StateTree {
         readonly values: OrderedSet<Ref>['values'],
         has(ref: Ref): boolean,
         readonly forEach: OrderedSet<Ref>['forEach'],
-        readonly map: OrderedSet<Ref>['map']
+        readonly map: OrderedSet<Ref>['map'],
+        toArray(): Ref[],
+        first(): Ref
     }
 
     interface _Map<T> {
@@ -197,4 +199,12 @@ namespace StateTree {
         if (!tree.transforms.has(root) || !tree.transforms.has(ref)) return false;
         return _subtreeHasRef(tree, root, ref);
     }
+
+    export function getDecoratorRoot(tree: StateTree, ref: StateTransform.Ref): StateTransform.Ref {
+        const children = tree.children.get(ref);
+        if (children.size !== 1) return ref;
+        const child = tree.transforms.get(children.first());
+        if (child.transformer.definition.isDecorator) return getDecoratorRoot(tree, child.ref);
+        return ref;
+    }
 }