diff --git a/src/mol-plugin-state/manager/structure/measurement.ts b/src/mol-plugin-state/manager/structure/measurement.ts index bbd3f14226a471b5c3bfb4c1c8cc8bd8ddffce0a..c18075a8f1319b7dbf93121d12f5347757066621 100644 --- a/src/mol-plugin-state/manager/structure/measurement.ts +++ b/src/mol-plugin-state/manager/structure/measurement.ts @@ -17,10 +17,12 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition'; import { MeasurementRepresentationCommonTextParams, LociLabelTextParams } from '../../../mol-repr/shape/loci/common'; import { LineParams } from '../../../mol-repr/structure/representation/line'; import { Expression } from '../../../mol-script/language/expression'; +import { Color } from '../../../mol-util/color'; export { StructureMeasurementManager }; export const MeasurementGroupTag = 'measurement-group'; +export const MeasurementOrderLabelTag = 'measurement-order-label'; export type StructureMeasurementCell = StateObjectCell<PluginStateObject.Shape.Representation3D, StateTransform<StateTransformer<PluginStateObject.Molecule.Structure.Selections, PluginStateObject.Shape.Representation3D, any>>> @@ -281,6 +283,41 @@ class StructureMeasurementManager extends StatefulPluginComponent<StructureMeasu await PluginCommands.State.Update(this.plugin, { state, tree: update, options: { doNotLogTiming: true } }); } + async addOrderLabels(locis: StructureElement.Loci[]) { + const update = this.getGroup(); + + const current = this.plugin.state.data.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Selections).withTag(MeasurementOrderLabelTag)); + for (const obj of current) + update.delete(obj); + + let order = 1; + for (const loci of locis) { + const cell = this.plugin.helpers.substructureParent.get(loci.structure); + if (!cell) continue; + + const dependsOn = [cell.transform.ref]; + + update + .apply(StateTransforms.Model.MultiStructureSelectionFromExpression, { + selections: [ + { key: 'a', ref: cell.transform.ref, expression: StructureElement.Loci.toExpression(loci) }, + ], + isTransitive: true, + label: 'Order' + }, { dependsOn, tags: MeasurementOrderLabelTag }) + .apply(StateTransforms.Representation.StructureSelectionsLabel3D, { + textColor: Color.fromRgb(255, 255, 255), + borderColor: Color.fromRgb(0, 0, 0), + borderWidth: 0.5, + textSize: 0.33, + customText: `${order++}` + }, { tags: MeasurementOrderLabelTag }); + } + + const state = this.plugin.state.data; + await PluginCommands.State.Update(this.plugin, { state, tree: update, options: { doNotLogTiming: true } }); + } + private _empty: any[] = []; private getTransforms<T extends StateTransformer<A, B, any>, A extends PluginStateObject.Molecule.Structure.Selections, B extends StateObject>(transformer: T) { const state = this.plugin.state.data; @@ -291,8 +328,15 @@ class StructureMeasurementManager extends StatefulPluginComponent<StructureMeasu } private sync() { + const labels = []; + for (const cell of this.getTransforms(StateTransforms.Representation.StructureSelectionsLabel3D) as StructureMeasurementCell[]) { + const tags = (cell.obj as any)['tags'] as string[]; + if (!tags || !tags.includes(MeasurementOrderLabelTag)) + labels.push(cell); + } + const updated = this.updateState({ - labels: this.getTransforms(StateTransforms.Representation.StructureSelectionsLabel3D), + labels, distances: this.getTransforms(StateTransforms.Representation.StructureSelectionsDistance3D), angles: this.getTransforms(StateTransforms.Representation.StructureSelectionsAngle3D), dihedrals: this.getTransforms(StateTransforms.Representation.StructureSelectionsDihedral3D), diff --git a/src/mol-plugin-ui/structure/measurements.tsx b/src/mol-plugin-ui/structure/measurements.tsx index 29763a3cfe262d53a12b4a2ecbfbf8b833caf3f1..088fe2c9e82b66276caf5451a8d26af01f617aab 100644 --- a/src/mol-plugin-ui/structure/measurements.tsx +++ b/src/mol-plugin-ui/structure/measurements.tsx @@ -62,7 +62,6 @@ export class MeasurementList extends PurePluginUIComponent { render() { const measurements = this.plugin.managers.structure.measurement.state; - return <div style={{ marginTop: '6px' }}> {this.renderGroup(measurements.labels, 'Labels')} {this.renderGroup(measurements.distances, 'Distances')} @@ -80,6 +79,7 @@ export class MeasurementControls extends PurePluginUIComponent<{}, { isBusy: boo componentDidMount() { this.subscribe(this.selection.events.additionsHistoryUpdated, () => { this.forceUpdate(); + this.updateOrderLabels(); }); this.subscribe(this.plugin.behaviors.state.isBusy, v => { @@ -87,6 +87,33 @@ export class MeasurementControls extends PurePluginUIComponent<{}, { isBusy: boo }); } + componentWillUnmount() { + this.clearOrderLabels(); + super.componentWillUnmount(); + } + + componentDidUpdate(prevProps: {}, prevState: { isBusy: boolean, action?: 'add' | 'options' }) { + if (this.state.action !== prevState.action) + this.updateOrderLabels(); + } + + clearOrderLabels() { + this.plugin.managers.structure.measurement.addOrderLabels([]); + } + + updateOrderLabels() { + if (this.state.action !== 'add') { + this.clearOrderLabels(); + return; + } + + const locis = []; + const history = this.selection.additionsHistory; + for (let idx = 0; idx < history.length && idx < 4; idx++) + locis.push(history[idx].loci); + this.plugin.managers.structure.measurement.addOrderLabels(locis); + } + get selection() { return this.plugin.managers.structure.selection; }