diff --git a/src/mol-plugin/state/actions/basic.ts b/src/mol-plugin/state/actions/basic.ts index 17f128c76354494119813d5354c774e83860a6bd..19dee261c1fa076a7729e6524cbbe6512af61230 100644 --- a/src/mol-plugin/state/actions/basic.ts +++ b/src/mol-plugin/state/actions/basic.ts @@ -81,13 +81,14 @@ const DownloadStructure = StateAction.create<PluginStateObject.Root, void, Downl } }); -export const OpenStructure = StateAction.create<PluginStateObject.Root, void, { file: File }>({ - from: [PluginStateObject.Root], +export const OpenStructure = StateAction.build({ + 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' }, - params: () => ({ file: PD.File({ accept: '.cif,.bcif' }) }), 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) }); @@ -130,8 +131,9 @@ function complexRepresentation(root: StateTreeBuilder.To<PluginStateObject.Molec // TODO: create spheres visual } -export const CreateComplexRepresentation = StateAction.create<PluginStateObject.Molecule.Structure, void, {}>({ - from: [PluginStateObject.Molecule.Structure], +export const CreateComplexRepresentation = StateAction.build({ + from: PluginStateObject.Molecule.Structure +})({ display: { name: 'Create Complex', description: 'Split the structure into Sequence/Water/Ligands/... ' @@ -143,15 +145,15 @@ export const CreateComplexRepresentation = StateAction.create<PluginStateObject. } }); -export const UpdateTrajectory = StateAction.create<PluginStateObject.Root, void, { action: 'advance' | 'reset', by?: number }>({ - from: [], +export const UpdateTrajectory = StateAction.build({ + 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' }, - params: () => ({ - action: PD.Select('advance', [['advance', 'Advance'], ['reset', 'Reset']]), - by: PD.Numeric(1, { min: -1, max: 1, step: 1 }, { isOptional: true }) - }), 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-state/action.ts b/src/mol-state/action.ts index b1e2ee0e0fd565fecd874e3676762928b78d47a4..cd867b8e5bc1657bd7465630b7789ebf75e7e29c 100644 --- a/src/mol-state/action.ts +++ b/src/mol-state/action.ts @@ -38,8 +38,7 @@ namespace StateAction { params: P } - export interface Definition<A extends StateObject = StateObject, T = any, P extends {} = {}> { - readonly from: StateObject.Ctor[], + export interface DefinitionBase<A extends StateObject = StateObject, T = any, P extends {} = {}> { readonly display?: { readonly name: string, readonly description?: string }, /** @@ -47,12 +46,15 @@ namespace StateAction { */ apply(params: ApplyParams<A, P>, globalCtx: unknown): T | Task<T>, - params?(a: A, globalCtx: unknown): { [K in keyof P]: PD.Any }, - /** Test if the transform can be applied to a given node */ isApplicable?(a: A, globalCtx: unknown): boolean } + export interface Definition<A extends StateObject = StateObject, T = any, P extends {} = {}> extends DefinitionBase<A, T, P> { + readonly from: StateObject.Ctor[], + params?(a: A, globalCtx: unknown): { [K in keyof P]: PD.Any } + } + export function create<A extends StateObject, T, P extends {} = {}>(definition: Definition<A, T, P>): StateAction<A, T, P> { const action: StateAction<A, T, P> = { create(params) { return { action, params }; }, @@ -74,4 +76,43 @@ namespace StateAction { } }) } + + export namespace Builder { + type ParamDefinition<P> = { [K in keyof P]-?: PD.Base<P[K]> } + + export interface Type<A extends StateObject.Ctor, P extends { }> { + from?: A | A[], + params?: ParamDefinition<P> | ((a: StateObject.From<A>, globalCtx: any) => ParamDefinition<P>) + } + + export interface Root { + <A extends StateObject.Ctor, P extends { }>(info: Type<A, P>): Define<StateObject.From<A>, Params<P>> + } + + type Optionals<P> = { [K in keyof P]-?: undefined extends P[K] ? K : never }[keyof P] + type NonOptionals<P> = { [K in keyof P]-?: undefined extends P[K] ? never: K }[keyof P] + type Params<P> = Pick<P, NonOptionals<P>> & Partial<Pick<P, Optionals<P>>> + + export interface Define<A extends StateObject, P> { + <T>(def: DefinitionBase<A, T, P>): StateAction<A, T, P> + } + + function root(info: Type<any, any>): Define<any, any> { + return def => create({ + from: info.from instanceof Array + ? info.from + : !!info.from ? [info.from] : [], + params: typeof info.params === 'object' + ? () => info.params as any + : !!info.params + ? info.params as any + : void 0, + ...def + }); + } + + export const build: Root = (info: any) => root(info); + } + + export const build = Builder.build; } \ No newline at end of file diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index e5c6e80b5588f6c79040fffbbad8ec67057d8833..5bdde061f0f1e2911e0eab1758845fe7d824ebd2 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -15,19 +15,18 @@ export namespace ParamDefinition { label?: string, description?: string, isHidden?: boolean, - isOptional?: boolean, } function setInfo<T extends Info>(param: T, info?: Info): T { if (!info) return param; if (info.description) param.description = info.description; if (info.label) param.label = info.label; - if (info.isOptional) param.isOptional = info.isOptional; if (info.isHidden) param.isHidden = info.isHidden; return param; } export interface Base<T> extends Info { + isOptional?: boolean, defaultValue: T }