diff --git a/src/mol-plugin/state/actions/basic.ts b/src/mol-plugin/state/actions/basic.ts index 19dee261c1fa076a7729e6524cbbe6512af61230..b1b2bacc5299487861a5c245db23909bbd512038 100644 --- a/src/mol-plugin/state/actions/basic.ts +++ b/src/mol-plugin/state/actions/basic.ts @@ -82,13 +82,10 @@ const DownloadStructure = StateAction.create<PluginStateObject.Root, void, Downl }); export const OpenStructure = StateAction.build({ + display: { name: 'Open Structure', description: 'Load a structure from file and create its default Assembly and visual' }, from: PluginStateObject.Root, params: { file: PD.File({ accept: '.cif,.bcif' }) } })({ - display: { - name: 'Open Structure', - description: 'Load a structure from file and create its default Assembly and visual' - }, apply({ params, state }) { const b = state.build(); const data = b.toRoot().apply(StateTransforms.Data.ReadFile, { file: params.file, isBinary: /\.bcif$/i.test(params.file.name) }); @@ -132,12 +129,9 @@ function complexRepresentation(root: StateTreeBuilder.To<PluginStateObject.Molec } export const CreateComplexRepresentation = StateAction.build({ + display: { name: 'Create Complex', description: 'Split the structure into Sequence/Water/Ligands/... ' }, from: PluginStateObject.Molecule.Structure })({ - display: { - name: 'Create Complex', - description: 'Split the structure into Sequence/Water/Ligands/... ' - }, apply({ ref, state }) { const root = state.build().to(ref); complexRepresentation(root); @@ -146,14 +140,12 @@ export const CreateComplexRepresentation = StateAction.build({ }); export const UpdateTrajectory = StateAction.build({ - params: () => ({ + display: { name: 'Update Trajectory' }, + params: { action: PD.Select<'advance' | 'reset'>('advance', [['advance', 'Advance'], ['reset', 'Reset']]), by: PD.makeOptional(PD.Numeric(1, { min: -1, max: 1, step: 1 })) - }) + } })({ - display: { - name: 'Update Trajectory' - }, apply({ params, state }) { const models = state.select(q => q.rootsOfType(PluginStateObject.Molecule.Model) .filter(c => c.transform.transformer === StateTransforms.Model.ModelFromTrajectory)); diff --git a/src/mol-plugin/state/transforms/data.ts b/src/mol-plugin/state/transforms/data.ts index 8ef6c9cbd712fe9e5ede6df0571adbdaea762fa3..0878ceb369e3b4567db73515b131ea54e8f22409 100644 --- a/src/mol-plugin/state/transforms/data.ts +++ b/src/mol-plugin/state/transforms/data.ts @@ -17,6 +17,7 @@ export { Download } type Download = typeof Download const Download = PluginStateTransform.BuiltIn({ name: 'download', + display: { name: 'Download', description: 'Download string or binary data from the specified URL' }, from: [SO.Root], to: [SO.Data.String, SO.Data.Binary], params: { @@ -25,10 +26,6 @@ const Download = PluginStateTransform.BuiltIn({ isBinary: PD.makeOptional(PD.Boolean(false, { description: 'If true, download data as binary (string otherwise)' })) } })({ - display: { - name: 'Download', - description: 'Download string or binary data from the specified URL' - }, apply({ params: p }, globalCtx: PluginContext) { return Task.create('Download', async ctx => { const data = await globalCtx.fetch(p.url, p.isBinary ? 'binary' : 'string').runInContext(ctx); @@ -51,18 +48,15 @@ export { ReadFile } type ReadFile = typeof ReadFile const ReadFile = PluginStateTransform.BuiltIn({ name: 'read-file', + display: { name: 'Read File', description: 'Read string or binary data from the specified file' }, from: SO.Root, to: [SO.Data.String, SO.Data.Binary], params: { file: PD.File(), label: PD.makeOptional(PD.Text('')), isBinary: PD.makeOptional(PD.Boolean(false, { description: 'If true, open file as as binary (string otherwise)' })) - }, + } })({ - display: { - name: 'Read File', - description: 'Read string or binary data from the specified file' - }, apply({ params: p }) { return Task.create('Open File', async ctx => { const data = await readFromFile(p.file, p.isBinary ? 'binary' : 'string').runInContext(ctx); @@ -85,13 +79,10 @@ export { ParseCif } type ParseCif = typeof ParseCif const ParseCif = PluginStateTransform.BuiltIn({ name: 'parse-cif', + display: { name: 'Parse CIF', description: 'Parse CIF from String or Binary data' }, from: [SO.Data.String, SO.Data.Binary], to: SO.Format.Cif })({ - display: { - name: 'Parse CIF', - description: 'Parse CIF from String or Binary data' - }, apply({ a }) { return Task.create('Parse CIF', async ctx => { const parsed = await (SO.Data.String.is(a) ? CIF.parse(a.data) : CIF.parseBinary(a.data)).runInContext(ctx); diff --git a/src/mol-plugin/state/transforms/model.ts b/src/mol-plugin/state/transforms/model.ts index 0903e9e504981e5e4aef1a89d04846391c2fdf47..35fe8c775ed2849dd5c191099b8cc9ec1807d0be 100644 --- a/src/mol-plugin/state/transforms/model.ts +++ b/src/mol-plugin/state/transforms/model.ts @@ -19,6 +19,7 @@ export { TrajectoryFromMmCif } type TrajectoryFromMmCif = typeof TrajectoryFromMmCif const TrajectoryFromMmCif = PluginStateTransform.BuiltIn({ name: 'trajectory-from-mmcif', + display: { name: 'Trajectory from mmCIF', description: 'Identify and create all separate models in the specified CIF data block' }, from: SO.Format.Cif, to: SO.Molecule.Trajectory, params(a) { @@ -26,12 +27,8 @@ const TrajectoryFromMmCif = PluginStateTransform.BuiltIn({ return { blockHeader: PD.makeOptional(PD.Select(blocks[0] && blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]), { description: 'Header of the block to parse' })) }; - }, + } })({ - display: { - name: 'Models from mmCIF', - description: 'Identify and create all separate models in the specified CIF data block' - }, isApplicable: a => a.data.blocks.length > 0, apply({ a, params }) { return Task.create('Parse mmCIF', async ctx => { @@ -51,14 +48,11 @@ const plus1 = (v: number) => v + 1, minus1 = (v: number) => v - 1; type ModelFromTrajectory = typeof ModelFromTrajectory const ModelFromTrajectory = PluginStateTransform.BuiltIn({ name: 'model-from-trajectory', + display: { name: 'Model from Trajectory', description: 'Create a molecular structure from the specified model.' }, from: SO.Molecule.Trajectory, to: SO.Molecule.Model, params: a => ({ modelIndex: PD.Converted(plus1, minus1, PD.Numeric(1, { min: 1, max: a.data.length, step: 1 }, { description: 'Model Index' })) }) })({ - display: { - name: 'Model from Trajectory', - description: 'Create a molecular structure from the specified model.' - }, 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}`); @@ -72,13 +66,10 @@ export { StructureFromModel } type StructureFromModel = typeof StructureFromModel const StructureFromModel = PluginStateTransform.BuiltIn({ name: 'structure-from-model', + display: { name: 'Structure from Model', description: 'Create a molecular structure from the specified model.' }, from: SO.Molecule.Model, - to: SO.Molecule.Structure, + to: SO.Molecule.Structure })({ - display: { - name: 'Structure from Model', - description: 'Create a molecular structure from the specified model.' - }, apply({ a }) { let s = Structure.ofModel(a.data); const label = { label: a.data.label, description: s.elementCount === 1 ? '1 element' : `${s.elementCount} elements` }; @@ -94,6 +85,7 @@ export { StructureAssemblyFromModel } type StructureAssemblyFromModel = typeof StructureAssemblyFromModel const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({ name: 'structure-assembly-from-model', + display: { name: 'Structure Assembly', description: 'Create a molecular structure assembly.' }, from: SO.Molecule.Model, to: SO.Molecule.Structure, params(a) { @@ -102,10 +94,6 @@ const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({ return { id: PD.makeOptional(PD.Select(ids.length ? ids[0][0] : '', ids, { label: 'Asm Id', description: 'Assembly Id' })) }; } })({ - display: { - name: 'Structure Assembly', - description: 'Create a molecular structure assembly.' - }, apply({ a, params }, plugin: PluginContext) { return Task.create('Build Assembly', async ctx => { let id = (params.id || '').trim(); @@ -132,17 +120,14 @@ export { StructureSelection } type StructureSelection = typeof StructureSelection const StructureSelection = PluginStateTransform.BuiltIn({ name: 'structure-selection', + display: { name: 'Structure Selection', description: 'Create a molecular structure from the specified model.' }, from: SO.Molecule.Structure, to: SO.Molecule.Structure, - params: () => ({ + params: { query: PD.Value<Expression>(MolScriptBuilder.struct.generator.all, { isHidden: true }), label: PD.makeOptional(PD.Text('', { isHidden: true })) - }) + } })({ - display: { - name: 'Structure Selection', - description: 'Create a molecular structure from the specified model.' - }, apply({ a, params }) { // TODO: use cache, add "update" const compiled = compile<Sel>(params.query); @@ -158,14 +143,11 @@ namespace StructureComplexElement { export type Types = 'atomic-sequence' | 'wat type StructureComplexElement = typeof StructureComplexElement const StructureComplexElement = PluginStateTransform.BuiltIn({ name: 'structure-complex-element', + display: { name: 'Complex Element', description: 'Create a molecular structure from the specified model.' }, from: SO.Molecule.Structure, to: SO.Molecule.Structure, - params: () => ({ type: PD.Text<StructureComplexElement.Types>('atomic-sequence', { isHidden: true }) }), + params: { type: PD.Text<StructureComplexElement.Types>('atomic-sequence', { isHidden: true }) } })({ - display: { - name: 'Complex Element', - description: 'Create a molecular structure from the specified model.' - }, apply({ a, params }) { // TODO: update function. diff --git a/src/mol-plugin/state/transforms/representation.ts b/src/mol-plugin/state/transforms/representation.ts index 2c3e9c4f9f959f634fcf929a8751da710738d232..ac80dc2cedcc6d0f653527415aba829f1da71718 100644 --- a/src/mol-plugin/state/transforms/representation.ts +++ b/src/mol-plugin/state/transforms/representation.ts @@ -17,6 +17,7 @@ export { StructureRepresentation3D } type StructureRepresentation3D = typeof StructureRepresentation3D const StructureRepresentation3D = PluginStateTransform.BuiltIn({ name: 'structure-representation-3d', + display: '3D Representation', from: SO.Molecule.Structure, to: SO.Molecule.Representation3D, params: (a, ctx: PluginContext) => ({ @@ -38,7 +39,6 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({ ) }) })({ - display: { name: '3D Representation' }, canAutoUpdate({ oldParams, newParams }) { // TODO: allow for small molecules return oldParams.type.name === newParams.type.name; diff --git a/src/mol-plugin/ui/state-tree.tsx b/src/mol-plugin/ui/state-tree.tsx index 01e85cc715b984d37961a48865ad6ffef2abd91f..34486bd4790ff6dffe66dd726be8d93c33b44016 100644 --- a/src/mol-plugin/ui/state-tree.tsx +++ b/src/mol-plugin/ui/state-tree.tsx @@ -162,7 +162,7 @@ class StateTreeNodeLabel extends PluginComponent<{ nodeRef: string, state: State let label: any; if (cell.status !== 'ok' || !cell.obj) { - const name = (n.transformer.definition.display && n.transformer.definition.display.name) || n.transformer.definition.name; + const name = n.transformer.definition.display.name; const title = `${cell.errorText}` label = <><b>{cell.status}</b> <a title={title} href='#' onClick={this.setCurrent}>{name}</a>: <i>{cell.errorText}</i></>; } else { diff --git a/src/mol-plugin/ui/state/apply-action.tsx b/src/mol-plugin/ui/state/apply-action.tsx index c78e3cf1128a1c91fe80147df15a7f7bae4ad77e..93a6cd3ab99833a0e9ee7207f979ef641f14131d 100644 --- a/src/mol-plugin/ui/state/apply-action.tsx +++ b/src/mol-plugin/ui/state/apply-action.tsx @@ -42,7 +42,6 @@ class ApplyActionContol extends TransformContolBase<ApplyActionContol.Props, App } getInfo() { return this._getInfo(this.props.nodeRef, this.props.state.transforms.get(this.props.nodeRef).version); } getHeader() { return this.props.action.definition.display; } - getHeaderFallback() { return this.props.action.id; } canApply() { return !this.state.error && !this.state.busy; } canAutoApply() { return false; } applyText() { return 'Apply'; } diff --git a/src/mol-plugin/ui/state/common.tsx b/src/mol-plugin/ui/state/common.tsx index 78defcc31e014db8c4ccc6159b40b428bf970b31..13c1127003fa784628283831752b528d5c7e9bf2 100644 --- a/src/mol-plugin/ui/state/common.tsx +++ b/src/mol-plugin/ui/state/common.tsx @@ -99,7 +99,6 @@ abstract class TransformContolBase<P, S extends TransformContolBase.ControlState abstract applyAction(): Promise<void>; abstract getInfo(): StateTransformParameters.Props['info']; abstract getHeader(): Transformer.Definition['display']; - abstract getHeaderFallback(): string; abstract canApply(): boolean; abstract canAutoApply(newParams: any): boolean; abstract applyText(): string; @@ -171,7 +170,7 @@ abstract class TransformContolBase<P, S extends TransformContolBase.ControlState return <div className='msp-transform-wrapper'> <div className='msp-transform-header'> - <button className='msp-btn msp-btn-block' onClick={this.toggleExpanded}>{(display && display.name) || this.getHeaderFallback()}</button> + <button className='msp-btn msp-btn-block' onClick={this.toggleExpanded}>{display.name}</button> {!this.state.isCollapsed && <button className='msp-btn msp-btn-link msp-transform-default-params' onClick={this.setDefault} disabled={this.state.busy} style={{ float: 'right'}} title='Set default params'>↻</button>} </div> {!this.state.isCollapsed && <> diff --git a/src/mol-plugin/ui/state/update-transform.tsx b/src/mol-plugin/ui/state/update-transform.tsx index d31f378fc934dacf5e584b0d22eaf845e83ea68f..c0fa6982706453424f3a1e9fac036975d9edc1c4 100644 --- a/src/mol-plugin/ui/state/update-transform.tsx +++ b/src/mol-plugin/ui/state/update-transform.tsx @@ -29,7 +29,6 @@ class UpdateTransformContol extends TransformContolBase<UpdateTransformContol.Pr applyAction() { return this.plugin.updateTransform(this.props.state, this.props.transform.ref, this.state.params); } getInfo() { return this._getInfo(this.props.transform); } getHeader() { return this.props.transform.transformer.definition.display; } - getHeaderFallback() { return this.props.transform.transformer.definition.name; } canApply() { return !this.state.error && !this.state.busy && !this.state.isInitial; } applyText() { return this.canApply() ? 'Update' : 'Nothing to Update'; } isUpdate() { return true; } diff --git a/src/mol-state/action.ts b/src/mol-state/action.ts index 264a9266ece3ad3f5213ae2ca2a711378e5e2c99..47b9540b2134bd12e18714b541ecaa898da65984 100644 --- a/src/mol-state/action.ts +++ b/src/mol-state/action.ts @@ -39,8 +39,6 @@ namespace StateAction { } export interface DefinitionBase<A extends StateObject = StateObject, T = any, P extends {} = {}> { - readonly display?: { readonly name: string, readonly description?: string }, - /** * Apply an action that modifies the State specified in Params. */ @@ -52,6 +50,7 @@ namespace StateAction { export interface Definition<A extends StateObject = StateObject, T = any, P extends {} = {}> extends DefinitionBase<A, T, P> { readonly from: StateObject.Ctor[], + readonly display: { readonly name: string, readonly description?: string }, params?(a: A, globalCtx: unknown): { [K in keyof P]: PD.Any } } @@ -80,7 +79,8 @@ namespace StateAction { export namespace Builder { export interface Type<A extends StateObject.Ctor, P extends { }> { from?: A | A[], - params?: PD.For<P> | ((a: StateObject.From<A>, globalCtx: any) => PD.For<P>) + params?: PD.For<P> | ((a: StateObject.From<A>, globalCtx: any) => PD.For<P>), + display?: string | { name: string, description?: string } } export interface Root { @@ -88,7 +88,7 @@ namespace StateAction { } export interface Define<A extends StateObject, P> { - <T>(def: DefinitionBase<A, T, P>): StateAction<A, T, P> + <T>(def: DefinitionBase<A, T, P>): StateAction<A, T, P>, } function root(info: Type<any, any>): Define<any, any> { @@ -96,6 +96,11 @@ namespace StateAction { from: info.from instanceof Array ? info.from : !!info.from ? [info.from] : [], + display: typeof info.display === 'string' + ? { name: info.display } + : !!info.display + ? info.display + : { name: 'Unnamed State Action' }, params: typeof info.params === 'object' ? () => info.params as any : !!info.params diff --git a/src/mol-state/transformer.ts b/src/mol-state/transformer.ts index 448272e76a94324ec9c08b773263fc7d7f17be62..05663bd8555f5da3b8ddcbaf23c0fd881acd5e74 100644 --- a/src/mol-state/transformer.ts +++ b/src/mol-state/transformer.ts @@ -9,6 +9,7 @@ import { StateObject } from './object'; import { Transform } from './transform'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { StateAction } from './action'; +import { capitalize } from 'mol-util/string'; export interface Transformer<A extends StateObject = StateObject, B extends StateObject = StateObject, P extends {} = {}> { apply(parent: Transform.Ref, params?: P, props?: Partial<Transform.Options>): Transform<A, B, P>, @@ -57,8 +58,6 @@ export namespace Transformer { // export type ParamsDefinition<A extends StateObject = StateObject, P = any> = (a: A, globalCtx: unknown) => { [K in keyof P]: PD.Any } export interface DefinitionBase<A extends StateObject = StateObject, B extends StateObject = StateObject, P extends {} = {}> { - readonly display?: { readonly name: string, readonly description?: string }, - /** * Apply the actual transformation. It must be pure (i.e. with no side effects). * Returns a task that produces the result of the result directly. @@ -89,6 +88,7 @@ export namespace Transformer { readonly name: string, readonly from: StateObject.Ctor[], readonly to: StateObject.Ctor[], + readonly display: { readonly name: string, readonly description?: string }, params?(a: A, globalCtx: unknown): { [K in keyof P]: PD.Any }, } @@ -151,7 +151,8 @@ export namespace Transformer { name: string, from: A | A[], to: B | B[], - params?: PD.For<P> | ((a: StateObject.From<A>, globalCtx: any) => PD.For<P>) + params?: PD.For<P> | ((a: StateObject.From<A>, globalCtx: any) => PD.For<P>), + display?: string | { name: string, description?: string } } export interface Root { @@ -167,6 +168,11 @@ export namespace Transformer { name: info.name, from: info.from instanceof Array ? info.from : [info.from], to: info.to instanceof Array ? info.to : [info.to], + display: typeof info.display === 'string' + ? { name: info.display } + : !!info.display + ? info.display + : { name: capitalize(info.name.replace(/[-]/g, ' ')) }, params: typeof info.params === 'object' ? () => info.params as any : !!info.params @@ -189,6 +195,7 @@ export namespace Transformer { name: 'root', from: [], to: [], + display: { name: 'Root' }, apply() { throw new Error('should never be applied'); }, update() { return UpdateResult.Unchanged; } })