Browse Source

mol-state: cell visibility support

David Sehnal 6 years ago
parent
commit
ffbf1010c4

+ 9 - 4
src/mol-plugin/behavior.ts

@@ -6,13 +6,18 @@
 
 export * from './behavior/behavior'
 
-import * as State from './behavior/built-in/state'
-import * as Representation from './behavior/built-in/representation'
+import * as StaticState from './behavior/static/state'
+import * as StaticRepresentation from './behavior/static/representation'
+import * as StaticCamera from './behavior/static/representation'
+
+import * as DynamicRepresentation from './behavior/dynamic/representation'
 
 export const BuiltInPluginBehaviors = {
-    State,
+    State: StaticState,
+    Representation: StaticRepresentation,
+    Camera: StaticCamera
 }
 
 export const PluginBehaviors = {
-    Representation
+    Representation: DynamicRepresentation
 }

+ 0 - 0
src/mol-plugin/behavior/built-in/camera.ts


+ 0 - 87
src/mol-plugin/behavior/built-in/representation.ts

@@ -1,87 +0,0 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author David Sehnal <david.sehnal@gmail.com>
- */
-
-import { PluginBehavior } from '../behavior';
-import { PluginStateObject as SO } from '../../state/objects';
-import { EmptyLoci, Loci, areLociEqual } from 'mol-model/loci';
-import { MarkerAction } from 'mol-geo/geometry/marker-data';
-
-export const AddRepresentationToCanvas = PluginBehavior.create({
-    name: 'add-representation-to-canvas',
-    ctor: class extends PluginBehavior.Handler {
-        register(): void {
-            this.subscribeObservable(this.ctx.events.state.data.object.created, o => {
-                if (!SO.isRepresentation3D(o.obj)) return;
-                this.ctx.canvas3d.add(o.obj.data);
-                this.ctx.canvas3d.requestDraw(true);
-            });
-            this.subscribeObservable(this.ctx.events.state.data.object.updated, o => {
-                if (o.oldObj && SO.isRepresentation3D(o.oldObj)) {
-                    this.ctx.canvas3d.remove(o.oldObj.data);
-                    this.ctx.canvas3d.requestDraw(true);
-                    o.oldObj.data.destroy();
-                }
-
-                const oo = o.obj;
-                if (!SO.isRepresentation3D(oo)) return;
-                this.ctx.canvas3d.add(oo.data);
-                this.ctx.canvas3d.requestDraw(true);
-            });
-            this.subscribeObservable(this.ctx.events.state.data.object.removed, o => {
-                const oo = o.obj;
-                if (!SO.isRepresentation3D(oo)) return;
-                this.ctx.canvas3d.remove(oo.data);
-                this.ctx.canvas3d.requestDraw(true);
-                oo.data.destroy();
-            });
-            // this.subscribeObservable(this.ctx.events.state.data.object.replaced, o => {
-            //     if (o.oldObj && SO.isRepresentation3D(o.oldObj)) {
-            //         this.ctx.canvas3d.remove(o.oldObj.data);
-            //         this.ctx.canvas3d.requestDraw(true);
-            //         o.oldObj.data.destroy();
-            //     }
-            //     if (o.newObj && SO.isRepresentation3D(o.newObj)) {
-            //         this.ctx.canvas3d.add(o.newObj.data);
-            //         this.ctx.canvas3d.requestDraw(true);
-            //     }
-            // });
-        }
-    },
-    display: { name: 'Add Representation To Canvas', group: 'Data' }
-});
-
-export const HighlightLoci = PluginBehavior.create({
-    name: 'representation-highlight-loci',
-    ctor: class extends PluginBehavior.Handler {
-        register(): void {
-            let prevLoci: Loci = EmptyLoci, prevRepr: any = void 0;
-            this.subscribeObservable(this.ctx.behaviors.canvas.highlightLoci, current => {
-                if (!this.ctx.canvas3d) return;
-
-                if (current.repr !== prevRepr || !areLociEqual(current.loci, prevLoci)) {
-                    this.ctx.canvas3d.mark(prevLoci, MarkerAction.RemoveHighlight);
-                    this.ctx.canvas3d.mark(current.loci, MarkerAction.Highlight);
-                    prevLoci = current.loci;
-                    prevRepr = current.repr;
-                }
-            });
-        }
-    },
-    display: { name: 'Highlight Loci on Canvas', group: 'Data' }
-});
-
-export const SelectLoci = PluginBehavior.create({
-    name: 'representation-select-loci',
-    ctor: class extends PluginBehavior.Handler {
-        register(): void {
-            this.subscribeObservable(this.ctx.behaviors.canvas.selectLoci, ({ loci }) => {
-                if (!this.ctx.canvas3d) return;
-                this.ctx.canvas3d.mark(loci, MarkerAction.Toggle);
-            });
-        }
-    },
-    display: { name: 'Select Loci on Canvas', group: 'Data' }
-});

+ 0 - 66
src/mol-plugin/behavior/built-in/state.ts

@@ -1,66 +0,0 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author David Sehnal <david.sehnal@gmail.com>
- */
-
-import { PluginCommands } from '../../command';
-import { PluginContext } from '../../context';
-
-export function registerAll(ctx: PluginContext) {
-    SetCurrentObject(ctx);
-    Update(ctx);
-    ApplyAction(ctx);
-    RemoveObject(ctx);
-    ToggleExpanded(ctx);
-}
-
-export function SetCurrentObject(ctx: PluginContext) {
-    PluginCommands.State.SetCurrentObject.subscribe(ctx, ({ state, ref }) => state.setCurrent(ref));
-}
-
-export function Update(ctx: PluginContext) {
-    PluginCommands.State.Update.subscribe(ctx, ({ state, tree }) => ctx.runTask(state.update(tree)));
-}
-
-export function ApplyAction(ctx: PluginContext) {
-    PluginCommands.State.ApplyAction.subscribe(ctx, ({ state, action, ref }) => ctx.runTask(state.apply(action.action, action.params, ref)));
-}
-
-export function RemoveObject(ctx: PluginContext) {
-    PluginCommands.State.RemoveObject.subscribe(ctx, ({ state, ref }) => {
-        const tree = state.tree.build().delete(ref).getTree();
-        return ctx.runTask(state.update(tree));
-    });
-}
-
-export function ToggleExpanded(ctx: PluginContext) {
-    PluginCommands.State.ToggleExpanded.subscribe(ctx, ({ state, ref }) => state.updateCellState(ref, ({ isCollapsed }) => ({ isCollapsed: !isCollapsed })));
-}
-
-// export const SetCurrentObject = PluginBehavior.create({
-//     name: 'set-current-data-object-behavior',
-//     ctor: PluginBehavior.simpleCommandHandler(PluginCommands.State.SetCurrentObject, ({ state, ref }, ctx) => state.setCurrent(ref)),
-//     display: { name: 'Set Current Handler', group: 'Data' }
-// });
-
-// export const Update = PluginBehavior.create({
-//     name: 'update-data-behavior',
-//     ctor: PluginBehavior.simpleCommandHandler(PluginCommands.State.Update, ({ state, tree }, ctx) => ctx.runTask(state.update(tree))),
-//     display: { name: 'Update Data Handler', group: 'Data' }
-// });
-
-// export const ApplyAction = PluginBehavior.create({
-//     name: 'update-data-behavior',
-//     ctor: PluginBehavior.simpleCommandHandler(PluginCommands.State.Update, ({ state, tree }, ctx) => ctx.runTask(state.update(tree))),
-//     display: { name: 'Update Data Handler', group: 'Data' }
-// });
-
-// export const RemoveObject = PluginBehavior.create({
-//     name: 'remove-object-data-behavior',
-//     ctor: PluginBehavior.simpleCommandHandler(PluginCommands.State.RemoveObject, ({ state, ref }, ctx) => {
-//         const tree = state.tree.build().delete(ref).getTree();
-//         return ctx.runTask(state.update(tree));
-//     }),
-//     display: { name: 'Remove Object Handler', group: 'Data' }
-// });

+ 42 - 0
src/mol-plugin/behavior/dynamic/representation.ts

@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { PluginBehavior } from '../behavior';
+import { EmptyLoci, Loci, areLociEqual } from 'mol-model/loci';
+import { MarkerAction } from 'mol-geo/geometry/marker-data';
+
+export const HighlightLoci = PluginBehavior.create({
+    name: 'representation-highlight-loci',
+    ctor: class extends PluginBehavior.Handler {
+        register(): void {
+            let prevLoci: Loci = EmptyLoci, prevRepr: any = void 0;
+            this.subscribeObservable(this.ctx.behaviors.canvas.highlightLoci, current => {
+                if (!this.ctx.canvas3d) return;
+
+                if (current.repr !== prevRepr || !areLociEqual(current.loci, prevLoci)) {
+                    this.ctx.canvas3d.mark(prevLoci, MarkerAction.RemoveHighlight);
+                    this.ctx.canvas3d.mark(current.loci, MarkerAction.Highlight);
+                    prevLoci = current.loci;
+                    prevRepr = current.repr;
+                }
+            });
+        }
+    },
+    display: { name: 'Highlight Loci on Canvas', group: 'Data' }
+});
+
+export const SelectLoci = PluginBehavior.create({
+    name: 'representation-select-loci',
+    ctor: class extends PluginBehavior.Handler {
+        register(): void {
+            this.subscribeObservable(this.ctx.behaviors.canvas.selectLoci, ({ loci }) => {
+                if (!this.ctx.canvas3d) return;
+                this.ctx.canvas3d.mark(loci, MarkerAction.Toggle);
+            });
+        }
+    },
+    display: { name: 'Select Loci on Canvas', group: 'Data' }
+});

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

@@ -0,0 +1,10 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { PluginContext } from 'mol-plugin/context';
+
+export function registerDefault(ctx: PluginContext) {
+}

+ 51 - 0
src/mol-plugin/behavior/static/representation.ts

@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { PluginStateObject as SO } from '../../state/objects';
+import { PluginContext } from 'mol-plugin/context';
+
+export function registerDefault(ctx: PluginContext) {
+    SyncRepresentationToCanvas(ctx);
+}
+
+export function SyncRepresentationToCanvas(ctx: PluginContext) {
+    ctx.events.state.data.object.created.subscribe(e => {
+        if (!SO.isRepresentation3D(e.obj)) return;
+        ctx.canvas3d.add(e.obj.data);
+        ctx.canvas3d.requestDraw(true);
+
+        // TODO: update visiblity
+    });
+    ctx.events.state.data.object.updated.subscribe(e => {
+        if (e.oldObj && SO.isRepresentation3D(e.oldObj)) {
+            ctx.canvas3d.remove(e.oldObj.data);
+            ctx.canvas3d.requestDraw(true);
+            e.oldObj.data.destroy();
+        }
+
+        if (!SO.isRepresentation3D(e.obj)) return;
+
+        // TODO: update visiblity
+        ctx.canvas3d.add(e.obj.data);
+        ctx.canvas3d.requestDraw(true);
+    });
+    ctx.events.state.data.object.removed.subscribe(e => {
+        const oo = e.obj;
+        if (!SO.isRepresentation3D(oo)) return;
+        ctx.canvas3d.remove(oo.data);
+        ctx.canvas3d.requestDraw(true);
+        oo.data.destroy();
+    });
+}
+
+export function UpdateRepresentationVisibility(ctx: PluginContext) {
+    ctx.events.state.data.object.cellState.subscribe(e => {
+        const cell = e.state.cells.get(e.ref)!;
+        if (!SO.isRepresentation3D(cell.obj)) return;
+
+        // TODO: update visiblity
+    })
+}

+ 53 - 0
src/mol-plugin/behavior/static/state.ts

@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { PluginCommands } from '../../command';
+import { PluginContext } from '../../context';
+import { StateTree, Transform, State } from 'mol-state';
+
+export function registerDefault(ctx: PluginContext) {
+    SetCurrentObject(ctx);
+    Update(ctx);
+    ApplyAction(ctx);
+    RemoveObject(ctx);
+    ToggleExpanded(ctx);
+    ToggleVisibility(ctx);
+}
+
+export function SetCurrentObject(ctx: PluginContext) {
+    PluginCommands.State.SetCurrentObject.subscribe(ctx, ({ state, ref }) => state.setCurrent(ref));
+}
+
+export function Update(ctx: PluginContext) {
+    PluginCommands.State.Update.subscribe(ctx, ({ state, tree }) => ctx.runTask(state.update(tree)));
+}
+
+export function ApplyAction(ctx: PluginContext) {
+    PluginCommands.State.ApplyAction.subscribe(ctx, ({ state, action, ref }) => ctx.runTask(state.apply(action.action, action.params, ref)));
+}
+
+export function RemoveObject(ctx: PluginContext) {
+    PluginCommands.State.RemoveObject.subscribe(ctx, ({ state, ref }) => {
+        const tree = state.tree.build().delete(ref).getTree();
+        return ctx.runTask(state.update(tree));
+    });
+}
+
+export function ToggleExpanded(ctx: PluginContext) {
+    PluginCommands.State.ToggleExpanded.subscribe(ctx, ({ state, ref }) => state.updateCellState(ref, ({ isCollapsed }) => ({ isCollapsed: !isCollapsed })));
+}
+
+export function ToggleVisibility(ctx: PluginContext) {
+    PluginCommands.State.ToggleVisibility.subscribe(ctx, ({ state, ref }) => setVisibility(state, ref, !state.tree.cellStates.get(ref).isHidden));
+}
+
+function setVisibility(state: State, root: Transform.Ref, value: boolean) {
+    StateTree.doPreOrder(state.tree, state.tree.transforms.get(root), { state, value }, setVisibilityVisitor);
+}
+
+function setVisibilityVisitor(t: Transform, tree: StateTree, ctx: { state: State, value: boolean }) {
+    ctx.state.updateCellState(t.ref, { isHidden: ctx.value });
+}

+ 3 - 1
src/mol-plugin/command/state.ts

@@ -16,4 +16,6 @@ export const Update = PluginCommand<{ state: State, tree: State.Tree | State.Bui
 
 export const RemoveObject = PluginCommand<{ state: State, ref: Transform.Ref }>();
 
-export const ToggleExpanded = PluginCommand<{ state: State, ref: Transform.Ref }>({ isImmediate: true });
+export const ToggleExpanded = PluginCommand<{ state: State, ref: Transform.Ref }>({ isImmediate: true });
+
+export const ToggleVisibility = PluginCommand<{ state: State, ref: Transform.Ref }>({ isImmediate: true });

+ 3 - 2
src/mol-plugin/context.ts

@@ -82,12 +82,13 @@ export class PluginContext {
     }
 
     private initBuiltInBehavior() {
-        BuiltInPluginBehaviors.State.registerAll(this);
+        BuiltInPluginBehaviors.State.registerDefault(this);
+        BuiltInPluginBehaviors.Representation.registerDefault(this);
+        BuiltInPluginBehaviors.Camera.registerDefault(this);
     }
 
     async _test_initBehaviors() {
         const tree = this.state.behavior.tree.build()
-            .toRoot().apply(PluginBehaviors.Representation.AddRepresentationToCanvas, { ref: PluginBehaviors.Representation.AddRepresentationToCanvas.id })
             .toRoot().apply(PluginBehaviors.Representation.HighlightLoci, { ref: PluginBehaviors.Representation.HighlightLoci.id })
             .toRoot().apply(PluginBehaviors.Representation.SelectLoci, { ref: PluginBehaviors.Representation.SelectLoci.id })
             .getTree();

+ 8 - 1
src/mol-plugin/ui/state-tree.tsx

@@ -66,9 +66,16 @@ export class StateTreeNode extends PluginComponent<{ nodeRef: string, state: Sta
             }}>{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 });
+            }}>{cellState.isHidden ? 'H' : 'V'}</a>]
+        </>;
+
         const children = this.props.state.tree.children.get(this.props.nodeRef);
         return <div>
-            {remove}{children.size === 0 ? void 0 : expander} {label}
+            {remove}{visibility}{children.size === 0 ? void 0 : expander} {label}
             {cellState.isCollapsed || children.size === 0
                 ? void 0
                 : <div style={{ marginLeft: '7px', paddingLeft: '3px', borderLeft: '1px solid #999' }}>{children.map(c => <StateTreeNode state={this.props.state} nodeRef={c!} key={c} />)}</div>