diff --git a/src/mol-plugin/behavior/static/representation.ts b/src/mol-plugin/behavior/static/representation.ts index d62cb8ea8af9bfe6333ee49c323d1ea584e38b9a..90b7e473802ea99cc02e3c9f76c5a23033008790 100644 --- a/src/mol-plugin/behavior/static/representation.ts +++ b/src/mol-plugin/behavior/static/representation.ts @@ -53,5 +53,5 @@ export function UpdateRepresentationVisibility(ctx: PluginContext) { } function updateVisibility(e: State.ObjectEvent, r: Representation<any>) { - r.setVisibility(!e.state.tree.cellStates.get(e.ref).isHidden); + r.setVisibility(!e.state.cellStates.get(e.ref).isHidden); } \ No newline at end of file diff --git a/src/mol-plugin/behavior/static/state.ts b/src/mol-plugin/behavior/static/state.ts index 6e6643a398448bad1fdc354133d9188dad74d0f4..f83a7ca8de9f4e087862ed2a02f3e52a4c24b073 100644 --- a/src/mol-plugin/behavior/static/state.ts +++ b/src/mol-plugin/behavior/static/state.ts @@ -64,11 +64,11 @@ export function ToggleExpanded(ctx: PluginContext) { } export function ToggleVisibility(ctx: PluginContext) { - PluginCommands.State.ToggleVisibility.subscribe(ctx, ({ state, ref }) => setVisibility(state, ref, !state.tree.cellStates.get(ref).isHidden)); + PluginCommands.State.ToggleVisibility.subscribe(ctx, ({ state, ref }) => setVisibility(state, ref, !state.cellStates.get(ref).isHidden)); } function setVisibility(state: State, root: Transform.Ref, value: boolean) { - StateTree.doPreOrder(state.tree, state.tree.transforms.get(root), { state, value }, setVisibilityVisitor); + StateTree.doPreOrder(state.tree, state.transforms.get(root), { state, value }, setVisibilityVisitor); } function setVisibilityVisitor(t: Transform, tree: StateTree, ctx: { state: State, value: boolean }) { diff --git a/src/mol-plugin/state/transforms/model.ts b/src/mol-plugin/state/transforms/model.ts index 220220e34ba9e50d403f0d30616d2ad07953182e..4c914e8ffe1af78436ae08c6794f5f5c046267f8 100644 --- a/src/mol-plugin/state/transforms/model.ts +++ b/src/mol-plugin/state/transforms/model.ts @@ -47,6 +47,7 @@ const ParseTrajectoryFromMmCif = PluginStateTransform.Create<SO.Data.Cif, SO.Mol }); export { CreateModelFromTrajectory } +const plus1 = (v: number) => v + 1, minus1 = (v: number) => v - 1; namespace CreateModelFromTrajectory { export interface Params { modelIndex: number } } const CreateModelFromTrajectory = PluginStateTransform.Create<SO.Molecule.Trajectory, SO.Molecule.Model, CreateModelFromTrajectory.Params>({ name: 'create-model-from-trajectory', @@ -58,7 +59,7 @@ const CreateModelFromTrajectory = PluginStateTransform.Create<SO.Molecule.Trajec to: [SO.Molecule.Model], params: { default: () => ({ modelIndex: 0 }), - definition: a => ({ modelIndex: PD.Numeric(0, { min: 0, max: Math.max(0, a.data.length - 1), step: 1 }, { description: 'Model Index' }) }) + definition: a => ({ modelIndex: PD.Converted(plus1, minus1, PD.Numeric(1, { min: 1, max: a.data.length, step: 1 }, { description: 'Model Index' })) }) }, isApplicable: a => a.data.length > 0, apply({ a, params }) { diff --git a/src/mol-plugin/ui/controls/parameters.tsx b/src/mol-plugin/ui/controls/parameters.tsx index d5c129e4440a4b08d2300214fceb23391ebef560..9a65e23bca41031435050954fc14585a12332c31 100644 --- a/src/mol-plugin/ui/controls/parameters.tsx +++ b/src/mol-plugin/ui/controls/parameters.tsx @@ -87,7 +87,10 @@ export class BoolControl extends SimpleParam<PD.Boolean> { export class NumberControl extends SimpleParam<PD.Numeric> { onChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.update(+e.target.value); } renderControl() { - return <input type='range' value={'' + this.props.value} min={this.props.param.min} max={this.props.param.max} step={this.props.param.step} onChange={this.onChange} disabled={this.props.isDisabled} />; + return <span> + <input type='range' value={'' + this.props.value} min={this.props.param.min} max={this.props.param.max} step={this.props.param.step} onChange={this.onChange} disabled={this.props.isDisabled} /> + <br />{this.props.value} + </span> } } @@ -243,7 +246,7 @@ export class ConvertedControl extends React.PureComponent<ParamProps<PD.Converte this.props.onChange({ name: this.props.name, param: this.props.param, - value: { name: e.value, params: this.props.param.toValue(e.value) } + value: this.props.param.toValue(e.value) }); } diff --git a/src/mol-plugin/ui/plugin.tsx b/src/mol-plugin/ui/plugin.tsx index bd0435deb4ac2c9adee7715d999c607500e79dc3..bb3ff2eeba2fe479de73488b56a8cebd9a1dfae2 100644 --- a/src/mol-plugin/ui/plugin.tsx +++ b/src/mol-plugin/ui/plugin.tsx @@ -129,7 +129,7 @@ export class CurrentObject extends PluginComponent { const type = obj && obj.obj ? obj.obj.type : void 0; - const transform = current.state.tree.transforms.get(ref); + const transform = current.state.transforms.get(ref); const actions = type ? current.state.actions.fromType(type) diff --git a/src/mol-plugin/ui/state-tree.tsx b/src/mol-plugin/ui/state-tree.tsx index 621024d58918565b20a3c12e9080b0032661b0de..9634c8dcf48433cf512bde18b2efb03cf213a4f6 100644 --- a/src/mol-plugin/ui/state-tree.tsx +++ b/src/mol-plugin/ui/state-tree.tsx @@ -33,7 +33,7 @@ class StateTreeNode extends PluginComponent<{ nodeRef: string, state: State }, { } get cellState() { - return this.props.state.tree.cellStates.get(this.props.nodeRef); + return this.props.state.cellStates.get(this.props.nodeRef); } componentDidMount() { @@ -104,7 +104,7 @@ class StateTreeNodeLabel extends PluginComponent<{ nodeRef: string, state: State } else if (isCurrent) { isCurrent = false; // have to check the node wasn't remove - if (e.state.tree.transforms.has(this.props.nodeRef)) this.forceUpdate(); + if (e.state.transforms.has(this.props.nodeRef)) this.forceUpdate(); } }); } @@ -125,7 +125,7 @@ class StateTreeNodeLabel extends PluginComponent<{ nodeRef: string, state: State } render() { - const n = this.props.state.tree.transforms.get(this.props.nodeRef)!; + const n = this.props.state.transforms.get(this.props.nodeRef)!; const cell = this.props.state.cells.get(this.props.nodeRef)!; const isCurrent = this.is(this.props.state.behaviors.currentObject.value); @@ -141,7 +141,7 @@ class StateTreeNodeLabel extends PluginComponent<{ nodeRef: string, state: State label = <><a href='#' onClick={this.setCurrent}>{obj.label}</a> {obj.description ? <small>{obj.description}</small> : void 0}</>; } - const cellState = this.props.state.tree.cellStates.get(this.props.nodeRef); + const cellState = this.props.state.cellStates.get(this.props.nodeRef); const visibility = <>[<a href='#' onClick={this.toggleVisible}>{cellState.isHidden ? 'H' : 'V'}</a>]</>; return <> diff --git a/src/mol-plugin/ui/state/apply-action.tsx b/src/mol-plugin/ui/state/apply-action.tsx index 2c616a6be4edb49c2ee7f56625edd5c7d79c1773..1af3b9071d9b9f017b9f9ff92b984d68759ddd34 100644 --- a/src/mol-plugin/ui/state/apply-action.tsx +++ b/src/mol-plugin/ui/state/apply-action.tsx @@ -22,7 +22,8 @@ namespace ApplyActionContol { } export interface ComponentState { - nodeRef: Transform.Ref, + ref: Transform.Ref, + version: string, params: any, error?: string, busy: boolean, @@ -38,24 +39,28 @@ class ApplyActionContol extends TransformContolBase<ApplyActionContol.Props, App ref: this.props.nodeRef }); } - getInfo() { return this._getInfo(this.props.nodeRef); } + 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; } isBusy() { return !!this.state.error || this.state.busy; } applyText() { return 'Apply'; } - private _getInfo = memoizeOne((t: Transform.Ref) => StateTransformParameters.infoFromAction(this.plugin, this.props.state, this.props.action, this.props.nodeRef)); + private _getInfo = memoizeOne((t: Transform.Ref, v: string) => StateTransformParameters.infoFromAction(this.plugin, this.props.state, this.props.action, this.props.nodeRef)); - state = { nodeRef: this.props.nodeRef, error: void 0, isInitial: true, params: this.getInfo().initialValues, busy: false }; + state = { ref: this.props.nodeRef, version: this.props.state.transforms.get(this.props.nodeRef).version, error: void 0, isInitial: true, params: this.getInfo().initialValues, busy: false }; static getDerivedStateFromProps(props: ApplyActionContol.Props, state: ApplyActionContol.ComponentState) { - if (props.nodeRef === state.nodeRef) return null; + if (props.nodeRef === state.ref) return null; + const version = props.state.transforms.get(props.nodeRef).version; + if (version === state.version) return null; + const source = props.state.cells.get(props.nodeRef)!.obj!; const definition = props.action.definition.params || { }; const initialValues = definition.default ? definition.default(source, props.plugin) : {}; const newState: Partial<ApplyActionContol.ComponentState> = { - nodeRef: props.nodeRef, + ref: props.nodeRef, + version, params: initialValues, isInitial: true, error: void 0 diff --git a/src/mol-plugin/ui/state/common.tsx b/src/mol-plugin/ui/state/common.tsx index 3ce020388d307fd17ddac75595a6a1d014765514..b5ebc0fb5de43bdb8441608e406a08cdc70af821 100644 --- a/src/mol-plugin/ui/state/common.tsx +++ b/src/mol-plugin/ui/state/common.tsx @@ -45,7 +45,7 @@ class StateTransformParameters extends PurePluginComponent<StateTransformParamet namespace StateTransformParameters { export interface Props { info: { - definition: Transformer.ParamsProvider, + definition: Transformer.ParamsDefinition, params: PD.Params, initialValues: any, source: StateObject, diff --git a/src/mol-state/action.ts b/src/mol-state/action.ts index 024fe3e0d3c14db89d0c145be1c67787ad200b74..e230f4e071b65a6ae4bd3cdbd9c8f74e692a1fb0 100644 --- a/src/mol-state/action.ts +++ b/src/mol-state/action.ts @@ -46,7 +46,7 @@ namespace StateAction { */ apply(params: ApplyParams<A, P>, globalCtx: unknown): T | Task<T>, - readonly params?: Transformer.ParamsProvider<A, P> + readonly params?: Transformer.ParamsDefinition<A, P> /** Test if the transform can be applied to a given node */ isApplicable?(a: A, globalCtx: unknown): boolean diff --git a/src/mol-state/state.ts b/src/mol-state/state.ts index 5c2f27e15f4465f27b1814fe5de794571ec08fed..8385b27f947ed19f1a8004c4bb5e1d0816357c1a 100644 --- a/src/mol-state/state.ts +++ b/src/mol-state/state.ts @@ -52,6 +52,8 @@ class State { readonly actions = new StateActionManager(); get tree(): StateTree { return this._tree; } + get transforms() { return (this._tree as StateTree).transforms; } + get cellStates() { return (this._tree as StateTree).cellStates; } get current() { return this.behaviors.currentObject.value.ref; } build() { return this._tree.build(); } diff --git a/src/mol-state/transformer.ts b/src/mol-state/transformer.ts index 673e2786960828599411424d1099503e9fd2052b..0a68047efc5c9cc700bb09315bd6856b2983821d 100644 --- a/src/mol-state/transformer.ts +++ b/src/mol-state/transformer.ts @@ -47,7 +47,7 @@ export namespace Transformer { export enum UpdateResult { Unchanged, Updated, Recreate } - export interface ParamsProvider<A extends StateObject = StateObject, P = any> { + export interface ParamsDefinition<A extends StateObject = StateObject, P = any> { /** Check the parameters and return a list of errors if the are not valid. */ default?(a: A, globalCtx: unknown): P, /** Specify default control descriptors for the parameters */ @@ -75,7 +75,7 @@ export namespace Transformer { */ update?(params: UpdateParams<A, B, P>, globalCtx: unknown): Task<UpdateResult> | UpdateResult, - readonly params?: ParamsProvider<A, P>, + readonly params?: ParamsDefinition<A, P>, /** Test if the transform can be applied to a given node */ isApplicable?(a: A, globalCtx: unknown): boolean, diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index 955906abca4e24c7fe9dbabccd88785038ebbdf3..e53915ce0a81d62a59ecd60635f3c2c389c035db 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -138,8 +138,8 @@ export namespace ParamDefinition { fromValue(v: T): C, toValue(v: C): T } - export function Converted<T, C extends Any>(defaultValue: T, converted: C, fromValue: (v: T) => C, toValue: (v: C) => T): Converted<T, C> { - return { type: 'converted', defaultValue, converted, fromValue, toValue }; + export function Converted<T, C extends Any>(fromValue: (v: T) => C['defaultValue'], toValue: (v: C['defaultValue']) => T, converted: C): Converted<T, C['defaultValue']> { + return { type: 'converted', defaultValue: toValue(converted.defaultValue), converted, fromValue, toValue }; } export type Any = Value<any> | Select<any> | MultiSelect<any> | Boolean | Text | Color | Numeric | Interval | LineGraph | Group<any> | Mapped<any> | Converted<any, any>