ui.tsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { CollapsableState, CollapsableControls } from '../../../mol-plugin-ui/base';
  7. import { ApplyActionControl } from '../../../mol-plugin-ui/state/apply-action';
  8. import { InitAssemblySymmetry3D, AssemblySymmetry3D, AssemblySymmetryPreset, tryCreateAssemblySymmetry } from './behavior';
  9. import { AssemblySymmetryProvider, AssemblySymmetryProps, AssemblySymmetryDataProvider, AssemblySymmetry } from './prop';
  10. import { ParameterControls } from '../../../mol-plugin-ui/controls/parameters';
  11. import { ParamDefinition as PD } from '../../../mol-util/param-definition';
  12. import { StructureHierarchyManager } from '../../../mol-plugin-state/manager/structure/hierarchy';
  13. import { StateAction, StateSelection } from '../../../mol-state';
  14. import { PluginStateObject } from '../../../mol-plugin-state/objects';
  15. import { PluginContext } from '../../../mol-plugin/context';
  16. import { Task } from '../../../mol-task';
  17. import { ExtensionSvg, CheckSvg } from '../../../mol-plugin-ui/controls/icons';
  18. interface AssemblySymmetryControlState extends CollapsableState {
  19. isBusy: boolean
  20. }
  21. export class AssemblySymmetryControls extends CollapsableControls<{}, AssemblySymmetryControlState> {
  22. protected defaultState(): AssemblySymmetryControlState {
  23. return {
  24. header: 'Assembly Symmetry',
  25. isCollapsed: false,
  26. isBusy: false,
  27. isHidden: true,
  28. brand: { accent: 'cyan', svg: ExtensionSvg }
  29. };
  30. }
  31. componentDidMount() {
  32. this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, () => {
  33. this.setState({
  34. isHidden: !this.canEnable(),
  35. description: StructureHierarchyManager.getSelectedStructuresDescription(this.plugin)
  36. });
  37. });
  38. this.subscribe(this.plugin.state.events.cell.stateUpdated, e => {
  39. if (e.cell.transform.transformer === AssemblySymmetry3D) this.forceUpdate();
  40. });
  41. this.subscribe(this.plugin.behaviors.state.isBusy, v => this.setState({ isBusy: v }));
  42. }
  43. get pivot() {
  44. return this.plugin.managers.structure.hierarchy.selection.structures[0];
  45. }
  46. canEnable() {
  47. const { selection } = this.plugin.managers.structure.hierarchy;
  48. if (selection.structures.length !== 1) return false;
  49. const pivot = this.pivot.cell;
  50. if (!pivot.obj) return false;
  51. return !!InitAssemblySymmetry3D.definition.isApplicable?.(pivot.obj, pivot.transform, this.plugin);
  52. }
  53. renderEnable() {
  54. const pivot = this.pivot;
  55. if (!pivot.cell.parent) return null;
  56. return <ApplyActionControl state={pivot.cell.parent} action={EnableAssemblySymmetry3D} initiallyCollapsed={true} nodeRef={pivot.cell.transform.ref} simpleApply={{ header: 'Enable', icon: CheckSvg }} />;
  57. }
  58. renderNoSymmetries() {
  59. return <div className='msp-row-text'>
  60. <div>No Symmetries for Assembly</div>
  61. </div>;
  62. }
  63. get params() {
  64. const structure = this.pivot.cell.obj?.data;
  65. const params = PD.clone(structure ? AssemblySymmetryProvider.getParams(structure) : AssemblySymmetryProvider.defaultParams);
  66. params.serverUrl.isHidden = true;
  67. params.symmetryIndex.options = [[-1, 'Off'], ...params.symmetryIndex.options];
  68. return params;
  69. }
  70. get values() {
  71. const structure = this.pivot.cell.obj?.data;
  72. if (structure) {
  73. return AssemblySymmetryProvider.props(structure);
  74. } else {
  75. return { ...PD.getDefaultValues(AssemblySymmetryProvider.defaultParams), symmetryIndex: -1 };
  76. }
  77. }
  78. async updateAssemblySymmetry(values: AssemblySymmetryProps) {
  79. const s = this.pivot;
  80. const currValues = AssemblySymmetryProvider.props(s.cell.obj!.data);
  81. if (PD.areEqual(AssemblySymmetryProvider.defaultParams, currValues, values)) return;
  82. if (s.properties) {
  83. const b = this.plugin.state.data.build();
  84. b.to(s.properties.cell).update(old => {
  85. old.properties[AssemblySymmetryProvider.descriptor.name] = values;
  86. });
  87. await b.commit();
  88. } else {
  89. const pd = this.plugin.customStructureProperties.getParams(s.cell.obj?.data);
  90. const params = PD.getDefaultValues(pd);
  91. params.properties[AssemblySymmetryProvider.descriptor.name] = values;
  92. await this.plugin.builders.structure.insertStructureProperties(s.cell, params);
  93. }
  94. for (const components of this.plugin.managers.structure.hierarchy.currentComponentGroups) {
  95. if (values.symmetryIndex === -1) {
  96. const name = components[0]?.representations[0]?.cell.transform.params?.colorTheme.name;
  97. if (name === AssemblySymmetry.Tag.Cluster) {
  98. await this.plugin.managers.structure.component.updateRepresentationsTheme(components, { color: 'default' });
  99. }
  100. } else {
  101. tryCreateAssemblySymmetry(this.plugin, s.cell);
  102. await this.plugin.managers.structure.component.updateRepresentationsTheme(components, { color: AssemblySymmetry.Tag.Cluster as any });
  103. }
  104. }
  105. }
  106. paramsOnChange = (options: AssemblySymmetryProps) => {
  107. this.updateAssemblySymmetry(options);
  108. }
  109. get hasAssemblySymmetry3D() {
  110. return !this.pivot.cell.parent || !!StateSelection.findTagInSubtree(this.pivot.cell.parent.tree, this.pivot.cell.transform.ref, AssemblySymmetry.Tag.Representation);
  111. }
  112. get enable() {
  113. return !this.hasAssemblySymmetry3D && this.values.symmetryIndex !== -1;
  114. }
  115. get noSymmetries() {
  116. const structure = this.pivot.cell.obj?.data;
  117. const data = structure && AssemblySymmetryDataProvider.get(structure).value;
  118. return data && data.filter(sym => sym.symbol !== 'C1').length === 0;
  119. }
  120. renderParams() {
  121. return <>
  122. <ParameterControls params={this.params} values={this.values} onChangeValues={this.paramsOnChange} />
  123. </>;
  124. }
  125. renderControls() {
  126. if (!this.pivot) return null;
  127. if (this.noSymmetries) return this.renderNoSymmetries();
  128. if (this.enable) return this.renderEnable();
  129. return this.renderParams();
  130. }
  131. }
  132. const EnableAssemblySymmetry3D = StateAction.build({
  133. from: PluginStateObject.Molecule.Structure,
  134. })(({ a, ref, state }, plugin: PluginContext) => Task.create('Enable Assembly Symmetry', async ctx => {
  135. await AssemblySymmetryPreset.apply(ref, Object.create(null), plugin);
  136. }));