diff --git a/package.json b/package.json index 8caa4927d2a5b7da67ed1f9289470f40acdbc255..88568d2470f3db4e04bbe4df623f8d09ddc4d397 100644 --- a/package.json +++ b/package.json @@ -17,12 +17,12 @@ "build-tsc": "tsc --incremental", "build-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html,ico}\" lib/", "build-webpack": "webpack --mode production", - "watch": "concurrently --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack\"", - "watch-viewer": "concurrently --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer\"", + "watch": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack\"", + "watch-viewer": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer\"", "watch-tsc": "tsc --watch --incremental", "watch-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html,ico}\" lib/ --watch", - "watch-webpack": "webpack -w --mode development --display minimal", - "watch-webpack-viewer": "webpack -w --mode development --display minimal --config ./webpack.config.viewer.js", + "watch-webpack": "webpack -w --mode development --display errors-only --info-verbosity verbose", + "watch-webpack-viewer": "webpack -w --mode development --display errors-only --info-verbosity verbose --config ./webpack.config.viewer.js", "serve": "http-server -p 1338", "model-server": "node lib/servers/model/server.js", "model-server-watch": "nodemon --watch lib lib/servers/model/server.js", diff --git a/src/apps/basic-wrapper/helpers.ts b/src/apps/basic-wrapper/helpers.ts index 7da9dbac5adfe07dbffa7d21139964acd3077ed3..447e863a4182081b7afbe39ffc644c7faa50a00e 100644 --- a/src/apps/basic-wrapper/helpers.ts +++ b/src/apps/basic-wrapper/helpers.ts @@ -8,11 +8,11 @@ import { Mat4, Vec3 } from '../../mol-math/linear-algebra'; import { PluginContext } from '../../mol-plugin/context'; import { PluginStateObject as PSO } from '../../mol-plugin-state/objects'; import { StateTransforms } from '../../mol-plugin-state/transforms'; -import { StructureRepresentation3DHelpers } from '../../mol-plugin-state/transforms/representation'; import { MolScriptBuilder as MS } from '../../mol-script/language/builder'; import { StateBuilder } from '../../mol-state'; import Expression from '../../mol-script/language/expression'; import { BuiltInColorThemeName } from '../../mol-theme/color'; +import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params'; type SupportedFormats = 'cif' | 'pdb' export namespace StateHelper { @@ -79,21 +79,18 @@ export namespace StateHelper { export function visual(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>) { visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }) .apply(StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'cartoon'), { tags: 'seq-visual' }); + createStructureRepresentationParams(ctx, void 0, { type: 'cartoon' }), { tags: 'seq-visual' }); visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' }) .apply(StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick'), { tags: 'het-visual' }); - // visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' }) - // .apply(StateTransforms.Representation.StructureRepresentation3D, - // StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', { alpha: 0.51 }), { tags: 'water-visual' }); + createStructureRepresentationParams(ctx, void 0, { type: 'ball-and-stick' }), { tags: 'het-visual' }); return visualRoot; } - export function ballsAndSticks(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>, expression: Expression, coloring?: BuiltInColorThemeName) { + export function ballsAndSticks(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>, expression: Expression, color?: BuiltInColorThemeName) { visualRoot .apply(StateTransforms.Model.StructureSelectionFromExpression, { expression }) .apply(StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', void 0, coloring), { tags: 'het-visual' }); + createStructureRepresentationParams(ctx, void 0, { type: 'ball-and-stick', color }), { tags: 'het-visual' }); return visualRoot; } diff --git a/src/apps/basic-wrapper/index.ts b/src/apps/basic-wrapper/index.ts index 04d5ebaff3a8cd1cdd3ce6442c318144fe3f33b5..9d87fa121b980b6c0659285b1a1ac8bd939f1623 100644 --- a/src/apps/basic-wrapper/index.ts +++ b/src/apps/basic-wrapper/index.ts @@ -9,7 +9,6 @@ import './index.html' import { PluginContext } from '../../mol-plugin/context'; import { PluginCommands } from '../../mol-plugin/commands'; import { StateTransforms } from '../../mol-plugin-state/transforms'; -import { StructureRepresentation3DHelpers } from '../../mol-plugin-state/transforms/representation'; import { Color } from '../../mol-util/color'; import { PluginStateObject as PSO, PluginStateObject } from '../../mol-plugin-state/objects'; import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in'; @@ -21,6 +20,7 @@ import { CustomToastMessage } from './controls'; import { EmptyLoci } from '../../mol-model/loci'; import { StructureSelection } from '../../mol-model/structure'; import { Script } from '../../mol-script/script'; +import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params'; require('mol-plugin-ui/skin/light.scss') type SupportedFormats = 'cif' | 'pdb' @@ -47,7 +47,7 @@ class BasicWrapper { } }); - this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(StripedResidues.propertyProvider.descriptor.name, StripedResidues.colorThemeProvider!); + this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(StripedResidues.colorThemeProvider!); this.plugin.managers.lociLabels.addProvider(StripedResidues.labelProvider!); this.plugin.customModelProperties.register(StripedResidues.propertyProvider, true); } @@ -76,16 +76,16 @@ class BasicWrapper { private visual(visualRoot: StateBuilder.To<PSO.Molecule.Structure>) { visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }, { ref: 'seq' }) .apply(StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'cartoon'), { ref: 'seq-visual' }); + createStructureRepresentationParams(this.plugin, void 0, { type: 'cartoon' }), { ref: 'seq-visual' }); visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' }) .apply(StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick'), { ref: 'het-visual' }); + createStructureRepresentationParams(this.plugin, void 0, { type: 'ball-and-stick' }), { ref: 'het-visual' }); visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' }) .apply(StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick', { alpha: 0.51 }), { ref: 'water-visual' }); + createStructureRepresentationParams(this.plugin, void 0, { type: 'ball-and-stick', typeParams: { alpha: 0.51 } }), { ref: 'water-visual' }); visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'spheres' }) .apply(StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'spacefill'), { ref: 'ihm-visual' }); + createStructureRepresentationParams(this.plugin, void 0, { type: 'spacefill' }), { ref: 'ihm-visual' }); return visualRoot; } diff --git a/src/apps/demos/lighting/index.ts b/src/apps/demos/lighting/index.ts index 51c74e24ad26dad487464730e1011b23c2898b30..7bf493ce279405f8356e8b2932a3b8cb48d2e04b 100644 --- a/src/apps/demos/lighting/index.ts +++ b/src/apps/demos/lighting/index.ts @@ -9,10 +9,10 @@ import './index.html' import { PluginContext } from '../../../mol-plugin/context'; import { PluginCommands } from '../../../mol-plugin/commands'; import { StateTransforms } from '../../../mol-plugin-state/transforms'; -import { StructureRepresentation3DHelpers } from '../../../mol-plugin-state/transforms/representation'; import { PluginStateObject as PSO } from '../../../mol-plugin-state/objects'; import { StateBuilder } from '../../../mol-state'; import { Canvas3DProps } from '../../../mol-canvas3d/canvas3d'; +import { createStructureRepresentationParams } from '../../../mol-plugin-state/helpers/structure-representation-params'; require('mol-plugin-ui/skin/light.scss') type SupportedFormats = 'cif' | 'pdb' @@ -134,10 +134,10 @@ class LightingDemo { private visual(visualRoot: StateBuilder.To<PSO.Molecule.Structure>) { visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }) .apply(StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'spacefill', {}, 'illustrative'), { ref: 'seq-visual' }); + createStructureRepresentationParams(this.plugin, void 0, { type: 'spacefill', color: 'illustrative' }), { ref: 'seq-visual' }); visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' }) .apply(StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick'), { ref: 'het-visual' }); + createStructureRepresentationParams(this.plugin, void 0, { type: 'ball-and-stick' }), { ref: 'het-visual' }); return visualRoot; } diff --git a/src/apps/viewer/extensions/cellpack/model.ts b/src/apps/viewer/extensions/cellpack/model.ts index bc3ead9ba8eca50f7680a3ccdd8d7b185b869b90..f215a0fded4ea140e1552dd221e2230b9d2503c7 100644 --- a/src/apps/viewer/extensions/cellpack/model.ts +++ b/src/apps/viewer/extensions/cellpack/model.ts @@ -16,7 +16,6 @@ import { trajectoryFromPDB } from '../../../../mol-model-formats/structure/pdb'; import { Mat4, Vec3, Quat } from '../../../../mol-math/linear-algebra'; import { SymmetryOperator } from '../../../../mol-math/geometry'; import { Task } from '../../../../mol-task'; -import { StructureRepresentation3DHelpers } from '../../../../mol-plugin-state/transforms/representation'; import { StateTransforms } from '../../../../mol-plugin-state/transforms'; import { distinctColors } from '../../../../mol-util/color/distinct'; import { ModelIndexColorThemeProvider } from '../../../../mol-theme/color/model-index'; @@ -30,6 +29,7 @@ import { CifCategory, CifField } from '../../../../mol-io/reader/cif'; import { mmCIF_Schema } from '../../../../mol-io/reader/cif/schema/mmcif'; import { Column } from '../../../../mol-data/db'; import { createModels } from '../../../../mol-model-formats/structure/basic/parser'; +import { createStructureRepresentationParams } from '../../../../mol-plugin-state/helpers/structure-representation-params'; function getCellPackModelUrl(fileName: string, baseUrl: string) { return `${baseUrl}/results/${fileName}` @@ -396,7 +396,7 @@ export const LoadCellPackModel = StateAction.build({ } cellpackTree .apply(StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.createParams(ctx, Structure.Empty, { + createStructureRepresentationParams(ctx, Structure.Empty, { ...getReprParams(ctx, params.preset), ...getColorParams(hue) }) @@ -412,7 +412,7 @@ export const LoadCellPackModel = StateAction.build({ .apply(StateTransforms.Model.StructureFromModel, undefined, { state: { isGhost: true } }) .apply(StateTransforms.Misc.CreateGroup, { label: 'HIV1_envelope_Membrane' }) .apply(StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.createParams(ctx, Structure.Empty, { + createStructureRepresentationParams(ctx, Structure.Empty, { ...getReprParams(ctx, params.preset), color: UniformColorThemeProvider }) diff --git a/src/apps/viewer/extensions/jolecule.ts b/src/apps/viewer/extensions/jolecule.ts index ae8a830ae34ca9a9f8c563440672b2311f1c1368..678a722fd7e4901046992bf3cfdbe49d4500d9fd 100644 --- a/src/apps/viewer/extensions/jolecule.ts +++ b/src/apps/viewer/extensions/jolecule.ts @@ -18,7 +18,7 @@ // import { UUID } from '../../../mol-util'; // import { ColorNames } from '../../../mol-util/color/names'; // import { Camera } from '../../../mol-canvas3d/camera'; -// import { StructureRepresentation3DHelpers } from '../../../mol-plugin/state/transforms/representation'; +// import { createStructureRepresentation3dParamss } from '../../../mol-plugin/state/transforms/representation'; // import { createDefaultStructureComplex } from '../../../mol-plugin/util/structure-complex-helper'; // export const CreateJoleculeState = StateAction.build({ @@ -108,13 +108,13 @@ // group // .apply(StateTransforms.Model.StructureSelectionFromExpression, { expression: MS.struct.modifier.wholeResidues([ expression ]), label: 'Residue' }) // .apply(StateTransforms.Representation.StructureRepresentation3D, -// StructureRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'ball-and-stick', { })); +// createStructureRepresentation3dParamss.getDefaultParamsStatic(plugin, 'ball-and-stick', { })); // } // if (params.e.selected && params.e.selected.length > 0) { // b.to(template.structure) // .apply(StateTransforms.Model.StructureSelectionFromExpression, { expression: createExpression(params.e.selected), label: `Selected` }) // .apply(StateTransforms.Representation.StructureRepresentation3D, -// StructureRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'ball-and-stick')); +// createStructureRepresentation3dParamss.getDefaultParamsStatic(plugin, 'ball-and-stick')); // } // // TODO // // for (const l of params.e.distances) { diff --git a/src/examples/proteopedia-wrapper/coloring.ts b/src/examples/proteopedia-wrapper/coloring.ts index 3b25496365d11cc143d1c182c1e8a273286a171b..2eb6d9e80cc9d175f53269e2133c2d343010afd6 100644 --- a/src/examples/proteopedia-wrapper/coloring.ts +++ b/src/examples/proteopedia-wrapper/coloring.ts @@ -94,7 +94,8 @@ export function createProteopediaCustomTheme(colors: number[]) { } } - const ProteopediaCustomColorThemeProvider: ColorTheme.Provider<ProteopediaCustomColorThemeParams> = { + return { + name: 'proteopedia-custom', label: 'Proteopedia Custom', category: 'Custom', factory: ProteopediaCustomColorTheme, @@ -102,6 +103,4 @@ export function createProteopediaCustomTheme(colors: number[]) { defaultValues: PD.getDefaultValues(ProteopediaCustomColorThemeParams), isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } - - return ProteopediaCustomColorThemeProvider; } \ No newline at end of file diff --git a/src/examples/proteopedia-wrapper/index.ts b/src/examples/proteopedia-wrapper/index.ts index 89856d0158b916243b401f0f4d6ccd4a3c6a01b2..54e6876b8956365a9fdf2ad1f19e7304c4f20204 100644 --- a/src/examples/proteopedia-wrapper/index.ts +++ b/src/examples/proteopedia-wrapper/index.ts @@ -10,7 +10,6 @@ import './index.html' import { PluginContext } from '../../mol-plugin/context'; import { PluginCommands } from '../../mol-plugin/commands'; import { StateTransforms } from '../../mol-plugin-state/transforms'; -import { StructureRepresentation3DHelpers } from '../../mol-plugin-state/transforms/representation'; import { Color } from '../../mol-util/color'; import { PluginStateObject as PSO, PluginStateObject } from '../../mol-plugin-state/objects'; import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in'; @@ -23,12 +22,10 @@ import { PluginState } from '../../mol-plugin/state'; import { Scheduler } from '../../mol-task'; import { createProteopediaCustomTheme } from './coloring'; import { MolScriptBuilder as MS } from '../../mol-script/language/builder'; -import { BuiltInStructureRepresentations } from '../../mol-repr/structure/registry'; -import { BuiltInColorThemes } from '../../mol-theme/color'; -import { BuiltInSizeThemes } from '../../mol-theme/size'; import { ColorNames } from '../../mol-util/color/names'; import { InitVolumeStreaming, CreateVolumeStreamingInfo } from '../../mol-plugin/behavior/dynamic/volume-streaming/transformers'; import { DefaultCanvas3DParams, Canvas3DProps } from '../../mol-canvas3d/canvas3d'; +import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params'; // import { Vec3 } from 'mol-math/linear-algebra'; // import { ParamDefinition } from 'mol-util/param-definition'; // import { Text } from 'mol-geo/geometry/text/text'; @@ -70,8 +67,8 @@ class MolStarProteopediaWrapper { const customColoring = createProteopediaCustomTheme((options && options.customColorList) || []); - this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add('proteopedia-custom', customColoring); - this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(EvolutionaryConservation.propertyProvider.descriptor.name, EvolutionaryConservation.colorThemeProvider!); + this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(customColoring); + this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(EvolutionaryConservation.colorThemeProvider!); this.plugin.managers.lociLabels.addProvider(EvolutionaryConservation.labelProvider!); this.plugin.customModelProperties.register(EvolutionaryConservation.propertyProvider, true); } @@ -127,9 +124,10 @@ class MolStarProteopediaWrapper { root.delete(StateElements.SequenceVisual); } else { root.applyOrUpdate(StateElements.SequenceVisual, StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin, - (style.sequence && style.sequence.kind) || 'cartoon', - (style.sequence && style.sequence.coloring) || 'unit-index', structure)); + createStructureRepresentationParams(this.plugin, structure, { + type: (style.sequence && style.sequence.kind) || 'cartoon', + color: (style.sequence && style.sequence.coloring) || 'unit-index' + })); } } @@ -142,9 +140,10 @@ class MolStarProteopediaWrapper { root.delete(StateElements.HetVisual); } else { root.applyOrUpdate(StateElements.HetVisual, StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin, - (style.hetGroups && style.hetGroups.kind) || 'ball-and-stick', - (style.hetGroups && style.hetGroups.coloring), structure)); + createStructureRepresentationParams(this.plugin, structure, { + type: (style.hetGroups && style.hetGroups.kind) || 'ball-and-stick', + color: style.hetGroups && style.hetGroups.coloring + })); } } } @@ -158,7 +157,7 @@ class MolStarProteopediaWrapper { root.delete(StateElements.Het3DSNFG); } else { root.applyOrUpdate(StateElements.Het3DSNFG, StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin, 'carbohydrate', void 0, structure)); + createStructureRepresentationParams(this.plugin, structure, { type: 'carbohydrate' })); } } } @@ -169,9 +168,11 @@ class MolStarProteopediaWrapper { root.delete(StateElements.WaterVisual); } else { root.applyOrUpdate(StateElements.WaterVisual, StateTransforms.Representation.StructureRepresentation3D, - StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin, - (style.water && style.water.kind) || 'ball-and-stick', - (style.water && style.water.coloring), structure, { alpha: 0.51 })); + createStructureRepresentationParams(this.plugin, structure, { + type: (style.water && style.water.kind) || 'ball-and-stick', + typeParams: { alpha: 0.51 }, + color: style.water && style.water.coloring + })); } } @@ -408,19 +409,17 @@ class MolStarProteopediaWrapper { private createSurVisualParams() { const asm = this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure; - return StructureRepresentation3DHelpers.createParams(this.plugin, asm.data, { - type: BuiltInStructureRepresentations['ball-and-stick'], - color: BuiltInColorThemes.uniform, colorParams: { value: ColorNames.gray }, - size: BuiltInSizeThemes.uniform, sizeParams: { value: 0.33 } + return createStructureRepresentationParams(this.plugin, asm.data, { + type: 'ball-and-stick', + color: 'uniform', colorParams: { value: ColorNames.gray }, + size: 'uniform', sizeParams: { value: 0.33 } }); } private createCoreVisualParams() { const asm = this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure; - return StructureRepresentation3DHelpers.createParams(this.plugin, asm.data, { - type: BuiltInStructureRepresentations['ball-and-stick'], - // color: [BuiltInColorThemes.uniform, () => ({ value: ColorNames.gray })], - // size: [BuiltInSizeThemes.uniform, () => ({ value: 0.33 } )] + return createStructureRepresentationParams(this.plugin, asm.data, { + type: 'ball-and-stick' }); } diff --git a/src/mol-model-props/common/custom-element-property.ts b/src/mol-model-props/common/custom-element-property.ts index 580ff14c2301a73f4654260a8cce790b1660c0e2..c174a0996430185bb6b79d77611fb60b52268667 100644 --- a/src/mol-model-props/common/custom-element-property.ts +++ b/src/mol-model-props/common/custom-element-property.ts @@ -98,6 +98,7 @@ namespace CustomElementProperty { } return { + name: modelProperty.descriptor.name, label: modelProperty.label, category: 'Custom', factory: Coloring, diff --git a/src/mol-model-props/computed/representations/interactions.ts b/src/mol-model-props/computed/representations/interactions.ts index b660c32650f0a9f0001f13a8f7e242efe9bf8908..876061217e676f5e9eda271a50fb05481477cc67 100644 --- a/src/mol-model-props/computed/representations/interactions.ts +++ b/src/mol-model-props/computed/representations/interactions.ts @@ -37,7 +37,8 @@ export function InteractionRepresentation(ctx: RepresentationContext, getParams: return Representation.createMulti('Interactions', ctx, getParams, StructureRepresentationStateBuilder, InteractionsVisuals as unknown as Representation.Def<Structure, InteractionsParams>) } -export const InteractionsRepresentationProvider: StructureRepresentationProvider<InteractionsParams> = { +export const InteractionsRepresentationProvider = StructureRepresentationProvider({ + name: 'interactions', label: 'Non-covalent Interactions', description: 'Displays non-covalent interactions as dashed cylinders.', factory: InteractionRepresentation, @@ -50,4 +51,4 @@ export const InteractionsRepresentationProvider: StructureRepresentationProvider attach: (ctx: CustomProperty.Context, structure: Structure) => InteractionsProvider.attach(ctx, structure, void 0, true), detach: (_, data) => InteractionsProvider.ref(data, false) } -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-model-props/computed/themes/accessible-surface-area.ts b/src/mol-model-props/computed/themes/accessible-surface-area.ts index 77a71797c1c4b1296b50d7950efe9d4b64f17393..d9023f779fdb9ab9fd8ced3750b4d81564ccee16 100644 --- a/src/mol-model-props/computed/themes/accessible-surface-area.ts +++ b/src/mol-model-props/computed/themes/accessible-surface-area.ts @@ -64,7 +64,8 @@ export function AccessibleSurfaceAreaColorTheme(ctx: ThemeDataContext, props: PD } } -export const AccessibleSurfaceAreaColorThemeProvider: ColorTheme.Provider<AccessibleSurfaceAreaColorThemeParams> = { +export const AccessibleSurfaceAreaColorThemeProvider: ColorTheme.Provider<AccessibleSurfaceAreaColorThemeParams, 'accessible-surface-area'> = { + name: 'accessible-surface-area', label: 'Accessible Surface Area', category: ColorTheme.Category.Residue, factory: AccessibleSurfaceAreaColorTheme, diff --git a/src/mol-model-props/computed/themes/interaction-type.ts b/src/mol-model-props/computed/themes/interaction-type.ts index 5ecf849e64ca364006f9c17266db03fcdc283703..90f272daad46a32d05cec343122ded64bb013161 100644 --- a/src/mol-model-props/computed/themes/interaction-type.ts +++ b/src/mol-model-props/computed/themes/interaction-type.ts @@ -106,7 +106,8 @@ export function InteractionTypeColorTheme(ctx: ThemeDataContext, props: PD.Value } } -export const InteractionTypeColorThemeProvider: ColorTheme.Provider<InteractionTypeColorThemeParams> = { +export const InteractionTypeColorThemeProvider: ColorTheme.Provider<InteractionTypeColorThemeParams, 'interaction-type'> = { + name: 'interaction-type', label: 'Interaction Type', category: ColorTheme.Category.Misc, factory: InteractionTypeColorTheme, diff --git a/src/mol-model-props/integrative/cross-link-restraint/color.ts b/src/mol-model-props/integrative/cross-link-restraint/color.ts index df0794ae9d0911acbc9e9210b7b1589b3f5f783f..b81d0a0c07d84790c400b71f19aee9215ea68f84 100644 --- a/src/mol-model-props/integrative/cross-link-restraint/color.ts +++ b/src/mol-model-props/integrative/cross-link-restraint/color.ts @@ -61,7 +61,8 @@ export function CrossLinkColorTheme(ctx: ThemeDataContext, props: PD.Values<Cros } } -export const CrossLinkColorThemeProvider: ColorTheme.Provider<CrossLinkColorThemeParams> = { +export const CrossLinkColorThemeProvider: ColorTheme.Provider<CrossLinkColorThemeParams, 'cross-link'> = { + name: 'cross-link', label: 'Cross Link', category: ColorTheme.Category.Misc, factory: CrossLinkColorTheme, diff --git a/src/mol-model-props/integrative/cross-link-restraint/representation.ts b/src/mol-model-props/integrative/cross-link-restraint/representation.ts index 465b1b2222f9d3727a1891ceca28aaf2272d7f15..d3117223c6fd71a3c54d084ff7768e9699124e6d 100644 --- a/src/mol-model-props/integrative/cross-link-restraint/representation.ts +++ b/src/mol-model-props/integrative/cross-link-restraint/representation.ts @@ -134,7 +134,8 @@ export function CrossLinkRestraintRepresentation(ctx: RepresentationContext, get return Representation.createMulti('CrossLinkRestraint', ctx, getParams, StructureRepresentationStateBuilder, CrossLinkRestraintVisuals as unknown as Representation.Def<Structure, CrossLinkRestraintParams>) } -export const CrossLinkRestraintRepresentationProvider: StructureRepresentationProvider<CrossLinkRestraintParams> = { +export const CrossLinkRestraintRepresentationProvider = StructureRepresentationProvider({ + name: CrossLinkRestraint.Tag.CrossLinkRestraint, label: 'Cross Link Restraint', description: 'Displays cross-link restraints.', factory: CrossLinkRestraintRepresentation, @@ -147,4 +148,4 @@ export const CrossLinkRestraintRepresentationProvider: StructureRepresentationPr attach: (ctx: CustomProperty.Context, structure: Structure) => CrossLinkRestraintProvider.attach(ctx, structure, void 0, true), detach: (_, data) => CrossLinkRestraintProvider.ref(data, false) } -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-model-props/pdbe/themes/structure-quality-report.ts b/src/mol-model-props/pdbe/themes/structure-quality-report.ts index 5d09d35abbe5e13050b798126ae3576e75fd2c54..a50de3460df42bbac7ab7d13f441b7d0a38abe40 100644 --- a/src/mol-model-props/pdbe/themes/structure-quality-report.ts +++ b/src/mol-model-props/pdbe/themes/structure-quality-report.ts @@ -77,7 +77,8 @@ export function StructureQualityReportColorTheme(ctx: ThemeDataContext, props: P } } -export const StructureQualityReportColorThemeProvider: ColorTheme.Provider<Params> = { +export const StructureQualityReportColorThemeProvider: ColorTheme.Provider<Params, 'pdbe-structure-quality-report'> = { + name: 'pdbe-structure-quality-report', label: 'Structure Quality Report', category: ColorTheme.Category.Validation, factory: StructureQualityReportColorTheme, diff --git a/src/mol-model-props/rcsb/representations/validation-report-clashes.ts b/src/mol-model-props/rcsb/representations/validation-report-clashes.ts index 9789877777bbf9cdf8f2e57f77f492b3f5a04388..8d43f0bf7f0639555f9fbc13a1780150d5dbc9b6 100644 --- a/src/mol-model-props/rcsb/representations/validation-report-clashes.ts +++ b/src/mol-model-props/rcsb/representations/validation-report-clashes.ts @@ -20,7 +20,7 @@ import { createLinkCylinderMesh, LinkCylinderParams, LinkCylinderStyle } from '. import { UnitsMeshParams, UnitsVisual, UnitsMeshVisual, StructureGroup } from '../../../mol-repr/structure/units-visual'; import { VisualUpdateState } from '../../../mol-repr/util'; import { LocationIterator } from '../../../mol-geo/util/location-iterator'; -import { ClashesProvider, IntraUnitClashes, InterUnitClashes } from '../validation-report'; +import { ClashesProvider, IntraUnitClashes, InterUnitClashes, ValidationReport } from '../validation-report'; import { CustomProperty } from '../../common/custom-property'; import { ComplexMeshParams, ComplexVisual, ComplexMeshVisual } from '../../../mol-repr/structure/complex-visual'; import { Color } from '../../../mol-util/color'; @@ -278,7 +278,8 @@ export function ClashesRepresentation(ctx: RepresentationContext, getParams: Rep return repr } -export const ClashesRepresentationProvider: StructureRepresentationProvider<ClashesParams> = { +export const ClashesRepresentationProvider = StructureRepresentationProvider({ + name: ValidationReport.Tag.Clashes, label: 'Validation Clashes', description: 'Displays clashes between atoms as disks. Data from wwPDB Validation Report, obtained via RCSB PDB.', factory: ClashesRepresentation, @@ -291,4 +292,4 @@ export const ClashesRepresentationProvider: StructureRepresentationProvider<Clas attach: (ctx: CustomProperty.Context, structure: Structure) => ClashesProvider.attach(ctx, structure, void 0, true), detach: (_, data) => ClashesProvider.ref(data, false) } -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts b/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts index 82bc4c97484c1ebf3b75d113bb0ba1b7ae5a03a6..830cbf51a709bea60256694d4a0af469fbb360fe 100644 --- a/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts +++ b/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts @@ -91,7 +91,8 @@ export function AssemblySymmetryClusterColorTheme(ctx: ThemeDataContext, props: } } -export const AssemblySymmetryClusterColorThemeProvider: ColorTheme.Provider<AssemblySymmetryClusterColorThemeParams> = { +export const AssemblySymmetryClusterColorThemeProvider: ColorTheme.Provider<AssemblySymmetryClusterColorThemeParams, AssemblySymmetry.Tag.Cluster> = { + name: AssemblySymmetry.Tag.Cluster, label: 'Assembly Symmetry Cluster', category: ColorTheme.Category.Symmetry, factory: AssemblySymmetryClusterColorTheme, diff --git a/src/mol-model-props/rcsb/themes/density-fit.ts b/src/mol-model-props/rcsb/themes/density-fit.ts index 13b682781be37ff398789ac2dbdfa290d69f697e..7a159a7dac918d2b5faca2a37ef9faabe845c82e 100644 --- a/src/mol-model-props/rcsb/themes/density-fit.ts +++ b/src/mol-model-props/rcsb/themes/density-fit.ts @@ -60,7 +60,8 @@ export function DensityFitColorTheme(ctx: ThemeDataContext, props: {}): ColorThe } } -export const DensityFitColorThemeProvider: ColorTheme.Provider<{}> = { +export const DensityFitColorThemeProvider: ColorTheme.Provider<{}, ValidationReport.Tag.DensityFit> = { + name: ValidationReport.Tag.DensityFit, label: 'Density Fit', category: ColorTheme.Category.Validation, factory: DensityFitColorTheme, diff --git a/src/mol-model-props/rcsb/themes/geometry-quality.ts b/src/mol-model-props/rcsb/themes/geometry-quality.ts index fc88baa9095edb71dd4a75f480d2e0a615a8d6c2..d6c1f9cf7860d6f6657068d777774805672ebc7b 100644 --- a/src/mol-model-props/rcsb/themes/geometry-quality.ts +++ b/src/mol-model-props/rcsb/themes/geometry-quality.ts @@ -100,7 +100,8 @@ export function GeometryQualityColorTheme(ctx: ThemeDataContext, props: PD.Value } } -export const GeometryQualityColorThemeProvider: ColorTheme.Provider<GeometricQualityColorThemeParams> = { +export const GeometryQualityColorThemeProvider: ColorTheme.Provider<GeometricQualityColorThemeParams, ValidationReport.Tag.GeometryQuality> = { + name: ValidationReport.Tag.GeometryQuality, label: 'Geometry Quality', category: ColorTheme.Category.Validation, factory: GeometryQualityColorTheme, diff --git a/src/mol-model-props/rcsb/themes/random-coil-index.ts b/src/mol-model-props/rcsb/themes/random-coil-index.ts index ca3943eab74c185cf8e37ab79bef352bb76857cc..c339e85cf2cf82f6cd56c407c0a991fca10c0436 100644 --- a/src/mol-model-props/rcsb/themes/random-coil-index.ts +++ b/src/mol-model-props/rcsb/themes/random-coil-index.ts @@ -51,7 +51,8 @@ export function RandomCoilIndexColorTheme(ctx: ThemeDataContext, props: {}): Col } } -export const RandomCoilIndexColorThemeProvider: ColorTheme.Provider<{}> = { +export const RandomCoilIndexColorThemeProvider: ColorTheme.Provider<{}, ValidationReport.Tag.RandomCoilIndex> = { + name: ValidationReport.Tag.RandomCoilIndex, label: 'Random Coil Index', category: ColorTheme.Category.Validation, factory: RandomCoilIndexColorTheme, diff --git a/src/mol-model/structure/structure/element/bundle.ts b/src/mol-model/structure/structure/element/bundle.ts index 4094ece7c7474da0717fbbbf11b84fdb9bb0457e..d8866b794e9a42182169b8bbbd6c183930cb395c 100644 --- a/src/mol-model/structure/structure/element/bundle.ts +++ b/src/mol-model/structure/structure/element/bundle.ts @@ -40,6 +40,10 @@ export namespace Bundle { return fromLoci(StructureSelection.toLociWithSourceUnits(StructureSelection.Singletons(parent, structure))) } + export function fromSelection(selection: StructureSelection) { + return fromLoci(StructureSelection.toLociWithSourceUnits(selection)); + } + export function fromLoci(loci: Loci): Bundle { const _elements: { unit: Unit diff --git a/src/mol-plugin-state/actions/structure.ts b/src/mol-plugin-state/actions/structure.ts index d6497365f5881ceb7227007cf7ad53b85db08cae..b806830fbe0a212c8189bba329949ca7ae64bafb 100644 --- a/src/mol-plugin-state/actions/structure.ts +++ b/src/mol-plugin-state/actions/structure.ts @@ -5,22 +5,19 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Loci } from '../../mol-model/loci'; -import { StructureElement } from '../../mol-model/structure'; import { PluginContext } from '../../mol-plugin/context'; import { StateAction, StateBuilder, StateSelection, StateTransformer } from '../../mol-state'; import { Task } from '../../mol-task'; -import { UUID } from '../../mol-util'; import { FileInfo } from '../../mol-util/file-info'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; +import { TrajectoryFormat } from '../builder/structure'; +import { BuildInTrajectoryFormat } from '../formats/trajectory'; import { RootStructureDefinition } from '../helpers/root-structure'; import { PluginStateObject } from '../objects'; import { StateTransforms } from '../transforms'; import { Download, ParsePsf } from '../transforms/data'; import { CoordinatesFromDcd, CustomModelProperties, CustomStructureProperties, TopologyFromPsf, TrajectoryFromModelAndCoordinates } from '../transforms/model'; import { DataFormatProvider, guessCifVariant } from './data-format'; -import { TrajectoryFormat } from '../builder/structure'; -import { BuildInTrajectoryFormat } from '../formats/trajectory'; export const MmcifProvider: DataFormatProvider<PluginStateObject.Data.String | PluginStateObject.Data.Binary> = { label: 'mmCIF', @@ -37,7 +34,7 @@ export const MmcifProvider: DataFormatProvider<PluginStateObject.Data.String | P return Task.create('mmCIF default builder', async taskCtx => { const { structure } = await ctx.builders.structure.parseStructure({ data, dataFormat: 'mmcif' }); if (options.visuals) { - await ctx.builders.structure.representation.structurePreset(structure, 'auto'); + await ctx.builders.structure.representation.applyPreset(structure, 'auto'); } }) } @@ -55,7 +52,7 @@ export const PdbProvider: DataFormatProvider<any> = { return Task.create('PDB default builder', async () => { const { structure } = await ctx.builders.structure.parseStructure({ data, dataFormat: 'pdb' }); if (options.visuals) { - await ctx.builders.structure.representation.structurePreset(structure, 'auto'); + await ctx.builders.structure.representation.applyPreset(structure, 'auto'); } }) } @@ -73,7 +70,7 @@ export const GroProvider: DataFormatProvider<any> = { return Task.create('GRO default builder', async () => { const { structure } = await ctx.builders.structure.parseStructure({ data, dataFormat: 'gro' }); if (options.visuals) { - await ctx.builders.structure.representation.structurePreset(structure, 'auto'); + await ctx.builders.structure.representation.applyPreset(structure, 'auto'); } }) } @@ -91,7 +88,7 @@ export const Provider3dg: DataFormatProvider<any> = { return Task.create('3DG default builder', async () => { const { structure } = await ctx.builders.structure.parseStructure({ data, dataFormat: '3dg' }); if (options.visuals) { - await ctx.builders.structure.representation.structurePreset(structure, 'auto'); + await ctx.builders.structure.representation.applyPreset(structure, 'auto'); } }) } @@ -249,7 +246,7 @@ const DownloadStructure = StateAction.build({ structureProperties: supportProps }); if (createRepr) { - await plugin.builders.structure.representation.structurePreset(structure, 'auto'); + await plugin.builders.structure.representation.applyPreset(structure, 'auto'); } } else { for (const download of downloadParams) { @@ -261,7 +258,7 @@ const DownloadStructure = StateAction.build({ structureProperties: supportProps }); if (createRepr) { - await plugin.builders.structure.representation.structurePreset(structure, 'auto'); + await plugin.builders.structure.representation.applyPreset(structure, 'auto'); } } } @@ -306,25 +303,11 @@ export const Create3DRepresentationPreset = StateAction.build({ isApplicable(a, _, plugin: PluginContext) { return plugin.builders.structure.representation.hasPreset(a.data); }, params(a, plugin: PluginContext) { return { - type: plugin.builders.structure.representation.getPresets(a.data) + type: plugin.builders.structure.representation.getPresetsWithOptions(a.data) }; } })(({ ref, params }, plugin: PluginContext) => { - plugin.builders.structure.representation.structurePreset(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.builders.structure.representation.hasPresetRepresentation(t.ref); }, - params(a, plugin: PluginContext) { - return { - type: plugin.builders.structure.representation.getPresets(a.data).select - }; - } -})(({ ref, params }, plugin: PluginContext) => { - // TODO: this will be completely handled by the managed and is just for testing purposes - plugin.builders.structure.representation.removePreset(params.type, ref); + return plugin.builders.structure.representation.applyPreset(ref, params.type.name, params.type.params); }); export const UpdateTrajectory = StateAction.build({ @@ -389,28 +372,6 @@ export const TransformStructureConformation = StateAction.build({ return state.updateTree(root); }); -export const StructureFromSelection = StateAction.build({ - display: { name: 'Structure from Current Selection', description: 'Create a new Structure from the current selection.' }, - from: PluginStateObject.Molecule.Structure, - params: { - label: PD.Text() - } - // isApplicable(a, t, ctx: PluginContext) { - // return t.transformer !== CustomModelProperties; - // } -})(async ({ a, ref, params, state }, plugin: PluginContext) => { - const sel = plugin.managers.structure.selection.getLoci(a.data); - if (Loci.isEmpty(sel)) return; - - const bundle = StructureElement.Bundle.fromLoci(sel); - - await plugin.builders.structure.tryCreateComponent(ref, { - type: { name: 'bundle', params: bundle }, - nullIfEmpty: true, - label: params.label - }, UUID.create22()); -}); - export const AddTrajectory = StateAction.build({ display: { name: 'Add Trajectory', description: 'Add trajectory from existing model/topology and coordinates.' }, from: PluginStateObject.Root, @@ -440,6 +401,6 @@ export const AddTrajectory = StateAction.build({ await state.updateTree(model).runInContext(taskCtx); const structure = await ctx.builders.structure.createStructure(model.selector); - await ctx.builders.structure.representation.structurePreset(structure, 'auto'); + await ctx.builders.structure.representation.applyPreset(structure, 'auto'); }).runInContext(taskCtx) })); \ No newline at end of file diff --git a/src/mol-plugin-state/builder/structure.ts b/src/mol-plugin-state/builder/structure.ts index 7fdb538172c0d67bbceed13e9bd3d2f4f19f20b2..98ab4c5515c65264daade24d6b6bd5fc7c024dcd 100644 --- a/src/mol-plugin-state/builder/structure.ts +++ b/src/mol-plugin-state/builder/structure.ts @@ -5,7 +5,7 @@ */ import { PluginContext } from '../../mol-plugin/context'; -import { StateObjectRef, StateObjectSelector, StateTransformer } from '../../mol-state'; +import { StateObjectRef, StateObjectSelector, StateTransformer, StateTransform } from '../../mol-state'; import { PluginStateObject as SO } from '../objects'; import { StateTransforms } from '../transforms'; import { RootStructureDefinition } from '../helpers/root-structure'; @@ -14,6 +14,7 @@ import { BuildInTrajectoryFormat, TrajectoryFormatProvider } from '../formats/tr import { StructureRepresentationBuilder } from './structure/representation'; import { StructureSelectionQuery } from '../helpers/structure-selection-query'; import { Task } from '../../mol-task'; +import { StructureElement } from '../../mol-model/structure'; export type TrajectoryFormat = 'pdb' | 'cif' | 'gro' | '3dg' @@ -95,10 +96,10 @@ export class StructureBuilder { } } - async createModel(trajectory: StateObjectRef<SO.Molecule.Trajectory>, params?: StateTransformer.Params<StateTransforms['Model']['ModelFromTrajectory']>) { + async createModel(trajectory: StateObjectRef<SO.Molecule.Trajectory>, params?: StateTransformer.Params<StateTransforms['Model']['ModelFromTrajectory']>, initialState?: Partial<StateTransform.State>) { const state = this.dataState; const model = state.build().to(trajectory) - .apply(StateTransforms.Model.ModelFromTrajectory, params || { modelIndex: 0 }, { tags: StructureBuilderTags.Model }); + .apply(StateTransforms.Model.ModelFromTrajectory, params || { modelIndex: 0 }, { tags: StructureBuilderTags.Model, state: initialState }); await this.plugin.runTask(this.dataState.updateTree(model, { revertOnError: true })); return model.selector; @@ -112,10 +113,10 @@ export class StructureBuilder { return props.selector; } - async createStructure(model: StateObjectRef<SO.Molecule.Model>, params?: RootStructureDefinition.Params) { + async createStructure(model: StateObjectRef<SO.Molecule.Model>, params?: RootStructureDefinition.Params, initialState?: Partial<StateTransform.State>) { const state = this.dataState; const structure = state.build().to(model) - .apply(StateTransforms.Model.StructureFromModel, { type: params || { name: 'assembly', params: { } } }, { tags: StructureBuilderTags.Structure }); + .apply(StateTransforms.Model.StructureFromModel, { type: params || { name: 'assembly', params: { } } }, { tags: StructureBuilderTags.Structure, state: initialState }); await this.plugin.runTask(this.dataState.updateTree(structure, { revertOnError: true })); return structure.selector; @@ -172,7 +173,9 @@ export class StructureBuilder { const transformParams: StructureComponentParams = query.referencesCurrent ? { - type: { name: 'bundle', params: await StructureSelectionQuery.getBundle(this.plugin, taskCtx, query, structureData) }, + type: { + name: 'bundle', + params: StructureElement.Bundle.fromSelection(await query.getSelection(this.plugin, taskCtx, structureData)) }, nullIfEmpty: true, label: label || query.label } : { diff --git a/src/mol-plugin-state/builder/structure/preset.ts b/src/mol-plugin-state/builder/structure/preset.ts index 0c6b3342d91740184d4af53fd8790267f7008242..24c268ee5f0bfc2830bba2ffb5e5f549fa1df599 100644 --- a/src/mol-plugin-state/builder/structure/preset.ts +++ b/src/mol-plugin-state/builder/structure/preset.ts @@ -75,15 +75,15 @@ const polymerAndLigand = StructureRepresentationProvider({ const { update, builder, typeParams, color } = reprBuilder(plugin, params); const representations = { - polymer: builder.builtInRepresentation(update, components.polymer, { type: 'cartoon', typeParams, color }), - ligand: builder.builtInRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams, color }), - nonStandard: builder.builtInRepresentation(update, components.nonStandard, { type: 'ball-and-stick', typeParams, color: color || 'polymer-id' }), + polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams, color }), + ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams, color }), + nonStandard: builder.buildRepresentation(update, components.nonStandard, { type: 'ball-and-stick', typeParams, color: color || 'polymer-id' }), branched: components.branched && { - ballAndStick: builder.builtInRepresentation(update, components.branched, { type: 'ball-and-stick', typeParams: { ...typeParams, alpha: 0.15 }, color }), - snfg3d: builder.builtInRepresentation(update, components.branched, { type: 'carbohydrate', typeParams, color }), + ballAndStick: builder.buildRepresentation(update, components.branched, { type: 'ball-and-stick', typeParams: { ...typeParams, alpha: 0.15 }, color }), + snfg3d: builder.buildRepresentation(update, components.branched, { type: 'carbohydrate', typeParams, color }), }, - water: builder.builtInRepresentation(update, components.water, { type: 'ball-and-stick', typeParams: { ...typeParams, alpha: 0.51 }, color }), - coarse: builder.builtInRepresentation(update, components.coarse, { type: 'spacefill', typeParams, color: color || 'polymer-id' }) + water: builder.buildRepresentation(update, components.water, { type: 'ball-and-stick', typeParams: { ...typeParams, alpha: 0.51 }, color }), + coarse: builder.buildRepresentation(update, components.coarse, { type: 'spacefill', typeParams, color: color || 'polymer-id' }) }; await state.updateTree(update, { revertOnError: false }).runInContext(ctx); @@ -103,8 +103,8 @@ const proteinAndNucleic = StructureRepresentationProvider({ const { update, builder, typeParams, color } = reprBuilder(plugin, params); const representations = { - protein: builder.builtInRepresentation(update, components.protein, { type: 'cartoon', typeParams, color }), - nucleic: builder.builtInRepresentation(update, components.nucleic, { type: 'gaussian-surface', typeParams, color }) + protein: builder.buildRepresentation(update, components.protein, { type: 'cartoon', typeParams, color }), + nucleic: builder.buildRepresentation(update, components.nucleic, { type: 'gaussian-surface', typeParams, color }) }; await state.updateTree(update, { revertOnError: true }).runInContext(ctx); @@ -142,7 +142,7 @@ const coarseSurface = StructureRepresentationProvider({ const { update, builder, typeParams, color } = reprBuilder(plugin, params); const representations = { - trace: builder.builtInRepresentation(update, components.trace, { type: 'gaussian-surface', typeParams: { ...typeParams, ...gaussianProps }, color }) + trace: builder.buildRepresentation(update, components.trace, { type: 'gaussian-surface', typeParams: { ...typeParams, ...gaussianProps }, color }) }; await state.updateTree(update, { revertOnError: true }).runInContext(ctx); @@ -161,7 +161,7 @@ const polymerCartoon = StructureRepresentationProvider({ const { update, builder, typeParams, color } = reprBuilder(plugin, params); const representations = { - polymer: builder.builtInRepresentation(update, components.polymer, { type: 'cartoon', typeParams, color }) + polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams, color }) }; await state.updateTree(update, { revertOnError: true }).runInContext(ctx); @@ -181,7 +181,7 @@ const atomicDetail = StructureRepresentationProvider({ const { update, builder, typeParams, color } = reprBuilder(plugin, params); const representations = { - all: builder.builtInRepresentation(update, components.all, { type: 'ball-and-stick', typeParams, color }) + all: builder.buildRepresentation(update, components.all, { type: 'ball-and-stick', typeParams, color }) }; await state.updateTree(update, { revertOnError: true }).runInContext(ctx); diff --git a/src/mol-plugin-state/builder/structure/representation.ts b/src/mol-plugin-state/builder/structure/representation.ts index 9d849849759a39b304b92e3653ac88c3ea138830..10fbf0113a16c4feb3005925ac6d322778be79ea 100644 --- a/src/mol-plugin-state/builder/structure/representation.ts +++ b/src/mol-plugin-state/builder/structure/representation.ts @@ -6,26 +6,22 @@ import { arrayFind } from '../../../mol-data/util'; import { Structure } from '../../../mol-model/structure'; -import { StateTransform, StateTree, StateSelection, StateObjectRef, StateBuilder } from '../../../mol-state'; +import { PluginContext } from '../../../mol-plugin/context'; +import { StateBuilder, StateObjectRef, StateObjectSelector } from '../../../mol-state'; import { Task } from '../../../mol-task'; import { isProductionMode } from '../../../mol-util/debug'; import { objectForEach } from '../../../mol-util/object'; import { ParamDefinition as PD } from '../../../mol-util/param-definition'; -import { PluginContext } from '../../../mol-plugin/context'; -import { PresetStructureReprentations } from './preset'; -import { StructureRepresentationProvider, RepresentationProviderTags } from './provider'; -import { UniqueArray } from '../../../mol-data/generic'; +import { createStructureRepresentationParams, StructureRepresentationBuiltInProps, StructureRepresentationProps } from '../../helpers/structure-representation-params'; import { PluginStateObject } from '../../objects'; -import { StructureRepresentation3D, StructureRepresentation3DHelpers } from '../../transforms/representation'; -import { RepresentationProvider } from '../../../mol-repr/representation'; -import { SizeTheme, BuiltInSizeThemeName } from '../../../mol-theme/size'; -import { ColorTheme, BuiltInColorThemeName } from '../../../mol-theme/color'; -import { BuiltInStructureRepresentationsName } from '../../../mol-repr/structure/registry'; +import { StructureRepresentation3D } from '../../transforms/representation'; +import { PresetStructureReprentations } from './preset'; +import { RepresentationProviderTags, StructureRepresentationProvider } from './provider'; export type StructureRepresentationProviderRef = keyof PresetStructureReprentations | StructureRepresentationProvider | string export class StructureRepresentationBuilder { - private providers: StructureRepresentationProvider[] = []; + private _providers: StructureRepresentationProvider[] = []; private providerMap: Map<string, StructureRepresentationProvider> = new Map(); private get dataState() { return this.plugin.state.dataState; } @@ -33,23 +29,33 @@ export class StructureRepresentationBuilder { private resolveProvider(ref: StructureRepresentationProviderRef) { return typeof ref === 'string' - ? PresetStructureReprentations[ref as keyof PresetStructureReprentations] ?? arrayFind(this.providers, p => p.id === ref) + ? PresetStructureReprentations[ref as keyof PresetStructureReprentations] ?? arrayFind(this._providers, p => p.id === ref) : ref; } hasPreset(s: Structure) { - for (const p of this.providers) { + for (const p of this._providers) { if (!p.isApplicable || p.isApplicable(s, this.plugin)) return true; } return false; } - get providerList(): ReadonlyArray<StructureRepresentationProvider> { return this.providers; } + get providers(): ReadonlyArray<StructureRepresentationProvider> { return this._providers; } + + getPresets(s?: Structure) { + if (!s) return this.providers; + const ret = []; + for (const p of this._providers) { + if (p.isApplicable && !p.isApplicable(s, this.plugin)) continue; + ret.push(p); + } + return ret; + } - getPresets(s: Structure) { + getPresetsWithOptions(s: Structure) { const options: [string, string][] = []; const map: { [K in string]: PD.Any } = Object.create(null); - for (const p of this.providers) { + for (const p of this._providers) { if (p.isApplicable && !p.isApplicable(s, this.plugin)) continue; options.push([p.id, p.display.name]); @@ -59,71 +65,18 @@ export class StructureRepresentationBuilder { return PD.MappedStatic(options[0][0], map, { options }); } - hasPresetRepresentation(ref: StateObjectRef) { - // TODO: make this state selection function? - 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)) { - s.found = true; - return false; - } - } - }).found; - } - - getPresetRepresentations(ref: StateObjectRef) { - const tree = this.plugin.state.dataState.tree; - 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)!); - } - }).found.array; - } - registerPreset(provider: StructureRepresentationProvider) { if (this.providerMap.has(provider.id)) { throw new Error(`Repr. provider with id '${provider.id}' already registered.`); } - // TODO: sort by group - this.providers.push(provider); + this._providers.push(provider); this.providerMap.set(provider.id, provider); } - removePreset(providerRef: StructureRepresentationProviderRef, structureRoot?: StateObjectRef) { - const id = this.resolveProvider(providerRef)?.id; - if (!id) return; - - const state = this.plugin.state.dataState; - const root = StateObjectRef.resolveRef(structureRoot) || StateTransform.RootRef; - const reprs = StateSelection.findWithAllTags(state.tree, root, new Set([id, RepresentationProviderTags.Representation])); - - const builder = state.build(); - for (const r of reprs) { - builder.delete(r.ref); - } - - const tree = builder.currentTree; - const selections = StateSelection.findWithAllTags(tree, root, new Set([RepresentationProviderTags.Component])); - - for (const s of selections) { - if (!tree.children.has(s.ref) || tree.children.get(s.ref).size === 0) builder.delete(s.ref); - } - - if (builder.editInfo.count === 0) return; - return this.plugin.runTask(state.updateTree(builder)); - } - - structurePreset<K extends keyof PresetStructureReprentations>(parent: StateObjectRef, preset: K, params?: StructureRepresentationProvider.Params<PresetStructureReprentations[K]>): Promise<StructureRepresentationProvider.State<PresetStructureReprentations[K]>> | undefined - structurePreset<P = any, S = {}>(parent: StateObjectRef, providers: StructureRepresentationProvider<P, S>, params?: P): Promise<S> | undefined - structurePreset(parent: StateObjectRef, providerId: string, params?: any): Promise<any> | undefined - structurePreset(parent: StateObjectRef, providerRef: string | StructureRepresentationProvider, params?: any): Promise<any> | undefined { + applyPreset<K extends keyof PresetStructureReprentations>(parent: StateObjectRef, preset: K, params?: StructureRepresentationProvider.Params<PresetStructureReprentations[K]>): Promise<StructureRepresentationProvider.State<PresetStructureReprentations[K]>> | undefined + applyPreset<P = any, S = {}>(parent: StateObjectRef, providers: StructureRepresentationProvider<P, S>, params?: P): Promise<S> | undefined + applyPreset(parent: StateObjectRef, providerId: string, params?: any): Promise<any> | undefined + applyPreset(parent: StateObjectRef, providerRef: string | StructureRepresentationProvider, params?: any): Promise<any> | undefined { const provider = this.resolveProvider(providerRef); if (!provider) return; @@ -143,13 +96,13 @@ export class StructureRepresentationBuilder { return this.plugin.runTask(task); } - async addRepresentation<R extends RepresentationProvider<Structure, any, any>, C extends ColorTheme.Provider<any>, S extends SizeTheme.Provider<any>> - (structure: StateObjectRef<PluginStateObject.Molecule.Structure>, props?: StructureRepresentation3DHelpers.Props<R, C, S>) { - + async addRepresentation<P extends StructureRepresentationBuiltInProps>(structure: StateObjectRef<PluginStateObject.Molecule.Structure>, props?: P): Promise<StateObjectSelector<PluginStateObject.Molecule.Structure.Representation3D>> + async addRepresentation<P extends StructureRepresentationProps>(structure: StateObjectRef<PluginStateObject.Molecule.Structure>, props?: P): Promise<StateObjectSelector<PluginStateObject.Molecule.Structure.Representation3D>> + async addRepresentation(structure: StateObjectRef<PluginStateObject.Molecule.Structure>, props?: any) { const data = StateObjectRef.resolveAndCheck(this.dataState, structure)?.obj?.data; if (!data) return; - const params = StructureRepresentation3DHelpers.createParams(this.plugin, data, props); + const params = createStructureRepresentationParams(this.plugin, data, props); const repr = this.dataState.build() .to(structure) .apply(StructureRepresentation3D, params, { tags: RepresentationProviderTags.Representation }); @@ -158,14 +111,14 @@ export class StructureRepresentationBuilder { return repr.selector; } - builtInRepresentation<R extends BuiltInStructureRepresentationsName, C extends BuiltInColorThemeName, S extends BuiltInSizeThemeName> - (builder: StateBuilder.Root, structure: StateObjectRef<PluginStateObject.Molecule.Structure> | undefined, props?: StructureRepresentation3DHelpers.BuildInProps<R, C, S>) { - + async buildRepresentation<P extends StructureRepresentationBuiltInProps>(builder: StateBuilder.Root, structure: StateObjectRef<PluginStateObject.Molecule.Structure> | undefined, props?: P): Promise<StateObjectSelector<PluginStateObject.Molecule.Structure.Representation3D>> + async buildRepresentation<P extends StructureRepresentationProps>(builder: StateBuilder.Root, structure: StateObjectRef<PluginStateObject.Molecule.Structure> | undefined, props?: P): Promise<StateObjectSelector<PluginStateObject.Molecule.Structure.Representation3D>> + async buildRepresentation(builder: StateBuilder.Root, structure: StateObjectRef<PluginStateObject.Molecule.Structure> | undefined, props?: any) { if (!structure) return; const data = StateObjectRef.resolveAndCheck(this.dataState, structure)?.obj?.data; if (!data) return; - const params = StructureRepresentation3DHelpers.createBuiltInParams(this.plugin, data, props); + const params = createStructureRepresentationParams(this.plugin, data, props); return builder .to(structure) .apply(StructureRepresentation3D, params, { tags: RepresentationProviderTags.Representation }) diff --git a/src/mol-plugin-state/helpers/structure-representation-params.ts b/src/mol-plugin-state/helpers/structure-representation-params.ts new file mode 100644 index 0000000000000000000000000000000000000000..151842f9a863cccac80208657e74ede48c88e350 --- /dev/null +++ b/src/mol-plugin-state/helpers/structure-representation-params.ts @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { Structure } from '../../mol-model/structure'; +import { PluginContext } from '../../mol-plugin/context'; +import { RepresentationProvider } from '../../mol-repr/representation'; +import { BuiltInStructureRepresentations, BuiltInStructureRepresentationsName } from '../../mol-repr/structure/registry' +import { StateTransformer } from '../../mol-state'; +import { BuiltInColorThemeName, BuiltInColorThemes, ColorTheme } from '../../mol-theme/color'; +import { BuiltInSizeThemeName, BuiltInSizeThemes, SizeTheme } from '../../mol-theme/size'; +import { ParamDefinition as PD } from '../../mol-util/param-definition'; +import { StructureRepresentation3D } from '../transforms/representation'; + +export interface StructureRepresentationBuiltInProps< + R extends BuiltInStructureRepresentationsName = BuiltInStructureRepresentationsName, + C extends BuiltInColorThemeName = BuiltInColorThemeName, + S extends BuiltInSizeThemeName = BuiltInSizeThemeName> { + /** Using any registered name will work, but code completion will break */ + type?: R, + typeParams?: Partial<RepresentationProvider.ParamValues<BuiltInStructureRepresentations[R]>>, + /** Using any registered name will work, but code completion will break */ + color?: C, + colorParams?: Partial<ColorTheme.ParamValues<BuiltInColorThemes[C]>>, + /** Using any registered name will work, but code completion will break */ + size?: S, + sizeParams?: Partial<SizeTheme.ParamValues<BuiltInSizeThemes[S]>> +} + +export interface StructureRepresentationProps< + R extends RepresentationProvider<Structure> = RepresentationProvider<Structure>, + C extends ColorTheme.Provider = ColorTheme.Provider, + S extends SizeTheme.Provider = SizeTheme.Provider> { + type?: R, + typeParams?: Partial<RepresentationProvider.ParamValues<R>>, + color?: C, + colorParams?: Partial<ColorTheme.ParamValues<C>>, + size?: S, + sizeParams?: Partial<SizeTheme.ParamValues<S>> +} + +export function createStructureRepresentationParams + <R extends BuiltInStructureRepresentationsName, C extends BuiltInColorThemeName, S extends BuiltInSizeThemeName> + (ctx: PluginContext, structure?: Structure, props?: StructureRepresentationBuiltInProps<R, C, S>): StateTransformer.Params<StructureRepresentation3D> +export function createStructureRepresentationParams + <R extends RepresentationProvider<Structure>, C extends ColorTheme.Provider, S extends SizeTheme.Provider> + (ctx: PluginContext, structure?: Structure, props?: StructureRepresentationProps<R, C, S>): StateTransformer.Params<StructureRepresentation3D> +export function createStructureRepresentationParams(ctx: PluginContext, structure?: Structure, props: any = {}): StateTransformer.Params<StructureRepresentation3D> { + const p = props as StructureRepresentationBuiltInProps; + if (typeof p.type === 'string' || typeof p.color === 'string' || typeof p.size === 'string') return createParamsByName(ctx, structure || Structure.Empty, props); + return createParamsProvider(ctx, structure || Structure.Empty, props); +} + +function createParamsByName(ctx: PluginContext, structure: Structure, props: StructureRepresentationBuiltInProps): StateTransformer.Params<StructureRepresentation3D> { + const typeProvider = (props.type && ctx.structureRepresentation.registry.get(props.type)) + || ctx.structureRepresentation.registry.default.provider; + const colorProvider = (props.color && ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(props.color)) + || ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(typeProvider.defaultColorTheme.name); + const sizeProvider = (props.size && ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(props.size)) + || ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(typeProvider.defaultSizeTheme.name); + + return createParamsProvider(ctx, structure, { + type: typeProvider, + typeParams: props.typeParams, + color: colorProvider, + colorParams: props.colorParams, + size: sizeProvider, + sizeParams: props.sizeParams + }); +} + +function createParamsProvider(ctx: PluginContext, structure: Structure, props: StructureRepresentationProps = {}): StateTransformer.Params<StructureRepresentation3D> { + const { themeCtx } = ctx.structureRepresentation + const themeDataCtx = { structure }; + + const repr = props.type || ctx.structureRepresentation.registry.default.provider; + const reprDefaultParams = PD.getDefaultValues(repr.getParams(themeCtx, structure)); + const reprParams = Object.assign(reprDefaultParams, props.typeParams); + + const color = props.color || themeCtx.colorThemeRegistry.get(repr.defaultColorTheme.name); + const colorDefaultParams = PD.getDefaultValues(color.getParams(themeDataCtx)); + if (color.name === repr.defaultColorTheme.name) Object.assign(colorDefaultParams, repr.defaultColorTheme.props); + const colorParams = Object.assign(colorDefaultParams, props.colorParams); + + const size = props.size || themeCtx.sizeThemeRegistry.get(repr.defaultSizeTheme.name); + const sizeDefaultParams = PD.getDefaultValues(size.getParams(themeDataCtx)); + if (size.name === repr.defaultSizeTheme.name) Object.assign(sizeDefaultParams, repr.defaultSizeTheme.props); + const sizeParams = Object.assign(sizeDefaultParams, props.sizeParams); + + return ({ + type: { name: repr.name, params: reprParams }, + colorTheme: { name: color.name, params: colorParams }, + sizeTheme: { name: size.name, params: sizeParams } + }); +} \ No newline at end of file diff --git a/src/mol-plugin-state/helpers/structure-selection-query.ts b/src/mol-plugin-state/helpers/structure-selection-query.ts index 4b5031b67622732ef5a95bdaa4cfd099d8ec642b..acda9ef6a0b6fa063673b41222a95efacb462649 100644 --- a/src/mol-plugin-state/helpers/structure-selection-query.ts +++ b/src/mol-plugin-state/helpers/structure-selection-query.ts @@ -8,10 +8,9 @@ import { CustomProperty } from '../../mol-model-props/common/custom-property'; import { AccessibleSurfaceAreaProvider, AccessibleSurfaceAreaSymbols } from '../../mol-model-props/computed/accessible-surface-area'; import { ValidationReport, ValidationReportProvider } from '../../mol-model-props/rcsb/validation-report'; -import { QueryContext, Structure, StructureQuery, StructureSelection, StructureElement } from '../../mol-model/structure'; +import { QueryContext, Structure, StructureQuery, StructureSelection } from '../../mol-model/structure'; import { BondType, NucleicBackboneAtoms, ProteinBackboneAtoms, SecondaryStructureType } from '../../mol-model/structure/model/types'; -import { PluginStateObject } from '../objects'; -import { StateTransforms } from '../transforms'; +import { PluginContext } from '../../mol-plugin/context'; import { MolScriptBuilder as MS } from '../../mol-script/language/builder'; import Expression from '../../mol-script/language/expression'; import { compile } from '../../mol-script/runtime/query/compiler'; @@ -19,7 +18,8 @@ import { StateBuilder } from '../../mol-state'; import { RuntimeContext } from '../../mol-task'; import { SetUtils } from '../../mol-util/set'; import { stringToWords } from '../../mol-util/string'; -import { PluginContext } from '../../mol-plugin/context'; +import { PluginStateObject } from '../objects'; +import { StateTransforms } from '../transforms'; export enum StructureSelectionCategory { Type = 'Type', @@ -46,6 +46,7 @@ interface StructureSelectionQuery { readonly referencesCurrent: boolean readonly query: StructureQuery readonly ensureCustomProperties?: (ctx: CustomProperty.Context, structure: Structure) => Promise<void> + getSelection(plugin: PluginContext, runtime: RuntimeContext, structure: Structure): Promise<StructureSelection> } interface StructureSelectionQueryProps { @@ -69,7 +70,16 @@ function StructureSelectionQuery(label: string, expression: Expression, props: S if (!_query) _query = compile<StructureSelection>(expression) return _query }, - ensureCustomProperties: props.ensureCustomProperties + ensureCustomProperties: props.ensureCustomProperties, + async getSelection(plugin, runtime, structure) { + const current = plugin.managers.structure.selection.getStructure(structure) + const currentSelection = current ? StructureSelection.Singletons(structure, current) : StructureSelection.Empty(structure); + if (props.ensureCustomProperties) { + await props.ensureCustomProperties({ fetch: plugin.fetch, runtime }, structure) + } + if (!_query) _query = compile<StructureSelection>(expression) + return _query(new QueryContext(structure, { currentSelection })); + } } } @@ -510,33 +520,32 @@ export function applyBuiltInSelection(to: StateBuilder.To<PluginStateObject.Mole { tags: customTag ? [query, customTag] : [query] }); } -namespace StructureSelectionQuery { - export async function getStructure(plugin: PluginContext, runtime: RuntimeContext, selectionQuery: StructureSelectionQuery, structure: Structure) { - const current = plugin.managers.structure.selection.getStructure(structure) - const currentSelection = current ? StructureSelection.Singletons(structure, current) : StructureSelection.Empty(structure); +// namespace StructureSelectionQuery { +// // export async function getStructure(plugin: PluginContext, runtime: RuntimeContext, selectionQuery: StructureSelectionQuery, structure: Structure) { +// // const current = plugin.managers.structure.selection.getStructure(structure) +// // const currentSelection = current ? StructureSelection.Singletons(structure, current) : StructureSelection.Empty(structure); - if (selectionQuery.ensureCustomProperties) { - await selectionQuery.ensureCustomProperties({ fetch: plugin.fetch, runtime }, structure) - } +// // if (selectionQuery.ensureCustomProperties) { +// // await selectionQuery.ensureCustomProperties({ fetch: plugin.fetch, runtime }, structure) +// // } - const result = selectionQuery.query(new QueryContext(structure, { currentSelection })) - return StructureSelection.unionStructure(result) - } +// // const result = selectionQuery.query(new QueryContext(structure, { currentSelection })) +// // return StructureSelection.unionStructure(result) +// // } - export async function getLoci(plugin: PluginContext, runtime: RuntimeContext, selectionQuery: StructureSelectionQuery, structure: Structure) { - const current = plugin.managers.structure.selection.getStructure(structure) - const currentSelection = current ? StructureSelection.Singletons(structure, current) : StructureSelection.Empty(structure); +// // export async function getSelection(plugin: PluginContext, runtime: RuntimeContext, selectionQuery: StructureSelectionQuery, structure: Structure) { +// // const current = plugin.managers.structure.selection.getStructure(structure) +// // const currentSelection = current ? StructureSelection.Singletons(structure, current) : StructureSelection.Empty(structure); - if (selectionQuery.ensureCustomProperties) { - await selectionQuery.ensureCustomProperties({ fetch: plugin.fetch, runtime }, structure) - } +// // if (selectionQuery.ensureCustomProperties) { +// // await selectionQuery.ensureCustomProperties({ fetch: plugin.fetch, runtime }, structure) +// // } - const result = selectionQuery.query(new QueryContext(structure, { currentSelection })) - return StructureSelection.toLociWithSourceUnits(result) - } +// // return selectionQuery.query(new QueryContext(structure, { currentSelection })); +// // } - export async function getBundle(plugin: PluginContext, runtime: RuntimeContext, selectionQuery: StructureSelectionQuery, structure: Structure) { - const loci = await getLoci(plugin, runtime, selectionQuery, structure); - return StructureElement.Bundle.fromLoci(loci); - } -} \ No newline at end of file +// // export async function getBundle(plugin: PluginContext, runtime: RuntimeContext, selectionQuery: StructureSelectionQuery, structure: Structure) { +// // const loci = await getLoci(plugin, runtime, selectionQuery, structure); +// // return StructureElement.Bundle.fromLoci(loci); +// // } +// } \ No newline at end of file diff --git a/src/mol-plugin-state/manager/structure/component.ts b/src/mol-plugin-state/manager/structure/component.ts index d98b1e08e325cdec6f24647f21e250ea4b89a906..0fa3f6c0252802f9475ada6ea73f04f36682b75e 100644 --- a/src/mol-plugin-state/manager/structure/component.ts +++ b/src/mol-plugin-state/manager/structure/component.ts @@ -31,8 +31,6 @@ interface StructureComponentManagerState { options: StructureComponentManager.Options } -// TODO: add/update representation in all selected components - class StructureComponentManager extends PluginComponent<StructureComponentManagerState> { readonly events = { optionsUpdated: this.ev<undefined>() @@ -113,7 +111,7 @@ class StructureComponentManager extends PluginComponent<StructureComponentManage return this.plugin.dataTransaction(async () => { await this.clearComponents(structures); for (const s of structures) { - await this.plugin.builders.structure.representation.structurePreset(s.cell, provider, params); + await this.plugin.builders.structure.representation.applyPreset(s.cell, provider, params); } }); } diff --git a/src/mol-plugin-state/manager/structure/hierarchy-state.ts b/src/mol-plugin-state/manager/structure/hierarchy-state.ts index fecc886d8272ca6f6a77ef47db5f73d746e49077..d46fb29abdcce2d7e6d4781ba82ad7f6cc52afe0 100644 --- a/src/mol-plugin-state/manager/structure/hierarchy-state.ts +++ b/src/mol-plugin-state/manager/structure/hierarchy-state.ts @@ -20,11 +20,13 @@ export function buildStructureHierarchy(state: State, previous?: StructureHierar export interface StructureHierarchy { trajectories: TrajectoryRef[], + models: ModelRef[], + structures: StructureRef[], refs: Map<StateTransform.Ref, HierarchyRef> } export function StructureHierarchy(): StructureHierarchy { - return { trajectories: [], refs: new Map() } + return { trajectories: [], models: [], structures: [], refs: new Map() } } interface RefBase<K extends string = string, T extends StateObject = StateObject> { @@ -47,12 +49,13 @@ function TrajectoryRef(cell: StateObjectCell<SO.Molecule.Trajectory>): Trajector } export interface ModelRef extends RefBase<'model', SO.Molecule.Model> { - trajectory: TrajectoryRef, + trajectory?: TrajectoryRef, properties?: ModelPropertiesRef, - structures: StructureRef[] + structures: StructureRef[], + genericRepresentations?: GenericRepresentationRef[], } -function ModelRef(cell: StateObjectCell<SO.Molecule.Model>, trajectory: TrajectoryRef): ModelRef { +function ModelRef(cell: StateObjectCell<SO.Molecule.Model>, trajectory?: TrajectoryRef): ModelRef { return { kind: 'model', cell, version: cell.transform.version, trajectory, structures: [] }; } @@ -65,18 +68,18 @@ function ModelPropertiesRef(cell: StateObjectCell<SO.Molecule.Model>, model: Mod } export interface StructureRef extends RefBase<'structure', SO.Molecule.Structure> { - model: ModelRef, + model?: ModelRef, properties?: StructurePropertiesRef, components: StructureComponentRef[], - // representations: StructureRepresentationRef[], currentFocus?: { focus?: StructureComponentRef, surroundings?: StructureComponentRef, }, + genericRepresentations?: GenericRepresentationRef[], // volumeStreaming?: .... } -function StructureRef(cell: StateObjectCell<SO.Molecule.Structure>, model: ModelRef): StructureRef { +function StructureRef(cell: StateObjectCell<SO.Molecule.Structure>, model?: ModelRef): StructureRef { return { kind: 'structure', cell, version: cell.transform.version, model, components: [] }; } @@ -92,6 +95,7 @@ export interface StructureComponentRef extends RefBase<'structure-component', SO structure: StructureRef, key?: string, representations: StructureRepresentationRef[], + genericRepresentations?: GenericRepresentationRef[] } function componentKey(cell: StateObjectCell<SO.Molecule.Structure>) { @@ -111,6 +115,14 @@ function StructureRepresentationRef(cell: StateObjectCell<SO.Molecule.Structure. return { kind: 'structure-representation', cell, version: cell.transform.version, component }; } +export interface GenericRepresentationRef extends RefBase<'generic-representation', SO.Any> { + parent: HierarchyRef +} + +function GenericRepresentationRef(cell: StateObjectCell<SO.Molecule.Structure.Representation3D>, parent: HierarchyRef): GenericRepresentationRef { + return { kind: 'generic-representation', cell, version: cell.transform.version, parent }; +} + interface BuildState { state: State, oldHierarchy: StructureHierarchy, @@ -160,16 +172,24 @@ const tagMap: [string, (state: BuildState, cell: StateObjectCell) => boolean | v state.currentTrajectory = createOrUpdateRefList(state, cell, state.hierarchy.trajectories, TrajectoryRef, cell); }, state => state.currentTrajectory = void 0], [StructureBuilderTags.Model, (state, cell) => { - if (!state.currentTrajectory) return false; - state.currentModel = createOrUpdateRefList(state, cell, state.currentTrajectory.models, ModelRef, cell, state.currentTrajectory); + if (state.currentTrajectory) { + state.currentModel = createOrUpdateRefList(state, cell, state.currentTrajectory.models, ModelRef, cell, state.currentTrajectory); + } else { + state.currentModel = ModelRef(cell) + } + state.hierarchy.models.push(state.currentModel); }, state => state.currentModel = void 0], [StructureBuilderTags.ModelProperties, (state, cell) => { if (!state.currentModel) return false; state.currentModel.properties = createOrUpdateRef(state, cell, state.currentModel.properties, ModelPropertiesRef, cell, state.currentModel); }, state => { }], [StructureBuilderTags.Structure, (state, cell) => { - if (!state.currentModel) return false; - state.currentStructure = createOrUpdateRefList(state, cell, state.currentModel.structures, StructureRef, cell, state.currentModel); + if (state.currentModel) { + state.currentStructure = createOrUpdateRefList(state, cell, state.currentModel.structures, StructureRef, cell, state.currentModel); + } else { + state.currentStructure = StructureRef(cell); + } + state.hierarchy.structures.push(state.currentStructure); }, state => state.currentStructure = void 0], [StructureBuilderTags.StructureProperties, (state, cell) => { if (!state.currentStructure) return false; @@ -230,8 +250,14 @@ function _doPreOrder(ctx: VisitorCtx, root: StateTransform) { } } - if (!onLeave && state.currentComponent && SO.Molecule.Structure.Representation3D.is(cell.obj)) { + if (!onLeave && !cell.state.isGhost && state.currentComponent && SO.Molecule.Structure.Representation3D.is(cell.obj)) { createOrUpdateRefList(state, cell, state.currentComponent.representations, StructureRepresentationRef, cell, state.currentComponent); + } else if (!cell.state.isGhost && SO.isRepresentation3D(cell.obj)) { + const genericTarget = state.currentComponent || state.currentModel || state.currentStructure; + if (genericTarget) { + if (!genericTarget.genericRepresentations) genericTarget.genericRepresentations = []; + genericTarget.genericRepresentations.push(GenericRepresentationRef(cell, genericTarget)); + } } const children = ctx.tree.children.get(root.ref); diff --git a/src/mol-plugin-state/manager/structure/hierarchy.ts b/src/mol-plugin-state/manager/structure/hierarchy.ts index 58760b04b93734926aa471a5ff3839fb69969d90..2b460b5df20e79e837216751969c6daebd8326fc 100644 --- a/src/mol-plugin-state/manager/structure/hierarchy.ts +++ b/src/mol-plugin-state/manager/structure/hierarchy.ts @@ -7,7 +7,6 @@ import { PluginContext } from '../../../mol-plugin/context'; import { StructureHierarchy, buildStructureHierarchy, ModelRef, StructureComponentRef, StructureRef, HierarchyRef, TrajectoryRef } from './hierarchy-state'; import { PluginComponent } from '../../component'; -import { StateTransform } from '../../../mol-state'; import { SetUtils } from '../../../mol-util/set'; interface StructureHierarchyManagerState { @@ -51,45 +50,20 @@ export class StructureHierarchyManager extends PluginComponent<StructureHierarch return this._currentSelectionSet; } - private syncCurrentTrajectories(hierarchy: StructureHierarchy, map: Map<StateTransform.Ref, HierarchyRef>): TrajectoryRef[] { - const current = this.state.current.trajectories; - if (current.length === 0) return hierarchy.trajectories.length > 0 ? [hierarchy.trajectories[0]] : []; - - const newCurrent: TrajectoryRef[] = []; - for (const c of current) { - const ref = map.get(c.cell.transform.ref) as TrajectoryRef; - if (ref) newCurrent.push(ref); - } - - if (newCurrent.length === 0) return hierarchy.trajectories.length > 0 ? [hierarchy.trajectories[0]] : []; - return newCurrent; - } - - private syncCurrentModels(hierarchy: StructureHierarchy, map: Map<StateTransform.Ref, HierarchyRef>, currentTrajectories: TrajectoryRef[]): ModelRef[] { - const current = this.state.current.models; - if (current.length === 0) return currentTrajectories[0]?.models || []; - - const newCurrent: ModelRef[] = []; - for (const c of current) { - const ref = map.get(c.cell.transform.ref) as ModelRef; - if (ref) newCurrent.push(ref); - } - - if (newCurrent.length === 0) return currentTrajectories[0]?.models || []; - return newCurrent; + get current() { + return this.state.current; } - private syncCurrentStructures(map: Map<StateTransform.Ref, HierarchyRef>, currentModels: ModelRef[]): StructureRef[] { - const current = this.state.current.structures; - if (current.length === 0) return Array.prototype.concat.apply([], currentModels.map(m => m.structures)); + private syncCurrent<T extends HierarchyRef>(hierarchy: StructureHierarchy, current: ReadonlyArray<T>, all: ReadonlyArray<T>): T[] { + if (current.length === 0) return all.length > 0 ? [all[0]] : []; - const newCurrent: StructureRef[] = []; + const newCurrent: T[] = []; for (const c of current) { - const ref = map.get(c.cell.transform.ref) as StructureRef; + const ref = hierarchy.refs.get(c.cell.transform.ref) as T; if (ref) newCurrent.push(ref); } - if (newCurrent.length === 0 && currentModels.length > 0) return Array.prototype.concat.apply([], currentModels.map(m => m.structures)); + if (newCurrent.length === 0) return all.length > 0 ? [all[0]] : []; return newCurrent; } @@ -98,15 +72,17 @@ export class StructureHierarchyManager extends PluginComponent<StructureHierarch if (update.added.length === 0 && update.updated.length === 0 && update.removed.length === 0) { return; } + this._currentComponentGroups = void 0; this._currentSelectionSet = void 0; - const trajectories = this.syncCurrentTrajectories(update.hierarchy, update.hierarchy.refs); - const models = this.syncCurrentModels(update.hierarchy, update.hierarchy.refs, trajectories); - const structures = this.syncCurrentStructures(update.hierarchy.refs, models); + const { hierarchy } = update; + const trajectories = this.syncCurrent(hierarchy, this.state.current.trajectories, hierarchy.trajectories); + const models = this.syncCurrent(hierarchy, this.state.current.models, hierarchy.models); + const structures = this.syncCurrent(hierarchy, this.state.current.structures, hierarchy.structures); - this.updateState({ hierarchy: update.hierarchy, current: { trajectories, models, structures }}); - this.behaviors.current.next({ hierarchy: update.hierarchy, trajectories, models, structures }); + this.updateState({ hierarchy, current: { trajectories, models, structures }}); + this.behaviors.current.next({ hierarchy, trajectories, models, structures }); } updateCurrent(refs: HierarchyRef[], action: 'add' | 'remove') { @@ -151,9 +127,9 @@ export class StructureHierarchyManager extends PluginComponent<StructureHierarch const tr = trajectory.cell.obj?.data!; for (let i = 0; i < tr.length; i++) { - const model = await this.plugin.builders.structure.createModel(trajectory.cell, { modelIndex: i }); + const model = await this.plugin.builders.structure.createModel(trajectory.cell, { modelIndex: i }, { isCollapsed: true }); const structure = await this.plugin.builders.structure.createStructure(model, { name: 'deposited', params: { } }); - await this.plugin.builders.structure.representation.structurePreset(structure, 'auto', { globalThemeName: 'model-index' }); + await this.plugin.builders.structure.representation.applyPreset(structure, 'auto', { globalThemeName: 'model-index' }); } }) } diff --git a/src/mol-plugin-state/manager/structure/selection.ts b/src/mol-plugin-state/manager/structure/selection.ts index de1866da39ac15e5b90d5b1f4e8002cca2acac2c..3e5f0aeae4cc65b86df977d10ce39a3120d87b23 100644 --- a/src/mol-plugin-state/manager/structure/selection.ts +++ b/src/mol-plugin-state/manager/structure/selection.ts @@ -10,7 +10,7 @@ import { BoundaryHelper } from '../../../mol-math/geometry/boundary-helper'; import { Vec3 } from '../../../mol-math/linear-algebra'; import { PrincipalAxes } from '../../../mol-math/linear-algebra/matrix/principal-axes'; import { EmptyLoci, Loci } from '../../../mol-model/loci'; -import { Structure, StructureElement } from '../../../mol-model/structure'; +import { Structure, StructureElement, StructureSelection } from '../../../mol-model/structure'; import { Boundary } from '../../../mol-model/structure/structure/util/boundary'; import { PluginContext } from '../../../mol-plugin/context'; import { StateObject } from '../../../mol-state'; @@ -380,11 +380,11 @@ export class StructureSelectionManager extends PluginComponent<StructureSelectio this.triggerInteraction(modifier, loci, applyGranularity); } - fromSelectionQuery(modifier: StructureSelectionModifier, selectionQuery: StructureSelectionQuery, applyGranularity = true) { + fromSelectionQuery(modifier: StructureSelectionModifier, query: StructureSelectionQuery, applyGranularity = true) { this.plugin.runTask(Task.create('Structure Selection', async runtime => { for (const s of this.applicableStructures) { - const loci = await StructureSelectionQuery.getLoci(this.plugin, runtime, selectionQuery, s); - this.triggerInteraction(modifier, loci, applyGranularity); + const loci = await query.getSelection(this.plugin, runtime, s); + this.triggerInteraction(modifier, StructureSelection.toLociWithSourceUnits(loci), applyGranularity); } })) } diff --git a/src/mol-plugin-state/transforms/model.ts b/src/mol-plugin-state/transforms/model.ts index 7ad2026ba3da222d5d78f476ba1cf10478146174..3ee379b0b03bc77755ae8447a78b7f2e5277c4b2 100644 --- a/src/mol-plugin-state/transforms/model.ts +++ b/src/mol-plugin-state/transforms/model.ts @@ -245,10 +245,11 @@ const ModelFromTrajectory = PluginStateTransform.BuiltIn({ })({ isApplicable: a => a.data.length > 0, apply({ a, params }) { - if (params.modelIndex < 0 || params.modelIndex >= a.data.length) throw new Error(`Invalid modelIndex ${params.modelIndex}`); + let modelIndex = params.modelIndex % a.data.length; + if (modelIndex < 0) modelIndex += a.data.length; const model = a.data[params.modelIndex]; - const label = `Model ${model.modelNum}` - const description = a.data.length === 1 ? undefined : `Model ${params.modelIndex + 1} of ${a.data.length}` + const label = `Model ${model.modelNum}`; + const description = a.data.length === 1 ? undefined : `of ${a.data.length}`; return new SO.Molecule.Model(model, { label, description }); } }); diff --git a/src/mol-plugin-state/transforms/representation.ts b/src/mol-plugin-state/transforms/representation.ts index 54e1ba859633632d755bc0f7018edffe841fff93..a57ec2f60d4a2a889339a90f6ed889d08f4b50e2 100644 --- a/src/mol-plugin-state/transforms/representation.ts +++ b/src/mol-plugin-state/transforms/representation.ts @@ -8,15 +8,12 @@ import { Structure, StructureElement } from '../../mol-model/structure'; import { VolumeData, VolumeIsoValue } from '../../mol-model/volume'; import { PluginContext } from '../../mol-plugin/context'; -import { RepresentationProvider } from '../../mol-repr/representation'; -import { BuiltInStructureRepresentationsName, BuiltInStructureRepresentations } from '../../mol-repr/structure/registry'; -import { StructureParams } from '../../mol-repr/structure/representation'; import { BuiltInVolumeRepresentationsName } from '../../mol-repr/volume/registry'; import { VolumeParams } from '../../mol-repr/volume/representation'; import { StateTransformer, StateObject } from '../../mol-state'; import { Task } from '../../mol-task'; -import { BuiltInColorThemeName, BuiltInColorThemes, ColorTheme } from '../../mol-theme/color'; -import { BuiltInSizeThemeName, BuiltInSizeThemes, SizeTheme } from '../../mol-theme/size'; +import { BuiltInColorThemeName, ColorTheme } from '../../mol-theme/color'; +import { BuiltInSizeThemeName, SizeTheme } from '../../mol-theme/size'; import { Theme } from '../../mol-theme/theme'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { PluginStateObject as SO, PluginStateTransform } from '../objects'; @@ -39,7 +36,6 @@ import { DihedralParams, DihedralRepresentation } from '../../mol-repr/shape/loc import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry'; export { StructureRepresentation3D } -export { StructureRepresentation3DHelpers } export { ExplodeStructureRepresentation3D } export { UnwindStructureAssemblyRepresentation3D } export { OverpaintStructureRepresentation3DFromScript } @@ -48,100 +44,6 @@ export { TransparencyStructureRepresentation3DFromScript } export { TransparencyStructureRepresentation3DFromBundle } export { VolumeRepresentation3D } -namespace StructureRepresentation3DHelpers { - export type BuildInProps<R extends BuiltInStructureRepresentationsName, C extends BuiltInColorThemeName, S extends BuiltInSizeThemeName> = { - type?: R, - typeParams?: Partial<RepresentationProvider.ParamValues<BuiltInStructureRepresentations[R]>>, - color?: C, - colorParams?: Partial<ColorTheme.ParamValues<BuiltInColorThemes[C]>>, - size?: S, - sizeParams?: Partial<SizeTheme.ParamValues<BuiltInSizeThemes[S]>> - } - - export type Props<R extends RepresentationProvider<Structure, any, any> = any, C extends ColorTheme.Provider<any> = any, S extends SizeTheme.Provider<any> = any> = { - type?: R, - typeParams?: Partial<RepresentationProvider.ParamValues<R>>, - color?: C, - colorParams?: Partial<ColorTheme.ParamValues<C>>, - size?: S, - sizeParams?: Partial<SizeTheme.ParamValues<S>> - } - - export function createBuiltInParams<R extends BuiltInStructureRepresentationsName, C extends BuiltInColorThemeName, S extends BuiltInSizeThemeName>( - ctx: PluginContext, structure: Structure, props: BuildInProps<R, C, S> = {} - ) { - const type = (props.type && ctx.structureRepresentation.registry.get(props.type)) - || ctx.structureRepresentation.registry.default.provider; - const color = (props.color && ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(props.color)) - || ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(type.defaultColorTheme.name); - const size = (props.size && ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(props.size)) - || ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(type.defaultSizeTheme.name); - - const ps: Props = { - type: type, - typeParams: props.typeParams, - color, - colorParams: props.colorParams, - size, - sizeParams: props.sizeParams - }; - - return createParams(ctx, structure, ps); - } - - export function createParams<R extends RepresentationProvider<Structure, any, any>, C extends ColorTheme.Provider<any>, S extends SizeTheme.Provider<any>>( - ctx: PluginContext, structure: Structure, props: Props<R, C, S> = {}): StateTransformer.Params<StructureRepresentation3D> { - - const { themeCtx } = ctx.structureRepresentation - const themeDataCtx = { structure } - - const repr = props.type || ctx.structureRepresentation.registry.default.provider; - const reprDefaultParams = PD.getDefaultValues(repr.getParams(themeCtx, structure)); - const reprParams = { ...reprDefaultParams, ...props.typeParams }; - - const color = props.color || themeCtx.colorThemeRegistry.get(repr.defaultColorTheme.name); - const colorDefaultParams = { ...PD.getDefaultValues(color.getParams(themeDataCtx)), ...repr.defaultColorTheme.props } - const colorParams = { ...colorDefaultParams, ...props.colorParams }; - - const size = props.size || themeCtx.sizeThemeRegistry.get(repr.defaultSizeTheme.name); - const sizeDefaultParams = { ...PD.getDefaultValues(size.getParams(themeDataCtx)), ...repr.defaultSizeTheme.props } - const sizeParams = { ...sizeDefaultParams, ...props.sizeParams }; - - return ({ - type: { name: ctx.structureRepresentation.registry.getName(repr), params: reprParams }, - colorTheme: { name: themeCtx.colorThemeRegistry.getName(color), params: colorParams }, - sizeTheme: { name: themeCtx.sizeThemeRegistry.getName(size), params: sizeParams } - }) - } - - export function getDefaultParamsWithTheme(ctx: PluginContext, reprName: BuiltInStructureRepresentationsName, colorName: BuiltInColorThemeName | undefined, structure: Structure, structureParams?: Partial<PD.Values<StructureParams>>): StateTransformer.Params<StructureRepresentation3D> { - const type = ctx.structureRepresentation.registry.get(reprName); - - const themeDataCtx = { structure }; - const color = colorName || type.defaultColorTheme.name; - const colorParams = ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(color).getParams(themeDataCtx); - const sizeParams = ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(type.defaultSizeTheme.name).getParams(themeDataCtx) - const structureDefaultParams = PD.getDefaultValues(type.getParams(ctx.structureRepresentation.themeCtx, structure)) - return ({ - type: { name: reprName, params: structureParams ? { ...structureDefaultParams, ...structureParams } : structureDefaultParams }, - colorTheme: { name: color, params: PD.getDefaultValues(colorParams) }, - sizeTheme: { name: type.defaultSizeTheme.name, params: PD.getDefaultValues(sizeParams) } - }) - } - - export function getDefaultParamsStatic(ctx: PluginContext, name: BuiltInStructureRepresentationsName, structureParams?: Partial<PD.Values<StructureParams>>, colorName?: BuiltInColorThemeName): StateTransformer.Params<StructureRepresentation3D> { - const type = ctx.structureRepresentation.registry.get(name); - const color = colorName || type.defaultColorTheme.name; - const colorParams = ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(color).defaultValues; - const sizeParams = ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(type.defaultSizeTheme.name).defaultValues - return ({ - type: { name, params: structureParams ? { ...type.defaultValues, ...structureParams } : type.defaultValues }, - colorTheme: { name: color, params: colorParams }, - sizeTheme: { name: type.defaultSizeTheme.name, params: sizeParams } - }) - } -} - type StructureRepresentation3D = typeof StructureRepresentation3D const StructureRepresentation3D = PluginStateTransform.BuiltIn({ name: 'structure-representation-3d', diff --git a/src/mol-plugin-ui/controls/common.tsx b/src/mol-plugin-ui/controls/common.tsx index 8dfd97e9720a6ba3dee22d6cf909bbce04a6c156..0739a952da5babb37e5bb7f86ccb7d8d647d0323 100644 --- a/src/mol-plugin-ui/controls/common.tsx +++ b/src/mol-plugin-ui/controls/common.tsx @@ -332,14 +332,14 @@ export class ToggleButton extends React.PureComponent<ToggleButtonProps> { } } -export class ExpandGroup extends React.PureComponent<{ header: string, initiallyExpanded?: boolean, noOffset?: boolean }, { isExpanded: boolean }> { +export class ExpandGroup extends React.PureComponent<{ header: string, initiallyExpanded?: boolean, noOffset?: boolean, marginTop?: 0 | string }, { isExpanded: boolean }> { state = { isExpanded: !!this.props.initiallyExpanded }; toggleExpanded = () => this.setState({ isExpanded: !this.state.isExpanded }); render() { return <> - <div className='msp-control-group-header' style={{ marginTop: '1px' }}> + <div className='msp-control-group-header' style={{ marginTop: this.props.marginTop !== void 0 ? this.props.marginTop : '1px' }}> <button className='msp-btn msp-btn-block' onClick={this.toggleExpanded}> <Icon name={this.state.isExpanded ? 'collapse' : 'expand'} /> {this.props.header} diff --git a/src/mol-plugin-ui/structure/components.tsx b/src/mol-plugin-ui/structure/components.tsx index 0107708e3772508f1b2b0ffcd68b3c15681ff577..6d991385a06d1fd52e1317b03ac1bd2ead3899f7 100644 --- a/src/mol-plugin-ui/structure/components.tsx +++ b/src/mol-plugin-ui/structure/components.tsx @@ -10,7 +10,7 @@ import { StructureComponentRef, StructureRepresentationRef, StructureRef } from import { PluginCommands } from '../../mol-plugin/commands'; import { State } from '../../mol-state'; import { ParamDefinition } from '../../mol-util/param-definition'; -import { CollapsableControls, CollapsableState, PurePluginUIComponent } from '../base'; +import { CollapsableControls, CollapsableState, PurePluginUIComponent, PluginUIComponent } from '../base'; import { ActionMenu } from '../controls/action-menu'; import { ExpandGroup, IconButton, ToggleButton } from '../controls/common'; import { Icon } from '../controls/icons'; @@ -84,8 +84,9 @@ class ComponentEditorControls extends PurePluginUIComponent<{}, ComponentEditorC const actions = [ ActionMenu.Item('Clear', null), ]; - // TODO: filter by applicable?? - for (const p of this.plugin.builders.structure.representation.providerList) { + const pivot = this.plugin.managers.structure.component.pivotStructure; + const providers = this.plugin.builders.structure.representation.getPresets(pivot?.cell.obj?.data) + for (const p of providers) { actions.push(ActionMenu.Item(p.display.name, p)); } return actions; @@ -183,12 +184,33 @@ class ComponentListControls extends PurePluginUIComponent { render() { const componentGroups = this.plugin.managers.structure.hierarchy.currentComponentGroups; - return <div> + if (componentGroups.length === 0) return null; + + return <div style={{ marginTop: '6px' }}> {componentGroups.map(g => <StructureComponentGroup key={g[0].cell.transform.ref} group={g} />)} + <CurrentFocus /> </div>; } } +class CurrentFocus extends PluginUIComponent { + findInteraction() { + const xs = this.plugin.managers.structure.hierarchy.current.structures; + for (const s of xs) { + if (s.currentFocus?.focus || s.currentFocus?.surroundings) return s.currentFocus; + } + } + + render() { + const interaction = this.findInteraction(); + if (!interaction) return null; + return <ExpandGroup header='Current Focus' marginTop={0} noOffset> + {interaction.focus && <StructureComponentGroup group={[interaction.focus]} />} + {interaction.surroundings && <StructureComponentGroup group={[interaction.surroundings]} />} + </ExpandGroup>; + } +} + type StructureComponentEntryActions = 'action' | 'remove' class StructureComponentGroup extends PurePluginUIComponent<{ group: StructureComponentRef[] }, { action?: StructureComponentEntryActions }> { @@ -283,8 +305,8 @@ class StructureComponentGroup extends PurePluginUIComponent<{ group: StructureCo const component = this.pivot; const cell = component.cell; const label = cell.obj?.label; - return <> - <div className='msp-control-row' style={{ marginTop: '6px' }}> + return <div style={{ marginBottom: '6px' }}> + <div className='msp-control-row'> <button className='msp-control-button-label' title={`${label}. Click to focus.`} onClick={this.focus} onMouseEnter={this.highlight} onMouseLeave={this.clearHighlight} style={{ textAlign: 'left' }}> {label} </button> @@ -299,7 +321,7 @@ class StructureComponentGroup extends PurePluginUIComponent<{ group: StructureCo <div className='msp-control-offset'> {component.representations.map(r => <StructureRepresentationEntry group={this.props.group} key={r.cell.transform.ref} representation={r} />)} </div> - </>; + </div>; } } diff --git a/src/mol-plugin-ui/structure/source.tsx b/src/mol-plugin-ui/structure/source.tsx index 6104707eae17411afbb5d2747722080a3a43203b..c2b98783eaa21da02e8f97a5a56d1d9decd66b15 100644 --- a/src/mol-plugin-ui/structure/source.tsx +++ b/src/mol-plugin-ui/structure/source.tsx @@ -62,8 +62,9 @@ export class StructureSourceControls extends CollapsableControls<{}, StructureSo if (structures.length === 1) { const s = structures[0]; - if (s.model.trajectory.models.length === 1) return s.cell.obj?.data.label; - return `${s.model.cell.obj?.label} | ${s.cell.obj?.data.label}`; + if (s.model?.trajectory?.models && s.model.trajectory.models.length === 1) return s.cell.obj?.data.label; + if (s.model) return `${s.model.cell.obj?.label} | ${s.cell.obj?.data.label}`; + return s.cell.obj?.data.label; } if (structures.length > 1) { diff --git a/src/mol-plugin/behavior/dynamic/custom-props/computed/accessible-surface-area.ts b/src/mol-plugin/behavior/dynamic/custom-props/computed/accessible-surface-area.ts index 3acedd05499f31d9b62a8eb6994f4849604a9acb..cbee2a620a2317eda07122e35ebcf95a82e80cc3 100644 --- a/src/mol-plugin/behavior/dynamic/custom-props/computed/accessible-surface-area.ts +++ b/src/mol-plugin/behavior/dynamic/custom-props/computed/accessible-surface-area.ts @@ -40,7 +40,7 @@ export const AccessibleSurfaceArea = PluginBehavior.create<{ autoAttach: boolean DefaultQueryRuntimeTable.addCustomProp(this.provider.descriptor); this.ctx.customStructureProperties.register(this.provider, this.params.autoAttach); - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add('accessible-surface-area', AccessibleSurfaceAreaColorThemeProvider) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(AccessibleSurfaceAreaColorThemeProvider) this.ctx.managers.lociLabels.addProvider(this.label); } @@ -49,7 +49,7 @@ export const AccessibleSurfaceArea = PluginBehavior.create<{ autoAttach: boolean // DefaultQueryRuntimeTable.removeCustomProp(this.provider.descriptor); this.ctx.customStructureProperties.unregister(this.provider.descriptor.name); - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove('accessible-surface-area') + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(AccessibleSurfaceAreaColorThemeProvider) this.ctx.managers.lociLabels.removeProvider(this.label); } }, diff --git a/src/mol-plugin/behavior/dynamic/custom-props/computed/interactions.ts b/src/mol-plugin/behavior/dynamic/custom-props/computed/interactions.ts index 8de7c19372e86c5873f61f76bc33754011e6f102..1c4c7546303a444d1cb34ba3d93251882fd0679b 100644 --- a/src/mol-plugin/behavior/dynamic/custom-props/computed/interactions.ts +++ b/src/mol-plugin/behavior/dynamic/custom-props/computed/interactions.ts @@ -99,16 +99,16 @@ export const Interactions = PluginBehavior.create<{ autoAttach: boolean, showToo register(): void { this.ctx.customStructureProperties.register(this.provider, this.params.autoAttach); - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add('interaction-type', InteractionTypeColorThemeProvider) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(InteractionTypeColorThemeProvider) this.ctx.managers.lociLabels.addProvider(this.label); - this.ctx.structureRepresentation.registry.add('interactions', InteractionsRepresentationProvider) + this.ctx.structureRepresentation.registry.add(InteractionsRepresentationProvider) } unregister() { this.ctx.customStructureProperties.unregister(this.provider.descriptor.name); - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove('interaction-type') + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(InteractionTypeColorThemeProvider) this.ctx.managers.lociLabels.removeProvider(this.label); - this.ctx.structureRepresentation.registry.remove('interactions') + this.ctx.structureRepresentation.registry.remove(InteractionsRepresentationProvider) } }, params: () => ({ diff --git a/src/mol-plugin/behavior/dynamic/custom-props/integrative/cross-link-restraint.ts b/src/mol-plugin/behavior/dynamic/custom-props/integrative/cross-link-restraint.ts index a1a105666a5813a1cf7583e3f6247a886b7f5ec4..d21a2f167107601918b10ad1063a0bdf23f0ddbb 100644 --- a/src/mol-plugin/behavior/dynamic/custom-props/integrative/cross-link-restraint.ts +++ b/src/mol-plugin/behavior/dynamic/custom-props/integrative/cross-link-restraint.ts @@ -12,8 +12,6 @@ import { CrossLinkRestraintRepresentationProvider } from '../../../../../mol-mod import { CrossLinkColorThemeProvider } from '../../../../../mol-model-props/integrative/cross-link-restraint/color'; import { CrossLinkRestraint as _CrossLinkRestraint } from '../../../../../mol-model-props/integrative/cross-link-restraint/property'; -const Tag = _CrossLinkRestraint.Tag - export const CrossLinkRestraint = PluginBehavior.create<{ }>({ name: 'integrative-cross-link-restraint', category: 'custom-props', @@ -24,15 +22,15 @@ export const CrossLinkRestraint = PluginBehavior.create<{ }>({ register(): void { this.provider.formatRegistry.add('mmCIF', crossLinkRestraintFromMmcif) - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(Tag.CrossLinkRestraint, CrossLinkColorThemeProvider) - this.ctx.structureRepresentation.registry.add(Tag.CrossLinkRestraint, CrossLinkRestraintRepresentationProvider) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(CrossLinkColorThemeProvider) + this.ctx.structureRepresentation.registry.add(CrossLinkRestraintRepresentationProvider) } unregister() { this.provider.formatRegistry.remove('mmCIF') - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(Tag.CrossLinkRestraint) - this.ctx.structureRepresentation.registry.remove(Tag.CrossLinkRestraint) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(CrossLinkColorThemeProvider) + this.ctx.structureRepresentation.registry.remove(CrossLinkRestraintRepresentationProvider) } } }); diff --git a/src/mol-plugin/behavior/dynamic/custom-props/pdbe/structure-quality-report.ts b/src/mol-plugin/behavior/dynamic/custom-props/pdbe/structure-quality-report.ts index a69898ccf86db0301862b4e2703defbc900ea19f..fb581f4a5cecc5bea376eff5cfb5201322b21589 100644 --- a/src/mol-plugin/behavior/dynamic/custom-props/pdbe/structure-quality-report.ts +++ b/src/mol-plugin/behavior/dynamic/custom-props/pdbe/structure-quality-report.ts @@ -46,7 +46,7 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo this.ctx.customModelProperties.register(this.provider, false); this.ctx.managers.lociLabels.addProvider(this.labelPDBeValidation); - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add('pdbe-structure-quality-report', StructureQualityReportColorThemeProvider) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(StructureQualityReportColorThemeProvider) } update(p: { autoAttach: boolean, showTooltip: boolean }) { @@ -60,7 +60,7 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo unregister() { this.ctx.customModelProperties.unregister(StructureQualityReportProvider.descriptor.name); this.ctx.managers.lociLabels.removeProvider(this.labelPDBeValidation); - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove('pdbe-structure-quality-report') + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(StructureQualityReportColorThemeProvider) } }, params: () => ({ diff --git a/src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts b/src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts index dd666747d956935cce3682ff7a48cb351e0fe197..217e24235c1260e512faa869fa1e95c57ec548d9 100644 --- a/src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts +++ b/src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts @@ -29,7 +29,7 @@ export const RCSBAssemblySymmetry = PluginBehavior.create<{ autoAttach: boolean register(): void { this.ctx.state.dataState.actions.add(InitAssemblySymmetry3D) this.ctx.customStructureProperties.register(this.provider, this.params.autoAttach); - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(Tag.Cluster, AssemblySymmetryClusterColorThemeProvider) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(AssemblySymmetryClusterColorThemeProvider) } update(p: { autoAttach: boolean }) { @@ -42,7 +42,7 @@ export const RCSBAssemblySymmetry = PluginBehavior.create<{ autoAttach: boolean unregister() { this.ctx.state.dataState.actions.remove(InitAssemblySymmetry3D) this.ctx.customStructureProperties.unregister(this.provider.descriptor.name); - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(Tag.Cluster) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(AssemblySymmetryClusterColorThemeProvider) } }, params: () => ({ diff --git a/src/mol-plugin/behavior/dynamic/custom-props/rcsb/validation-report.ts b/src/mol-plugin/behavior/dynamic/custom-props/rcsb/validation-report.ts index bea24c4b3f90af7d010862e2df3744fae691c4ec..8ccddb2f64265369c19574d5a585ef2866769bf8 100644 --- a/src/mol-plugin/behavior/dynamic/custom-props/rcsb/validation-report.ts +++ b/src/mol-plugin/behavior/dynamic/custom-props/rcsb/validation-report.ts @@ -16,8 +16,6 @@ import { DensityFitColorThemeProvider } from '../../../../../mol-model-props/rcs import { cantorPairing } from '../../../../../mol-data/util'; import { DefaultQueryRuntimeTable } from '../../../../../mol-script/runtime/query/compiler'; -const Tag = ValidationReport.Tag - export const RCSBValidationReport = PluginBehavior.create<{ autoAttach: boolean, showTooltip: boolean }>({ name: 'rcsb-validation-report-prop', category: 'custom-props', @@ -44,11 +42,11 @@ export const RCSBValidationReport = PluginBehavior.create<{ autoAttach: boolean, this.ctx.managers.lociLabels.addProvider(this.label); - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(Tag.DensityFit, DensityFitColorThemeProvider) - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(Tag.GeometryQuality, GeometryQualityColorThemeProvider) - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(Tag.RandomCoilIndex, RandomCoilIndexColorThemeProvider) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(DensityFitColorThemeProvider) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(GeometryQualityColorThemeProvider) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add(RandomCoilIndexColorThemeProvider) - this.ctx.structureRepresentation.registry.add(Tag.Clashes, ClashesRepresentationProvider) + this.ctx.structureRepresentation.registry.add(ClashesRepresentationProvider) } update(p: { autoAttach: boolean, showTooltip: boolean }) { @@ -67,11 +65,11 @@ export const RCSBValidationReport = PluginBehavior.create<{ autoAttach: boolean, this.ctx.managers.lociLabels.removeProvider(this.label); - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(Tag.DensityFit) - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(Tag.GeometryQuality) - this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(Tag.RandomCoilIndex) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(DensityFitColorThemeProvider) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(GeometryQualityColorThemeProvider) + this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove(RandomCoilIndexColorThemeProvider) - this.ctx.structureRepresentation.registry.remove(Tag.Clashes) + this.ctx.structureRepresentation.registry.remove(ClashesRepresentationProvider) } }, params: () => ({ diff --git a/src/mol-plugin/behavior/dynamic/selection/structure-representation-interaction.ts b/src/mol-plugin/behavior/dynamic/selection/structure-representation-interaction.ts index 95bfa17c61b7eb0a8c15968501182a1c6f53cfa5..a67405d1c0eaef89de872134ff23484d3531bb56 100644 --- a/src/mol-plugin/behavior/dynamic/selection/structure-representation-interaction.ts +++ b/src/mol-plugin/behavior/dynamic/selection/structure-representation-interaction.ts @@ -5,23 +5,22 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Structure, StructureElement, Bond } from '../../../../mol-model/structure'; -import { PluginBehavior } from '../../../../mol-plugin/behavior'; -import { PluginCommands } from '../../../commands'; +import { InteractionsRepresentationProvider } from '../../../../mol-model-props/computed/representations/interactions'; +import { InteractionTypeColorThemeProvider } from '../../../../mol-model-props/computed/themes/interaction-type'; +import { EmptyLoci, isEmptyLoci, Loci } from '../../../../mol-model/loci'; +import { Bond, Structure, StructureElement } from '../../../../mol-model/structure'; +import { createStructureRepresentationParams } from '../../../../mol-plugin-state/helpers/structure-representation-params'; import { PluginStateObject } from '../../../../mol-plugin-state/objects'; import { StateTransforms } from '../../../../mol-plugin-state/transforms'; -import { StructureRepresentation3DHelpers } from '../../../../mol-plugin-state/transforms/representation'; -import { BuiltInStructureRepresentations } from '../../../../mol-repr/structure/registry'; +import { PluginBehavior } from '../../../../mol-plugin/behavior'; import { MolScriptBuilder as MS } from '../../../../mol-script/language/builder'; import { StateObjectCell, StateSelection, StateTransform } from '../../../../mol-state'; -import { BuiltInColorThemes } from '../../../../mol-theme/color'; import { BuiltInSizeThemes } from '../../../../mol-theme/size'; -import { ButtonsType, ModifiersKeys } from '../../../../mol-util/input/input-observer'; import { Binding } from '../../../../mol-util/binding'; +import { ButtonsType, ModifiersKeys } from '../../../../mol-util/input/input-observer'; import { ParamDefinition as PD } from '../../../../mol-util/param-definition'; -import { isEmptyLoci, Loci, EmptyLoci } from '../../../../mol-model/loci'; -import { InteractionsRepresentationProvider } from '../../../../mol-model-props/computed/representations/interactions'; -import { InteractionTypeColorThemeProvider } from '../../../../mol-model-props/computed/themes/interaction-type'; +import { PluginCommands } from '../../../commands'; +import { PluginContext } from '../../../context'; const B = ButtonsType const M = ModifiersKeys @@ -30,10 +29,38 @@ const Trigger = Binding.Trigger const DefaultStructureRepresentationInteractionBindings = { clickInteractionAroundOnly: Binding([Trigger(B.Flag.Secondary, M.create()), Trigger(B.Flag.Primary, M.create({ control: true }))], 'Show the structure interaction around only the clicked element using ${triggers}.'), } -const StructureRepresentationInteractionParams = { - bindings: PD.Value(DefaultStructureRepresentationInteractionBindings, { isHidden: true }), +// const StructureRepresentationInteractionParams = { +// bindings: PD.Value(DefaultStructureRepresentationInteractionBindings, { isHidden: true }), +// } + +const StructureRepresentationInteractionParams = (plugin: PluginContext) => { + + const reprParams = StateTransforms.Representation.StructureRepresentation3D.definition.params!(void 0, plugin) as PD.Params; + return { + bindings: PD.Value(DefaultStructureRepresentationInteractionBindings, { isHidden: true }), + focusParams: PD.Group(reprParams, { + label: 'Focus', + customDefault: createStructureRepresentationParams(plugin, void 0, { type: 'ball-and-stick', size: 'uniform' }) + }), + surroundingsParams: PD.Group(reprParams, { + label: 'Surroundings', + customDefault: createStructureRepresentationParams(plugin, void 0, { type: 'ball-and-stick', color: 'element-symbol', size: 'uniform' }) + }), + nciParams: PD.Group(reprParams, { + label: 'Non-covalent Int.', + // customDefault: createStructureRepresentationParams(plugin, void 0, { type: 'ball-and-stick', color: 'element-symbol', size: 'uniform' }) + customDefault: createStructureRepresentationParams(plugin, void 0, { + type: InteractionsRepresentationProvider, + color: InteractionTypeColorThemeProvider, + size: BuiltInSizeThemes.uniform + }) + }) + }; } -type StructureRepresentationInteractionProps = PD.Values<typeof StructureRepresentationInteractionParams> + +type StructureRepresentationInteractionProps = PD.ValuesFor<ReturnType<typeof StructureRepresentationInteractionParams>> + +//PD.Values<typeof StructureRepresentationInteractionParams> export enum StructureRepresentationInteractionTags { Group = 'structure-interaction-group', @@ -47,65 +74,49 @@ export enum StructureRepresentationInteractionTags { const TagSet: Set<StructureRepresentationInteractionTags> = new Set([StructureRepresentationInteractionTags.Group, StructureRepresentationInteractionTags.ResidueSel, StructureRepresentationInteractionTags.ResidueRepr, StructureRepresentationInteractionTags.SurrSel, StructureRepresentationInteractionTags.SurrRepr, StructureRepresentationInteractionTags.SurrNciRepr]) export class StructureRepresentationInteractionBehavior extends PluginBehavior.WithSubscribers<StructureRepresentationInteractionProps> { - private createResVisualParams(s: Structure) { - return StructureRepresentation3DHelpers.createParams(this.plugin, s, { - type: BuiltInStructureRepresentations['ball-and-stick'], - size: BuiltInSizeThemes.uniform - }); - } - - private createSurVisualParams(s: Structure) { - return StructureRepresentation3DHelpers.createParams(this.plugin, s, { - type: BuiltInStructureRepresentations['ball-and-stick'], - color: BuiltInColorThemes['element-symbol'], - size: BuiltInSizeThemes.uniform - }); - } - - private createSurNciVisualParams(s: Structure) { - return StructureRepresentation3DHelpers.createParams(this.plugin, s, { - type: InteractionsRepresentationProvider, - color: InteractionTypeColorThemeProvider, - size: BuiltInSizeThemes.uniform - }); - } - private ensureShape(cell: StateObjectCell<PluginStateObject.Molecule.Structure>) { const state = this.plugin.state.dataState, tree = state.tree; const builder = state.build(); const refs = StateSelection.findUniqueTagsInSubtree(tree, cell.transform.ref, TagSet); if (!refs['structure-interaction-group']) { - refs['structure-interaction-group'] = builder.to(cell).group(StateTransforms.Misc.CreateGroup, - { label: 'Current Focus' }, { tags: StructureRepresentationInteractionTags.Group }).ref; + refs['structure-interaction-group'] = builder + .to(cell) + .group(StateTransforms.Misc.CreateGroup, { label: 'Current Focus' }, { tags: StructureRepresentationInteractionTags.Group }).ref; } // Selections if (!refs[StructureRepresentationInteractionTags.ResidueSel]) { - refs[StructureRepresentationInteractionTags.ResidueSel] = builder.to(refs['structure-interaction-group']).apply(StateTransforms.Model.StructureSelectionFromBundle, - { bundle: { } as any, label: 'Residue' }, { tags: StructureRepresentationInteractionTags.ResidueSel }).ref; + refs[StructureRepresentationInteractionTags.ResidueSel] = builder + .to(refs['structure-interaction-group']) + .apply(StateTransforms.Model.StructureSelectionFromBundle, + { bundle: { } as any, label: 'Focus' }, { tags: StructureRepresentationInteractionTags.ResidueSel }).ref; } if (!refs[StructureRepresentationInteractionTags.SurrSel]) { - refs[StructureRepresentationInteractionTags.SurrSel] = builder.to(refs['structure-interaction-group']).apply(StateTransforms.Model.StructureSelectionFromExpression, - { expression: { } as any, label: 'Surroundings' }, { tags: StructureRepresentationInteractionTags.SurrSel }).ref; + refs[StructureRepresentationInteractionTags.SurrSel] = builder + .to(refs['structure-interaction-group']) + .apply(StateTransforms.Model.StructureSelectionFromExpression, + { expression: { } as any, label: 'Surroundings' }, { tags: StructureRepresentationInteractionTags.SurrSel }).ref; } // Representations - // TODO: ability to customize how it looks in the behavior params if (!refs[StructureRepresentationInteractionTags.ResidueRepr]) { - refs[StructureRepresentationInteractionTags.ResidueRepr] = builder.to(refs['structure-interaction-residue-sel']!).apply(StateTransforms.Representation.StructureRepresentation3D, - this.createResVisualParams(cell.obj!.data), { tags: StructureRepresentationInteractionTags.ResidueRepr }).ref; + refs[StructureRepresentationInteractionTags.ResidueRepr] = builder + .to(refs['structure-interaction-residue-sel']!) + .apply(StateTransforms.Representation.StructureRepresentation3D, this.params.focusParams, { tags: StructureRepresentationInteractionTags.ResidueRepr }).ref; } if (!refs[StructureRepresentationInteractionTags.SurrRepr]) { - refs[StructureRepresentationInteractionTags.SurrRepr] = builder.to(refs['structure-interaction-surr-sel']!).apply(StateTransforms.Representation.StructureRepresentation3D, - this.createSurVisualParams(cell.obj!.data), { tags: StructureRepresentationInteractionTags.SurrRepr }).ref; + refs[StructureRepresentationInteractionTags.SurrRepr] = builder + .to(refs['structure-interaction-surr-sel']!) + .apply(StateTransforms.Representation.StructureRepresentation3D,this.params.nciParams, { tags: StructureRepresentationInteractionTags.SurrRepr }).ref; } if (!refs[StructureRepresentationInteractionTags.SurrNciRepr]) { - refs[StructureRepresentationInteractionTags.SurrNciRepr] = builder.to(refs['structure-interaction-surr-sel']!).apply(StateTransforms.Representation.StructureRepresentation3D, - this.createSurNciVisualParams(cell.obj!.data), { tags: StructureRepresentationInteractionTags.SurrNciRepr }).ref; + refs[StructureRepresentationInteractionTags.SurrNciRepr] = builder + .to(refs['structure-interaction-surr-sel']!) + .apply(StateTransforms.Representation.StructureRepresentation3D, this.params.surroundingsParams, { tags: StructureRepresentationInteractionTags.SurrNciRepr }).ref; } return { state, builder, refs }; @@ -202,7 +213,24 @@ export class StructureRepresentationInteractionBehavior extends PluginBehavior.W } async update(params: StructureRepresentationInteractionProps) { - return false; + this.params = params; + + const state = this.plugin.state.dataState; + const builder = state.build(); + + const all = StateSelection.Generators.root.subtree(); + for (const repr of state.select(all.withTag(StructureRepresentationInteractionTags.ResidueRepr))) { + builder.to(repr).update(this.params.focusParams); + } + for (const repr of state.select(all.withTag(StructureRepresentationInteractionTags.SurrRepr))) { + builder.to(repr).update(this.params.surroundingsParams); + } + for (const repr of state.select(all.withTag(StructureRepresentationInteractionTags.SurrNciRepr))) { + builder.to(repr).update(this.params.nciParams); + } + + await PluginCommands.State.Update(this.plugin, { state, tree: builder, options: { doNotLogTiming: true, doNotUpdateCurrent: true } }); + return true; } } @@ -211,5 +239,5 @@ export const StructureRepresentationInteraction = PluginBehavior.create({ display: { name: 'Structure Representation Interaction' }, category: 'interaction', ctor: StructureRepresentationInteractionBehavior, - params: () => StructureRepresentationInteractionParams + params: (_, plugin) => StructureRepresentationInteractionParams(plugin) }); \ No newline at end of file diff --git a/src/mol-plugin/index.ts b/src/mol-plugin/index.ts index 18ab0aa31e3582b5cfddea29e6bc8c65b5ccd327..89241ee2b201c40cb1546a5d5e53c0e3e7f9e112 100644 --- a/src/mol-plugin/index.ts +++ b/src/mol-plugin/index.ts @@ -27,7 +27,6 @@ export const DefaultPluginSpec: PluginSpec = { PluginSpec.Action(StateActions.Volume.DownloadDensity), PluginSpec.Action(StateActions.DataFormat.OpenFiles), PluginSpec.Action(StateActions.Structure.Create3DRepresentationPreset), - PluginSpec.Action(StateActions.Structure.Remove3DRepresentationPreset), PluginSpec.Action(StateActions.Structure.EnableModelCustomProps), PluginSpec.Action(StateActions.Structure.EnableStructureCustomProps), @@ -62,8 +61,6 @@ export const DefaultPluginSpec: PluginSpec = { PluginSpec.Action(StateTransforms.Volume.VolumeFromCcp4), PluginSpec.Action(StateTransforms.Representation.VolumeRepresentation3D), - - PluginSpec.Action(StateActions.Structure.StructureFromSelection), ], behaviors: [ PluginSpec.Behavior(PluginBehaviors.Representation.HighlightLoci), diff --git a/src/mol-plugin/spec.ts b/src/mol-plugin/spec.ts index e6ea6ddb4afc40f69a9224d08e4cf1a2d2b72c2f..c2310e3e42a5b4eec45ccac010e4832de4a98299 100644 --- a/src/mol-plugin/spec.ts +++ b/src/mol-plugin/spec.ts @@ -9,7 +9,6 @@ import { StateTransformer, StateAction } from '../mol-state'; import { StateTransformParameters } from '../mol-plugin-ui/state/common'; import { PluginLayoutStateProps } from './layout'; import { PluginStateAnimation } from '../mol-plugin-state/animation/model'; -import { ParamDefinition as PD } from '../mol-util/param-definition'; import { PluginConfigItem } from './config'; export { PluginSpec } @@ -49,10 +48,7 @@ namespace PluginSpec { } export function Behavior<T extends StateTransformer>(transformer: T, defaultParams: Partial<StateTransformer.Params<T>> = {}): Behavior { - const params = transformer.definition.params - ? PD.getDefaultValues(transformer.definition.params(undefined, undefined)) - : {} - return { transformer, defaultParams: { ...params, ...defaultParams } }; + return { transformer, defaultParams }; } export interface LayoutControls { diff --git a/src/mol-repr/representation.ts b/src/mol-repr/representation.ts index 6d7dd2e51aa2726d761bdce17e5305f65eb3e720..9db6be47d707f7260e97c524884b6a7c6223f811 100644 --- a/src/mol-repr/representation.ts +++ b/src/mol-repr/representation.ts @@ -39,7 +39,8 @@ export type RepresentationFactory<D, P extends PD.Params, S extends Representati // -export interface RepresentationProvider<D, P extends PD.Params, S extends Representation.State> { +export interface RepresentationProvider<D = any, P extends PD.Params = any, S extends Representation.State = any, Id extends string = string> { + readonly name: Id, readonly label: string readonly description: string readonly factory: RepresentationFactory<D, P, S> @@ -86,18 +87,24 @@ export class RepresentationRegistry<D, S extends Representation.State> { constructor() {}; - add<P extends PD.Params>(name: string, provider: RepresentationProvider<D, P, S>) { - this._list.push({ name, provider }) - this._map.set(name, provider) - this._name.set(provider, name) + add<P extends PD.Params>(provider: RepresentationProvider<D, P, S>) { + if (this._map.has(provider.name)) { + throw new Error(`${provider.name} already registered.`); + } + + this._list.push({ name: provider.name, provider }) + this._map.set(provider.name, provider) + this._name.set(provider, provider.name) } - getName(provider: RepresentationProvider<D, any, S>): string { + getName(provider: RepresentationProvider<D, any, any>): string { if (!this._name.has(provider)) throw new Error(`'${provider.label}' is not a registered represenatation provider.`); return this._name.get(provider)!; } - remove(name: string) { + remove(provider: RepresentationProvider<D, any, any>) { + const name = provider.name; + this._list.splice(this._list.findIndex(e => e.name === name), 1) const p = this._map.get(name); if (p) { diff --git a/src/mol-repr/structure/registry.ts b/src/mol-repr/structure/registry.ts index 5ac581d3aa5d8a011fa38f72efe8a2ab5a6d7a8d..619692a89298bdc35a4220be61b9366329409a31 100644 --- a/src/mol-repr/structure/registry.ts +++ b/src/mol-repr/structure/registry.ts @@ -5,7 +5,7 @@ */ import { Structure } from '../../mol-model/structure'; -import { RepresentationProvider, RepresentationRegistry } from '../representation'; +import { RepresentationRegistry } from '../representation'; import { CartoonRepresentationProvider } from './representation/cartoon'; import { BallAndStickRepresentationProvider } from './representation/ball-and-stick'; import { GaussianSurfaceRepresentationProvider } from './representation/gaussian-surface'; @@ -18,13 +18,14 @@ import { MolecularSurfaceRepresentationProvider } from './representation/molecul import { EllipsoidRepresentationProvider } from './representation/ellipsoid'; import { OrientationRepresentationProvider } from './representation/orientation'; import { LabelRepresentationProvider } from './representation/label'; +import { objectForEach } from '../../mol-util/object'; export class StructureRepresentationRegistry extends RepresentationRegistry<Structure, StructureRepresentationState> { constructor() { super() - Object.keys(BuiltInStructureRepresentations).forEach(name => { - const p = (BuiltInStructureRepresentations as { [k: string]: RepresentationProvider<Structure, any, StructureRepresentationState> })[name] - this.add(name, p) + objectForEach(BuiltInStructureRepresentations, (p, k) => { + if (p.name !== k) throw new Error(`Fix BuiltInStructureRepresentations to have matching names. ${p.name} ${k}`); + this.add(p as any) }) } } @@ -43,6 +44,7 @@ export const BuiltInStructureRepresentations = { 'putty': PuttyRepresentationProvider, 'spacefill': SpacefillRepresentationProvider, } + export type BuiltInStructureRepresentations = typeof BuiltInStructureRepresentations export type BuiltInStructureRepresentationsName = keyof typeof BuiltInStructureRepresentations export const BuiltInStructureRepresentationsNames = Object.keys(BuiltInStructureRepresentations) diff --git a/src/mol-repr/structure/representation.ts b/src/mol-repr/structure/representation.ts index a01d70ab45d288d9054a15a7832c37eae3170bb6..3d1b0b4e5d1668896564eb298ad253b83eb3b475 100644 --- a/src/mol-repr/structure/representation.ts +++ b/src/mol-repr/structure/representation.ts @@ -38,8 +38,8 @@ export const StructureRepresentationStateBuilder: Representation.StateBuilder<St export interface StructureRepresentation<P extends RepresentationProps = {}> extends Representation<Structure, P, StructureRepresentationState> { } -export type StructureRepresentationProvider<P extends PD.Params> = RepresentationProvider<Structure, P, StructureRepresentationState> - +export type StructureRepresentationProvider<P extends PD.Params, Id extends string = string> = RepresentationProvider<Structure, P, StructureRepresentationState, Id> +export function StructureRepresentationProvider<P extends PD.Params, Id extends string>(p: StructureRepresentationProvider<P, Id>): StructureRepresentationProvider<P, Id> { return p; } // export const StructureParams = { ...BaseGeometry.Params } diff --git a/src/mol-repr/structure/representation/ball-and-stick.ts b/src/mol-repr/structure/representation/ball-and-stick.ts index 726ccb195a32719265846ba1d81abdb8fc6d89a3..92b9476de1c28acf5ff6402f87771f8afb8967d7 100644 --- a/src/mol-repr/structure/representation/ball-and-stick.ts +++ b/src/mol-repr/structure/representation/ball-and-stick.ts @@ -41,7 +41,8 @@ export function BallAndStickRepresentation(ctx: RepresentationContext, getParams return Representation.createMulti('Ball & Stick', ctx, getParams, StructureRepresentationStateBuilder, BallAndStickVisuals as unknown as Representation.Def<Structure, BallAndStickParams>) } -export const BallAndStickRepresentationProvider: StructureRepresentationProvider<BallAndStickParams> = { +export const BallAndStickRepresentationProvider = StructureRepresentationProvider({ + name: 'ball-and-stick', label: 'Ball & Stick', description: 'Displays atoms as spheres and bonds as cylinders.', factory: BallAndStickRepresentation, @@ -50,4 +51,4 @@ export const BallAndStickRepresentationProvider: StructureRepresentationProvider defaultColorTheme: { name: 'element-symbol' }, defaultSizeTheme: { name: 'physical' }, isApplicable: (structure: Structure) => structure.elementCount > 0 -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/structure/representation/carbohydrate.ts b/src/mol-repr/structure/representation/carbohydrate.ts index 2b5b6ae894fed378596d0eb7646a34875b014082..1fe767038778f6f6e9d6ddb956707c91424c50f1 100644 --- a/src/mol-repr/structure/representation/carbohydrate.ts +++ b/src/mol-repr/structure/representation/carbohydrate.ts @@ -36,7 +36,8 @@ export function CarbohydrateRepresentation(ctx: RepresentationContext, getParams return Representation.createMulti('Carbohydrate', ctx, getParams, StructureRepresentationStateBuilder, CarbohydrateVisuals as unknown as Representation.Def<Structure, CarbohydrateParams>) } -export const CarbohydrateRepresentationProvider: StructureRepresentationProvider<CarbohydrateParams> = { +export const CarbohydrateRepresentationProvider = StructureRepresentationProvider({ + name: 'carbohydrate', label: 'Carbohydrate', description: 'Displays carbohydrate symbols (3D SNFG).', factory: CarbohydrateRepresentation, @@ -45,4 +46,4 @@ export const CarbohydrateRepresentationProvider: StructureRepresentationProvider defaultColorTheme: { name: 'carbohydrate-symbol' }, defaultSizeTheme: { name: 'uniform' }, isApplicable: (structure: Structure) => structure.carbohydrates.elements.length > 0 -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/structure/representation/cartoon.ts b/src/mol-repr/structure/representation/cartoon.ts index 8b110a87b128c96daad2b01a8a55689905998c78..166e7bae184ad880ba7fa9058c0550335b38943a 100644 --- a/src/mol-repr/structure/representation/cartoon.ts +++ b/src/mol-repr/structure/representation/cartoon.ts @@ -55,7 +55,8 @@ export function CartoonRepresentation(ctx: RepresentationContext, getParams: Rep return Representation.createMulti('Cartoon', ctx, getParams, StructureRepresentationStateBuilder, CartoonVisuals as unknown as Representation.Def<Structure, CartoonParams>) } -export const CartoonRepresentationProvider: StructureRepresentationProvider<CartoonParams> = { +export const CartoonRepresentationProvider = StructureRepresentationProvider({ + name: 'cartoon', label: 'Cartoon', description: 'Displays ribbons, planks, tubes smoothly following the trace atoms of polymers.', factory: CartoonRepresentation, @@ -68,4 +69,4 @@ export const CartoonRepresentationProvider: StructureRepresentationProvider<Cart attach: (ctx: CustomProperty.Context, structure: Structure) => SecondaryStructureProvider.attach(ctx, structure, void 0, true), detach: (_, data) => SecondaryStructureProvider.ref(data, false) } -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/structure/representation/ellipsoid.ts b/src/mol-repr/structure/representation/ellipsoid.ts index 9d8f9cf10bedc2f8764f4c40b33ad0520b3d9e2d..b481aebc5a85b7d5e126bd2b0fe455a7b6834db3 100644 --- a/src/mol-repr/structure/representation/ellipsoid.ts +++ b/src/mol-repr/structure/representation/ellipsoid.ts @@ -41,7 +41,8 @@ export function EllipsoidRepresentation(ctx: RepresentationContext, getParams: R return Representation.createMulti('Ellipsoid', ctx, getParams, StructureRepresentationStateBuilder, EllipsoidVisuals as unknown as Representation.Def<Structure, EllipsoidParams>) } -export const EllipsoidRepresentationProvider: StructureRepresentationProvider<EllipsoidParams> = { +export const EllipsoidRepresentationProvider = StructureRepresentationProvider({ + name: 'ellipsoid', label: 'Ellipsoid', description: 'Displays anisotropic displacement ellipsoids of atomic elements plus bonds as cylinders.', factory: EllipsoidRepresentation, @@ -50,4 +51,4 @@ export const EllipsoidRepresentationProvider: StructureRepresentationProvider<El defaultColorTheme: { name: 'element-symbol' }, defaultSizeTheme: { name: 'uniform' }, isApplicable: (structure: Structure) => structure.elementCount > 0 && structure.models.some(m => m.customProperties.has(AtomSiteAnisotrop.Descriptor)) -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/structure/representation/gaussian-surface.ts b/src/mol-repr/structure/representation/gaussian-surface.ts index 937be1af81bcca283521484956ef4b6e81381ae4..b72cb0c4323f6914fd0908c4142d0d01f90f21ea 100644 --- a/src/mol-repr/structure/representation/gaussian-surface.ts +++ b/src/mol-repr/structure/representation/gaussian-surface.ts @@ -35,7 +35,8 @@ export function GaussianSurfaceRepresentation(ctx: RepresentationContext, getPar return Representation.createMulti('Gaussian Surface', ctx, getParams, StructureRepresentationStateBuilder, GaussianSurfaceVisuals as unknown as Representation.Def<Structure, GaussianSurfaceParams>) } -export const GaussianSurfaceRepresentationProvider: StructureRepresentationProvider<GaussianSurfaceParams> = { +export const GaussianSurfaceRepresentationProvider = StructureRepresentationProvider({ + name: 'gaussian-surface', label: 'Gaussian Surface', description: 'Displays a gaussian molecular surface.', factory: GaussianSurfaceRepresentation, @@ -44,4 +45,4 @@ export const GaussianSurfaceRepresentationProvider: StructureRepresentationProvi defaultColorTheme: { name: 'polymer-id' }, defaultSizeTheme: { name: 'uniform' }, isApplicable: (structure: Structure) => structure.elementCount > 0 -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/structure/representation/gaussian-volume.ts b/src/mol-repr/structure/representation/gaussian-volume.ts index 7d8e00bb3262bab4666ed95409e49cfdac744c75..4f66376c01f4e27eeae1e88fcbfe49056c8770e7 100644 --- a/src/mol-repr/structure/representation/gaussian-volume.ts +++ b/src/mol-repr/structure/representation/gaussian-volume.ts @@ -28,7 +28,8 @@ export function GaussianVolumeRepresentation(ctx: RepresentationContext, getPara return Representation.createMulti('Gaussian Volume', ctx, getParams, StructureRepresentationStateBuilder, GaussianVolumeVisuals as unknown as Representation.Def<Structure, GaussianVolumeParams>) } -export const GaussianVolumeRepresentationProvider: StructureRepresentationProvider<GaussianVolumeParams> = { +export const GaussianVolumeRepresentationProvider = StructureRepresentationProvider({ + name: 'gaussian-volume', label: 'Gaussian Volume', description: 'Displays a gaussian molecular density using direct volume rendering.', factory: GaussianVolumeRepresentation, @@ -37,4 +38,4 @@ export const GaussianVolumeRepresentationProvider: StructureRepresentationProvid defaultColorTheme: { name: 'polymer-id' }, defaultSizeTheme: { name: 'uniform' }, isApplicable: (structure: Structure) => structure.elementCount > 0 -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/structure/representation/label.ts b/src/mol-repr/structure/representation/label.ts index a5de0013eabdf27f788bb70557f2b239d7256eda..68f97b02b0ff747dc903dff01fb0e22b87d078a2 100644 --- a/src/mol-repr/structure/representation/label.ts +++ b/src/mol-repr/structure/representation/label.ts @@ -32,7 +32,8 @@ export function LabelRepresentation(ctx: RepresentationContext, getParams: Repre return repr } -export const LabelRepresentationProvider: StructureRepresentationProvider<LabelParams> = { +export const LabelRepresentationProvider = StructureRepresentationProvider({ + name: 'label', label: 'Label', description: 'Displays labels.', factory: LabelRepresentation, @@ -41,4 +42,4 @@ export const LabelRepresentationProvider: StructureRepresentationProvider<LabelP defaultColorTheme: { name: 'uniform' }, defaultSizeTheme: { name: 'uniform' }, isApplicable: (structure: Structure) => structure.elementCount > 0 -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/structure/representation/molecular-surface.ts b/src/mol-repr/structure/representation/molecular-surface.ts index ae8dca9fa45760cdbad07c7bf95163f4fc56cbb0..81e46fd20a69b499b24fe0c60fe7ea2dd3a17298 100644 --- a/src/mol-repr/structure/representation/molecular-surface.ts +++ b/src/mol-repr/structure/representation/molecular-surface.ts @@ -33,7 +33,8 @@ export function MolecularSurfaceRepresentation(ctx: RepresentationContext, getPa return Representation.createMulti('Molecular Surface', ctx, getParams, StructureRepresentationStateBuilder, MolecularSurfaceVisuals as unknown as Representation.Def<Structure, MolecularSurfaceParams>) } -export const MolecularSurfaceRepresentationProvider: StructureRepresentationProvider<MolecularSurfaceParams> = { +export const MolecularSurfaceRepresentationProvider = StructureRepresentationProvider({ + name: 'molecular-surface', label: 'Molecular Surface', description: 'Displays a molecular surface.', factory: MolecularSurfaceRepresentation, @@ -42,4 +43,4 @@ export const MolecularSurfaceRepresentationProvider: StructureRepresentationProv defaultColorTheme: { name: 'polymer-id' }, defaultSizeTheme: { name: 'uniform' }, isApplicable: (structure: Structure) => structure.elementCount > 0 -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/structure/representation/orientation.ts b/src/mol-repr/structure/representation/orientation.ts index ce6c1907f0e16ab5079fd37a0c3512ee0e34dce3..f37d17b653ed0ffbfc27126131dac7023e67ee01 100644 --- a/src/mol-repr/structure/representation/orientation.ts +++ b/src/mol-repr/structure/representation/orientation.ts @@ -30,7 +30,8 @@ export function OrientationRepresentation(ctx: RepresentationContext, getParams: return Representation.createMulti('Orientation', ctx, getParams, StructureRepresentationStateBuilder, OrientationVisuals as unknown as Representation.Def<Structure, OrientationParams>) } -export const OrientationRepresentationProvider: StructureRepresentationProvider<OrientationParams> = { +export const OrientationRepresentationProvider = StructureRepresentationProvider({ + name: 'orientation', label: 'Orientation', description: 'Displays orientation ellipsoids for polymer chains.', factory: OrientationRepresentation, @@ -39,4 +40,4 @@ export const OrientationRepresentationProvider: StructureRepresentationProvider< defaultColorTheme: { name: 'polymer-id' }, defaultSizeTheme: { name: 'uniform' }, isApplicable: (structure: Structure) => structure.elementCount > 0 -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/structure/representation/point.ts b/src/mol-repr/structure/representation/point.ts index 6766e7380d8db08518f8ac793650e28943218141..1597904f8f250fc06c9819181655b65873d603e5 100644 --- a/src/mol-repr/structure/representation/point.ts +++ b/src/mol-repr/structure/representation/point.ts @@ -31,7 +31,8 @@ export function PointRepresentation(ctx: RepresentationContext, getParams: Repre return Representation.createMulti('Point', ctx, getParams, StructureRepresentationStateBuilder, PointVisuals as unknown as Representation.Def<Structure, PointParams>) } -export const PointRepresentationProvider: StructureRepresentationProvider<PointParams> = { +export const PointRepresentationProvider = StructureRepresentationProvider({ + name: 'point', label: 'Point', description: 'Displays elements (atoms, coarse spheres) as spheres.', factory: PointRepresentation, @@ -40,4 +41,4 @@ export const PointRepresentationProvider: StructureRepresentationProvider<PointP defaultColorTheme: { name: 'element-symbol' }, defaultSizeTheme: { name: 'physical' }, isApplicable: (structure: Structure) => structure.elementCount > 0 -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/structure/representation/putty.ts b/src/mol-repr/structure/representation/putty.ts index 2623e847ce1ee4fa64fc46755b516eb90b384dda..29504744dae1fafab864c0210ebb0281a24de2ad 100644 --- a/src/mol-repr/structure/representation/putty.ts +++ b/src/mol-repr/structure/representation/putty.ts @@ -43,7 +43,8 @@ export function PuttyRepresentation(ctx: RepresentationContext, getParams: Repre return Representation.createMulti('Putty', ctx, getParams, StructureRepresentationStateBuilder, PuttyVisuals as unknown as Representation.Def<Structure, PuttyParams>) } -export const PuttyRepresentationProvider: StructureRepresentationProvider<PuttyParams> = { +export const PuttyRepresentationProvider = StructureRepresentationProvider({ + name: 'putty', label: 'Putty', description: 'Displays a tube smoothly following the trace atoms of polymers.', factory: PuttyRepresentation, @@ -52,4 +53,4 @@ export const PuttyRepresentationProvider: StructureRepresentationProvider<PuttyP defaultColorTheme: { name: 'polymer-id' }, defaultSizeTheme: { name: 'uncertainty' }, isApplicable: (structure: Structure) => structure.polymerResidueCount > 0 -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/structure/representation/spacefill.ts b/src/mol-repr/structure/representation/spacefill.ts index fb6b69862cb5f45483ac7522f8d8a52b79315c8e..fe34dcaceef0d34f6af49f8269761dcc443e51ca 100644 --- a/src/mol-repr/structure/representation/spacefill.ts +++ b/src/mol-repr/structure/representation/spacefill.ts @@ -31,7 +31,8 @@ export function SpacefillRepresentation(ctx: RepresentationContext, getParams: R return Representation.createMulti('Spacefill', ctx, getParams, StructureRepresentationStateBuilder, SpacefillVisuals as unknown as Representation.Def<Structure, SpacefillParams>) } -export const SpacefillRepresentationProvider: StructureRepresentationProvider<SpacefillParams> = { +export const SpacefillRepresentationProvider = StructureRepresentationProvider({ + name: 'spacefill', label: 'Spacefill', description: 'Displays atomic/coarse elements as spheres.', factory: SpacefillRepresentation, @@ -40,4 +41,4 @@ export const SpacefillRepresentationProvider: StructureRepresentationProvider<Sp defaultColorTheme: { name: 'element-symbol' }, defaultSizeTheme: { name: 'physical' }, isApplicable: (structure: Structure) => structure.elementCount > 0 -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/volume/direct-volume.ts b/src/mol-repr/volume/direct-volume.ts index 7c01c26c392918a930c9867e17002e606dd78c48..840b57a9d1c075b47eeb9d24ffcfccbc30d16967 100644 --- a/src/mol-repr/volume/direct-volume.ts +++ b/src/mol-repr/volume/direct-volume.ts @@ -179,7 +179,8 @@ export function DirectVolumeRepresentation(ctx: RepresentationContext, getParams return VolumeRepresentation('Direct Volume', ctx, getParams, DirectVolumeVisual) } -export const DirectVolumeRepresentationProvider: VolumeRepresentationProvider<DirectVolumeParams> = { +export const DirectVolumeRepresentationProvider = VolumeRepresentationProvider({ + name: 'direct-volume', label: 'Direct Volume', description: 'Direct volume rendering of volumetric data.', factory: DirectVolumeRepresentation, @@ -188,4 +189,4 @@ export const DirectVolumeRepresentationProvider: VolumeRepresentationProvider<Di defaultColorTheme: { name: 'uniform' }, defaultSizeTheme: { name: 'uniform' }, isApplicable: (volume: VolumeData) => volume.data.data.length > 0 -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/volume/isosurface.ts b/src/mol-repr/volume/isosurface.ts index 8657b53842beabe1f358e2cf91bf7300a0ae8d43..3bea659f16ac74e8d0bcb880b296ae28abe51fc5 100644 --- a/src/mol-repr/volume/isosurface.ts +++ b/src/mol-repr/volume/isosurface.ts @@ -164,7 +164,8 @@ export function IsosurfaceRepresentation(ctx: RepresentationContext, getParams: return Representation.createMulti('Isosurface', ctx, getParams, Representation.StateBuilder, IsosurfaceVisuals as unknown as Representation.Def<VolumeData, IsosurfaceParams>) } -export const IsosurfaceRepresentationProvider: VolumeRepresentationProvider<IsosurfaceParams> = { +export const IsosurfaceRepresentationProvider = VolumeRepresentationProvider({ + name: 'isosurface', label: 'Isosurface', description: 'Displays an isosurface of volumetric data.', factory: IsosurfaceRepresentation, @@ -173,4 +174,4 @@ export const IsosurfaceRepresentationProvider: VolumeRepresentationProvider<Isos defaultColorTheme: { name: 'uniform' }, defaultSizeTheme: { name: 'uniform' }, isApplicable: (volume: VolumeData) => volume.data.data.length > 0 -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mol-repr/volume/registry.ts b/src/mol-repr/volume/registry.ts index 3177b30bbe29691774232f16977f77a74bb0268c..13119ecdeed793027fa423c55a1cb0451f3894fa 100644 --- a/src/mol-repr/volume/registry.ts +++ b/src/mol-repr/volume/registry.ts @@ -4,16 +4,19 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { RepresentationProvider, RepresentationRegistry, Representation } from '../representation'; +import { RepresentationRegistry, Representation } from '../representation'; import { VolumeData } from '../../mol-model/volume'; import { IsosurfaceRepresentationProvider } from './isosurface'; +import { objectForEach } from '../../mol-util/object'; export class VolumeRepresentationRegistry extends RepresentationRegistry<VolumeData, Representation.State> { constructor() { super() Object.keys(BuiltInVolumeRepresentations).forEach(name => { - const p = (BuiltInVolumeRepresentations as { [k: string]: RepresentationProvider<VolumeData, any, Representation.State> })[name] - this.add(name, p) + objectForEach(BuiltInVolumeRepresentations, (p, k) => { + if (p.name !== k) throw new Error(`Fix BuiltInVolumeRepresentations to have matching names. ${p.name} ${k}`); + this.add(p as any) + }) }) } } diff --git a/src/mol-repr/volume/representation.ts b/src/mol-repr/volume/representation.ts index f8625e4f0618de01e98273b4028e8314d919b5a1..762f3a0a44b066022fd95e2910d36e3ec4e03aa3 100644 --- a/src/mol-repr/volume/representation.ts +++ b/src/mol-repr/volume/representation.ts @@ -200,7 +200,8 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet export interface VolumeRepresentation<P extends VolumeParams> extends Representation<VolumeData, P> { } -export type VolumeRepresentationProvider<P extends VolumeParams> = RepresentationProvider<VolumeData, P, Representation.State> +export type VolumeRepresentationProvider<P extends VolumeParams, Id extends string = string> = RepresentationProvider<VolumeData, P, Representation.State, Id> +export function VolumeRepresentationProvider<P extends VolumeParams, Id extends string>(p: VolumeRepresentationProvider<P, Id>): VolumeRepresentationProvider<P, Id> { return p; } // diff --git a/src/mol-theme/color.ts b/src/mol-theme/color.ts index e1481c7fff6eb8fb5c3dcb950b6820177c5f93e0..2e34f61fec8cef0b50ca96301982423eaf867e70 100644 --- a/src/mol-theme/color.ts +++ b/src/mol-theme/color.ts @@ -70,8 +70,8 @@ namespace ColorTheme { return themeA.contextHash === themeB.contextHash && themeA.factory === themeB.factory && deepEqual(themeA.props, themeB.props) } - export interface Provider<P extends PD.Params> extends ThemeProvider<ColorTheme<P>, P> { } - export const EmptyProvider: Provider<{}> = { label: '', category: '', factory: EmptyFactory, getParams: () => ({}), defaultValues: {}, isApplicable: () => true } + export interface Provider<P extends PD.Params = any, Id extends string = string> extends ThemeProvider<ColorTheme<P>, P, Id> { } + export const EmptyProvider: Provider<{}> = { name: '', label: '', category: '', factory: EmptyFactory, getParams: () => ({}), defaultValues: {}, isApplicable: () => true } export type Registry = ThemeRegistry<ColorTheme<any>> export function createRegistry() { @@ -81,6 +81,8 @@ namespace ColorTheme { export type ParamValues<C extends ColorTheme.Provider<any>> = C extends ColorTheme.Provider<infer P> ? PD.Values<P> : never } +export function ColorThemeProvider<P extends PD.Params, Id extends string>(p: ColorTheme.Provider<P, Id>): ColorTheme.Provider<P, Id> { return p; } + export const BuiltInColorThemes = { 'carbohydrate-symbol': CarbohydrateSymbolColorThemeProvider, 'chain-id': ChainIdColorThemeProvider, diff --git a/src/mol-theme/color/carbohydrate-symbol.ts b/src/mol-theme/color/carbohydrate-symbol.ts index 39d41725491f48c9bf5ee3fcccdcc363d401d4c5..d3e306bef684c075cf20a755c6412adf89355f7b 100644 --- a/src/mol-theme/color/carbohydrate-symbol.ts +++ b/src/mol-theme/color/carbohydrate-symbol.ts @@ -60,7 +60,8 @@ export function CarbohydrateSymbolColorTheme(ctx: ThemeDataContext, props: PD.Va } } -export const CarbohydrateSymbolColorThemeProvider: ColorTheme.Provider<CarbohydrateSymbolColorThemeParams> = { +export const CarbohydrateSymbolColorThemeProvider: ColorTheme.Provider<CarbohydrateSymbolColorThemeParams, 'carbohydrate-symbol'> = { + name: 'carbohydrate-symbol', label: 'Carbohydrate Symbol', category: ColorTheme.Category.Residue, factory: CarbohydrateSymbolColorTheme, diff --git a/src/mol-theme/color/chain-id.ts b/src/mol-theme/color/chain-id.ts index 46b587c708517f24ee6c052fe6f7c47376c21a87..de4438232c901ec46aaca9545277ee7317b6a088 100644 --- a/src/mol-theme/color/chain-id.ts +++ b/src/mol-theme/color/chain-id.ts @@ -117,7 +117,8 @@ export function ChainIdColorTheme(ctx: ThemeDataContext, props: PD.Values<ChainI } } -export const ChainIdColorThemeProvider: ColorTheme.Provider<ChainIdColorThemeParams> = { +export const ChainIdColorThemeProvider: ColorTheme.Provider<ChainIdColorThemeParams, 'chain-id'> = { + name: 'chain-id', label: 'Chain Id', category: ColorTheme.Category.Chain, factory: ChainIdColorTheme, diff --git a/src/mol-theme/color/element-index.ts b/src/mol-theme/color/element-index.ts index 0e796512a00b6af51a604b3a92276aa49f1bf17f..b085cee85b45d2e920c333419d26c003ca4d28fe 100644 --- a/src/mol-theme/color/element-index.ts +++ b/src/mol-theme/color/element-index.ts @@ -71,7 +71,8 @@ export function ElementIndexColorTheme(ctx: ThemeDataContext, props: PD.Values<E } } -export const ElementIndexColorThemeProvider: ColorTheme.Provider<ElementIndexColorThemeParams> = { +export const ElementIndexColorThemeProvider: ColorTheme.Provider<ElementIndexColorThemeParams, 'element-index'> = { + name: 'element-index', label: 'Element Index', category: ColorTheme.Category.Atom, factory: ElementIndexColorTheme, diff --git a/src/mol-theme/color/element-symbol.ts b/src/mol-theme/color/element-symbol.ts index 3582d1414f04afaac51849cf3cd262c4b8c6af71..906bf70af4df5bab81e955fc0ea107cf506d8256 100644 --- a/src/mol-theme/color/element-symbol.ts +++ b/src/mol-theme/color/element-symbol.ts @@ -67,7 +67,8 @@ export function ElementSymbolColorTheme(ctx: ThemeDataContext, props: PD.Values< } } -export const ElementSymbolColorThemeProvider: ColorTheme.Provider<ElementSymbolColorThemeParams> = { +export const ElementSymbolColorThemeProvider: ColorTheme.Provider<ElementSymbolColorThemeParams, 'element-symbol'> = { + name: 'element-symbol', label: 'Element Symbol', category: ColorTheme.Category.Atom, factory: ElementSymbolColorTheme, diff --git a/src/mol-theme/color/entity-source.ts b/src/mol-theme/color/entity-source.ts index 641839576b59aba23a4e8ac23672aa9150928f64..e7acc9db0c43ed44c55122aad3c1122481e1065a 100644 --- a/src/mol-theme/color/entity-source.ts +++ b/src/mol-theme/color/entity-source.ts @@ -173,7 +173,8 @@ export function EntitySourceColorTheme(ctx: ThemeDataContext, props: PD.Values<E } } -export const EntitySourceColorThemeProvider: ColorTheme.Provider<EntitySourceColorThemeParams> = { +export const EntitySourceColorThemeProvider: ColorTheme.Provider<EntitySourceColorThemeParams, 'entity-source'> = { + name: 'entity-source', label: 'Entity Source', category: ColorTheme.Category.Chain, factory: EntitySourceColorTheme, diff --git a/src/mol-theme/color/hydrophobicity.ts b/src/mol-theme/color/hydrophobicity.ts index 0879eba6cb1ffa117f0e410320afc056e1f01dfd..10ce176cf29ec89d2d7cd1debc70df545bff72a0 100644 --- a/src/mol-theme/color/hydrophobicity.ts +++ b/src/mol-theme/color/hydrophobicity.ts @@ -92,7 +92,8 @@ export function HydrophobicityColorTheme(ctx: ThemeDataContext, props: PD.Values } } -export const HydrophobicityColorThemeProvider: ColorTheme.Provider<HydrophobicityColorThemeParams> = { +export const HydrophobicityColorThemeProvider: ColorTheme.Provider<HydrophobicityColorThemeParams, 'hydrophobicity'> = { + name: 'hydrophobicity', label: 'Hydrophobicity', category: ColorTheme.Category.Residue, factory: HydrophobicityColorTheme, diff --git a/src/mol-theme/color/illustrative.ts b/src/mol-theme/color/illustrative.ts index 9b86d8b97a76e5ac85504745ffb30c46fa28b17a..cee5e8e87c5638cde2cb336821a4f2bc6eeabaf7 100644 --- a/src/mol-theme/color/illustrative.ts +++ b/src/mol-theme/color/illustrative.ts @@ -74,7 +74,8 @@ export function IllustrativeColorTheme(ctx: ThemeDataContext, props: PD.Values<I } } -export const IllustrativeColorThemeProvider: ColorTheme.Provider<IllustrativeColorThemeParams> = { +export const IllustrativeColorThemeProvider: ColorTheme.Provider<IllustrativeColorThemeParams, 'illustrative'> = { + name: 'illustrative', label: 'Illustrative', category: ColorTheme.Category.Misc, factory: IllustrativeColorTheme, diff --git a/src/mol-theme/color/model-index.ts b/src/mol-theme/color/model-index.ts index b8d49fe68fee5595cf0a3a025545f73bbf6778a1..46e6b2f665e7e2abfff1ebaa924ffc722fbb0c14 100644 --- a/src/mol-theme/color/model-index.ts +++ b/src/mol-theme/color/model-index.ts @@ -64,7 +64,8 @@ export function ModelIndexColorTheme(ctx: ThemeDataContext, props: PD.Values<Mod } } -export const ModelIndexColorThemeProvider: ColorTheme.Provider<ModelIndexColorThemeParams> = { +export const ModelIndexColorThemeProvider: ColorTheme.Provider<ModelIndexColorThemeParams, 'model-index'> = { + name: 'model-index', label: 'Model Index', category: ColorTheme.Category.Chain, factory: ModelIndexColorTheme, diff --git a/src/mol-theme/color/molecule-type.ts b/src/mol-theme/color/molecule-type.ts index 1692e649728c5564deef6859b770c0bd6677e060..74a700999187ba2dd1d18d5146899cc917089529 100644 --- a/src/mol-theme/color/molecule-type.ts +++ b/src/mol-theme/color/molecule-type.ts @@ -76,7 +76,8 @@ export function MoleculeTypeColorTheme(ctx: ThemeDataContext, props: PD.Values<M } } -export const MoleculeTypeColorThemeProvider: ColorTheme.Provider<MoleculeTypeColorThemeParams> = { +export const MoleculeTypeColorThemeProvider: ColorTheme.Provider<MoleculeTypeColorThemeParams, 'molecule-type'> = { + name: 'molecule-type', label: 'Molecule Type', category: ColorTheme.Category.Residue, factory: MoleculeTypeColorTheme, diff --git a/src/mol-theme/color/occupancy.ts b/src/mol-theme/color/occupancy.ts index 47686503c292c9da785e2fd077b2617de628be14..a2da83eef6a61a94a4bd4609159cce50844ac7dd 100644 --- a/src/mol-theme/color/occupancy.ts +++ b/src/mol-theme/color/occupancy.ts @@ -58,7 +58,8 @@ export function OccupancyColorTheme(ctx: ThemeDataContext, props: PD.Values<Occu } } -export const OccupancyColorThemeProvider: ColorTheme.Provider<OccupancyColorThemeParams> = { +export const OccupancyColorThemeProvider: ColorTheme.Provider<OccupancyColorThemeParams, 'occupancy'> = { + name: 'occupancy', label: 'Occupancy', category: ColorTheme.Category.Atom, factory: OccupancyColorTheme, diff --git a/src/mol-theme/color/operator-hkl.ts b/src/mol-theme/color/operator-hkl.ts index b6adab5f2161bd87dd6eb2c6a8fe864295714184..45c5c8a837c3266e6fd21605af5cb098b062c93f 100644 --- a/src/mol-theme/color/operator-hkl.ts +++ b/src/mol-theme/color/operator-hkl.ts @@ -117,7 +117,8 @@ export function OperatorHklColorTheme(ctx: ThemeDataContext, props: PD.Values<Op } } -export const OperatorHklColorThemeProvider: ColorTheme.Provider<OperatorHklColorThemeParams> = { +export const OperatorHklColorThemeProvider: ColorTheme.Provider<OperatorHklColorThemeParams, 'operator-hkl'> = { + name: 'operator-hkl', label: 'Operator HKL', category: ColorTheme.Category.Symmetry, factory: OperatorHklColorTheme, diff --git a/src/mol-theme/color/operator-name.ts b/src/mol-theme/color/operator-name.ts index 3c4b60895f0dabda9af8c4bf6a817ed6f11d5830..6ea025e90fde8d7b753aa0a9651a1425fcdaeb70 100644 --- a/src/mol-theme/color/operator-name.ts +++ b/src/mol-theme/color/operator-name.ts @@ -83,7 +83,8 @@ export function OperatorNameColorTheme(ctx: ThemeDataContext, props: PD.Values<O } } -export const OperatorNameColorThemeProvider: ColorTheme.Provider<OperatorNameColorThemeParams> = { +export const OperatorNameColorThemeProvider: ColorTheme.Provider<OperatorNameColorThemeParams, 'operator-name'> = { + name: 'operator-name', label: 'Operator Name', category: ColorTheme.Category.Symmetry, factory: OperatorNameColorTheme, diff --git a/src/mol-theme/color/polymer-id.ts b/src/mol-theme/color/polymer-id.ts index 68649703483620535f88e05a03f19076ad7831d2..4749bfa52c46542bd6a97d2333c330b25314a241 100644 --- a/src/mol-theme/color/polymer-id.ts +++ b/src/mol-theme/color/polymer-id.ts @@ -126,7 +126,8 @@ export function PolymerIdColorTheme(ctx: ThemeDataContext, props: PD.Values<Poly } } -export const PolymerIdColorThemeProvider: ColorTheme.Provider<PolymerIdColorThemeParams> = { +export const PolymerIdColorThemeProvider: ColorTheme.Provider<PolymerIdColorThemeParams, 'polymer-id'> = { + name: 'polymer-id', label: 'Polymer Chain Id', category: ColorTheme.Category.Chain, factory: PolymerIdColorTheme, diff --git a/src/mol-theme/color/polymer-index.ts b/src/mol-theme/color/polymer-index.ts index 6d6c86dc9ae258c16509e6478d0b1a63ce6d974f..f514c0804e4941e2c78a8d7146709ca67b780e63 100644 --- a/src/mol-theme/color/polymer-index.ts +++ b/src/mol-theme/color/polymer-index.ts @@ -86,7 +86,8 @@ export function PolymerIndexColorTheme(ctx: ThemeDataContext, props: PD.Values<P } } -export const PolymerIndexColorThemeProvider: ColorTheme.Provider<PolymerIndexColorThemeParams> = { +export const PolymerIndexColorThemeProvider: ColorTheme.Provider<PolymerIndexColorThemeParams, 'polymer-index'> = { + name: 'polymer-index', label: 'Polymer Chain Instance', category: ColorTheme.Category.Chain, factory: PolymerIndexColorTheme, diff --git a/src/mol-theme/color/residue-name.ts b/src/mol-theme/color/residue-name.ts index 741601e1cd2e6f37dd068d3d59857ac24b4e45de..dc341a3112288acdf64366475de46bf6d0a67194 100644 --- a/src/mol-theme/color/residue-name.ts +++ b/src/mol-theme/color/residue-name.ts @@ -128,7 +128,8 @@ export function ResidueNameColorTheme(ctx: ThemeDataContext, props: PD.Values<Re } } -export const ResidueNameColorThemeProvider: ColorTheme.Provider<ResidueNameColorThemeParams> = { +export const ResidueNameColorThemeProvider: ColorTheme.Provider<ResidueNameColorThemeParams, 'residue-name'> = { + name: 'residue-name', label: 'Residue Name', category: ColorTheme.Category.Residue, factory: ResidueNameColorTheme, diff --git a/src/mol-theme/color/secondary-structure.ts b/src/mol-theme/color/secondary-structure.ts index c3854195eb4e536ebfe50c20ba10ce0f1bf5bd34..34ed6fd0e18c654420f4eac9ec57a5f6938a30d1 100644 --- a/src/mol-theme/color/secondary-structure.ts +++ b/src/mol-theme/color/secondary-structure.ts @@ -111,7 +111,8 @@ export function SecondaryStructureColorTheme(ctx: ThemeDataContext, props: PD.Va } } -export const SecondaryStructureColorThemeProvider: ColorTheme.Provider<SecondaryStructureColorThemeParams> = { +export const SecondaryStructureColorThemeProvider: ColorTheme.Provider<SecondaryStructureColorThemeParams, 'secondary-structure'> = { + name: 'secondary-structure', label: 'Secondary Structure', category: ColorTheme.Category.Residue, factory: SecondaryStructureColorTheme, diff --git a/src/mol-theme/color/sequence-id.ts b/src/mol-theme/color/sequence-id.ts index 26881241a45d546ec50da3cba5c17b4cf6314487..3c5d062ba38b1896264cdb1fc53fe20096bc4af0 100644 --- a/src/mol-theme/color/sequence-id.ts +++ b/src/mol-theme/color/sequence-id.ts @@ -99,7 +99,8 @@ export function SequenceIdColorTheme(ctx: ThemeDataContext, props: PD.Values<Seq } } -export const SequenceIdColorThemeProvider: ColorTheme.Provider<SequenceIdColorThemeParams> = { +export const SequenceIdColorThemeProvider: ColorTheme.Provider<SequenceIdColorThemeParams, 'sequence-id'> = { + name: 'sequence-id', label: 'Sequence Id', category: ColorTheme.Category.Residue, factory: SequenceIdColorTheme, diff --git a/src/mol-theme/color/shape-group.ts b/src/mol-theme/color/shape-group.ts index 8a8232657dec24eac00254c08ba2bf2a458b4dc7..12900fa1390e35cf3b517fa876f1845cf43791b8 100644 --- a/src/mol-theme/color/shape-group.ts +++ b/src/mol-theme/color/shape-group.ts @@ -35,7 +35,8 @@ export function ShapeGroupColorTheme(ctx: ThemeDataContext, props: PD.Values<Sha } } -export const ShapeGroupColorThemeProvider: ColorTheme.Provider<ShapeGroupColorThemeParams> = { +export const ShapeGroupColorThemeProvider: ColorTheme.Provider<ShapeGroupColorThemeParams, 'shape-group'> = { + name: 'shape-group', label: 'Shape Group', category: ColorTheme.Category.Misc, factory: ShapeGroupColorTheme, diff --git a/src/mol-theme/color/uncertainty.ts b/src/mol-theme/color/uncertainty.ts index 512dbea67781636037f14c4bbf34b9cf7202acf4..66f71fb766d9f8b9325aed2e7a478f3d0c9721f5 100644 --- a/src/mol-theme/color/uncertainty.ts +++ b/src/mol-theme/color/uncertainty.ts @@ -62,7 +62,8 @@ export function UncertaintyColorTheme(ctx: ThemeDataContext, props: PD.Values<Un } } -export const UncertaintyColorThemeProvider: ColorTheme.Provider<UncertaintyColorThemeParams> = { +export const UncertaintyColorThemeProvider: ColorTheme.Provider<UncertaintyColorThemeParams, 'uncertainty'> = { + name: 'uncertainty', label: 'Uncertainty/Disorder', category: ColorTheme.Category.Atom, factory: UncertaintyColorTheme, diff --git a/src/mol-theme/color/uniform.ts b/src/mol-theme/color/uniform.ts index 2fd01719375da61b3e1693a7ba213095e8895981..e86b5fbc0b2a84b77d8dbc9adccd42f38db9bc0d 100644 --- a/src/mol-theme/color/uniform.ts +++ b/src/mol-theme/color/uniform.ts @@ -35,7 +35,8 @@ export function UniformColorTheme(ctx: ThemeDataContext, props: PD.Values<Unifor } } -export const UniformColorThemeProvider: ColorTheme.Provider<UniformColorThemeParams> = { +export const UniformColorThemeProvider: ColorTheme.Provider<UniformColorThemeParams, 'uniform'> = { + name: 'uniform', label: 'Uniform', category: ColorTheme.Category.Misc, factory: UniformColorTheme, diff --git a/src/mol-theme/color/unit-index.ts b/src/mol-theme/color/unit-index.ts index 3cc6cdcf26bbd93a71bda07611a6e1201cd149c7..3a58492bb95ba69250bd407bebe500aad06b6814 100644 --- a/src/mol-theme/color/unit-index.ts +++ b/src/mol-theme/color/unit-index.ts @@ -71,7 +71,8 @@ export function UnitIndexColorTheme(ctx: ThemeDataContext, props: PD.Values<Unit } } -export const UnitIndexColorThemeProvider: ColorTheme.Provider<UnitIndexColorThemeParams> = { +export const UnitIndexColorThemeProvider: ColorTheme.Provider<UnitIndexColorThemeParams, 'unit-index'> = { + name: 'unit-index', label: 'Chain Instance', category: ColorTheme.Category.Chain, factory: UnitIndexColorTheme, diff --git a/src/mol-theme/size.ts b/src/mol-theme/size.ts index a1dace2fd0ee280188ded8ae79f44b9fdb2fbe87..bd5bfe16e01ef5bd6894aba6efed60c1d7eada54 100644 --- a/src/mol-theme/size.ts +++ b/src/mol-theme/size.ts @@ -31,8 +31,8 @@ namespace SizeTheme { return themeA.factory === themeB.factory && deepEqual(themeA.props, themeB.props) } - export interface Provider<P extends PD.Params> extends ThemeProvider<SizeTheme<P>, P> { } - export const EmptyProvider: Provider<{}> = { label: '', category: '', factory: EmptyFactory, getParams: () => ({}), defaultValues: {}, isApplicable: () => true } + export interface Provider<P extends PD.Params = any, Id extends string = string> extends ThemeProvider<SizeTheme<P>, P, Id> { } + export const EmptyProvider: Provider<{}> = { name: '', label: '', category: '', factory: EmptyFactory, getParams: () => ({}), defaultValues: {}, isApplicable: () => true } export type Registry = ThemeRegistry<SizeTheme<any>> export function createRegistry() { diff --git a/src/mol-theme/size/physical.ts b/src/mol-theme/size/physical.ts index 8622967d19f8e774b71b9446d580530e5f9ce01d..441c555c6a5be2f18b0d2105d223d75e358b2283 100644 --- a/src/mol-theme/size/physical.ts +++ b/src/mol-theme/size/physical.ts @@ -56,7 +56,8 @@ export function PhysicalSizeTheme(ctx: ThemeDataContext, props: PD.Values<Physic } } -export const PhysicalSizeThemeProvider: SizeTheme.Provider<PhysicalSizeThemeParams> = { +export const PhysicalSizeThemeProvider: SizeTheme.Provider<PhysicalSizeThemeParams, 'physical'> = { + name: 'physical', label: 'Physical', category: '', factory: PhysicalSizeTheme, diff --git a/src/mol-theme/size/shape-group.ts b/src/mol-theme/size/shape-group.ts index b7eaa993fe5d1afcf5af100b6c4fb2ce215f2c26..811b1cb9598d39e8c7889142cb8123ca89319405 100644 --- a/src/mol-theme/size/shape-group.ts +++ b/src/mol-theme/size/shape-group.ts @@ -34,7 +34,8 @@ export function ShapeGroupSizeTheme(ctx: ThemeDataContext, props: PD.Values<Shap } } -export const ShapeGroupSizeThemeProvider: SizeTheme.Provider<ShapeGroupSizeThemeParams> = { +export const ShapeGroupSizeThemeProvider: SizeTheme.Provider<ShapeGroupSizeThemeParams, 'shape-group'> = { + name: 'shape-group', label: 'Shape Group', category: '', factory: ShapeGroupSizeTheme, diff --git a/src/mol-theme/size/uncertainty.ts b/src/mol-theme/size/uncertainty.ts index bbeec077745086a04cdb72d76cd9ef911cd0595f..17d988096d37315551456eb2daf7b6798942bb45 100644 --- a/src/mol-theme/size/uncertainty.ts +++ b/src/mol-theme/size/uncertainty.ts @@ -52,7 +52,8 @@ export function UncertaintySizeTheme(ctx: ThemeDataContext, props: PD.Values<Unc } } -export const UncertaintySizeThemeProvider: SizeTheme.Provider<UncertaintySizeThemeParams> = { +export const UncertaintySizeThemeProvider: SizeTheme.Provider<UncertaintySizeThemeParams, 'uncertainty'> = { + name: 'uncertainty', label: 'Uncertainty/Disorder', category: '', factory: UncertaintySizeTheme, diff --git a/src/mol-theme/size/uniform.ts b/src/mol-theme/size/uniform.ts index 32b2718744f145c5ec3540eefb8a7326f46f7d0a..05ca264927adc31f278cd044a4317e61e8b70c64 100644 --- a/src/mol-theme/size/uniform.ts +++ b/src/mol-theme/size/uniform.ts @@ -30,7 +30,8 @@ export function UniformSizeTheme(ctx: ThemeDataContext, props: PD.Values<Uniform } } -export const UniformSizeThemeProvider: SizeTheme.Provider<UniformSizeThemeParams> = { +export const UniformSizeThemeProvider: SizeTheme.Provider<UniformSizeThemeParams, 'uniform'> = { + name: 'uniform', label: 'Uniform', category: '', factory: UniformSizeTheme, diff --git a/src/mol-theme/theme.ts b/src/mol-theme/theme.ts index 1ed6dbce22cf95c6b8e486e390cacd730595cad6..185feacc45dceef8f8e1c310edb16607006e2466 100644 --- a/src/mol-theme/theme.ts +++ b/src/mol-theme/theme.ts @@ -11,6 +11,7 @@ import { VolumeData } from '../mol-model/volume'; import { ParamDefinition as PD } from '../mol-util/param-definition'; import { Shape } from '../mol-model/shape'; import { CustomProperty } from '../mol-model-props/common/custom-property'; +import { objectForEach } from '../mol-util/object'; export interface ThemeRegistryContext { colorThemeRegistry: ColorTheme.Registry @@ -64,7 +65,8 @@ namespace Theme { // -export interface ThemeProvider<T extends ColorTheme<P> | SizeTheme<P>, P extends PD.Params> { +export interface ThemeProvider<T extends ColorTheme<P> | SizeTheme<P>, P extends PD.Params, Id extends string = string> { + readonly name: Id readonly label: string readonly category: string readonly factory: (ctx: ThemeDataContext, props: PD.Values<P>) => T @@ -91,7 +93,10 @@ export class ThemeRegistry<T extends ColorTheme<any> | SizeTheme<any>> { get types(): [string, string, string][] { return getTypes(this._list) } constructor(builtInThemes: { [k: string]: ThemeProvider<T, any> }, private emptyProvider: ThemeProvider<T, any>) { - Object.keys(builtInThemes).forEach(name => this.add(name, builtInThemes[name])) + objectForEach(builtInThemes, (p, k) => { + if (p.name !== k) throw new Error(`Fix build in themes to have matching names. ${p.name} ${k}`); + this.add(p as any) + }) } private sort() { @@ -103,14 +108,19 @@ export class ThemeRegistry<T extends ColorTheme<any> | SizeTheme<any>> { }); } - add<P extends PD.Params>(name: string, provider: ThemeProvider<T, P>) { + add<P extends PD.Params>(provider: ThemeProvider<T, P>) { + if (this._map.has(provider.name)) { + throw new Error(`${provider.name} already registered.`); + } + + const name = provider.name; this._list.push({ name, provider }) this._map.set(name, provider) this._name.set(provider, name) this.sort(); } - remove(name: string) { + remove(provider: ThemeProvider<T, any>) { this._list.splice(this._list.findIndex(e => e.name === name), 1) const p = this._map.get(name); if (p) { diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index 809f990c31456dae3e0c5a3221f3fa7f0e69cb7e..0aad1234bcabd937702f3d2f57cf18a2ab0c1e33 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -199,8 +199,8 @@ export namespace ParamDefinition { isExpanded?: boolean, isFlat?: boolean } - export function Group<T>(params: For<T>, info?: Info & { isExpanded?: boolean, isFlat?: boolean }): Group<Normalize<T>> { - const ret = setInfo<Group<Normalize<T>>>({ type: 'group', defaultValue: getDefaultValues(params as any as Params) as any, params: params as any as Params }, info); + export function Group<T>(params: For<T>, info?: Info & { isExpanded?: boolean, isFlat?: boolean, customDefault?: any }): Group<Normalize<T>> { + const ret = setInfo<Group<Normalize<T>>>({ type: 'group', defaultValue: info?.customDefault || getDefaultValues(params as any as Params) as any, params: params as any as Params }, info); if (info && info.isExpanded) ret.isExpanded = info.isExpanded; if (info && info.isFlat) ret.isFlat = info.isFlat; return ret; diff --git a/webpack.config.common.js b/webpack.config.common.js index 070ac2bebe39213416f2493de1b19308add85466..386a5a8d8c4a9ad1b90a1eaf4b48ef21d23e2cf1 100644 --- a/webpack.config.common.js +++ b/webpack.config.common.js @@ -29,14 +29,6 @@ const sharedConfig = { // failOnError: false, // cwd: process.cwd(), // }), - new webpack.ProvidePlugin({ - '__assign': ['tslib', '__assign'], - '__extends': ['tslib', '__extends'], - '__awaiter': ['tslib', '__awaiter'], - '__generator': ['tslib', '__generator'], - '__spread': ['tslib', '__spread'], - '__spreadArrays': ['tslib', '__spreadArrays'], - }), new ExtraWatchWebpackPlugin({ files: [ './lib/**/*.scss', @@ -55,6 +47,9 @@ const sharedConfig = { path.resolve(__dirname, 'lib/') ], }, + watchOptions: { + aggregateTimeout: 750 + }, devtool: '' }