From ba3eee8cade12ec09e90808ca89e8825b3c42834 Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Sun, 10 Mar 2019 15:57:46 +0100 Subject: [PATCH] adder more static label options to structures, various fixes --- src/mol-plugin/state/actions/structure.ts | 8 ++++---- src/mol-plugin/state/animation/built-in.ts | 6 ++++++ src/mol-plugin/state/transforms/data.ts | 14 +++++++------- src/mol-plugin/state/transforms/misc.ts | 2 +- src/mol-plugin/state/transforms/model.ts | 12 ++++++------ src/mol-plugin/state/transforms/representation.ts | 13 +++++++++---- src/mol-plugin/state/transforms/volume.ts | 4 ++-- src/mol-plugin/ui/controls/parameters.tsx | 3 ++- src/mol-plugin/util/structure-labels.ts | 15 ++++++++++----- src/mol-util/param-definition.ts | 7 ++++--- 10 files changed, 51 insertions(+), 33 deletions(-) diff --git a/src/mol-plugin/state/actions/structure.ts b/src/mol-plugin/state/actions/structure.ts index 76b4b0d9f..714adecf2 100644 --- a/src/mol-plugin/state/actions/structure.ts +++ b/src/mol-plugin/state/actions/structure.ts @@ -69,8 +69,8 @@ export const GroProvider: DataFormatProvider<any> = { // const DownloadStructurePdbIdSourceOptions = PD.Group({ - supportProps: PD.asOptional(PD.Boolean(false)), - asTrajectory: PD.asOptional(PD.Boolean(false, { description: 'Load all entries into a single trajectory.' })) + supportProps: PD.Optional(PD.Boolean(false)), + asTrajectory: PD.Optional(PD.Boolean(false, { description: 'Load all entries into a single trajectory.' })) }); export { DownloadStructure }; @@ -97,7 +97,7 @@ const DownloadStructure = StateAction.build({ format: PD.Select('cif', [['cif', 'CIF'], ['pdb', 'PDB']]), isBinary: PD.Boolean(false), options: PD.Group({ - supportProps: PD.asOptional(PD.Boolean(false)) + supportProps: PD.Optional(PD.Boolean(false)) }) }, { isFlat: true }) }, { @@ -242,7 +242,7 @@ export const UpdateTrajectory = StateAction.build({ display: { name: 'Update Trajectory' }, params: { action: PD.Select<'advance' | 'reset'>('advance', [['advance', 'Advance'], ['reset', 'Reset']]), - by: PD.asOptional(PD.Numeric(1, { min: -1, max: 1, step: 1 })) + by: PD.Optional(PD.Numeric(1, { min: -1, max: 1, step: 1 })) } })(({ params, state }) => { const models = state.selectQ(q => q.ofTransformer(StateTransforms.Model.ModelFromTrajectory)); diff --git a/src/mol-plugin/state/animation/built-in.ts b/src/mol-plugin/state/animation/built-in.ts index 0c58a509e..308bc1bd6 100644 --- a/src/mol-plugin/state/animation/built-in.ts +++ b/src/mol-plugin/state/animation/built-in.ts @@ -113,6 +113,9 @@ export const AnimateAssemblyUnwind = PluginStateAnimation.create({ const update = state.build(); let changed = false; for (const r of reprs) { + // TODO: find a better way to handle this, perhaps add a different state object?? + if (r.transform.transformer === StateTransforms.Representation.StructureLabels3D) continue; + const unwinds = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Representation.UnwindStructureAssemblyRepresentation3D, r.transform.ref)); if (unwinds.length > 0) continue; @@ -180,6 +183,9 @@ export const AnimateUnitsExplode = PluginStateAnimation.create({ const update = state.build(); let changed = false; for (const r of reprs) { + // TODO: find a better way to handle this, perhaps add a different state object?? + if (r.transform.transformer === StateTransforms.Representation.StructureLabels3D) continue; + const explodes = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Representation.ExplodeStructureRepresentation3D, r.transform.ref)); if (explodes.length > 0) continue; diff --git a/src/mol-plugin/state/transforms/data.ts b/src/mol-plugin/state/transforms/data.ts index d04b01d59..aa0554a56 100644 --- a/src/mol-plugin/state/transforms/data.ts +++ b/src/mol-plugin/state/transforms/data.ts @@ -25,8 +25,8 @@ const Download = PluginStateTransform.BuiltIn({ to: [SO.Data.String, SO.Data.Binary], params: { url: PD.Text('https://www.ebi.ac.uk/pdbe/static/entry/1cbs_updated.cif', { description: 'Resource URL. Must be the same domain or support CORS.' }), - label: PD.asOptional(PD.Text('')), - isBinary: PD.asOptional(PD.Boolean(false, { description: 'If true, download data as binary (string otherwise)' })) + label: PD.Optional(PD.Text('')), + isBinary: PD.Optional(PD.Boolean(false, { description: 'If true, download data as binary (string otherwise)' })) } })({ apply({ params: p }, globalCtx: PluginContext) { @@ -58,10 +58,10 @@ const DownloadBlob = PluginStateTransform.BuiltIn({ sources: PD.ObjectList({ id: PD.Text('', { label: 'Unique ID' }), url: PD.Text('https://www.ebi.ac.uk/pdbe/static/entry/1cbs_updated.cif', { description: 'Resource URL. Must be the same domain or support CORS.' }), - isBinary: PD.asOptional(PD.Boolean(false, { description: 'If true, download data as binary (string otherwise)' })), - canFail: PD.asOptional(PD.Boolean(false, { description: 'Indicate whether the download can fail and not be included in the blob as a result.' })) + isBinary: PD.Optional(PD.Boolean(false, { description: 'If true, download data as binary (string otherwise)' })), + canFail: PD.Optional(PD.Boolean(false, { description: 'Indicate whether the download can fail and not be included in the blob as a result.' })) }, e => `${e.id}: ${e.url}`), - maxConcurrency: PD.asOptional(PD.Numeric(4, { min: 1, max: 12, step: 1 }, { description: 'The maximum number of concurrent downloads.' })) + maxConcurrency: PD.Optional(PD.Numeric(4, { min: 1, max: 12, step: 1 }, { description: 'The maximum number of concurrent downloads.' })) } })({ apply({ params }, plugin: PluginContext) { @@ -102,8 +102,8 @@ const ReadFile = PluginStateTransform.BuiltIn({ to: [SO.Data.String, SO.Data.Binary], params: { file: PD.File(), - label: PD.asOptional(PD.Text('')), - isBinary: PD.asOptional(PD.Boolean(false, { description: 'If true, open file as as binary (string otherwise)' })) + label: PD.Optional(PD.Text('')), + isBinary: PD.Optional(PD.Boolean(false, { description: 'If true, open file as as binary (string otherwise)' })) } })({ apply({ params: p }) { diff --git a/src/mol-plugin/state/transforms/misc.ts b/src/mol-plugin/state/transforms/misc.ts index 86f3d9611..69aac3a93 100644 --- a/src/mol-plugin/state/transforms/misc.ts +++ b/src/mol-plugin/state/transforms/misc.ts @@ -18,7 +18,7 @@ const CreateGroup = PluginStateTransform.BuiltIn({ to: SO.Group, params: { label: PD.Text('Group'), - description: PD.asOptional(PD.Text('')) + description: PD.Optional(PD.Text('')) } })({ apply({ params }) { diff --git a/src/mol-plugin/state/transforms/model.ts b/src/mol-plugin/state/transforms/model.ts index 57dd2bfa1..dd54e9dc4 100644 --- a/src/mol-plugin/state/transforms/model.ts +++ b/src/mol-plugin/state/transforms/model.ts @@ -71,12 +71,12 @@ const TrajectoryFromMmCif = PluginStateTransform.BuiltIn({ params(a) { if (!a) { return { - blockHeader: PD.asOptional(PD.Text(void 0, { description: 'Header of the block to parse. If none is specifed, the 1st data block in the file is used.' })) + blockHeader: PD.Optional(PD.Text(void 0, { description: 'Header of the block to parse. If none is specifed, the 1st data block in the file is used.' })) }; } const { blocks } = a.data; return { - blockHeader: PD.asOptional(PD.Select(blocks[0] && blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]), { description: 'Header of the block to parse' })) + blockHeader: PD.Optional(PD.Select(blocks[0] && blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]), { description: 'Header of the block to parse' })) }; } })({ @@ -181,12 +181,12 @@ const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({ to: SO.Molecule.Structure, params(a) { if (!a) { - return { id: PD.asOptional(PD.Text('', { label: 'Assembly Id', description: 'Assembly Id. Value \'deposited\' can be used to specify deposited asymmetric unit.' })) }; + return { id: PD.Optional(PD.Text('', { label: 'Assembly Id', description: 'Assembly Id. Value \'deposited\' can be used to specify deposited asymmetric unit.' })) }; } const model = a.data; const ids = model.symmetry.assemblies.map(a => [a.id, `${a.id}: ${stringToWords(a.details)}`] as [string, string]); ids.push(['deposited', 'Deposited']); - return { id: PD.asOptional(PD.Select(ids[0][0], ids, { label: 'Asm Id', description: 'Assembly Id' })) }; + return { id: PD.Optional(PD.Select(ids[0][0], ids, { label: 'Asm Id', description: 'Assembly Id' })) }; } })({ apply({ a, params }, plugin: PluginContext) { @@ -258,7 +258,7 @@ const StructureSelection = PluginStateTransform.BuiltIn({ to: SO.Molecule.Structure, params: { query: PD.Value<Expression>(MolScriptBuilder.struct.generator.all, { isHidden: true }), - label: PD.asOptional(PD.Text('', { isHidden: true })) + label: PD.Optional(PD.Text('', { isHidden: true })) } })({ apply({ a, params, cache }) { @@ -295,7 +295,7 @@ const UserStructureSelection = PluginStateTransform.BuiltIn({ to: SO.Molecule.Structure, params: { query: PD.ScriptExpression({ language: 'mol-script', expression: '(sel.atom.atom-groups :residue-test (= atom.resname ALA))' }), - label: PD.asOptional(PD.Text('')) + label: PD.Optional(PD.Text('')) } })({ apply({ a, params, cache }) { diff --git a/src/mol-plugin/state/transforms/representation.ts b/src/mol-plugin/state/transforms/representation.ts index d13614ea4..b5c9e1a82 100644 --- a/src/mol-plugin/state/transforms/representation.ts +++ b/src/mol-plugin/state/transforms/representation.ts @@ -202,9 +202,13 @@ const StructureLabels3D = PluginStateTransform.BuiltIn({ target: PD.MappedStatic('residues', { 'elements': PD.Group({ }), 'residues': PD.Group({ }), - 'static-text': PD.Group({ value: PD.Text('') }, { isFlat: true }) + 'static-text': PD.Group({ + value: PD.Text(''), + size: PD.Optional(PD.Numeric(1, { min: 1, max: 1000, step: 0.1 })), + // TODO: this changes the position while rotated etc... fix + position: PD.Optional(Text.Params.attachment) + }, { isFlat: true }) }), - // PD.Select<'elements' | 'residues'>('residues', [['residues', 'Residues'], ['elements', 'Elements']]), options: PD.Group({ ...Text.Params, @@ -215,8 +219,9 @@ const StructureLabels3D = PluginStateTransform.BuiltIn({ }) } })({ - canAutoUpdate({ a, oldParams, newParams }) { - return newParams.target.name === 'static-text' || newParams.target.name === oldParams.target.name + canAutoUpdate({ oldParams, newParams }) { + return (oldParams.target.name === 'static-text' && newParams.target.name === 'static-text' && oldParams.target.params.value === newParams.target.params.value) + || newParams.target.name === oldParams.target.name; }, apply({ a, params }) { return Task.create('Structure Labels', async ctx => { diff --git a/src/mol-plugin/state/transforms/volume.ts b/src/mol-plugin/state/transforms/volume.ts index 399293a21..6861dc237 100644 --- a/src/mol-plugin/state/transforms/volume.ts +++ b/src/mol-plugin/state/transforms/volume.ts @@ -68,12 +68,12 @@ const VolumeFromDensityServerCif = PluginStateTransform.BuiltIn({ params(a) { if (!a) { return { - blockHeader: PD.asOptional(PD.Text(void 0, { description: 'Header of the block to parse. If none is specifed, the 1st data block in the file is used.' })) + blockHeader: PD.Optional(PD.Text(void 0, { description: 'Header of the block to parse. If none is specifed, the 1st data block in the file is used.' })) }; } const blocks = a.data.blocks.slice(1); // zero block contains query meta-data return { - blockHeader: PD.asOptional(PD.Select(blocks[0] && blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]), { description: 'Header of the block to parse' })) + blockHeader: PD.Optional(PD.Select(blocks[0] && blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]), { description: 'Header of the block to parse' })) }; } })({ diff --git a/src/mol-plugin/ui/controls/parameters.tsx b/src/mol-plugin/ui/controls/parameters.tsx index 8267741e1..72135f24d 100644 --- a/src/mol-plugin/ui/controls/parameters.tsx +++ b/src/mol-plugin/ui/controls/parameters.tsx @@ -181,7 +181,8 @@ export class NumberInputControl extends React.PureComponent<ParamProps<PD.Numeri export class NumberRangeControl extends SimpleParam<PD.Numeric> { onChange = (v: number) => { this.update(v); } renderControl() { - return <Slider value={this.props.value} min={this.props.param.min!} max={this.props.param.max!} + const value = typeof this.props.value === 'undefined' ? this.props.param.defaultValue : this.props.value; + return <Slider value={value} min={this.props.param.min!} max={this.props.param.max!} step={this.props.param.step} onChange={this.onChange} disabled={this.props.isDisabled} onEnter={this.props.onEnter} /> } } diff --git a/src/mol-plugin/util/structure-labels.ts b/src/mol-plugin/util/structure-labels.ts index af3b335de..c6e944b29 100644 --- a/src/mol-plugin/util/structure-labels.ts +++ b/src/mol-plugin/util/structure-labels.ts @@ -50,20 +50,25 @@ function getLabelsShape(ctx: RuntimeContext, data: LabelsData, props: PD.Values< const boundaryHelper = new BoundaryHelper(); function getLabelData(structure: Structure, params: StateTransformer.Params<StructureLabels3D>): LabelsData { if (params.target.name === 'static-text') { - return getLabelDataStatic(structure, params.target.params.value); + return getLabelDataStatic(structure, params.target.params.value, params.target.params.size || 1, params.target.params.position || 'middle-center'); } else { return getLabelDataComputed(structure, params.target.name); } } -function getLabelDataStatic(structure: Structure, text: string): LabelsData { +function getLabelDataStatic(structure: Structure, text: string, size: number, position: Text.Params['attachment']['defaultValue']): LabelsData { const boundary = structure.boundary.sphere; + let oX = 0, oY = 0; + if (position.indexOf('left') >= 0) oX = -boundary.radius; + if (position.indexOf('right') >= 0) oX = boundary.radius; + if (position.indexOf('top') >= 0) oY = boundary.radius; + if (position.indexOf('bottom') >= 0) oY = -boundary.radius; return { texts: [text], - positions: [boundary.center], - sizes: [1], - depths: [boundary.radius] + positions: [Vec3.add(Vec3.zero(), boundary.center, Vec3.create(oX, oY, 0))], + sizes: [size], + depths: [boundary.radius + Math.sqrt(oX * oX + oY * oY)] }; } diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index e2ce230f3..a7f08f3cf 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -36,9 +36,10 @@ export namespace ParamDefinition { type: T['type'] } - export function asOptional<T>(p: Base<T>): Base<T | undefined> { - p.isOptional = true; - return p; + export function Optional<T>(p: Base<T>): Base<T | undefined> { + const ret = { ...p }; + ret.isOptional = true; + return ret; } export interface Value<T> extends Base<T> { -- GitLab