From 8fb730857214f26963c2261730614de071b3241a Mon Sep 17 00:00:00 2001 From: Alexander Rose <alex.rose@rcsb.org> Date: Mon, 22 Jul 2019 17:35:17 -0700 Subject: [PATCH] wip, OverpaintControls --- src/mol-plugin/ui/controls.tsx | 144 ++++++++++++++++++++++++++++++++- src/mol-plugin/ui/plugin.tsx | 3 +- 2 files changed, 143 insertions(+), 4 deletions(-) diff --git a/src/mol-plugin/ui/controls.tsx b/src/mol-plugin/ui/controls.tsx index 2758c3d29..972d6596b 100644 --- a/src/mol-plugin/ui/controls.tsx +++ b/src/mol-plugin/ui/controls.tsx @@ -1,7 +1,8 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import * as React from 'react'; @@ -9,12 +10,20 @@ import { PluginCommands } from '../../mol-plugin/command'; import { UpdateTrajectory } from '../../mol-plugin/state/actions/structure'; import { PluginUIComponent } from './base'; import { LociLabelEntry } from '../../mol-plugin/util/loci-label-manager'; -import { IconButton } from './controls/common'; +import { IconButton, Icon } from './controls/common'; import { PluginStateObject } from '../../mol-plugin/state/objects'; import { StateTransforms } from '../../mol-plugin/state/transforms'; -import { StateTransformer } from '../../mol-state'; +import { StateTransformer, StateSelection } from '../../mol-state'; import { ModelFromTrajectory } from '../../mol-plugin/state/transforms/model'; import { AnimationControls } from './state/animation'; +import { ParamDefinition as PD} from '../../mol-util/param-definition'; +import { ColorNames } from '../../mol-util/color/tables'; +import { ParameterControls } from './controls/parameters'; +import { Color } from '../../mol-util/color'; +import { formatMolScript } from '../../mol-script/language/expression-formatter'; +import { StructureElement, Structure } from '../../mol-model/structure'; +import { isEmptyLoci } from '../../mol-model/loci'; +import { MolScriptBuilder } from '../../mol-script/language/builder'; export class TrajectoryViewportControls extends PluginUIComponent<{}, { show: boolean, label: string }> { state = { show: false, label: '' } @@ -249,4 +258,133 @@ export class LociLabelControl extends PluginUIComponent<{}, { entries: ReadonlyA {this.state.entries.map((e, i) => <div key={'' + i}>{e}</div>)} </div>; } +} + +export class OverpaintControls extends PluginUIComponent<{}, { params: PD.Values<typeof OverpaintControls.Params> }> { + state = { params: PD.getDefaultValues(OverpaintControls.Params) } + + static Params = { + color: PD.Color(ColorNames.cyan) + }; + + private layers = new Map<Structure, Map<string, { script: { language: string, expression: string }, color: Color }>>() + + componentDidMount() { + // TODO handle Representation3D object creation + this.subscribe(this.plugin.events.state.object.created, ({ ref, state }) => { + this.sync() + }); + } + + sync = async () => { + const state = this.plugin.state.dataState; + const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3D)); + + const update = state.build(); + for (const r of reprs) { + const overpaint = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Representation.OverpaintStructureRepresentation3D, r.transform.ref).withTag('overpaint-manager')); + + const structure = r.obj!.data.source.data + const rootStructure = structure.parent || structure + + const layers = this.layers.get(rootStructure) + if (!layers) continue + + const props = { layers: Array.from(layers.values()), alpha: 1 } + + if (overpaint.length > 0) { + update.to(overpaint[0]).update(props) + } else { + update.to(r.transform.ref) + .apply(StateTransforms.Representation.OverpaintStructureRepresentation3D, props, { tags: 'overpaint-manager' }); + } + } + + await this.plugin.runTask(state.updateTree(update, { doNotUpdateCurrent: true })); + } + + add = async () => { + const state = this.plugin.state.dataState; + const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3D)); + + const update = state.build(); + for (const r of reprs) { + const overpaint = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Representation.OverpaintStructureRepresentation3D, r.transform.ref).withTag('overpaint-manager')); + + const structure = r.obj!.data.source.data + const rootStructure = structure.parent || structure + + const loci = this.plugin.helpers.structureSelection.get(rootStructure) + const scriptExpression = isEmptyLoci(loci) + ? MolScriptBuilder.struct.generator.empty() + : StructureElement.Loci.toScriptExpression(loci) + const expression = formatMolScript(scriptExpression) + + if (!this.layers.has(rootStructure)) this.layers.set(rootStructure, new Map()) + const layers = this.layers.get(rootStructure)! + + layers.set(`${this.state.params.color}|${expression}`, { + script: { language: 'mol-script', expression }, + color: this.state.params.color + }) + const props = { layers: Array.from(layers.values()), alpha: 1 } + + if (overpaint.length > 0) { + update.to(overpaint[0]).update(props) + } else { + update.to(r.transform.ref) + .apply(StateTransforms.Representation.OverpaintStructureRepresentation3D, props, { tags: 'overpaint-manager' }); + } + } + + await this.plugin.runTask(state.updateTree(update, { doNotUpdateCurrent: true })); + } + + clearAll = async () => { + const state = this.plugin.state.dataState; + const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3D)); + + this.layers.clear() + + const update = state.build(); + for (const r of reprs) { + const overpaint = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Representation.OverpaintStructureRepresentation3D, r.transform.ref).withTag('overpaint-manager')); + + if (overpaint.length > 0) { + update.to(overpaint[0]).update({ layers: [], alpha: 1 }) + } + } + + await this.plugin.runTask(state.updateTree(update, { doNotUpdateCurrent: true })); + } + + render() { + return <div className='msp-transform-wrapper'> + <div className='msp-transform-header'> + <button className='msp-btn msp-btn-block'>Structure Selection Overpaint</button> + </div> + <div> + <ParameterControls params={OverpaintControls.Params} values={this.state.params} onChange={p => { + const params = { ...this.state.params, [p.name]: p.value }; + this.setState({ params }); + }}/> + + <div className='msp-btn-row-group'> + <button className='msp-btn msp-btn-block msp-form-control' onClick={this.add}>Add</button> + {/* <button className='msp-btn msp-btn-block msp-form-control' onClick={this.add}>Clear</button> */} + <button className='msp-btn msp-btn-block msp-form-control' onClick={this.clearAll}>Clear All</button> + </div> + </div> + </div> + } +} + +export class ToolsWrapper extends PluginUIComponent { + render() { + return <div> + <div className='msp-section-header'><Icon name='code' /> Tools</div> + + <OverpaintControls /> + </div>; + } } \ No newline at end of file diff --git a/src/mol-plugin/ui/plugin.tsx b/src/mol-plugin/ui/plugin.tsx index 615a35103..983dfb57e 100644 --- a/src/mol-plugin/ui/plugin.tsx +++ b/src/mol-plugin/ui/plugin.tsx @@ -12,7 +12,7 @@ import { LogEntry } from '../../mol-util/log-entry'; import * as React from 'react'; import { PluginContext } from '../context'; import { PluginReactContext, PluginUIComponent } from './base'; -import { LociLabelControl, TrajectoryViewportControls, StateSnapshotViewportControls, AnimationViewportControls } from './controls'; +import { LociLabelControl, TrajectoryViewportControls, StateSnapshotViewportControls, AnimationViewportControls, ToolsWrapper } from './controls'; import { StateSnapshots } from './state'; import { StateObjectActions } from './state/actions'; import { StateTree } from './state/tree'; @@ -109,6 +109,7 @@ export class ControlsWrapper extends PluginUIComponent { <CurrentObject /> {/* <AnimationControlsWrapper /> */} {/* <CameraSnapshots /> */} + <ToolsWrapper /> <StateSnapshots /> </div>; } -- GitLab