Browse Source

mol-plugin: wip

David Sehnal 6 years ago
parent
commit
2d10e5d648

+ 1 - 1
src/mol-plugin/behavior.ts

@@ -8,7 +8,7 @@ export * from './behavior/behavior'
 
 import * as StaticState from './behavior/static/state'
 import * as StaticRepresentation from './behavior/static/representation'
-import * as StaticCamera from './behavior/static/representation'
+import * as StaticCamera from './behavior/static/camera'
 
 import * as DynamicRepresentation from './behavior/dynamic/representation'
 

+ 17 - 0
src/mol-plugin/behavior/static/camera.ts

@@ -5,6 +5,23 @@
  */
 
 import { PluginContext } from 'mol-plugin/context';
+import { PluginCommands } from 'mol-plugin/command';
+import { PluginStateObject as SO } from '../../state/objects';
 
 export function registerDefault(ctx: PluginContext) {
+    Reset(ctx);
 }
+
+export function Reset(ctx: PluginContext) {
+    PluginCommands.Camera.Reset.subscribe(ctx, () => {
+        const sel = ctx.state.data.select(q => q.root.subtree().ofType(SO.Molecule.Structure));
+        if (!sel.length) return;
+
+        const center = (sel[0].obj! as SO.Molecule.Structure).data.boundary.sphere.center;
+        ctx.canvas3d.camera.setState({ target: center });
+        ctx.canvas3d.requestDraw(true);
+
+        // TODO
+        // ctx.canvas3d.resetCamera();
+    })
+}

+ 4 - 1
src/mol-plugin/command.ts

@@ -5,8 +5,11 @@
  */
 
 import * as State from './command/state';
+import * as Camera from './command/camera';
 
 export * from './command/command';
+
 export const PluginCommands = {
-    State
+    State,
+    Camera
 }

+ 9 - 0
src/mol-plugin/command/camera.ts

@@ -0,0 +1,9 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { PluginCommand } from './command';
+
+export const Reset = PluginCommand<{}>({ isImmediate: true });

+ 0 - 13
src/mol-plugin/context.ts

@@ -116,10 +116,6 @@ export class PluginContext {
         return PluginCommands.State.Update.dispatch(this, { state, tree });
     }
 
-    _test_createState(id: string) {
-        this.runTask(this.state.data.apply(CreateStructureFromPDBe, { id }));
-    }
-
     private initEvents() {
         merge(this.events.state.data.object.created, this.events.state.behavior.object.created).subscribe(o => {
             if (!SO.isBehavior(o.obj)) return;
@@ -140,15 +136,6 @@ export class PluginContext {
         });
     }
 
-    _test_centerView() {
-        const sel = this.state.data.select(q => q.root.subtree().ofType(SO.Molecule.Structure.type));
-        if (!sel.length) return;
-
-        const center = (sel[0].obj! as SO.Molecule.Structure).data.boundary.sphere.center;
-        this.canvas3d.camera.setState({ target: center });
-        this.canvas3d.requestDraw(true);
-    }
-
     constructor() {
         this.initEvents();
         this.initBuiltInBehavior();

+ 0 - 0
src/mol-plugin/state/camera.ts


+ 2 - 1
src/mol-plugin/ui/base.tsx

@@ -12,7 +12,7 @@ export const PluginReactContext = React.createContext(void 0 as any as PluginCon
 
 export abstract class PluginComponent<P = {}, S = {}, SS = {}> extends React.Component<P, S, SS> {
     static contextType = PluginReactContext;
-    readonly context: PluginContext;
+    readonly plugin: PluginContext;
 
     private subs: Subscription[] | undefined = void 0;
 
@@ -30,6 +30,7 @@ export abstract class PluginComponent<P = {}, S = {}, SS = {}> extends React.Com
 
     constructor(props: P, context?: any) {
         super(props, context);
+        this.plugin = context;
         if (this.init) this.init();
     }
 }

+ 13 - 15
src/mol-plugin/ui/controls.tsx

@@ -17,18 +17,16 @@ export class Controls extends PluginComponent<{ }, { }> {
 
     private _snap: any = void 0;
     private getSnapshot = () => {
-        this._snap = this.context.state.getSnapshot();
+        this._snap = this.plugin.state.getSnapshot();
         console.log(btoa(JSON.stringify(this._snap)));
     }
     private setSnapshot = () => {
         if (!this._snap) return;
-        this.context.state.setSnapshot(this._snap);
+        this.plugin.state.setSnapshot(this._snap);
     }
 
     render() {
         return <div>
-            <button onClick={() => this.context._test_centerView()}>Center View</button><br />
-            <hr />
             <button onClick={this.getSnapshot}>Get Snapshot</button>
             <button onClick={this.setSnapshot}>Set Snapshot</button>
         </div>;
@@ -40,16 +38,16 @@ export class _test_TrajectoryControls extends PluginComponent {
     render() {
         return <div>
             <b>Trajectory: </b>
-            <button onClick={() => PluginCommands.State.ApplyAction.dispatch(this.context, {
-                state: this.context.state.data,
+            <button onClick={() => PluginCommands.State.ApplyAction.dispatch(this.plugin, {
+                state: this.plugin.state.data,
                 action: UpdateTrajectory.create({ action: 'advance', by: -1 })
             })}>&lt;&lt;</button>
-            <button onClick={() => PluginCommands.State.ApplyAction.dispatch(this.context, {
-                state: this.context.state.data,
+            <button onClick={() => PluginCommands.State.ApplyAction.dispatch(this.plugin, {
+                state: this.plugin.state.data,
                 action: UpdateTrajectory.create({ action: 'reset' })
             })}>Reset</button>
-            <button onClick={() => PluginCommands.State.ApplyAction.dispatch(this.context, {
-                state: this.context.state.data,
+            <button onClick={() => PluginCommands.State.ApplyAction.dispatch(this.plugin, {
+                state: this.plugin.state.data,
                 action: UpdateTrajectory.create({ action: 'advance', by: +1 })
             })}>&gt;&gt;</button><br />
         </div>
@@ -67,7 +65,7 @@ export class _test_ApplyAction extends PluginComponent<{ nodeRef: Transform.Ref,
         if (!p || !p.default) return {};
         const obj = this.getObj();
         if (!obj.obj) return {};
-        return p.default(obj.obj, this.context);
+        return p.default(obj.obj, this.plugin);
     }
 
     private getParamDef() {
@@ -75,12 +73,12 @@ export class _test_ApplyAction extends PluginComponent<{ nodeRef: Transform.Ref,
         if (!p || !p.controls) return {};
         const obj = this.getObj();
         if (!obj.obj) return {};
-        return p.controls(obj.obj, this.context);
+        return p.controls(obj.obj, this.plugin);
     }
 
     private create() {
         console.log('Apply Action', this.state.params);
-        PluginCommands.State.ApplyAction.dispatch(this.context, {
+        PluginCommands.State.ApplyAction.dispatch(this.plugin, {
             state: this.props.state,
             action: this.props.action.create(this.state.params),
             ref: this.props.nodeRef
@@ -130,12 +128,12 @@ export class _test_UpdateTransform extends PluginComponent<{ state: State, nodeR
         const src = this.getCell(cell.sourceRef);
         if (!src || !src.obj) return void 0;
 
-        return def.params.controls(src.obj, this.context);
+        return def.params.controls(src.obj, this.plugin);
     }
 
     private update() {
         console.log(this.props.nodeRef, this.state.params);
-        this.context.updateTransform(this.props.state, this.props.nodeRef, this.state.params);
+        this.plugin.updateTransform(this.props.state, this.props.nodeRef, this.state.params);
     }
 
     // componentDidMount() {

+ 6 - 5
src/mol-plugin/ui/plugin.tsx

@@ -7,7 +7,7 @@
 import * as React from 'react';
 import { PluginContext } from '../context';
 import { StateTree } from './state-tree';
-import { Viewport } from './viewport';
+import { Viewport, ViewportControls } from './viewport';
 import { Controls, _test_UpdateTransform, _test_ApplyAction, _test_TrajectoryControls } from './controls';
 import { PluginComponent, PluginReactContext } from './base';
 import { merge } from 'rxjs';
@@ -27,6 +27,7 @@ export class Plugin extends React.Component<{ plugin: PluginContext }, {}> {
                     <div style={{ position: 'absolute', left: '10px', top: '10px', height: '100%', color: 'white' }}>
                         <_test_TrajectoryControls />
                     </div>
+                    <ViewportControls />
                 </div>
                 <div style={{ position: 'absolute', width: '300px', right: '0', height: '100%', padding: '10px' }}>
                     <_test_CurrentObject />
@@ -41,23 +42,23 @@ export class Plugin extends React.Component<{ plugin: PluginContext }, {}> {
 export class _test_CurrentObject extends PluginComponent {
     componentDidMount() {
         let current: State.ObjectEvent | undefined = void 0;
-        this.subscribe(merge(this.context.behaviors.state.data.currentObject, this.context.behaviors.state.behavior.currentObject), o => {
+        this.subscribe(merge(this.plugin.behaviors.state.data.currentObject, this.plugin.behaviors.state.behavior.currentObject), o => {
             current = o;
             this.forceUpdate()
         });
 
-        this.subscribe(this.context.events.state.data.object.updated, ({ ref, state }) => {
+        this.subscribe(this.plugin.events.state.data.object.updated, ({ ref, state }) => {
             if (!current || current.ref !== ref && current.state !== state) return;
             this.forceUpdate();
         });
     }
 
     render() {
-        const current = this.context.behaviors.state.data.currentObject.value;
+        const current = this.plugin.behaviors.state.data.currentObject.value;
 
         const ref = current.ref;
         // const n = this.props.plugin.state.data.tree.nodes.get(ref)!;
-        const obj = this.context.state.data.cells.get(ref)!;
+        const obj = this.plugin.state.data.cells.get(ref)!;
 
         const type = obj && obj.obj ? obj.obj.type : void 0;
 

+ 6 - 6
src/mol-plugin/ui/state-tree.tsx

@@ -28,7 +28,7 @@ export class StateTree extends PluginComponent<{ state: State }, { }> {
 
 export class StateTreeNode extends PluginComponent<{ nodeRef: string, state: State }, { }> {
     componentDidMount() {
-        this.subscribe(merge(this.context.events.state.data.object.cellState, this.context.events.state.behavior.object.cellState), o => {
+        this.subscribe(merge(this.plugin.events.state.data.object.cellState, this.plugin.events.state.behavior.object.cellState), o => {
             if (o.ref === this.props.nodeRef && o.state === this.props.state) this.forceUpdate();
         });
     }
@@ -39,7 +39,7 @@ export class StateTreeNode extends PluginComponent<{ nodeRef: string, state: Sta
 
         const remove = <>[<a href='#' onClick={e => {
             e.preventDefault();
-            PluginCommands.State.RemoveObject.dispatch(this.context, { state: this.props.state, ref: this.props.nodeRef });
+            PluginCommands.State.RemoveObject.dispatch(this.plugin, { state: this.props.state, ref: this.props.nodeRef });
         }}>X</a>]</>
 
         let label: any;
@@ -47,13 +47,13 @@ export class StateTreeNode extends PluginComponent<{ nodeRef: string, state: Sta
             const name = (n.transformer.definition.display && n.transformer.definition.display.name) || n.transformer.definition.name;
             label = <><b>{cell.status}</b> <a href='#' onClick={e => {
                 e.preventDefault();
-                PluginCommands.State.SetCurrentObject.dispatch(this.context, { state: this.props.state, ref: this.props.nodeRef });
+                PluginCommands.State.SetCurrentObject.dispatch(this.plugin, { state: this.props.state, ref: this.props.nodeRef });
             }}>{name}</a>: <i>{cell.errorText}</i></>;
         } else {
             const obj = cell.obj as PluginStateObject.Any;
             label = <><a href='#' onClick={e => {
                 e.preventDefault();
-                PluginCommands.State.SetCurrentObject.dispatch(this.context, { state: this.props.state, ref: this.props.nodeRef });
+                PluginCommands.State.SetCurrentObject.dispatch(this.plugin, { state: this.props.state, ref: this.props.nodeRef });
             }}>{obj.label}</a> {obj.description ? <small>{obj.description}</small> : void 0}</>;
         }
 
@@ -62,14 +62,14 @@ export class StateTreeNode extends PluginComponent<{ nodeRef: string, state: Sta
         const expander = <>
             [<a href='#' onClick={e => {
                 e.preventDefault();
-                PluginCommands.State.ToggleExpanded.dispatch(this.context, { state: this.props.state, ref: this.props.nodeRef });
+                PluginCommands.State.ToggleExpanded.dispatch(this.plugin, { state: this.props.state, ref: this.props.nodeRef });
             }}>{cellState.isCollapsed ? '+' : '-'}</a>]
         </>;
 
         const visibility = <>
             [<a href='#' onClick={e => {
                 e.preventDefault();
-                PluginCommands.State.ToggleVisibility.dispatch(this.context, { state: this.props.state, ref: this.props.nodeRef });
+                PluginCommands.State.ToggleVisibility.dispatch(this.plugin, { state: this.props.state, ref: this.props.nodeRef });
             }}>{cellState.isHidden ? 'H' : 'V'}</a>]
         </>;
 

+ 17 - 4
src/mol-plugin/ui/viewport.tsx

@@ -9,11 +9,24 @@ import * as React from 'react';
 import { ButtonsType } from 'mol-util/input/input-observer';
 import { Canvas3dIdentifyHelper } from 'mol-plugin/util/canvas3d-identify';
 import { PluginComponent } from './base';
+import { PluginCommands } from 'mol-plugin/command';
 
 interface ViewportState {
     noWebGl: boolean
 }
 
+export class ViewportControls extends PluginComponent {
+    resetCamera = () => {
+        PluginCommands.Camera.Reset.dispatch(this.plugin, {});
+    }
+
+    render() {
+        return <div style={{ position: 'absolute', right: '10px', top: '10px', height: '100%', color: 'white' }}>
+            <button onClick={this.resetCamera}>Reset Camera</button>
+        </div>
+    }
+}
+
 export class Viewport extends PluginComponent<{ }, ViewportState> {
     private container: HTMLDivElement | null = null;
     private canvas: HTMLCanvasElement | null = null;
@@ -23,19 +36,19 @@ export class Viewport extends PluginComponent<{ }, ViewportState> {
     };
 
     private handleResize = () => {
-         this.context.canvas3d.handleResize();
+         this.plugin.canvas3d.handleResize();
     }
 
     componentDidMount() {
-        if (!this.canvas || !this.container || !this.context.initViewer(this.canvas, this.container)) {
+        if (!this.canvas || !this.container || !this.plugin.initViewer(this.canvas, this.container)) {
             this.setState({ noWebGl: true });
         }
         this.handleResize();
 
-        const canvas3d = this.context.canvas3d;
+        const canvas3d = this.plugin.canvas3d;
         this.subscribe(canvas3d.input.resize, this.handleResize);
 
-        const idHelper = new Canvas3dIdentifyHelper(this.context, 15);
+        const idHelper = new Canvas3dIdentifyHelper(this.plugin, 15);
 
         this.subscribe(canvas3d.input.move, ({x, y, inside, buttons}) => {
             if (!inside || buttons) { return; }

+ 3 - 3
src/mol-state/state/selection.ts

@@ -51,8 +51,8 @@ namespace StateSelection {
         withStatus(s: StateObjectCell.Status): Builder;
         subtree(): Builder;
         children(): Builder;
-        ofType(t: StateObject.Type): Builder;
-        ancestorOfType(t: StateObject.Type): Builder;
+        ofType(t: StateObject.Ctor): Builder;
+        ancestorOfType(t: StateObject.Ctor): Builder;
 
         select(state: State): CellSeq
     }
@@ -184,7 +184,7 @@ namespace StateSelection {
     }
 
     registerModifier('ofType', ofType);
-    export function ofType(b: Selector, t: StateObject.Type) { return filter(b, n => n.obj ? n.obj.type === t : false); }
+    export function ofType(b: Selector, t: StateObject.Ctor) { return filter(b, n => n.obj ? n.obj.type === t.type : false); }
 
     registerModifier('ancestorOfType', ancestorOfType);
     export function ancestorOfType(b: Selector, types: StateObject.Ctor[]) { return unique(mapEntity(b, (n, s) => findAncestorOfType(s.tree, s.cells, n.transform.ref, types))); }