diff --git a/src/mol-app/component/color-theme.tsx b/src/mol-app/component/color-theme.tsx index e546c25bd4eaafd8da71102d14d122bf5a5b6c16..bf3c58078c39ac4674b18d09dd7be1a865c705f2 100644 --- a/src/mol-app/component/color-theme.tsx +++ b/src/mol-app/component/color-theme.tsx @@ -9,7 +9,7 @@ import { ColorTheme } from 'mol-theme/color'; import { Color } from 'mol-util/color'; export interface ColorThemeComponentProps { - colorTheme: ColorTheme + colorTheme: ColorTheme<any> } export interface ColorThemeComponentState { diff --git a/src/mol-geo/geometry/color-data.ts b/src/mol-geo/geometry/color-data.ts index 43c2bd3109c284ce351ef9f04a1a6b253ea6c310..1f4fb376a56cf1749fc400a2d2b99cb24d384661 100644 --- a/src/mol-geo/geometry/color-data.ts +++ b/src/mol-geo/geometry/color-data.ts @@ -22,7 +22,7 @@ export type ColorData = { dColorType: ValueCell<string>, } -export function createColors(locationIt: LocationIterator, colorTheme: ColorTheme, colorData?: ColorData): ColorData { +export function createColors(locationIt: LocationIterator, colorTheme: ColorTheme<any>, colorData?: ColorData): ColorData { switch (getGranularity(locationIt, colorTheme.granularity)) { case 'uniform': return createUniformColor(locationIt, colorTheme.color, colorData) case 'group': return createGroupColor(locationIt, colorTheme.color, colorData) diff --git a/src/mol-geo/geometry/size-data.ts b/src/mol-geo/geometry/size-data.ts index a1651cc4b101448934fc03aeed09779377b98855..6cb0e8b755d5be410438441fff5ef7f8e46e9e04 100644 --- a/src/mol-geo/geometry/size-data.ts +++ b/src/mol-geo/geometry/size-data.ts @@ -21,7 +21,7 @@ export type SizeData = { dSizeType: ValueCell<string>, } -export function createSizes(locationIt: LocationIterator, sizeTheme: SizeTheme, sizeData?: SizeData): SizeData { +export function createSizes(locationIt: LocationIterator, sizeTheme: SizeTheme<any>, sizeData?: SizeData): SizeData { switch (getGranularity(locationIt, sizeTheme.granularity)) { case 'uniform': return createUniformSize(locationIt, sizeTheme.size, sizeData) case 'group': return createGroupSize(locationIt, sizeTheme.size, sizeData) 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 7bfbff51a3c7105a2d45bef7cfd76d8a7db90c50..d739f926c065dc8969bd1833f4e696d45de133af 100644 --- a/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts +++ b/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts @@ -113,5 +113,6 @@ export const AssemblySymmetryClusterColorThemeProvider: ColorTheme.Provider<Asse label: 'RCSB Assembly Symmetry Cluster', factory: AssemblySymmetryClusterColorTheme, getParams: getAssemblySymmetryClusterColorThemeParams, - defaultValues: PD.getDefaultValues(AssemblySymmetryClusterColorThemeParams) + defaultValues: PD.getDefaultValues(AssemblySymmetryClusterColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && ctx.structure.models[0].customProperties.has(AssemblySymmetry.Descriptor) } \ No newline at end of file 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 948edad6cfe81e0a08819b3b10cef2c7b2be568b..61a09e969723d1c0d28ece8064cee69b88f11b95 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 @@ -12,6 +12,7 @@ import { StructureElement } from 'mol-model/structure'; import { CustomPropertyRegistry } from 'mol-plugin/util/custom-prop-registry'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { PluginBehavior } from '../../../behavior'; +import { ThemeDataContext } from 'mol-theme/theme'; export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: boolean }>({ name: 'pdbe-structure-quality-report-prop', @@ -34,13 +35,12 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo this.ctx.customModelProperties.register(this.provider); this.ctx.lociLabels.addProvider(labelPDBeValidation); - // TODO: support filtering of themes based on the input structure - // in this case, it would check structure.models[0].customProperties.has(StructureQualityReport.Descriptor) this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add('pdbe-structure-quality-report', { label: 'PDBe Structure Quality Report', factory: StructureQualityReportColorTheme, getParams: () => ({}), - defaultValues: {} + defaultValues: {}, + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && ctx.structure.models[0].customProperties.has(StructureQualityReport.Descriptor) }) } 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 e7c7ce4f56bcb76775d47642e46b3c4a50a9eb60..5fac2530910d894c4df21d9fd33e380737dfd2ae 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 @@ -31,9 +31,6 @@ export const RCSBAssemblySymmetry = PluginBehavior.create<{ autoAttach: boolean register(): void { this.ctx.customModelProperties.register(this.provider); this.ctx.lociLabels.addProvider(labelAssemblySymmetryAxes); - - // TODO: support filtering of themes and representations based on the input structure - // in this case, it would check structure.models[0].customProperties.has(AssemblySymmetry.Descriptor) this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add('rcsb-assembly-symmetry-cluster', AssemblySymmetryClusterColorThemeProvider) this.ctx.structureRepresentation.registry.add('rcsb-assembly-symmetry-axes', AssemblySymmetryAxesRepresentationProvider) } diff --git a/src/mol-plugin/context.ts b/src/mol-plugin/context.ts index 588fc0dc6212d1502a7db970819c1ff4ccc2b7f7..069805cb01d623126d81116f43fd632e0449076e 100644 --- a/src/mol-plugin/context.ts +++ b/src/mol-plugin/context.ts @@ -73,7 +73,7 @@ export class PluginContext { readonly structureRepresentation = { registry: new StructureRepresentationRegistry(), - themeCtx: { colorThemeRegistry: new ColorTheme.Registry(), sizeThemeRegistry: new SizeTheme.Registry() } as ThemeRegistryContext + themeCtx: { colorThemeRegistry: ColorTheme.createRegistry(), sizeThemeRegistry: SizeTheme.createRegistry() } as ThemeRegistryContext } readonly customModelProperties = new CustomPropertyRegistry(); diff --git a/src/mol-plugin/state/transforms/representation.ts b/src/mol-plugin/state/transforms/representation.ts index 443148667a10e9acc946c16eb85d9a53cdf230ec..942816e5e0463b49aef7da8014af37a51ca69958 100644 --- a/src/mol-plugin/state/transforms/representation.ts +++ b/src/mol-plugin/state/transforms/representation.ts @@ -50,21 +50,23 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({ from: SO.Molecule.Structure, to: SO.Molecule.Representation3D, params: (a, ctx: PluginContext) => { - const type = ctx.structureRepresentation.registry.get(ctx.structureRepresentation.registry.default.name); + const { registry, themeCtx } = ctx.structureRepresentation + const type = registry.get(registry.default.name); + const dataCtx = { structure: a.data } return ({ type: PD.Mapped<any>( - ctx.structureRepresentation.registry.default.name, - ctx.structureRepresentation.registry.types, - name => PD.Group<any>(ctx.structureRepresentation.registry.get(name).getParams(ctx.structureRepresentation.themeCtx, a.data))), + registry.default.name, + registry.types, + name => PD.Group<any>(registry.get(name).getParams(themeCtx, a.data))), colorTheme: PD.Mapped<any>( type.defaultColorTheme, - ctx.structureRepresentation.themeCtx.colorThemeRegistry.types, - name => PD.Group<any>(ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(name).getParams({ structure: a.data })) + themeCtx.colorThemeRegistry.getApplicableTypes(dataCtx), + name => PD.Group<any>(themeCtx.colorThemeRegistry.get(name).getParams(dataCtx)) ), sizeTheme: PD.Mapped<any>( type.defaultSizeTheme, - ctx.structureRepresentation.themeCtx.sizeThemeRegistry.types, - name => PD.Group<any>(ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(name).getParams({ structure: a.data })) + themeCtx.sizeThemeRegistry.types, + name => PD.Group<any>(themeCtx.sizeThemeRegistry.get(name).getParams(dataCtx)) ) }) } diff --git a/src/mol-theme/color.ts b/src/mol-theme/color.ts index 75bbc2eee2c4b815bc5be4407d2fb7df229e2c10..ba17219d3f3ed1d39ed855a0e5188ef2ba811311 100644 --- a/src/mol-theme/color.ts +++ b/src/mol-theme/color.ts @@ -11,7 +11,7 @@ import { CarbohydrateSymbolColorThemeProvider } from './color/carbohydrate-symbo import { UniformColorThemeProvider } from './color/uniform'; import { deepEqual } from 'mol-util'; import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { ThemeDataContext } from './theme'; +import { ThemeDataContext, ThemeRegistry, ThemeProvider } from './theme'; import { ChainIdColorThemeProvider } from './color/chain-id'; import { CrossLinkColorThemeProvider } from './color/cross-link'; import { ElementIndexColorThemeProvider } from './color/element-index'; @@ -32,7 +32,7 @@ export type LocationColor = (location: Location, isSecondary: boolean) => Color export type ColorThemeProps = { [k: string]: any } export { ColorTheme } -interface ColorTheme<P extends PD.Params = {}> { +interface ColorTheme<P extends PD.Params> { readonly factory: ColorTheme.Factory<P> readonly granularity: ColorType readonly color: LocationColor @@ -47,56 +47,16 @@ namespace ColorTheme { const EmptyColor = Color(0xCCCCCC) export const Empty: ColorTheme<{}> = { factory: EmptyFactory, granularity: 'uniform', color: () => EmptyColor, props: {} } - export function areEqual(themeA: ColorTheme, themeB: ColorTheme) { + export function areEqual(themeA: ColorTheme<any>, themeB: ColorTheme<any>) { return themeA.factory === themeB.factory && deepEqual(themeA.props, themeB.props) } - export interface Provider<P extends PD.Params> { - readonly label: string - readonly factory: (ctx: ThemeDataContext, props: PD.Values<P>) => ColorTheme<P> - readonly getParams: (ctx: ThemeDataContext) => P - readonly defaultValues: PD.Values<P> - } - export const EmptyProvider: Provider<{}> = { label: '', factory: EmptyFactory, getParams: () => ({}), defaultValues: {} } - - export class Registry { - private _list: { name: string, provider: Provider<any> }[] = [] - private _map = new Map<string, Provider<any>>() - - get default() { return this._list[0]; } - get types(): [string, string][] { - return this._list.map(e => [e.name, e.provider.label] as [string, string]); - } - - constructor() { - Object.keys(BuiltInColorThemes).forEach(name => { - const p = (BuiltInColorThemes as { [k: string]: Provider<any> })[name] - this.add(name, p) - }) - } - - add<P extends PD.Params>(name: string, provider: Provider<P>) { - this._list.push({ name, provider }) - this._map.set(name, provider) - } - - remove(name: string) { - this._list.splice(this._list.findIndex(e => e.name === name)) - this._map.delete(name) - } - - get<P extends PD.Params>(name: string): Provider<P> { - return this._map.get(name) || EmptyProvider as unknown as Provider<P> - } - - create(name: string, ctx: ThemeDataContext, props = {}) { - const provider = this.get(name) - return provider.factory(ctx, { ...PD.getDefaultValues(provider.getParams(ctx)), ...props }) - } + export interface Provider<P extends PD.Params> extends ThemeProvider<ColorTheme<P>, P> { } + export const EmptyProvider: Provider<{}> = { label: '', factory: EmptyFactory, getParams: () => ({}), defaultValues: {}, isApplicable: () => true } - get list() { - return this._list - } + export type Registry = ThemeRegistry<ColorTheme<any>> + export function createRegistry() { + return new ThemeRegistry(BuiltInColorThemes as { [k: string]: Provider<any> }, EmptyProvider) } } diff --git a/src/mol-theme/color/carbohydrate-symbol.ts b/src/mol-theme/color/carbohydrate-symbol.ts index 550c8f35d7799542fb62eba8903f7f1fdf5e50f2..72c7382c1917c3da8cda266d395ccec0e478e688 100644 --- a/src/mol-theme/color/carbohydrate-symbol.ts +++ b/src/mol-theme/color/carbohydrate-symbol.ts @@ -78,5 +78,6 @@ export const CarbohydrateSymbolColorThemeProvider: ColorTheme.Provider<Carbohydr label: 'Carbohydrate Symbol', factory: CarbohydrateSymbolColorTheme, getParams: getCarbohydrateSymbolColorThemeParams, - defaultValues: PD.getDefaultValues(CarbohydrateSymbolColorThemeParams) + defaultValues: PD.getDefaultValues(CarbohydrateSymbolColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/color/chain-id.ts b/src/mol-theme/color/chain-id.ts index eb37bf31c59088815d2d7401d5ef14645601c14e..c89d0600260ec58d9855c8317cf2c5f251d099f8 100644 --- a/src/mol-theme/color/chain-id.ts +++ b/src/mol-theme/color/chain-id.ts @@ -95,5 +95,6 @@ export const ChainIdColorThemeProvider: ColorTheme.Provider<ChainIdColorThemePar label: 'Chain Id', factory: ChainIdColorTheme, getParams: getChainIdColorThemeParams, - defaultValues: PD.getDefaultValues(ChainIdColorThemeParams) + defaultValues: PD.getDefaultValues(ChainIdColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/color/cross-link.ts b/src/mol-theme/color/cross-link.ts index bfe6cc0acb1bf17374e3d745b804d63dfb3c4859..d3cdf4b806a4c22633b3c13213cb7bef2b8712ea 100644 --- a/src/mol-theme/color/cross-link.ts +++ b/src/mol-theme/color/cross-link.ts @@ -72,5 +72,6 @@ export const CrossLinkColorThemeProvider: ColorTheme.Provider<CrossLinkColorThem label: 'Cross Link', factory: CrossLinkColorTheme, getParams: getCrossLinkColorThemeParams, - defaultValues: PD.getDefaultValues(CrossLinkColorThemeParams) + defaultValues: PD.getDefaultValues(CrossLinkColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/color/element-index.ts b/src/mol-theme/color/element-index.ts index c650f6c99f5847e7965840b431dbc08411571220..3636026ab977035052e72b019f6b24dc0adf83a1 100644 --- a/src/mol-theme/color/element-index.ts +++ b/src/mol-theme/color/element-index.ts @@ -72,5 +72,6 @@ export const ElementIndexColorThemeProvider: ColorTheme.Provider<ElementIndexCol label: 'Element Index', factory: ElementIndexColorTheme, getParams: getElementIndexColorThemeParams, - defaultValues: PD.getDefaultValues(ElementIndexColorThemeParams) + defaultValues: PD.getDefaultValues(ElementIndexColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/color/element-symbol.ts b/src/mol-theme/color/element-symbol.ts index bc15c9f232aedca3b9334eb6cd3f6751b2ba4438..28055bab2c48b626b43dbf4c615500674d119307 100644 --- a/src/mol-theme/color/element-symbol.ts +++ b/src/mol-theme/color/element-symbol.ts @@ -64,5 +64,6 @@ export const ElementSymbolColorThemeProvider: ColorTheme.Provider<ElementSymbolC label: 'Element Symbol', factory: ElementSymbolColorTheme, getParams: getElementSymbolColorThemeParams, - defaultValues: PD.getDefaultValues(ElementSymbolColorThemeParams) + defaultValues: PD.getDefaultValues(ElementSymbolColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/color/molecule-type.ts b/src/mol-theme/color/molecule-type.ts index b91c557afd98c6abb6dde170ad0a6ee4519b7aee..ad643930c68e537ff08231c8cd378f7d1b3d6f59 100644 --- a/src/mol-theme/color/molecule-type.ts +++ b/src/mol-theme/color/molecule-type.ts @@ -73,5 +73,6 @@ export const MoleculeTypeColorThemeProvider: ColorTheme.Provider<MoleculeTypeCol label: 'Molecule Type', factory: MoleculeTypeColorTheme, getParams: getMoleculeTypeColorThemeParams, - defaultValues: PD.getDefaultValues(MoleculeTypeColorThemeParams) + defaultValues: PD.getDefaultValues(MoleculeTypeColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/color/polymer-id.ts b/src/mol-theme/color/polymer-id.ts index 41b92030a827d5ab17c10d122a9c66370a6bf623..87c1c75aef281c170ca71dee0765f5ea8f6b80cd 100644 --- a/src/mol-theme/color/polymer-id.ts +++ b/src/mol-theme/color/polymer-id.ts @@ -102,5 +102,6 @@ export const PolymerIdColorThemeProvider: ColorTheme.Provider<PolymerIdColorThem label: 'Polymer Id', factory: PolymerIdColorTheme, getParams: getPolymerIdColorThemeParams, - defaultValues: PD.getDefaultValues(PolymerIdColorThemeParams) + defaultValues: PD.getDefaultValues(PolymerIdColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/color/polymer-index.ts b/src/mol-theme/color/polymer-index.ts index a51257fc888bfbc14189a5f8a42aaa398419354e..d13fe8d175cd249eaad5cea8c25ad3cdf6c6b3c0 100644 --- a/src/mol-theme/color/polymer-index.ts +++ b/src/mol-theme/color/polymer-index.ts @@ -70,5 +70,6 @@ export const PolymerIndexColorThemeProvider: ColorTheme.Provider<PolymerIndexCol label: 'Polymer Index', factory: PolymerIndexColorTheme, getParams: getPolymerIndexColorThemeParams, - defaultValues: PD.getDefaultValues(PolymerIndexColorThemeParams) + defaultValues: PD.getDefaultValues(PolymerIndexColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/color/residue-name.ts b/src/mol-theme/color/residue-name.ts index 682ae8a4bbe2aebbae81f9d5002a7ed6c66c7604..999bf2a9b274bc9369be3625cf7d7daa895b0a6d 100644 --- a/src/mol-theme/color/residue-name.ts +++ b/src/mol-theme/color/residue-name.ts @@ -129,5 +129,6 @@ export const ResidueNameColorThemeProvider: ColorTheme.Provider<ResidueNameColor label: 'Residue Name', factory: ResidueNameColorTheme, getParams: getResidueNameColorThemeParams, - defaultValues: PD.getDefaultValues(ResidueNameColorThemeParams) + defaultValues: PD.getDefaultValues(ResidueNameColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/color/secondary-structure.ts b/src/mol-theme/color/secondary-structure.ts index 6f2d094feecf2db20216fea84f4bc134997029bd..384c5fb0b7d3c37031ef670b0d17a9e7b9f79ade 100644 --- a/src/mol-theme/color/secondary-structure.ts +++ b/src/mol-theme/color/secondary-structure.ts @@ -96,5 +96,6 @@ export const SecondaryStructureColorThemeProvider: ColorTheme.Provider<Secondary label: 'Secondary Structure', factory: SecondaryStructureColorTheme, getParams: getSecondaryStructureColorThemeParams, - defaultValues: PD.getDefaultValues(SecondaryStructureColorThemeParams) + defaultValues: PD.getDefaultValues(SecondaryStructureColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/color/sequence-id.ts b/src/mol-theme/color/sequence-id.ts index cb8e49ffaacbfd888b3597cfb959c9c84dce9d83..b0dd084b66297adc2c42259e73a118cec3102283 100644 --- a/src/mol-theme/color/sequence-id.ts +++ b/src/mol-theme/color/sequence-id.ts @@ -103,5 +103,6 @@ export const SequenceIdColorThemeProvider: ColorTheme.Provider<SequenceIdColorTh label: 'Sequence Id', factory: SequenceIdColorTheme, getParams: getSequenceIdColorThemeParams, - defaultValues: PD.getDefaultValues(SequenceIdColorThemeParams) + defaultValues: PD.getDefaultValues(SequenceIdColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/color/shape-group.ts b/src/mol-theme/color/shape-group.ts index b6cbba700b95935cda88dcd0ae6f4a393f2cbfe4..66c51e853aa7eb81ddece5f6fed64e74188c3bde 100644 --- a/src/mol-theme/color/shape-group.ts +++ b/src/mol-theme/color/shape-group.ts @@ -39,5 +39,6 @@ export const ShapeGroupColorThemeProvider: ColorTheme.Provider<ShapeGroupColorTh label: 'Shape Group', factory: ShapeGroupColorTheme, getParams: getShapeGroupColorThemeParams, - defaultValues: PD.getDefaultValues(ShapeGroupColorThemeParams) + defaultValues: PD.getDefaultValues(ShapeGroupColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.shape } \ No newline at end of file diff --git a/src/mol-theme/color/uniform.ts b/src/mol-theme/color/uniform.ts index 8c702a9989c01c2bed0ebcd2e19068fc21a91a54..c18b62c9afaf9b1f436d22bab4397eeabae0e68e 100644 --- a/src/mol-theme/color/uniform.ts +++ b/src/mol-theme/color/uniform.ts @@ -38,5 +38,6 @@ export const UniformColorThemeProvider: ColorTheme.Provider<UniformColorThemePar label: 'Uniform', factory: UniformColorTheme, getParams: getUniformColorThemeParams, - defaultValues: PD.getDefaultValues(UniformColorThemeParams) + defaultValues: PD.getDefaultValues(UniformColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => true } \ No newline at end of file diff --git a/src/mol-theme/color/unit-index.ts b/src/mol-theme/color/unit-index.ts index 4f9d14883d8cb91649250617549a839ed390970b..ac25d51137c1cc75d40afcbd15def80d3876d63d 100644 --- a/src/mol-theme/color/unit-index.ts +++ b/src/mol-theme/color/unit-index.ts @@ -61,5 +61,6 @@ export const UnitIndexColorThemeProvider: ColorTheme.Provider<UnitIndexColorThem label: 'Unit Index', factory: UnitIndexColorTheme, getParams: getUnitIndexColorThemeParams, - defaultValues: PD.getDefaultValues(UnitIndexColorThemeParams) + defaultValues: PD.getDefaultValues(UnitIndexColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/size.ts b/src/mol-theme/size.ts index 16179eb0d6462a413625d7ac0eecdf3092fe977e..11dd2158880ad7e64bbb34e211da8f5c35836aad 100644 --- a/src/mol-theme/size.ts +++ b/src/mol-theme/size.ts @@ -7,12 +7,12 @@ import { SizeType, LocationSize } from 'mol-geo/geometry/size-data'; import { UniformSizeThemeProvider } from './size/uniform'; import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { ThemeDataContext } from 'mol-theme/theme'; +import { ThemeDataContext, ThemeRegistry, ThemeProvider } from 'mol-theme/theme'; import { PhysicalSizeThemeProvider } from './size/physical'; import { deepEqual } from 'mol-util'; export { SizeTheme } -interface SizeTheme<P extends PD.Params = {}> { +interface SizeTheme<P extends PD.Params> { readonly factory: SizeTheme.Factory<P> readonly granularity: SizeType readonly size: LocationSize @@ -25,56 +25,16 @@ namespace SizeTheme { export const EmptyFactory = () => Empty export const Empty: SizeTheme<{}> = { factory: EmptyFactory, granularity: 'uniform', size: () => 1, props: {} } - export function areEqual(themeA: SizeTheme, themeB: SizeTheme) { + export function areEqual(themeA: SizeTheme<any>, themeB: SizeTheme<any>) { return themeA.factory === themeB.factory && deepEqual(themeA.props, themeB.props) } - export interface Provider<P extends PD.Params> { - readonly label: string - readonly factory: Factory<P> - readonly getParams: (ctx: ThemeDataContext) => P - readonly defaultValues: PD.Values<P> - } - export const EmptyProvider: Provider<{}> = { label: '', factory: EmptyFactory, getParams: () => ({}), defaultValues: {} } - - export class Registry { - private _list: { name: string, provider: Provider<any> }[] = [] - private _map = new Map<string, Provider<any>>() - - get default() { return this._list[0]; } - get types(): [string, string][] { - return this._list.map(e => [e.name, e.provider.label] as [string, string]); - } - - constructor() { - Object.keys(BuiltInSizeThemes).forEach(name => { - const p = (BuiltInSizeThemes as { [k: string]: Provider<any> })[name] - this.add(name, p) - }) - } - - add<P extends PD.Params>(name: string, provider: Provider<P>) { - this._list.push({ name, provider }) - this._map.set(name, provider) - } - - remove(name: string) { - this._list.splice(this._list.findIndex(e => e.name === name)) - this._map.delete(name) - } - - get<P extends PD.Params>(name: string): Provider<P> { - return this._map.get(name) || EmptyProvider as unknown as Provider<P> - } - - create(name: string, ctx: ThemeDataContext, props = {}) { - const provider = this.get(name) - return provider.factory(ctx, { ...PD.getDefaultValues(provider.getParams(ctx)), ...props }) - } + export interface Provider<P extends PD.Params> extends ThemeProvider<SizeTheme<P>, P> { } + export const EmptyProvider: Provider<{}> = { label: '', factory: EmptyFactory, getParams: () => ({}), defaultValues: {}, isApplicable: () => true } - get list() { - return this._list - } + export type Registry = ThemeRegistry<SizeTheme<any>> + export function createRegistry() { + return new ThemeRegistry(BuiltInSizeThemes as { [k: string]: Provider<any> }, EmptyProvider) } } diff --git a/src/mol-theme/size/physical.ts b/src/mol-theme/size/physical.ts index b856912c418d09ae35c8e6aca966378b9381d30d..3d141c045e72f9699af758be2fb56501855d48a6 100644 --- a/src/mol-theme/size/physical.ts +++ b/src/mol-theme/size/physical.ts @@ -60,5 +60,6 @@ export const PhysicalSizeThemeProvider: SizeTheme.Provider<PhysicalSizeThemePara label: 'Physical', factory: PhysicalSizeTheme, getParams: getPhysicalSizeThemeParams, - defaultValues: PD.getDefaultValues(PhysicalSizeThemeParams) + defaultValues: PD.getDefaultValues(PhysicalSizeThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure } \ No newline at end of file diff --git a/src/mol-theme/size/uniform.ts b/src/mol-theme/size/uniform.ts index 3d91d0c353985aeb0a5b5baedf15b7b93f775cee..69c7fd832889abd3f869f2770ad7bfba58525997 100644 --- a/src/mol-theme/size/uniform.ts +++ b/src/mol-theme/size/uniform.ts @@ -34,5 +34,6 @@ export const UniformSizeThemeProvider: SizeTheme.Provider<UniformSizeThemeParams label: 'Uniform', factory: UniformSizeTheme, getParams: getUniformSizeThemeParams, - defaultValues: PD.getDefaultValues(UniformSizeThemeParams) + defaultValues: PD.getDefaultValues(UniformSizeThemeParams), + isApplicable: (ctx: ThemeDataContext) => true } \ No newline at end of file diff --git a/src/mol-theme/theme.ts b/src/mol-theme/theme.ts index ad2222c388cba75c6509875228e11e6c5226afc3..7808942b8a2700939012c553f0b2c8cb2daa4a45 100644 --- a/src/mol-theme/theme.ts +++ b/src/mol-theme/theme.ts @@ -9,6 +9,7 @@ import { SizeTheme } from './size'; import { Structure } from 'mol-model/structure'; import { VolumeData } from 'mol-model/volume'; import { ParamDefinition as PD } from 'mol-util/param-definition'; +import { Shape } from 'mol-model/shape'; export interface ThemeRegistryContext { colorThemeRegistry: ColorTheme.Registry @@ -19,11 +20,12 @@ export interface ThemeDataContext { [k: string]: any structure?: Structure volume?: VolumeData + shape?: Shape } export interface Theme { - color: ColorTheme - size: SizeTheme + color: ColorTheme<any> + size: SizeTheme<any> // label: LabelTheme // TODO } @@ -43,4 +45,59 @@ export function createTheme(ctx: ThemeRegistryContext, data: ThemeDataContext, p export function createEmptyTheme(): Theme { return { color: ColorTheme.Empty, size: SizeTheme.Empty } +} + +// + +export interface ThemeProvider<T extends ColorTheme<P> | SizeTheme<P>, P extends PD.Params> { + readonly label: string + readonly factory: (ctx: ThemeDataContext, props: PD.Values<P>) => T + readonly getParams: (ctx: ThemeDataContext) => P + readonly defaultValues: PD.Values<P> + readonly isApplicable: (ctx: ThemeDataContext) => boolean +} + +function getTypes(list: { name: string, provider: ThemeProvider<any, any> }[]) { + return list.map(e => [e.name, e.provider.label] as [string, string]); +} + +export class ThemeRegistry<T extends ColorTheme<any> | SizeTheme<any>> { + private _list: { name: string, provider: ThemeProvider<T, any> }[] = [] + private _map = new Map<string, ThemeProvider<T, any>>() + + get default() { return this._list[0]; } + get list() { return this._list } + get types(): [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])) + } + + add<P extends PD.Params>(name: string, provider: ThemeProvider<T, P>) { + this._list.push({ name, provider }) + this._map.set(name, provider) + } + + remove(name: string) { + this._list.splice(this._list.findIndex(e => e.name === name)) + this._map.delete(name) + console.log('removed', name, this._list, this._map) + } + + get<P extends PD.Params>(name: string): ThemeProvider<T, P> { + return this._map.get(name) || this.emptyProvider + } + + create(name: string, ctx: ThemeDataContext, props = {}) { + const provider = this.get(name) + return provider.factory(ctx, { ...PD.getDefaultValues(provider.getParams(ctx)), ...props }) + } + + getApplicableList(ctx: ThemeDataContext) { + return this._list.filter(e => e.provider.isApplicable(ctx)); + } + + getApplicableTypes(ctx: ThemeDataContext) { + return getTypes(this.getApplicableList(ctx)) + } } \ No newline at end of file