Browse Source

mol-plugin: custom param editors for transformers, assembly fix

David Sehnal 6 years ago
parent
commit
ac637b67ba

+ 20 - 9
src/mol-plugin/context.ts

@@ -29,6 +29,7 @@ import { VolumeRepresentationRegistry } from 'mol-repr/volume/registry';
 import { PLUGIN_VERSION, PLUGIN_VERSION_DATE } from './version';
 import { PluginLayout } from './layout';
 import { List } from 'immutable';
+import { StateTransformParameters } from './ui/state/common';
 
 export class PluginContext {
     private disposed = false;
@@ -87,6 +88,7 @@ export class PluginContext {
     }
 
     readonly customModelProperties = new CustomPropertyRegistry();
+    readonly customParamEditors = new Map<string, StateTransformParameters.Class>();
 
     initViewer(canvas: HTMLCanvasElement, container: HTMLDivElement) {
         try {
@@ -136,6 +138,16 @@ export class PluginContext {
         this.disposed = true;
     }
 
+    applyTransform(state: State, a: Transform.Ref, transformer: Transformer, params: any) {
+        const tree = state.tree.build().to(a).apply(transformer, params);
+        return PluginCommands.State.Update.dispatch(this, { state, tree });
+    }
+
+    updateTransform(state: State, a: Transform.Ref, params: any) {
+        const tree = state.build().to(a).update(params);
+        return PluginCommands.State.Update.dispatch(this, { state, tree });
+    }
+
     private initBuiltInBehavior() {
         BuiltInPluginBehaviors.State.registerDefault(this);
         BuiltInPluginBehaviors.Representation.registerDefault(this);
@@ -145,7 +157,7 @@ export class PluginContext {
         merge(this.state.dataState.events.log, this.state.behaviorState.events.log).subscribe(e => this.events.log.next(e));
     }
 
-    async initBehaviors() {
+    private async initBehaviors() {
         const tree = this.state.behaviorState.tree.build();
 
         for (const b of this.spec.behaviors) {
@@ -155,20 +167,18 @@ export class PluginContext {
         await this.runTask(this.state.behaviorState.updateTree(tree, true));
     }
 
-    initDataActions() {
+    private initDataActions() {
         for (const a of this.spec.actions) {
             this.state.dataState.actions.add(a.action);
         }
     }
 
-    applyTransform(state: State, a: Transform.Ref, transformer: Transformer, params: any) {
-        const tree = state.tree.build().to(a).apply(transformer, params);
-        return PluginCommands.State.Update.dispatch(this, { state, tree });
-    }
+    private initCustomParamEditors() {
+        if (!this.spec.customParamEditors) return;
 
-    updateTransform(state: State, a: Transform.Ref, params: any) {
-        const tree = state.build().to(a).update(params);
-        return PluginCommands.State.Update.dispatch(this, { state, tree });
+        for (const [t, e] of this.spec.customParamEditors) {
+            this.customParamEditors.set(t.id, e);
+        }
     }
 
     constructor(public spec: PluginSpec) {
@@ -178,6 +188,7 @@ export class PluginContext {
 
         this.initBehaviors();
         this.initDataActions();
+        this.initCustomParamEditors();
 
         this.lociLabels = new LociLabelManager(this);
 

+ 1 - 0
src/mol-plugin/spec.ts

@@ -14,6 +14,7 @@ export { PluginSpec }
 interface PluginSpec {
     actions: PluginSpec.Action[],
     behaviors: PluginSpec.Behavior[],
+    customParamEditors?: [StateAction | Transformer, StateTransformParameters.Class][]
     initialLayout?: PluginLayoutStateProps
 }
 

+ 5 - 3
src/mol-plugin/state/transforms/model.ts

@@ -140,17 +140,19 @@ const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({
     apply({ a, params }, plugin: PluginContext) {
         return Task.create('Build Assembly', async ctx => {
             const model = a.data;
-            const id = params.id;
-            const asm = ModelSymmetry.findAssembly(model, id || '');
+            let id = params.id;
+            let asm = ModelSymmetry.findAssembly(model, id || '');
             if (!!id && id !== 'deposited' && !asm) throw new Error(`Assembly '${id}' not found`);
 
             const base = Structure.ofModel(model);
-            if (!asm) {
+            if ((id && !asm) || model.symmetry.assemblies.length === 0) {
                 if (!!id && id !== 'deposited') plugin.log.warn(`Model '${a.label}' has no assembly, returning deposited structure.`);
                 const label = { label: a.data.label, description: structureDesc(base) };
                 return new SO.Molecule.Structure(base, label);
             }
 
+            asm = model.symmetry.assemblies[0];
+            id = asm.id;
             const s = await StructureSymmetry.buildAssembly(base, id!).runInContext(ctx);
             const props = { label: `Assembly ${id}`, description: structureDesc(s) };
             return new SO.Molecule.Structure(s, props);

+ 1 - 0
src/mol-plugin/ui/state/apply-action.tsx

@@ -41,6 +41,7 @@ class ApplyActionContol extends TransformContolBase<ApplyActionContol.Props, App
         });
     }
     getInfo() { return this._getInfo(this.props.nodeRef, this.props.state.transforms.get(this.props.nodeRef).version); }
+    getTransformerId() { return this.props.state.transforms.get(this.props.nodeRef).transformer.id; }
     getHeader() { return this.props.action.definition.display; }
     canApply() { return !this.state.error && !this.state.busy; }
     canAutoApply() { return false; }

+ 7 - 1
src/mol-plugin/ui/state/common.tsx

@@ -102,6 +102,7 @@ abstract class TransformContolBase<P, S extends TransformContolBase.ControlState
     abstract getInfo(): StateTransformParameters.Props['info'];
     abstract getHeader(): Transformer.Definition['display'];
     abstract canApply(): boolean;
+    abstract getTransformerId(): string;
     abstract canAutoApply(newParams: any): boolean;
     abstract applyText(): string;
     abstract isUpdate(): boolean;
@@ -170,13 +171,18 @@ abstract class TransformContolBase<P, S extends TransformContolBase.ControlState
 
         const display = this.getHeader();
 
+        const tId = this.getTransformerId();
+        const ParamEditor: StateTransformParameters.Class = this.plugin.customParamEditors.has(tId)
+            ? this.plugin.customParamEditors.get(tId)!
+            : StateTransformParameters;
+
         return <div className='msp-transform-wrapper'>
             <div className='msp-transform-header'>
                 <button className='msp-btn msp-btn-block' onClick={this.toggleExpanded}>{display.name}</button>
                 {!this.state.isCollapsed && <button className='msp-btn msp-btn-link msp-transform-default-params' onClick={this.setDefault} disabled={this.state.busy} style={{ float: 'right'}} title='Set default params'>↻</button>}
             </div>
             {!this.state.isCollapsed && <>
-                <StateTransformParameters info={info} events={this.events} params={this.state.params} isDisabled={this.state.busy} />
+                <ParamEditor info={info} events={this.events} params={this.state.params} isDisabled={this.state.busy} />
 
                 <div className='msp-transform-apply-wrap'>
                     <button className='msp-btn msp-btn-block msp-transform-refresh msp-form-control' title='Refresh params' onClick={this.refresh} disabled={this.state.busy || this.state.isInitial}>

+ 1 - 0
src/mol-plugin/ui/state/update-transform.tsx

@@ -28,6 +28,7 @@ namespace UpdateTransformContol {
 class UpdateTransformContol extends TransformContolBase<UpdateTransformContol.Props, UpdateTransformContol.ComponentState> {
     applyAction() { return this.plugin.updateTransform(this.props.state, this.props.transform.ref, this.state.params); }
     getInfo() { return this._getInfo(this.props.transform); }
+    getTransformerId() { return this.props.transform.transformer.id; }
     getHeader() { return this.props.transform.transformer.definition.display; }
     canApply() { return !this.state.error && !this.state.busy && !this.state.isInitial; }
     applyText() { return this.canApply() ? 'Update' : 'Nothing to Update'; }