Skip to content
Snippets Groups Projects
Select Git revision
  • 7fe8234cbd9bfb63c5a4c225eb97f6f56aff3246
  • master default protected
  • rednatco-v2
  • base-pairs-ladder
  • rednatco
  • test
  • ntc-tube-uniform-color
  • ntc-tube-missing-atoms
  • restore-vertex-array-per-program
  • watlas2
  • dnatco_new
  • cleanup-old-nodejs
  • webmmb
  • fix_auth_seq_id
  • update_deps
  • ext_dev
  • ntc_balls
  • nci-2
  • plugin
  • bugfix-0.4.5
  • nci
  • v0.5.0-dev.1
  • v0.4.5
  • v0.4.4
  • v0.4.3
  • v0.4.2
  • v0.4.1
  • v0.4.0
  • v0.3.12
  • v0.3.11
  • v0.3.10
  • v0.3.9
  • v0.3.8
  • v0.3.7
  • v0.3.6
  • v0.3.5
  • v0.3.4
  • v0.3.3
  • v0.3.2
  • v0.3.1
  • v0.3.0
41 results

state.ts

Blame
  • user avatar
    David Sehnal authored
    mol-state: allow Transformer.Params to accept undefined source StateObject to be able to auto-generate docs
    7fe8234c
    History
    state.ts 6.25 KiB
    /**
     * 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';
    import { PluginStateSnapshotManager } from 'mol-plugin/state/snapshots';
    import { PluginStateObject as SO, PluginStateObject } from '../../state/objects';
    import { EmptyLoci, EveryLoci } from 'mol-model/loci';
    import { Structure } from 'mol-model/structure';
    import { getFormattedTime } from 'mol-util/date';
    import { readFromFile } from 'mol-util/data-source';
    
    export function registerDefault(ctx: PluginContext) {
        SyncBehaviors(ctx);
        SetCurrentObject(ctx);
        Update(ctx);
        ApplyAction(ctx);
        RemoveObject(ctx);
        ToggleExpanded(ctx);
        ToggleVisibility(ctx);
        Highlight(ctx);
        ClearHighlight(ctx);
        Snapshots(ctx);
    }
    
    export function SyncBehaviors(ctx: PluginContext) {
        ctx.events.state.object.created.subscribe(o => {
            if (!SO.isBehavior(o.obj)) return;
            o.obj.data.register(o.ref);
        });
    
        ctx.events.state.object.removed.subscribe(o => {
            if (!SO.isBehavior(o.obj)) return;
            o.obj.data.unregister();
        });
    
        ctx.events.state.object.updated.subscribe(o => {
            if (o.action === 'recreate') {
                if (o.oldObj && SO.isBehavior(o.oldObj)) o.oldObj.data.unregister();
                if (o.obj && SO.isBehavior(o.obj)) o.obj.data.register(o.ref);
            }
        });
    }
    
    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.cellStates.get(ref).isHidden));
    }
    
    function setVisibility(state: State, root: Transform.Ref, value: boolean) {
        StateTree.doPreOrder(state.tree, state.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 });
    }
    
    // TODO make isHighlighted and isSelect part of StateObjectCell.State and subscribe from there???
    // TODO select structures of subtree
    // TODO should also work for volumes and shapes
    export function Highlight(ctx: PluginContext) {
        PluginCommands.State.Highlight.subscribe(ctx, ({ state, ref }) => {
            const cell = state.select(ref)[0]
            const repr = cell && SO.isRepresentation3D(cell.obj) ? cell.obj.data : undefined
            if (cell && cell.obj && cell.obj.type === PluginStateObject.Molecule.Structure.type) {
                ctx.behaviors.canvas.highlightLoci.next({ loci: Structure.Loci(cell.obj.data) })
            } else if (repr) {
                ctx.behaviors.canvas.highlightLoci.next({ loci: EveryLoci, repr })
            }
        });
    }
    
    export function ClearHighlight(ctx: PluginContext) {
        PluginCommands.State.ClearHighlight.subscribe(ctx, ({ state, ref }) => {
            ctx.behaviors.canvas.highlightLoci.next({ loci: EmptyLoci })
        });
    }
    
    export function Snapshots(ctx: PluginContext) {
        PluginCommands.State.Snapshots.Clear.subscribe(ctx, () => {
            ctx.state.snapshots.clear();
        });
    
        PluginCommands.State.Snapshots.Remove.subscribe(ctx, ({ id }) => {
            ctx.state.snapshots.remove(id);
        });
    
        PluginCommands.State.Snapshots.Add.subscribe(ctx, ({ name, description }) => {
            const entry = PluginStateSnapshotManager.Entry(ctx.state.getSnapshot(), name, description);
            ctx.state.snapshots.add(entry);
        });
    
        PluginCommands.State.Snapshots.Apply.subscribe(ctx, ({ id }) => {
            const e = ctx.state.snapshots.getEntry(id);
            return ctx.state.setSnapshot(e.snapshot);
        });
    
        PluginCommands.State.Snapshots.Upload.subscribe(ctx, ({ name, description, serverUrl }) => {
            return fetch(`${serverUrl}/set?name=${encodeURIComponent(name || '')}&description=${encodeURIComponent(description || '')}`, {
                method: 'POST',
                mode: 'cors',
                referrer: 'no-referrer',
                headers: { 'Content-Type': 'application/json; charset=utf-8' },
                body: JSON.stringify(ctx.state.getSnapshot())
            }) as any as Promise<void>;
        });
    
        PluginCommands.State.Snapshots.Fetch.subscribe(ctx, async ({ url }) => {
            const req = await fetch(url, { referrer: 'no-referrer' });
            const json = await req.json();
            return ctx.state.setSnapshot(json.data);
        });
    
        PluginCommands.State.Snapshots.DownloadToFile.subscribe(ctx, ({ name }) => {
            const element = document.createElement('a');
            const json = JSON.stringify(ctx.state.getSnapshot(), null, 2);
            element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(json));
            element.setAttribute('download', `mol-star_state_${(name || getFormattedTime())}.json`);
            element.style.display = 'none';
            document.body.appendChild(element);
            element.click();
            document.body.removeChild(element);
        });
    
        PluginCommands.State.Snapshots.OpenFile.subscribe(ctx, async ({ file }) => {
            try {
                const data = await readFromFile(file, 'string').run();
                const json = JSON.parse(data as string);
                await ctx.state.setSnapshot(json);
            } catch (e) {
                ctx.log.error(`Reading JSON state: ${e}`);
            }
        });
    }