From 80cf7c1dd2363d0369ae4fd4b14b84be44a6127b Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Wed, 4 Mar 2020 15:01:46 +0100 Subject: [PATCH] wip state builders --- src/mol-plugin-state/actions/structure.ts | 45 ++++++-------- src/mol-plugin-state/builder/parser.ts | 1 + .../builder/structure-model.ts | 1 + .../structure-representation.ts} | 61 +++++++++++-------- .../builder/structure/component.ts | 1 + .../structure/preset.ts | 13 ++-- .../structure/provider.ts | 5 ++ .../builder/structure/representation.ts | 0 .../model.ts => helpers/root-structure.ts} | 2 +- src/mol-plugin-state/transforms/model.ts | 6 +- src/mol-plugin/context.ts | 8 +-- src/mol-state/object.ts | 24 ++++++++ src/mol-util/param-definition.ts | 2 +- 13 files changed, 101 insertions(+), 68 deletions(-) create mode 100644 src/mol-plugin-state/builder/parser.ts create mode 100644 src/mol-plugin-state/builder/structure-model.ts rename src/mol-plugin-state/{representation/structure.ts => builder/structure-representation.ts} (60%) create mode 100644 src/mol-plugin-state/builder/structure/component.ts rename src/mol-plugin-state/{representation => builder}/structure/preset.ts (94%) rename src/mol-plugin-state/{representation => builder}/structure/provider.ts (80%) create mode 100644 src/mol-plugin-state/builder/structure/representation.ts rename src/mol-plugin-state/{representation/model.ts => helpers/root-structure.ts} (99%) diff --git a/src/mol-plugin-state/actions/structure.ts b/src/mol-plugin-state/actions/structure.ts index 8406a9269..30268ed3d 100644 --- a/src/mol-plugin-state/actions/structure.ts +++ b/src/mol-plugin-state/actions/structure.ts @@ -17,7 +17,7 @@ import { FileInfo } from '../../mol-util/file-info'; import { Task } from '../../mol-task'; import { StructureElement } from '../../mol-model/structure'; import { createDefaultStructureComplex } from '../../mol-plugin/util/structure-complex-helper'; -import { ModelStructureRepresentation } from '../representation/model'; +import { RootStructureDefinition } from '../helpers/root-structure'; export const MmcifProvider: DataFormatProvider<any> = { label: 'mmCIF', @@ -121,7 +121,7 @@ type StructureFormat = 'pdb' | 'cif' | 'gro' | '3dg' // const DownloadModelRepresentationOptions = PD.Group({ - type: ModelStructureRepresentation.getParams(void 0, 'assembly').type, + type: RootStructureDefinition.getParams(void 0, 'assembly').type, noRepresentation: PD.Optional(PD.Boolean(false, { description: 'Omit creating default representation.' })) }, { isExpanded: false }); @@ -141,27 +141,27 @@ const DownloadStructure = StateAction.build({ id: PD.Text('1cbs', { label: 'PDB Id(s)', description: 'One or more comma separated PDB ids.' }), structure: DownloadModelRepresentationOptions, options: DownloadStructurePdbIdSourceOptions - }, { isFlat: true }), + }, { isFlat: true, label: 'PDBe Updated' }), 'rcsb': PD.Group({ id: PD.Text('1tqn', { label: 'PDB Id(s)', description: 'One or more comma separated PDB ids.' }), structure: DownloadModelRepresentationOptions, options: DownloadStructurePdbIdSourceOptions - }, { isFlat: true }), + }, { isFlat: true, label: 'RCSB' }), 'pdb-dev': PD.Group({ id: PD.Text('PDBDEV_00000001', { label: 'PDBDev Id(s)', description: 'One or more comma separated ids.' }), structure: DownloadModelRepresentationOptions, options: DownloadStructurePdbIdSourceOptions - }, { isFlat: true }), + }, { isFlat: true, label: 'PDBDEV' }), 'bcif-static': PD.Group({ id: PD.Text('1tqn', { label: 'PDB Id(s)', description: 'One or more comma separated PDB ids.' }), structure: DownloadModelRepresentationOptions, options: DownloadStructurePdbIdSourceOptions - }, { isFlat: true }), + }, { isFlat: true, label: 'BinaryCIF (static PDBe Updated)' }), 'swissmodel': PD.Group({ id: PD.Text('Q9Y2I8', { label: 'UniProtKB AC(s)', description: 'One or more comma separated ACs.' }), structure: DownloadModelRepresentationOptions, options: DownloadStructurePdbIdSourceOptions - }, { isFlat: true, description: 'Loads the best homology model or experimental structure' }), + }, { isFlat: true, label: 'SWISS-MODEL', description: 'Loads the best homology model or experimental structure' }), 'url': PD.Group({ url: PD.Text(''), format: PD.Select('cif', [['cif', 'CIF'], ['pdb', 'PDB']] as ['cif' | 'pdb', string][]), @@ -171,16 +171,7 @@ const DownloadStructure = StateAction.build({ supportProps: PD.Optional(PD.Boolean(false)), createRepresentation: PD.Optional(PD.Boolean(true)) }) - }, { isFlat: true }) - }, { - options: [ - ['pdbe-updated', 'PDBe Updated'], - ['rcsb', 'RCSB'], - ['pdb-dev', 'PDBDEV'], - ['bcif-static', 'BinaryCIF (static PDBe Updated)'], - ['swissmodel', 'SWISS-MODEL'], - ['url', 'URL'] - ] + }, { isFlat: true, label: 'URL' }) }) } })(({ params, state }, plugin: PluginContext) => Task.create('Download Structure', async ctx => { @@ -240,7 +231,7 @@ const DownloadStructure = StateAction.build({ const struct = createStructure(state.build().to(traj), supportProps, src.params.structure.type); await state.updateTree(struct, { revertIfAborted: true }).runInContext(ctx); if (createRepr) { - await plugin.structureRepresentation.manager.apply(struct.ref, plugin.structureRepresentation.manager.defaultProvider); + await plugin.builders.structureRepresentation.apply(struct.ref, 'auto'); } } else { for (const download of downloadParams) { @@ -250,7 +241,7 @@ const DownloadStructure = StateAction.build({ const struct = createStructure(traj, supportProps, src.params.structure.type); await state.updateTree(struct, { revertIfAborted: true }).runInContext(ctx); if (createRepr) { - await plugin.structureRepresentation.manager.apply(struct.ref, plugin.structureRepresentation.manager.defaultProvider); + await plugin.builders.structureRepresentation.apply(struct.ref, 'auto'); } } } @@ -306,7 +297,7 @@ export function createModelTree(b: StateBuilder.To<PluginStateObject.Data.Binary return parsed.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 }); } -function createStructure(b: StateBuilder.To<PluginStateObject.Molecule.Model>, supportProps: boolean, params?: ModelStructureRepresentation.Params) { +function createStructure(b: StateBuilder.To<PluginStateObject.Molecule.Model>, supportProps: boolean, params?: RootStructureDefinition.Params) { let root = b; if (supportProps) { root = root.apply(StateTransforms.Model.CustomModelProperties); @@ -314,7 +305,7 @@ function createStructure(b: StateBuilder.To<PluginStateObject.Molecule.Model>, s return root.apply(StateTransforms.Model.StructureFromModel, { type: params || { name: 'assembly', params: { } } }); } -function createStructureAndVisuals(ctx: PluginContext, b: StateBuilder.To<PluginStateObject.Molecule.Model>, supportProps: boolean, params?: ModelStructureRepresentation.Params) { +function createStructureAndVisuals(ctx: PluginContext, b: StateBuilder.To<PluginStateObject.Molecule.Model>, supportProps: boolean, params?: RootStructureDefinition.Params) { const structure = createStructure(b, supportProps, params); createDefaultStructureComplex(ctx, structure); return b; @@ -323,28 +314,28 @@ function createStructureAndVisuals(ctx: PluginContext, b: StateBuilder.To<Plugin export const Create3DRepresentationPreset = StateAction.build({ display: { name: '3D Representation Preset', description: 'Create one of preset 3D representations.' }, from: PluginStateObject.Molecule.Structure, - isApplicable(a, _, plugin: PluginContext) { return plugin.structureRepresentation.manager.hasProvider(a.data); }, + isApplicable(a, _, plugin: PluginContext) { return plugin.builders.structureRepresentation.hasProvider(a.data); }, params(a, plugin: PluginContext) { return { - type: plugin.structureRepresentation.manager.getOptions(a.data) + type: plugin.builders.structureRepresentation.getOptions(a.data) }; } })(({ ref, params }, plugin: PluginContext) => { - plugin.structureRepresentation.manager.apply(ref, params.type.name, params.type.params); + plugin.builders.structureRepresentation.apply(ref, params.type.name, params.type.params); }); export const Remove3DRepresentationPreset = StateAction.build({ display: { name: 'Remove 3D Representation Preset', description: 'Remove 3D representations.' }, from: PluginStateObject.Molecule.Structure, - isApplicable(_, t, plugin: PluginContext) { return plugin.structureRepresentation.manager.hasManagedRepresentation(t.ref); }, + isApplicable(_, t, plugin: PluginContext) { return plugin.builders.structureRepresentation.hasManagedRepresentation(t.ref); }, params(a, plugin: PluginContext) { return { - type: plugin.structureRepresentation.manager.getOptions(a.data).select + type: plugin.builders.structureRepresentation.getOptions(a.data).select }; } })(({ ref, params }, plugin: PluginContext) => { // TODO: this will be completely handled by the managed and is just for testing purposes - plugin.structureRepresentation.manager.remove(params.type, ref); + plugin.builders.structureRepresentation.remove(params.type, ref); }); export const UpdateTrajectory = StateAction.build({ diff --git a/src/mol-plugin-state/builder/parser.ts b/src/mol-plugin-state/builder/parser.ts new file mode 100644 index 000000000..6cdd27e0f --- /dev/null +++ b/src/mol-plugin-state/builder/parser.ts @@ -0,0 +1 @@ +// TODO: parsing \ No newline at end of file diff --git a/src/mol-plugin-state/builder/structure-model.ts b/src/mol-plugin-state/builder/structure-model.ts new file mode 100644 index 000000000..2e61db74a --- /dev/null +++ b/src/mol-plugin-state/builder/structure-model.ts @@ -0,0 +1 @@ +// TODO: create managed trajectory / model / structure \ No newline at end of file diff --git a/src/mol-plugin-state/representation/structure.ts b/src/mol-plugin-state/builder/structure-representation.ts similarity index 60% rename from src/mol-plugin-state/representation/structure.ts rename to src/mol-plugin-state/builder/structure-representation.ts index 0f3b755b2..d9ad2e3cc 100644 --- a/src/mol-plugin-state/representation/structure.ts +++ b/src/mol-plugin-state/builder/structure-representation.ts @@ -1,12 +1,12 @@ /** - * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> */ import { arrayFind } from '../../mol-data/util'; import { Structure } from '../../mol-model/structure'; -import { StateTransform, StateTree, StateSelection } from '../../mol-state'; +import { StateTransform, StateTree, StateSelection, StateObjectRef } from '../../mol-state'; import { Task } from '../../mol-task'; import { isProductionMode } from '../../mol-util/debug'; import { objectForEach } from '../../mol-util/object'; @@ -19,12 +19,20 @@ import { UniqueArray } from '../../mol-data/generic'; // TODO: support quality // TODO: support ignore hydrogens -export class StructureRepresentationManager { +export type StructureRepresentationProviderRef = keyof PresetStructureReprentations | StructureRepresentationProvider | string + +export class StructureRepresentationBuilder { private providers: StructureRepresentationProvider[] = []; private providerMap: Map<string, StructureRepresentationProvider> = new Map(); readonly defaultProvider = PresetStructureReprentations.auto; + private resolveProvider(ref: StructureRepresentationProviderRef) { + return typeof ref === 'string' + ? PresetStructureReprentations[ref as keyof PresetStructureReprentations] ?? arrayFind(this.providers, p => p.id === ref) + : ref; + } + hasProvider(s: Structure) { for (const p of this.providers) { if (!p.isApplicable || p.isApplicable(s, this.plugin)) return true; @@ -45,10 +53,12 @@ export class StructureRepresentationManager { return PD.MappedStatic(options[0][0], map, { options }); } - hasManagedRepresentation(ref: StateTransform.Ref) { - const tree = this.plugin.state.dataState.tree; + hasManagedRepresentation(ref: StateObjectRef) { // TODO: make this state selection function? - return StateTree.doPreOrder(tree, tree.transforms.get(ref), { found: false, map: this.providerMap }, (n, _, s) => { + const tree = this.plugin.state.dataState.tree; + const root = StateObjectRef.resolve(this.plugin.state.dataState, ref); + if (!root) return false; + return StateTree.doPreOrder(tree, root.transform, { found: false, map: this.providerMap }, (n, _, s) => { if (!n.tags) return; for (const t of n.tags) { if (s.map.has(t)) { @@ -59,10 +69,11 @@ export class StructureRepresentationManager { }).found; } - getManagedRepresentations(ref: StateTransform.Ref) { - // TODO: check if Structure etc. + getManagedRepresentations(ref: StateObjectRef) { const tree = this.plugin.state.dataState.tree; - return StateTree.doPreOrder(tree, tree.transforms.get(ref), { found: UniqueArray.create<string, StructureRepresentationProvider>(), map: this.providerMap }, (n, _, s) => { + const root = StateObjectRef.resolve(this.plugin.state.dataState, ref); + if (!root) return []; + return StateTree.doPreOrder(tree, root.transform, { found: UniqueArray.create<string, StructureRepresentationProvider>(), map: this.providerMap }, (n, _, s) => { if (!n.tags) return; for (const t of n.tags) { if (s.map.has(t)) UniqueArray.add(s.found, t, s.map.get(t)!); @@ -79,11 +90,12 @@ export class StructureRepresentationManager { this.providerMap.set(provider.id, provider); } - remove(providerOrId: StructureRepresentationProvider | string, structureRoot?: StateTransform.Ref) { - const root = structureRoot || StateTransform.RootRef; - const id = typeof providerOrId === 'string' ? providerOrId : providerOrId.id; - + remove(providerRef: StructureRepresentationProviderRef, structureRoot?: StateObjectRef) { + const id = this.resolveProvider(providerRef)?.id; + if (!id) return; + const state = this.plugin.state.dataState; + const root = StateObjectRef.resolveRef(state, structureRoot) || StateTransform.RootRef; const reprs = StateSelection.findWithAllTags(state.tree, root, new Set([id, RepresentationProviderTags.Representation])); const builder = state.build(); @@ -101,33 +113,30 @@ export class StructureRepresentationManager { if (builder.editInfo.count === 0) return; return this.plugin.runTask(state.updateTree(builder)); } - - apply<P = any, S = {}>(ref: StateTransform.Ref, providerOrId: StructureRepresentationProvider<P, S> | string, params?: P) { - const provider = typeof providerOrId === 'string' - ? arrayFind(this.providers, p => p.id === providerOrId) - : providerOrId; + + apply<K extends keyof PresetStructureReprentations>(parent: StateObjectRef, preset: K, params?: StructureRepresentationProvider.Params<PresetStructureReprentations[K]>): Promise<StructureRepresentationProvider.State<PresetStructureReprentations[K]>> | undefined + apply<P = any, S = {}>(parent: StateObjectRef, providers: StructureRepresentationProvider<P, S>, params?: P): Promise<S> | undefined + apply(parent: StateObjectRef, providerId: string, params?: any): Promise<any> | undefined + apply(parent: StateObjectRef, providerRef: string | StructureRepresentationProvider, params?: any): Promise<any> | undefined { + const provider = this.resolveProvider(providerRef); if (!provider) return; const state = this.plugin.state.dataState; - const cell = state.cells.get(ref); - if (!cell || !cell.obj || cell.status !== 'ok') { + const cell = StateObjectRef.resolveAndCheck(state, parent); + if (!cell) { if (!isProductionMode) console.warn(`Applying structure repr. provider to bad cell.`); return; } const prms = params || (provider.params - ? PD.getDefaultValues(provider.params(cell.obj.data, this.plugin)) + ? PD.getDefaultValues(provider.params(cell.obj!.data, this.plugin)) : {}) - const task = Task.create<S>(`${provider.display.name}`, ctx => provider.apply(ctx, state, cell, prms, this.plugin) as Promise<S>); + const task = Task.create(`${provider.display.name}`, ctx => provider.apply(ctx, state, cell, prms, this.plugin) as Promise<any>); return this.plugin.runTask(task); } - // init() { - // objectForEach(PresetStructureReprentations, r => this.register(r)); - // } - constructor(public plugin: PluginContext) { objectForEach(PresetStructureReprentations, r => this.register(r)); } diff --git a/src/mol-plugin-state/builder/structure/component.ts b/src/mol-plugin-state/builder/structure/component.ts new file mode 100644 index 000000000..4d536466a --- /dev/null +++ b/src/mol-plugin-state/builder/structure/component.ts @@ -0,0 +1 @@ +// TODO: built in structure components \ No newline at end of file diff --git a/src/mol-plugin-state/representation/structure/preset.ts b/src/mol-plugin-state/builder/structure/preset.ts similarity index 94% rename from src/mol-plugin-state/representation/structure/preset.ts rename to src/mol-plugin-state/builder/structure/preset.ts index 6e6cc4a3f..001688655 100644 --- a/src/mol-plugin-state/representation/structure/preset.ts +++ b/src/mol-plugin-state/builder/structure/preset.ts @@ -71,7 +71,7 @@ const defaultPreset = StructureRepresentationProvider({ .applyOrUpdateTagged(reprTags, StateTransforms.Representation.StructureRepresentation3D, StructureRepresentation3DHelpers.getDefaultParamsWithTheme(plugin, 'spacefill', 'polymer-id', structure, {})); - await state.updateTree(root, { revertIfAborted: true }).runInContext(ctx); + await state.updateTree(root, { revertOnError: true }).runInContext(ctx); return { ligand: { @@ -98,7 +98,7 @@ const proteinAndNucleic = StructureRepresentationProvider({ .applyOrUpdateTagged(reprTags, StateTransforms.Representation.StructureRepresentation3D, StructureRepresentation3DHelpers.getDefaultParams(plugin, 'gaussian-surface', structure)); - await state.updateTree(root, { revertIfAborted: true }).runInContext(ctx); + await state.updateTree(root, { revertOnError: true }).runInContext(ctx); return {}; } }); @@ -119,7 +119,7 @@ const capsid = StructureRepresentationProvider({ applySelection(root, 'polymer') .applyOrUpdateTagged(reprTags, StateTransforms.Representation.StructureRepresentation3D, params); - await state.updateTree(root, { revertIfAborted: true }).runInContext(ctx); + await state.updateTree(root, { revertOnError: true }).runInContext(ctx); return {}; } }); @@ -143,7 +143,7 @@ const coarseCapsid = StructureRepresentationProvider({ applySelection(root, 'trace') .applyOrUpdateTagged(reprTags, StateTransforms.Representation.StructureRepresentation3D, params); - await state.updateTree(root, { revertIfAborted: true }).runInContext(ctx); + await state.updateTree(root, { revertOnError: true }).runInContext(ctx); return {}; } }); @@ -164,7 +164,7 @@ const cartoon = StructureRepresentationProvider({ applySelection(root, 'polymer') .applyOrUpdateTagged(reprTags, StateTransforms.Representation.StructureRepresentation3D, params); - await state.updateTree(root, { revertIfAborted: true }).runInContext(ctx); + await state.updateTree(root, { revertOnError: true }).runInContext(ctx); return {}; } }); @@ -186,4 +186,5 @@ export const PresetStructureReprentations = { capsid, coarseCapsid, cartoon -}; \ No newline at end of file +}; +export type PresetStructureReprentations = typeof PresetStructureReprentations; \ No newline at end of file diff --git a/src/mol-plugin-state/representation/structure/provider.ts b/src/mol-plugin-state/builder/structure/provider.ts similarity index 80% rename from src/mol-plugin-state/representation/structure/provider.ts rename to src/mol-plugin-state/builder/structure/provider.ts index 68fadcff8..b05900e0b 100644 --- a/src/mol-plugin-state/representation/structure/provider.ts +++ b/src/mol-plugin-state/builder/structure/provider.ts @@ -21,6 +21,11 @@ export interface StructureRepresentationProvider<P = any, S = {}> { // remove?(state: State, ref: string, plugin: PluginContext): void } +export namespace StructureRepresentationProvider { + export type Params<P extends StructureRepresentationProvider> = P extends StructureRepresentationProvider<infer T> ? T : never; + export type State<P extends StructureRepresentationProvider> = P extends StructureRepresentationProvider<infer _, infer S> ? S : never; +} + export const enum RepresentationProviderTags { Representation = 'preset-structure-representation', Selection = 'preset-structure-selection' diff --git a/src/mol-plugin-state/builder/structure/representation.ts b/src/mol-plugin-state/builder/structure/representation.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/mol-plugin-state/representation/model.ts b/src/mol-plugin-state/helpers/root-structure.ts similarity index 99% rename from src/mol-plugin-state/representation/model.ts rename to src/mol-plugin-state/helpers/root-structure.ts index cbcda309a..73e8573f6 100644 --- a/src/mol-plugin-state/representation/model.ts +++ b/src/mol-plugin-state/helpers/root-structure.ts @@ -16,7 +16,7 @@ import { Assembly, Symmetry } from '../../mol-model/structure/model/properties/s import { PluginStateObject as SO } from '../objects'; import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry'; -export namespace ModelStructureRepresentation { +export namespace RootStructureDefinition { export function getParams(model?: Model, defaultValue?: 'deposited' | 'assembly' | 'symmetry' | 'symmetry-mates' | 'symmetry-assembly') { const symmetry = model && ModelSymmetry.Provider.get(model) diff --git a/src/mol-plugin-state/transforms/model.ts b/src/mol-plugin-state/transforms/model.ts index 2d30fde12..9eb4b2eb2 100644 --- a/src/mol-plugin-state/transforms/model.ts +++ b/src/mol-plugin-state/transforms/model.ts @@ -26,7 +26,7 @@ import { parse3DG } from '../../mol-io/reader/3dg/parser'; import { trajectoryFrom3DG } from '../../mol-model-formats/structure/3dg'; import { StructureSelectionQueries } from '../../mol-plugin/util/structure-selection-helper'; import { StructureQueryHelper } from '../../mol-plugin/util/structure-query'; -import { ModelStructureRepresentation } from '../representation/model'; +import { RootStructureDefinition } from '../helpers/root-structure'; import { parseDcd } from '../../mol-io/reader/dcd/parser'; import { coordinatesFromDcd } from '../../mol-model-formats/structure/dcd'; import { topologyFromPsf } from '../../mol-model-formats/structure/psf'; @@ -273,11 +273,11 @@ const StructureFromModel = PluginStateTransform.BuiltIn({ display: { name: 'Structure', description: 'Create a molecular structure (deposited, assembly, or symmetry) from the specified model.' }, from: SO.Molecule.Model, to: SO.Molecule.Structure, - params(a) { return ModelStructureRepresentation.getParams(a && a.data); } + params(a) { return RootStructureDefinition.getParams(a && a.data); } })({ apply({ a, params }, plugin: PluginContext) { return Task.create('Build Structure', async ctx => { - return ModelStructureRepresentation.create(plugin, ctx, a.data, params && params.type); + return RootStructureDefinition.create(plugin, ctx, a.data, params && params.type); }) }, update: ({ a, b, oldParams, newParams }) => { diff --git a/src/mol-plugin/context.ts b/src/mol-plugin/context.ts index c57da37a5..faf97bf3d 100644 --- a/src/mol-plugin/context.ts +++ b/src/mol-plugin/context.ts @@ -43,7 +43,7 @@ import { StructureOverpaintHelper } from './util/structure-overpaint-helper'; import { PluginToastManager } from './util/toast'; import { StructureMeasurementManager } from './util/structure-measurement'; import { ViewportScreenshotHelper } from './util/viewport-screenshot'; -import { StructureRepresentationManager } from '../mol-plugin-state/representation/structure'; +import { StructureRepresentationBuilder } from '../mol-plugin-state/builder/structure-representation'; import { CustomProperty } from '../mol-model-props/common/custom-property'; import { PluginConfigManager } from './config'; import { DataBuilder } from '../mol-plugin-state/builder/data'; @@ -113,7 +113,6 @@ export class PluginContext { readonly structureRepresentation = { registry: new StructureRepresentationRegistry(), themeCtx: { colorThemeRegistry: ColorTheme.createRegistry(), sizeThemeRegistry: SizeTheme.createRegistry() } as ThemeRegistryContext, - manager: void 0 as any as StructureRepresentationManager } as const readonly volumeRepresentation = { @@ -126,7 +125,8 @@ export class PluginContext { } as const readonly builders = { - data: new DataBuilder(this) + data: new DataBuilder(this), + structureRepresentation: void 0 as any as StructureRepresentationBuilder }; readonly customModelProperties = new CustomProperty.Registry<Model>(); @@ -282,7 +282,7 @@ export class PluginContext { this.interactivity = new Interactivity(this); this.lociLabels = new LociLabelManager(this); - (this.structureRepresentation.manager as StructureRepresentationManager)= new StructureRepresentationManager(this); + (this.builders.structureRepresentation as StructureRepresentationBuilder)= new StructureRepresentationBuilder(this); this.log.message(`Mol* Plugin ${PLUGIN_VERSION} [${PLUGIN_VERSION_DATE.toLocaleString()}]`); if (!isProductionMode) this.log.message(`Development mode enabled`); diff --git a/src/mol-state/object.ts b/src/mol-state/object.ts index 7eb322f52..9267cf6db 100644 --- a/src/mol-state/object.ts +++ b/src/mol-state/object.ts @@ -169,4 +169,28 @@ export class StateObjectSelector<S extends StateObject = StateObject, T extends export namespace StateObjectSelector { export type Obj<S extends StateObjectSelector> = S extends StateObjectSelector<infer A> ? A : never export type Transformer<S extends StateObjectSelector> = S extends StateObjectSelector<any, infer T> ? T : never +} + +export type StateObjectRef<S extends StateObject = StateObject> = StateObjectSelector<S> | StateObjectCell<S> | StateTransform.Ref + +export namespace StateObjectRef { + export function resolveRef<S extends StateObject>(state: State, ref?: StateObjectRef<S>): StateTransform.Ref | undefined { + if (!ref) return; + if (typeof ref === 'string') return ref; + if (StateObjectCell.is(ref)) return ref.transform.ref; + return ref.cell?.transform.ref; + } + + export function resolve<S extends StateObject>(state: State, ref?: StateObjectRef<S>): StateObjectCell<S> | undefined { + if (!ref) return; + if (StateObjectCell.is(ref)) return ref; + if (typeof ref === 'string') return state.cells.get(ref) as StateObjectCell<S> | undefined; + return ref.cell; + } + + export function resolveAndCheck<S extends StateObject>(state: State, ref?: StateObjectRef<S>): StateObjectCell<S> | undefined { + const cell = resolve(state, ref); + if (!cell || !cell.obj || cell.status !== 'ok') return; + return cell; + } } \ No newline at end of file diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index 468a178ff..1bdf40672 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -221,7 +221,7 @@ export namespace ParamDefinition { export function MappedStatic<C extends Params>(defaultKey: keyof C, map: C, info?: Info & { options?: [keyof C, string][] }): Mapped<NamedParamUnion<C>> { const options: [string, string][] = info && info.options ? info.options as [string, string][] - : Object.keys(map).map(k => [k, stringToWords(k)]) as [string, string][]; + : Object.keys(map).map(k => [k, map[k].label || stringToWords(k)]) as [string, string][]; const name = checkDefaultKey(defaultKey, options); return setInfo<Mapped<NamedParamUnion<C>>>({ type: 'mapped', -- GitLab