diff --git a/src/cli/state-docs/pd-to-md.ts b/src/cli/state-docs/pd-to-md.ts index 1e0d4ef4b5b6d05f602b010bdc029fe4385bcac8..0e0fa7af5d7cb90ea0707a0f076f97707842bedb 100644 --- a/src/cli/state-docs/pd-to-md.ts +++ b/src/cli/state-docs/pd-to-md.ts @@ -26,7 +26,8 @@ function paramInfo(param: PD.Any, offset: number): string { case 'file': return `JavaScript File Handle`; case 'file-list': return `JavaScript FileList Handle`; case 'select': return `One of ${oToS(param.options)}`; - case 'value-ref': return `Reference to a state object.`; + case 'value-ref': return `Reference to a runtime defined value.`; + case 'data-ref': return `Reference to a computed data value.`; case 'text': return 'String'; case 'interval': return `Interval [min, max]`; case 'group': return `Object with:\n${getParams(param.params, offset + 2)}`; diff --git a/src/mol-plugin-ui/controls/parameters.tsx b/src/mol-plugin-ui/controls/parameters.tsx index c21ac30f1d7e65a4abd617df1bae3898976ae49e..885e96d8045f16d69612e18f6ec29cb04dd1db63 100644 --- a/src/mol-plugin-ui/controls/parameters.tsx +++ b/src/mol-plugin-ui/controls/parameters.tsx @@ -186,6 +186,7 @@ function controlFor(param: PD.Any): ParamControl | undefined { case 'file-list': return FileListControl; case 'select': return SelectControl; case 'value-ref': return ValueRefControl; + case 'data-ref': return void 0; case 'text': return TextControl; case 'interval': return typeof param.min !== 'undefined' && typeof param.max !== 'undefined' ? BoundedIntervalControl : IntervalControl; diff --git a/src/mol-state/state.ts b/src/mol-state/state.ts index 3e65f8a033d048aab9b1bcfcaee2ff1c9142a9f5..5412004ec782bad22477a5315b2d246e0b9862a9 100644 --- a/src/mol-state/state.ts +++ b/src/mol-state/state.ts @@ -328,6 +328,8 @@ class State { const oldTree = this._tree; this._tree = _tree; + const cells = this.cells; + const ctx: UpdateContext = { parent: this, editInfo: StateBuilder.is(tree) ? tree.editInfo : void 0, @@ -346,7 +348,9 @@ class State { changed: false, hadError: false, wasAborted: false, - newCurrent: void 0 + newCurrent: void 0, + + getCellData: ref => cells.get(ref)!.obj?.data }; this.errorFree = true; @@ -454,7 +458,9 @@ interface UpdateContext { changed: boolean, hadError: boolean, wasAborted: boolean, - newCurrent?: Ref + newCurrent?: Ref, + + getCellData: (ref: string) => any } async function update(ctx: UpdateContext) { @@ -841,7 +847,7 @@ function resolveParams(ctx: UpdateContext, transform: StateTransform, src: State (transform.params as any) = transform.params ? assignIfUndefined(transform.params, defaultValues) : defaultValues; - ParamDefinition.resolveValueRefs(definition, transform.params); + ParamDefinition.resolveRefs(definition, transform.params, ctx.getCellData); return { definition, values: transform.params }; } diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index 1a441a9d8120c7ddb39518b0ea2258f1ea514e75..7d66032de13e696e3d090a09386144e6a6e5d569 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -296,6 +296,13 @@ export namespace ParamDefinition { return setInfo<ValueRef<T>>({ type: 'value-ref', defaultValue: { ref: info?.defaultRef ?? '', getValue: unsetGetValue as any }, getOptions, resolveRef }, info); } + export interface DataRef<T = any> extends Base<{ ref: string, getValue: () => T }> { + type: 'data-ref' + } + export function DataRef<T>(info?: Info & { defaultRef?: string }) { + return setInfo<DataRef<T>>({ type: 'data-ref', defaultValue: { ref: info?.defaultRef ?? '', getValue: unsetGetValue as any } }, info); + } + export interface Converted<T, C> extends Base<T> { type: 'converted', converted: Any, @@ -329,7 +336,7 @@ export namespace ParamDefinition { export type Any = | Value<any> | Select<any> | MultiSelect<any> | BooleanParam | Text | Color | Vec3 | Mat4 | Numeric | FileParam | UrlParam | FileListParam | Interval | LineGraph - | ColorList | Group<any> | Mapped<any> | Converted<any, any> | Conditioned<any, any, any> | Script | ObjectList | ValueRef + | ColorList | Group<any> | Mapped<any> | Converted<any, any> | Conditioned<any, any, any> | Script | ObjectList | ValueRef | DataRef export type Params = { [k: string]: Any } export type Values<T extends Params> = { [k in keyof T]: T[k]['defaultValue'] } @@ -360,29 +367,33 @@ export namespace ParamDefinition { return () => resolve(ref); } - function resolveRefValue(p: Any, value: any) { + function resolveRefValue(p: Any, value: any, getData: (ref: string) => any) { if (!value) return; if (p.type === 'value-ref') { const v = value as ValueRef['defaultValue']; if (!v.ref) v.getValue = () => { throw new Error('Unset ref in ValueRef value.'); }; else v.getValue = _resolveRef(p.resolveRef, v.ref); + } else if (p.type === 'data-ref') { + const v = value as ValueRef['defaultValue']; + if (!v.ref) v.getValue = () => { throw new Error('Unset ref in ValueRef value.'); }; + else v.getValue = _resolveRef(getData, v.ref); } else if (p.type === 'group') { - resolveValueRefs(p.params, value); + resolveRefs(p.params, value, getData); } else if (p.type === 'mapped') { const v = value as NamedParams; const param = p.map(v.name); - resolveRefValue(param, v.params); + resolveRefValue(param, v.params, getData); } else if (p.type === 'object-list') { if (!hasValueRef(p.element)) return; for (const e of value) { - resolveValueRefs(p.element, e); + resolveRefs(p.element, e, getData); } } } function hasParamValueRef(p: Any) { - if (p.type === 'value-ref') { + if (p.type === 'value-ref' || p.type === 'data-ref') { return true; } else if (p.type === 'group') { if (hasValueRef(p.params)) return true; @@ -403,9 +414,9 @@ export namespace ParamDefinition { return false; } - export function resolveValueRefs(params: Params, values: any) { + export function resolveRefs(params: Params, values: any, getData: (ref: string) => any) { for (const n of Object.keys(params)) { - resolveRefValue(params[n], values?.[n]); + resolveRefValue(params[n], values?.[n], getData); } }