diff --git a/src/apps/state-docs/pd-to-md.ts b/src/apps/state-docs/pd-to-md.ts index f0df30519f9e4e18dfd3cd60509d6b45baf244f0..a55d372a06c822da0839c01d8cc612cff4a898f9 100644 --- a/src/apps/state-docs/pd-to-md.ts +++ b/src/apps/state-docs/pd-to-md.ts @@ -39,7 +39,7 @@ function paramInfo(param: PD.Any, offset: number): string { } } -function oToS(options: readonly (readonly [string, string])[]) { +function oToS(options: readonly (readonly [string, string] | [string, string, string])[]) { return options.map(o => `'${o[0]}'`).join(', '); } diff --git a/src/examples/proteopedia-wrapper/coloring.ts b/src/examples/proteopedia-wrapper/coloring.ts index 0f7bc4b3a5f423f5ccabcdb4f5cb38ca521508fb..3b25496365d11cc143d1c182c1e8a273286a171b 100644 --- a/src/examples/proteopedia-wrapper/coloring.ts +++ b/src/examples/proteopedia-wrapper/coloring.ts @@ -96,6 +96,7 @@ export function createProteopediaCustomTheme(colors: number[]) { const ProteopediaCustomColorThemeProvider: ColorTheme.Provider<ProteopediaCustomColorThemeParams> = { label: 'Proteopedia Custom', + category: 'Custom', factory: ProteopediaCustomColorTheme, getParams: getChainIdColorThemeParams, defaultValues: PD.getDefaultValues(ProteopediaCustomColorThemeParams), diff --git a/src/mol-model-props/common/custom-element-property.ts b/src/mol-model-props/common/custom-element-property.ts index 3dea414a939e75449f7438195624b5387c5b300f..4684a20e428f90b48a8ec7f6b404faf13f19e911 100644 --- a/src/mol-model-props/common/custom-element-property.ts +++ b/src/mol-model-props/common/custom-element-property.ts @@ -99,6 +99,7 @@ namespace CustomElementProperty { return { label: modelProperty.label, + category: 'Custom', factory: Coloring, getParams: () => ({}), defaultValues: {}, 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 fe2a60134c831deb06d546d4bec2c49f7ec8252c..3218bc0b5ba49050ebe101babd7c00dee5ff774b 100644 --- a/src/mol-model-props/computed/themes/accessible-surface-area.ts +++ b/src/mol-model-props/computed/themes/accessible-surface-area.ts @@ -68,6 +68,7 @@ export function AccessibleSurfaceAreaColorTheme(ctx: ThemeDataContext, props: PD export const AccessibleSurfaceAreaColorThemeProvider: ColorTheme.Provider<AccessibleSurfaceAreaColorThemeParams> = { label: 'Accessible Surface Area', + category: ColorTheme.Category.Computed, factory: AccessibleSurfaceAreaColorTheme, getParams: getAccessibleSurfaceAreaColorThemeParams, defaultValues: PD.getDefaultValues(AccessibleSurfaceAreaColorThemeParams), diff --git a/src/mol-model-props/computed/themes/interaction-type.ts b/src/mol-model-props/computed/themes/interaction-type.ts index d6ede61affd4cb58b9bb04faf2037961e431ad13..f816d2b4180da5ebad18bba0ec03c5578bf36d90 100644 --- a/src/mol-model-props/computed/themes/interaction-type.ts +++ b/src/mol-model-props/computed/themes/interaction-type.ts @@ -108,6 +108,7 @@ export function InteractionTypeColorTheme(ctx: ThemeDataContext, props: PD.Value export const InteractionTypeColorThemeProvider: ColorTheme.Provider<InteractionTypeColorThemeParams> = { label: 'Interaction Type', + category: ColorTheme.Category.Computed, factory: InteractionTypeColorTheme, getParams: getInteractionTypeColorThemeParams, defaultValues: PD.getDefaultValues(InteractionTypeColorThemeParams), 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 4000f437139cccdbca5c6892e00bd0e0b07770b2..3ba49d73d14c505ae0192d5584ae459fc5940173 100644 --- a/src/mol-model-props/integrative/cross-link-restraint/color.ts +++ b/src/mol-model-props/integrative/cross-link-restraint/color.ts @@ -63,6 +63,7 @@ export function CrossLinkColorTheme(ctx: ThemeDataContext, props: PD.Values<Cros export const CrossLinkColorThemeProvider: ColorTheme.Provider<CrossLinkColorThemeParams> = { label: 'Cross Link', + category: ColorTheme.Category.Advanced, factory: CrossLinkColorTheme, getParams: getCrossLinkColorThemeParams, defaultValues: PD.getDefaultValues(CrossLinkColorThemeParams), 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 e3296bab946d7dc478f50b5b20c3cfe05a533ef4..a4b23e9eb54470a393a5df10319088adc69b6b74 100644 --- a/src/mol-model-props/pdbe/themes/structure-quality-report.ts +++ b/src/mol-model-props/pdbe/themes/structure-quality-report.ts @@ -79,6 +79,7 @@ export function StructureQualityReportColorTheme(ctx: ThemeDataContext, props: P export const StructureQualityReportColorThemeProvider: ColorTheme.Provider<Params> = { label: 'PDBe Structure Quality Report', + category: 'PDBe', factory: StructureQualityReportColorTheme, getParams: ctx => { const issueTypes = StructureQualityReport.getIssueTypes(ctx.structure); 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 b8e1d2f7c712961ea20b358d91856fd191274744..cbab8e1e4645869dcf81445f074bce354bf00abb 100644 --- a/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts +++ b/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts @@ -93,6 +93,7 @@ export function AssemblySymmetryClusterColorTheme(ctx: ThemeDataContext, props: export const AssemblySymmetryClusterColorThemeProvider: ColorTheme.Provider<AssemblySymmetryClusterColorThemeParams> = { label: 'RCSB Assembly Symmetry Cluster', + category: 'RCSB', factory: AssemblySymmetryClusterColorTheme, getParams: getAssemblySymmetryClusterColorThemeParams, defaultValues: PD.getDefaultValues(AssemblySymmetryClusterColorThemeParams), diff --git a/src/mol-model-props/rcsb/themes/density-fit.ts b/src/mol-model-props/rcsb/themes/density-fit.ts index 9bc3d3d0fe4f8756e9483ad1b205e2966629a677..319c3c60297e757a40f7c5880c1db54d23e78ec1 100644 --- a/src/mol-model-props/rcsb/themes/density-fit.ts +++ b/src/mol-model-props/rcsb/themes/density-fit.ts @@ -62,6 +62,7 @@ export function DensityFitColorTheme(ctx: ThemeDataContext, props: {}): ColorThe export const DensityFitColorThemeProvider: ColorTheme.Provider<{}> = { label: 'RCSB Density Fit', + category: 'RCSB', factory: DensityFitColorTheme, getParams: () => ({}), defaultValues: PD.getDefaultValues({}), diff --git a/src/mol-model-props/rcsb/themes/geometry-quality.ts b/src/mol-model-props/rcsb/themes/geometry-quality.ts index 1f39b8de4b19e47b1765c0c85ae93cbe7ab9c64f..ca6d54e3507eebe3a716fdb56e70f272864985d2 100644 --- a/src/mol-model-props/rcsb/themes/geometry-quality.ts +++ b/src/mol-model-props/rcsb/themes/geometry-quality.ts @@ -102,6 +102,7 @@ export function GeometryQualityColorTheme(ctx: ThemeDataContext, props: PD.Value export const GeometryQualityColorThemeProvider: ColorTheme.Provider<GeometricQualityColorThemeParams> = { label: 'RCSB Geometry Quality', + category: 'RCSB', factory: GeometryQualityColorTheme, getParams: getGeometricQualityColorThemeParams, defaultValues: PD.getDefaultValues(getGeometricQualityColorThemeParams({})), 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 596aa205587e6fbbade46e08d205404414e226a5..c8a7e90f21bbbd3c54f40048a7312dbe0c21c85f 100644 --- a/src/mol-model-props/rcsb/themes/random-coil-index.ts +++ b/src/mol-model-props/rcsb/themes/random-coil-index.ts @@ -53,6 +53,7 @@ export function RandomCoilIndexColorTheme(ctx: ThemeDataContext, props: {}): Col export const RandomCoilIndexColorThemeProvider: ColorTheme.Provider<{}> = { label: 'RCSB Random Coil Index', + category: 'RCSB', factory: RandomCoilIndexColorTheme, getParams: () => ({}), defaultValues: PD.getDefaultValues({}), diff --git a/src/mol-plugin-ui/controls/action-menu.tsx b/src/mol-plugin-ui/controls/action-menu.tsx index 0d67b8c80475d366ef9b372ebc6772fee5cd8168..bc223a0debb329857133837a6d9f9735cd9765e8 100644 --- a/src/mol-plugin-ui/controls/action-menu.tsx +++ b/src/mol-plugin-ui/controls/action-menu.tsx @@ -7,6 +7,7 @@ import * as React from 'react' import { Icon } from './common'; import { Subscription, BehaviorSubject, Observable } from 'rxjs'; +import { ParamDefinition } from '../../mol-util/param-definition'; export class ActionMenu { private _command: BehaviorSubject<ActionMenu.Command>; @@ -139,16 +140,29 @@ export namespace ActionMenu { } } - class Section extends React.PureComponent<{ menu: ActionMenu, header?: string, items: Spec, onSelect: OnSelect, current: Item | undefined }, { isExpanded: boolean }> { - state = { isExpanded: false } + type SectionProps = { menu: ActionMenu, header?: string, items: Spec, onSelect: OnSelect, current: Item | undefined } + type SectionState = { items: Spec, current: Item | undefined, isExpanded: boolean } + + class Section extends React.PureComponent<SectionProps, SectionState> { + state = { + items: this.props.items, + current: this.props.current, + isExpanded: !!this.props.current && !!findCurrent(this.props.items, this.props.current.value) + } toggleExpanded = (e: React.MouseEvent<HTMLButtonElement>) => { this.setState({ isExpanded: !this.state.isExpanded }); e.currentTarget.blur(); } + static getDerivedStateFromProps(props: SectionProps, state: SectionState) { + if (props.items === state.items && props.current === state.current) return null; + return { items: props.items, current: props.current, isExpanded: props.current && !!findCurrent(props.items, props.current.value) } + } + render() { const { header, items, onSelect, current, menu } = this.props; + if (typeof items === 'string') return null; if (isItem(items)) return <Action menu={menu} item={items} onSelect={onSelect} current={current} /> return <div> @@ -196,4 +210,47 @@ export namespace ActionMenu { if (value) return { name, icon: iconOrValue, value }; return { name, value: iconOrValue }; } + + function createSpecFromSelectParamSimple(param: ParamDefinition.Select<any>) { + const spec: Item[] = []; + for (const [v, l] of param.options) { + spec.push(ActionMenu.Item(l, v)); + } + return spec as Spec; + } + + function createSpecFromSelectParamCategories(param: ParamDefinition.Select<any>) { + const cats = new Map<string, (Item | string)[]>(); + const spec: (Item | (Item | string)[] | string)[] = []; + for (const [v, l, c] of param.options) { + if (!!c) { + let cat = cats.get(c); + if (!cat) { + cat = [c]; + cats.set(c, cat); + spec.push(cat); + } + cat.push(ActionMenu.Item(l, v)); + } else { + spec.push(ActionMenu.Item(l, v)); + } + } + return spec as Spec; + } + + export function createSpecFromSelectParam(param: ParamDefinition.Select<any>) { + for (const o of param.options) { + if (!!o[2]) return createSpecFromSelectParamCategories(param); + } + return createSpecFromSelectParamSimple(param); + } + + export function findCurrent(spec: Spec, value: any): Item | undefined { + if (typeof spec === 'string') return; + if (isItem(spec)) return spec.value === value ? spec : void 0; + for (const s of spec) { + const found = findCurrent(s, value); + if (found) return found; + } + } } \ No newline at end of file diff --git a/src/mol-plugin-ui/controls/parameters.tsx b/src/mol-plugin-ui/controls/parameters.tsx index f52c546ccc97e69402aa253f5a666c0933e93173..2576f59e727f1a7fc59e0b1f69c53b020103fff4 100644 --- a/src/mol-plugin-ui/controls/parameters.tsx +++ b/src/mol-plugin-ui/controls/parameters.tsx @@ -8,7 +8,7 @@ import { Vec2, Vec3 } from '../../mol-math/linear-algebra'; import { Color } from '../../mol-util/color'; import { ColorListName, getColorListFromName } from '../../mol-util/color/lists'; -import { memoize1 } from '../../mol-util/memoize'; +import { memoize1, memoizeLatest } from '../../mol-util/memoize'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { camelCaseToWords } from '../../mol-util/string'; import * as React from 'react'; @@ -328,22 +328,14 @@ export class SelectControl extends SimpleParam<PD.Select<string | number>> { this.update(value); } + items = memoizeLatest((param: PD.Select<any>) => ActionMenu.createSpecFromSelectParam(param)); + renderControl() { - const isInvalid = this.props.value !== void 0 && !this.props.param.options.some(e => e[0] === this.props.value); - const items: ActionMenu.Item[] = []; - let current: ActionMenu.Item | undefined = void 0; - if (isInvalid) { - current = ActionMenu.Item(`[Invalid] ${this.props.value}`, this.props.value); - items.push(current); - } - for (const [value, label] of this.props.param.options) { - const item = ActionMenu.Item(label, value); - items.push(item); - if (value === this.props.value) current = item; - } + const items = this.items(this.props.param); + const current = ActionMenu.findCurrent(items, this.props.value); return <ActionMenu.Toggle menu={this.menu} disabled={this.props.isDisabled} - onSelect={this.onSelect} items={items as ActionMenu.Spec} label={current?.name} + onSelect={this.onSelect} items={items as ActionMenu.Spec} label={current?.name || `[Invalid] ${this.props.value}`} current={current} />; } diff --git a/src/mol-theme/color.ts b/src/mol-theme/color.ts index 67537bb8ff32bf4ab8bde1e6e473231bf470f800..6efcc769161ac2472ea82fdf9c7ac70d73ec817d 100644 --- a/src/mol-theme/color.ts +++ b/src/mol-theme/color.ts @@ -46,6 +46,13 @@ interface ColorTheme<P extends PD.Params> { readonly legend?: Readonly<ScaleLegend | TableLegend> } namespace ColorTheme { + export const enum Category { + Basic = 'Basic', + Advanced = 'Advanced', + Computed = 'Computed', + Misc = 'Miscellaneous' + } + export type Props = { [k: string]: any } export type Factory<P extends PD.Params> = (ctx: ThemeDataContext, props: PD.Values<P>) => ColorTheme<P> export const EmptyFactory = () => Empty @@ -62,7 +69,7 @@ namespace ColorTheme { } export interface Provider<P extends PD.Params> extends ThemeProvider<ColorTheme<P>, P> { } - export const EmptyProvider: Provider<{}> = { label: '', factory: EmptyFactory, getParams: () => ({}), defaultValues: {}, isApplicable: () => true } + export const EmptyProvider: Provider<{}> = { label: '', category: '', factory: EmptyFactory, getParams: () => ({}), defaultValues: {}, isApplicable: () => true } export type Registry = ThemeRegistry<ColorTheme<any>> export function createRegistry() { diff --git a/src/mol-theme/color/carbohydrate-symbol.ts b/src/mol-theme/color/carbohydrate-symbol.ts index f29d10170f11dffba9626bc8ac4a212e68db3d94..853e7cf9ce3828c1288be8b09521914d6b4ef342 100644 --- a/src/mol-theme/color/carbohydrate-symbol.ts +++ b/src/mol-theme/color/carbohydrate-symbol.ts @@ -61,7 +61,8 @@ export function CarbohydrateSymbolColorTheme(ctx: ThemeDataContext, props: PD.Va } export const CarbohydrateSymbolColorThemeProvider: ColorTheme.Provider<CarbohydrateSymbolColorThemeParams> = { - label: 'Carbohydrate Symbol', + label: 'Carbohydrate Symbol', + category: ColorTheme.Category.Advanced, factory: CarbohydrateSymbolColorTheme, getParams: getCarbohydrateSymbolColorThemeParams, defaultValues: PD.getDefaultValues(CarbohydrateSymbolColorThemeParams), diff --git a/src/mol-theme/color/chain-id.ts b/src/mol-theme/color/chain-id.ts index 16c072ff40491cae1f2c181df6d4eef3194fe1fa..d9ae75cb9d3fb4282a2016974059d54ec0afdb20 100644 --- a/src/mol-theme/color/chain-id.ts +++ b/src/mol-theme/color/chain-id.ts @@ -119,6 +119,7 @@ export function ChainIdColorTheme(ctx: ThemeDataContext, props: PD.Values<ChainI export const ChainIdColorThemeProvider: ColorTheme.Provider<ChainIdColorThemeParams> = { label: 'Chain Id', + category: ColorTheme.Category.Basic, factory: ChainIdColorTheme, getParams: getChainIdColorThemeParams, defaultValues: PD.getDefaultValues(ChainIdColorThemeParams), diff --git a/src/mol-theme/color/element-index.ts b/src/mol-theme/color/element-index.ts index be94f3376dd57a6609497ea829522055eff3e7d2..d2e13588ba64f46174ae2a5889d90800c3374d41 100644 --- a/src/mol-theme/color/element-index.ts +++ b/src/mol-theme/color/element-index.ts @@ -73,6 +73,7 @@ export function ElementIndexColorTheme(ctx: ThemeDataContext, props: PD.Values<E export const ElementIndexColorThemeProvider: ColorTheme.Provider<ElementIndexColorThemeParams> = { label: 'Element Index', + category: ColorTheme.Category.Basic, factory: ElementIndexColorTheme, getParams: getElementIndexColorThemeParams, defaultValues: PD.getDefaultValues(ElementIndexColorThemeParams), diff --git a/src/mol-theme/color/element-symbol.ts b/src/mol-theme/color/element-symbol.ts index 6f2f8881f7d016719366e50f9c3730ad96ed996d..8c559ff64356da9d0083e9bb1fa9098f9edf14e6 100644 --- a/src/mol-theme/color/element-symbol.ts +++ b/src/mol-theme/color/element-symbol.ts @@ -69,6 +69,7 @@ export function ElementSymbolColorTheme(ctx: ThemeDataContext, props: PD.Values< export const ElementSymbolColorThemeProvider: ColorTheme.Provider<ElementSymbolColorThemeParams> = { label: 'Element Symbol', + category: ColorTheme.Category.Basic, factory: ElementSymbolColorTheme, getParams: getElementSymbolColorThemeParams, defaultValues: PD.getDefaultValues(ElementSymbolColorThemeParams), diff --git a/src/mol-theme/color/entity-source.ts b/src/mol-theme/color/entity-source.ts index a8ac312bfe1693d8be1637d780f1709702303b5d..e8b4e71bc264df06283932b4566ad48039df0320 100644 --- a/src/mol-theme/color/entity-source.ts +++ b/src/mol-theme/color/entity-source.ts @@ -175,6 +175,7 @@ export function EntitySourceColorTheme(ctx: ThemeDataContext, props: PD.Values<E export const EntitySourceColorThemeProvider: ColorTheme.Provider<EntitySourceColorThemeParams> = { label: 'Entity Source', + category: ColorTheme.Category.Advanced, factory: EntitySourceColorTheme, getParams: getEntitySourceColorThemeParams, defaultValues: PD.getDefaultValues(EntitySourceColorThemeParams), diff --git a/src/mol-theme/color/hydrophobicity.ts b/src/mol-theme/color/hydrophobicity.ts index 47f3b94e424b93a3c2741a2bee072659f82f87f2..e49e3f25cc77111133365feb1e1a55d1b5c5605b 100644 --- a/src/mol-theme/color/hydrophobicity.ts +++ b/src/mol-theme/color/hydrophobicity.ts @@ -94,6 +94,7 @@ export function HydrophobicityColorTheme(ctx: ThemeDataContext, props: PD.Values export const HydrophobicityColorThemeProvider: ColorTheme.Provider<HydrophobicityColorThemeParams> = { label: 'Hydrophobicity', + category: ColorTheme.Category.Advanced, factory: HydrophobicityColorTheme, getParams: getHydrophobicityColorThemeParams, defaultValues: PD.getDefaultValues(HydrophobicityColorThemeParams), diff --git a/src/mol-theme/color/illustrative.ts b/src/mol-theme/color/illustrative.ts index 6025f1eed563a09a307540d332fc67f3f4583bd7..9b86d8b97a76e5ac85504745ffb30c46fa28b17a 100644 --- a/src/mol-theme/color/illustrative.ts +++ b/src/mol-theme/color/illustrative.ts @@ -76,6 +76,7 @@ export function IllustrativeColorTheme(ctx: ThemeDataContext, props: PD.Values<I export const IllustrativeColorThemeProvider: ColorTheme.Provider<IllustrativeColorThemeParams> = { label: 'Illustrative', + category: ColorTheme.Category.Misc, factory: IllustrativeColorTheme, getParams: getIllustrativeColorThemeParams, defaultValues: PD.getDefaultValues(IllustrativeColorThemeParams), diff --git a/src/mol-theme/color/model-index.ts b/src/mol-theme/color/model-index.ts index fd98c44f77c4797a3710b20f0313f8969e25b899..f7cc54bf7cdd7df506716c5e56f2239bc1d31c4f 100644 --- a/src/mol-theme/color/model-index.ts +++ b/src/mol-theme/color/model-index.ts @@ -61,6 +61,7 @@ export function ModelIndexColorTheme(ctx: ThemeDataContext, props: PD.Values<Mod export const ModelIndexColorThemeProvider: ColorTheme.Provider<ModelIndexColorThemeParams> = { label: 'Model Index', + category: ColorTheme.Category.Basic, factory: ModelIndexColorTheme, getParams: getModelIndexColorThemeParams, defaultValues: PD.getDefaultValues(ModelIndexColorThemeParams), diff --git a/src/mol-theme/color/molecule-type.ts b/src/mol-theme/color/molecule-type.ts index 49f891381cf11888e0264233757fc4051bdc2707..668f8ccfe8b6fc9becc285f90490bb814433ee5d 100644 --- a/src/mol-theme/color/molecule-type.ts +++ b/src/mol-theme/color/molecule-type.ts @@ -78,6 +78,7 @@ export function MoleculeTypeColorTheme(ctx: ThemeDataContext, props: PD.Values<M export const MoleculeTypeColorThemeProvider: ColorTheme.Provider<MoleculeTypeColorThemeParams> = { label: 'Molecule Type', + category: ColorTheme.Category.Advanced, factory: MoleculeTypeColorTheme, getParams: getMoleculeTypeColorThemeParams, defaultValues: PD.getDefaultValues(MoleculeTypeColorThemeParams), diff --git a/src/mol-theme/color/occupancy.ts b/src/mol-theme/color/occupancy.ts index cf609f010a192f7adad85f8c1846d376b30e2627..7cfa1c4580b737c2c65a4349ec72e83ec553ebe0 100644 --- a/src/mol-theme/color/occupancy.ts +++ b/src/mol-theme/color/occupancy.ts @@ -60,6 +60,7 @@ export function OccupancyColorTheme(ctx: ThemeDataContext, props: PD.Values<Occu export const OccupancyColorThemeProvider: ColorTheme.Provider<OccupancyColorThemeParams> = { label: 'Occupancy', + category: ColorTheme.Category.Advanced, factory: OccupancyColorTheme, getParams: getOccupancyColorThemeParams, defaultValues: PD.getDefaultValues(OccupancyColorThemeParams), diff --git a/src/mol-theme/color/operator-hkl.ts b/src/mol-theme/color/operator-hkl.ts index 2469356eaa12799c0496bf2f27cad96a04184311..d08c290333e47d901e051a0e339a778063c7f9f5 100644 --- a/src/mol-theme/color/operator-hkl.ts +++ b/src/mol-theme/color/operator-hkl.ts @@ -119,6 +119,7 @@ export function OperatorHklColorTheme(ctx: ThemeDataContext, props: PD.Values<Op export const OperatorHklColorThemeProvider: ColorTheme.Provider<OperatorHklColorThemeParams> = { label: 'Operator HKL', + category: ColorTheme.Category.Advanced, factory: OperatorHklColorTheme, getParams: getOperatorHklColorThemeParams, defaultValues: PD.getDefaultValues(OperatorHklColorThemeParams), diff --git a/src/mol-theme/color/operator-name.ts b/src/mol-theme/color/operator-name.ts index 16d48b147f4833878b6bd90452f70ac5dbb5a06d..61b4e95c4e3c9704615e298547173aa6d7adc9cb 100644 --- a/src/mol-theme/color/operator-name.ts +++ b/src/mol-theme/color/operator-name.ts @@ -85,6 +85,7 @@ export function OperatorNameColorTheme(ctx: ThemeDataContext, props: PD.Values<O export const OperatorNameColorThemeProvider: ColorTheme.Provider<OperatorNameColorThemeParams> = { label: 'Operator Name', + category: ColorTheme.Category.Advanced, factory: OperatorNameColorTheme, getParams: getOperatorNameColorThemeParams, defaultValues: PD.getDefaultValues(OperatorNameColorThemeParams), diff --git a/src/mol-theme/color/polymer-id.ts b/src/mol-theme/color/polymer-id.ts index 46955e905c48bad6d951683869e8c9f3fb5f94ee..3e796d3d9aa2e4449bb203f54102619271c90421 100644 --- a/src/mol-theme/color/polymer-id.ts +++ b/src/mol-theme/color/polymer-id.ts @@ -128,6 +128,7 @@ export function PolymerIdColorTheme(ctx: ThemeDataContext, props: PD.Values<Poly export const PolymerIdColorThemeProvider: ColorTheme.Provider<PolymerIdColorThemeParams> = { label: 'Polymer Id', + category: ColorTheme.Category.Basic, factory: PolymerIdColorTheme, getParams: getPolymerIdColorThemeParams, defaultValues: PD.getDefaultValues(PolymerIdColorThemeParams), diff --git a/src/mol-theme/color/polymer-index.ts b/src/mol-theme/color/polymer-index.ts index 02bfa5b44266b20e431980f35b4d78545a5b5dbd..ef37ce818edc5571e0e9a25e7a1e8a891065279a 100644 --- a/src/mol-theme/color/polymer-index.ts +++ b/src/mol-theme/color/polymer-index.ts @@ -88,6 +88,7 @@ export function PolymerIndexColorTheme(ctx: ThemeDataContext, props: PD.Values<P export const PolymerIndexColorThemeProvider: ColorTheme.Provider<PolymerIndexColorThemeParams> = { label: 'Polymer Index', + category: ColorTheme.Category.Advanced, factory: PolymerIndexColorTheme, getParams: getPolymerIndexColorThemeParams, defaultValues: PD.getDefaultValues(PolymerIndexColorThemeParams), diff --git a/src/mol-theme/color/residue-name.ts b/src/mol-theme/color/residue-name.ts index 175518740b31ad358793378ecab7c42799e4bc7b..72259d10f211d7b9116dc81b684ea34d27f8b713 100644 --- a/src/mol-theme/color/residue-name.ts +++ b/src/mol-theme/color/residue-name.ts @@ -130,6 +130,7 @@ export function ResidueNameColorTheme(ctx: ThemeDataContext, props: PD.Values<Re export const ResidueNameColorThemeProvider: ColorTheme.Provider<ResidueNameColorThemeParams> = { label: 'Residue Name', + category: ColorTheme.Category.Basic, factory: ResidueNameColorTheme, getParams: getResidueNameColorThemeParams, defaultValues: PD.getDefaultValues(ResidueNameColorThemeParams), diff --git a/src/mol-theme/color/secondary-structure.ts b/src/mol-theme/color/secondary-structure.ts index 9eef3bb1c704290a78bd9cb9112104af87a1125a..6afa2dc1b3b038bc6b32472432ea68fe9542ddf2 100644 --- a/src/mol-theme/color/secondary-structure.ts +++ b/src/mol-theme/color/secondary-structure.ts @@ -113,6 +113,7 @@ export function SecondaryStructureColorTheme(ctx: ThemeDataContext, props: PD.Va export const SecondaryStructureColorThemeProvider: ColorTheme.Provider<SecondaryStructureColorThemeParams> = { label: 'Secondary Structure', + category: ColorTheme.Category.Basic, factory: SecondaryStructureColorTheme, getParams: getSecondaryStructureColorThemeParams, defaultValues: PD.getDefaultValues(SecondaryStructureColorThemeParams), diff --git a/src/mol-theme/color/sequence-id.ts b/src/mol-theme/color/sequence-id.ts index 66457c0b576b579c692cae88ab9ccdc728aec05b..90f5038eca3641248a6562dce33939ac2a15aa0f 100644 --- a/src/mol-theme/color/sequence-id.ts +++ b/src/mol-theme/color/sequence-id.ts @@ -101,6 +101,7 @@ export function SequenceIdColorTheme(ctx: ThemeDataContext, props: PD.Values<Seq export const SequenceIdColorThemeProvider: ColorTheme.Provider<SequenceIdColorThemeParams> = { label: 'Sequence Id', + category: ColorTheme.Category.Basic, factory: SequenceIdColorTheme, getParams: getSequenceIdColorThemeParams, defaultValues: PD.getDefaultValues(SequenceIdColorThemeParams), diff --git a/src/mol-theme/color/shape-group.ts b/src/mol-theme/color/shape-group.ts index 1c3166fafdadbefae4f83b7b9cd12d708a46ddf3..d5b5ba87ee925e22856186514992d09ed34c9a7a 100644 --- a/src/mol-theme/color/shape-group.ts +++ b/src/mol-theme/color/shape-group.ts @@ -37,6 +37,7 @@ export function ShapeGroupColorTheme(ctx: ThemeDataContext, props: PD.Values<Sha export const ShapeGroupColorThemeProvider: ColorTheme.Provider<ShapeGroupColorThemeParams> = { label: 'Shape Group', + category: ColorTheme.Category.Advanced, factory: ShapeGroupColorTheme, getParams: getShapeGroupColorThemeParams, defaultValues: PD.getDefaultValues(ShapeGroupColorThemeParams), diff --git a/src/mol-theme/color/uncertainty.ts b/src/mol-theme/color/uncertainty.ts index d7511cb0533f6554bf50d9d92797ef1b0df223f5..7e87f0127e065efc0c65a7b3615967a79590f257 100644 --- a/src/mol-theme/color/uncertainty.ts +++ b/src/mol-theme/color/uncertainty.ts @@ -64,6 +64,7 @@ export function UncertaintyColorTheme(ctx: ThemeDataContext, props: PD.Values<Un export const UncertaintyColorThemeProvider: ColorTheme.Provider<UncertaintyColorThemeParams> = { label: 'Uncertainty/Disorder', + category: ColorTheme.Category.Advanced, factory: UncertaintyColorTheme, getParams: getUncertaintyColorThemeParams, defaultValues: PD.getDefaultValues(UncertaintyColorThemeParams), diff --git a/src/mol-theme/color/uniform.ts b/src/mol-theme/color/uniform.ts index 6bc0e8bdc70be6be9be3c061eb5c7936ab8d270d..e018b914d22ad253040c4894c09549670239e49e 100644 --- a/src/mol-theme/color/uniform.ts +++ b/src/mol-theme/color/uniform.ts @@ -37,6 +37,7 @@ export function UniformColorTheme(ctx: ThemeDataContext, props: PD.Values<Unifor export const UniformColorThemeProvider: ColorTheme.Provider<UniformColorThemeParams> = { label: 'Uniform', + category: ColorTheme.Category.Basic, factory: UniformColorTheme, getParams: getUniformColorThemeParams, defaultValues: PD.getDefaultValues(UniformColorThemeParams), diff --git a/src/mol-theme/color/unit-index.ts b/src/mol-theme/color/unit-index.ts index bb6bb9c5bbc40dead1edf85da2ec110fb3011d13..bcd5e7314f9bf66aaaa28bd0403cd8f991e8c1dd 100644 --- a/src/mol-theme/color/unit-index.ts +++ b/src/mol-theme/color/unit-index.ts @@ -73,6 +73,7 @@ export function UnitIndexColorTheme(ctx: ThemeDataContext, props: PD.Values<Unit export const UnitIndexColorThemeProvider: ColorTheme.Provider<UnitIndexColorThemeParams> = { label: 'Unit Index', + category: ColorTheme.Category.Advanced, factory: UnitIndexColorTheme, getParams: getUnitIndexColorThemeParams, defaultValues: PD.getDefaultValues(UnitIndexColorThemeParams), diff --git a/src/mol-theme/size.ts b/src/mol-theme/size.ts index 71c79b8d22d463ca3b3efa0779c41e5b9d77f227..2283474f79175887aa15b56780d5c71b6c01fffa 100644 --- a/src/mol-theme/size.ts +++ b/src/mol-theme/size.ts @@ -32,7 +32,7 @@ namespace SizeTheme { } export interface Provider<P extends PD.Params> extends ThemeProvider<SizeTheme<P>, P> { } - export const EmptyProvider: Provider<{}> = { label: '', factory: EmptyFactory, getParams: () => ({}), defaultValues: {}, isApplicable: () => true } + export const EmptyProvider: Provider<{}> = { 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 4456ad2091c98280488f9c1dd34f1e42784efc6a..8622967d19f8e774b71b9446d580530e5f9ce01d 100644 --- a/src/mol-theme/size/physical.ts +++ b/src/mol-theme/size/physical.ts @@ -58,6 +58,7 @@ export function PhysicalSizeTheme(ctx: ThemeDataContext, props: PD.Values<Physic export const PhysicalSizeThemeProvider: SizeTheme.Provider<PhysicalSizeThemeParams> = { label: 'Physical', + category: '', factory: PhysicalSizeTheme, getParams: getPhysicalSizeThemeParams, defaultValues: PD.getDefaultValues(PhysicalSizeThemeParams), diff --git a/src/mol-theme/size/shape-group.ts b/src/mol-theme/size/shape-group.ts index 2e2f867d55c5910a8ca844a4cb42215c77607412..b7eaa993fe5d1afcf5af100b6c4fb2ce215f2c26 100644 --- a/src/mol-theme/size/shape-group.ts +++ b/src/mol-theme/size/shape-group.ts @@ -36,6 +36,7 @@ export function ShapeGroupSizeTheme(ctx: ThemeDataContext, props: PD.Values<Shap export const ShapeGroupSizeThemeProvider: SizeTheme.Provider<ShapeGroupSizeThemeParams> = { label: 'Shape Group', + category: '', factory: ShapeGroupSizeTheme, getParams: getShapeGroupSizeThemeParams, defaultValues: PD.getDefaultValues(ShapeGroupSizeThemeParams), diff --git a/src/mol-theme/size/uncertainty.ts b/src/mol-theme/size/uncertainty.ts index 5f9da065b4b8331ac620db16e6e4b806446ac176..bbeec077745086a04cdb72d76cd9ef911cd0595f 100644 --- a/src/mol-theme/size/uncertainty.ts +++ b/src/mol-theme/size/uncertainty.ts @@ -54,6 +54,7 @@ export function UncertaintySizeTheme(ctx: ThemeDataContext, props: PD.Values<Unc export const UncertaintySizeThemeProvider: SizeTheme.Provider<UncertaintySizeThemeParams> = { label: 'Uncertainty/Disorder', + category: '', factory: UncertaintySizeTheme, getParams: getUncertaintySizeThemeParams, defaultValues: PD.getDefaultValues(UncertaintySizeThemeParams), diff --git a/src/mol-theme/size/uniform.ts b/src/mol-theme/size/uniform.ts index 4d82bef1048e7b01b74c711df38221f3fd3aafdd..32b2718744f145c5ec3540eefb8a7326f46f7d0a 100644 --- a/src/mol-theme/size/uniform.ts +++ b/src/mol-theme/size/uniform.ts @@ -32,6 +32,7 @@ export function UniformSizeTheme(ctx: ThemeDataContext, props: PD.Values<Uniform export const UniformSizeThemeProvider: SizeTheme.Provider<UniformSizeThemeParams> = { label: 'Uniform', + category: '', factory: UniformSizeTheme, getParams: getUniformSizeThemeParams, defaultValues: PD.getDefaultValues(UniformSizeThemeParams), diff --git a/src/mol-theme/theme.ts b/src/mol-theme/theme.ts index ce5350a5a696a2b2315415576755f1556667dea2..d654af18e25a59ea33a7fb09b4541c0d9abe9b09 100644 --- a/src/mol-theme/theme.ts +++ b/src/mol-theme/theme.ts @@ -60,7 +60,8 @@ namespace Theme { // export interface ThemeProvider<T extends ColorTheme<P> | SizeTheme<P>, P extends PD.Params> { - readonly label: string + readonly label: string + readonly category: string readonly factory: (ctx: ThemeDataContext, props: PD.Values<P>) => T readonly getParams: (ctx: ThemeDataContext) => P readonly defaultValues: PD.Values<P> @@ -69,7 +70,7 @@ export interface ThemeProvider<T extends ColorTheme<P> | SizeTheme<P>, P extends } function getTypes(list: { name: string, provider: ThemeProvider<any, any> }[]) { - return list.map(e => [e.name, e.provider.label] as [string, string]); + return list.map(e => [e.name, e.provider.label, e.provider.category] as [string, string, string]); } export class ThemeRegistry<T extends ColorTheme<any> | SizeTheme<any>> { @@ -79,16 +80,26 @@ export class ThemeRegistry<T extends ColorTheme<any> | SizeTheme<any>> { get default() { return this._list[0] } get list() { return this._list } - get types(): [string, string][] { return getTypes(this._list) } + 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])) } + private sort() { + this._list.sort((a, b) => { + if (a.provider.category === b.provider.category) { + return a.provider.label < b.provider.label ? -1 : a.provider.label > b.provider.label ? 1 : 0; + } + return a.provider.category < b.provider.label ? -1 : 1; + }); + } + add<P extends PD.Params>(name: string, provider: ThemeProvider<T, P>) { this._list.push({ name, provider }) this._map.set(name, provider) this._name.set(provider, name) + this.sort(); } remove(name: string) { diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index b2ccbedced6a35e78831242833476f2cad94c435..064528cf1dcaed4fa8b74f2933ab496587071fe8 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -65,9 +65,9 @@ export namespace ParamDefinition { export interface Select<T extends string | number> extends Base<T> { type: 'select' /** array of (value, label) tuples */ - options: readonly (readonly [T, string])[] + options: readonly (readonly [T, string] | [T, string, string])[] } - export function Select<T extends string | number>(defaultValue: T, options: readonly (readonly [T, string])[], info?: Info): Select<T> { + export function Select<T extends string | number>(defaultValue: T, options: readonly (readonly [T, string] | [T, string, string])[], info?: Info): Select<T> { return setInfo<Select<T>>({ type: 'select', defaultValue: checkDefaultKey(defaultValue, options), options }, info) } @@ -201,7 +201,7 @@ export namespace ParamDefinition { select: Select<string>, map(name: string): Any } - export function Mapped<T>(defaultKey: string, names: [string, string][], map: (name: string) => Any, info?: Info): Mapped<NamedParams<T>> { + export function Mapped<T>(defaultKey: string, names: ([string, string] | [string, string, string])[], map: (name: string) => Any, info?: Info): Mapped<NamedParams<T>> { const name = checkDefaultKey(defaultKey, names); return setInfo<Mapped<NamedParams<T>>>({ type: 'mapped', @@ -406,7 +406,7 @@ export namespace ParamDefinition { return ret; } - function checkDefaultKey<T>(k: T, options: readonly (readonly [T, string])[]) { + function checkDefaultKey<T>(k: T, options: readonly (readonly [T, string] | [T, string, string])[]) { for (const o of options) { if (o[0] === k) return k; }