strucmotif.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
  5. * @author Alexander Rose <alex.rose@weirdbyte.de>
  6. */
  7. import * as React from 'react';
  8. import {CollapsableControls, PurePluginUIComponent} from 'molstar/lib/mol-plugin-ui/base';
  9. import {Button, IconButton} from 'molstar/lib/mol-plugin-ui/controls/common';
  10. import {
  11. ArrowDownwardSvg,
  12. ArrowUpwardSvg,
  13. DeleteOutlinedSvg,
  14. HelpOutlineSvg,
  15. Icon
  16. } from 'molstar/lib/mol-plugin-ui/controls/icons';
  17. import {ActionMenu} from 'molstar/lib/mol-plugin-ui/controls/action-menu';
  18. import {StructureSelectionHistoryEntry} from 'molstar/lib/mol-plugin-state/manager/structure/selection';
  19. import {StructureElement} from 'molstar/lib/mol-model/structure/structure';
  20. import {ToggleSelectionModeButton} from 'molstar/lib/mol-plugin-ui/structure/selection';
  21. export class StrucmotifSubmitControls extends CollapsableControls {
  22. protected defaultState() {
  23. return {
  24. header: 'Structural Motif Search',
  25. isCollapsed: false,
  26. brand: { accent: 'gray' as const, svg: SearchIconSvg }
  27. };
  28. }
  29. renderControls() {
  30. return <>
  31. <SubmitControls />
  32. </>;
  33. }
  34. }
  35. const _SearchIcon = <svg width='24px' height='24px' viewBox='0 0 24 24'><path d='M8 5v14l11-7z' /></svg>;
  36. export function SearchIconSvg() { return _SearchIcon; }
  37. export class SubmitControls extends PurePluginUIComponent<{}, { isBusy: boolean }> {
  38. state = { isBusy: false }
  39. componentDidMount() {
  40. this.subscribe(this.selection.events.additionsHistoryUpdated, () => {
  41. this.forceUpdate();
  42. });
  43. this.subscribe(this.plugin.behaviors.state.isBusy, v => {
  44. this.setState({ isBusy: v });
  45. });
  46. }
  47. get selection() {
  48. return this.plugin.managers.structure.selection;
  49. }
  50. submitSearch = () => {
  51. const loci = this.plugin.managers.structure.selection.additionsHistory;
  52. // this.plugin.managers.structure.measurement.addAngle(loci[0].loci, loci[1].loci, loci[2].loci);
  53. console.log(loci[0].loci.elements);
  54. window.open('https://rcsb.org', '_blank');
  55. }
  56. get actions(): ActionMenu.Items {
  57. const history = this.selection.additionsHistory;
  58. const ret: ActionMenu.Item[] = [
  59. { kind: 'item', label: `Submit Search ${history.length < 3 ? ' (3 selections required)' : ''}`, value: this.submitSearch, disabled: history.length < 3 },
  60. ];
  61. return ret;
  62. }
  63. selectAction: ActionMenu.OnSelect = item => {
  64. if (!item) return;
  65. (item?.value as any)();
  66. }
  67. highlight(loci: StructureElement.Loci) {
  68. this.plugin.managers.interactivity.lociHighlights.highlightOnly({ loci }, false);
  69. }
  70. moveHistory(e: StructureSelectionHistoryEntry, direction: 'up' | 'down') {
  71. this.plugin.managers.structure.selection.modifyHistory(e, direction, 4);
  72. }
  73. focusLoci(loci: StructureElement.Loci) {
  74. this.plugin.managers.camera.focusLoci(loci);
  75. }
  76. historyEntry(e: StructureSelectionHistoryEntry, idx: number) {
  77. const history = this.plugin.managers.structure.selection.additionsHistory;
  78. return <div className='msp-flex-row' key={e.id}>
  79. <Button noOverflow title='Click to focus. Hover to highlight.' onClick={() => this.focusLoci(e.loci)} style={{ width: 'auto', textAlign: 'left' }} onMouseEnter={() => this.highlight(e.loci)} onMouseLeave={this.plugin.managers.interactivity.lociHighlights.clearHighlights}>
  80. {idx}. <span dangerouslySetInnerHTML={{ __html: e.label }} />
  81. </Button>
  82. {history.length > 1 && <IconButton svg={ArrowUpwardSvg} small={true} className='msp-form-control' onClick={() => this.moveHistory(e, 'up')} flex='20px' title={'Move up'} />}
  83. {history.length > 1 && <IconButton svg={ArrowDownwardSvg} small={true} className='msp-form-control' onClick={() => this.moveHistory(e, 'down')} flex='20px' title={'Move down'} />}
  84. <IconButton svg={DeleteOutlinedSvg} small={true} className='msp-form-control' onClick={() => this.plugin.managers.structure.selection.modifyHistory(e, 'remove')} flex title={'Remove'} />
  85. </div>;
  86. }
  87. add() {
  88. const history = this.plugin.managers.structure.selection.additionsHistory;
  89. const entries: JSX.Element[] = [];
  90. for (let i = 0, _i = Math.min(history.length, 10); i < _i; i++) {
  91. entries.push(this.historyEntry(history[i], i + 1));
  92. }
  93. return <>
  94. <ActionMenu items={this.actions} onSelect={this.selectAction} />
  95. {entries.length > 0 && <div className='msp-control-offset'>
  96. {entries}
  97. </div>}
  98. {entries.length === 0 && <div className='msp-control-offset msp-help-text'>
  99. <div className='msp-help-description'><Icon svg={HelpOutlineSvg} inline />Add one or more selections (toggle <ToggleSelectionModeButton inline /> mode)</div>
  100. </div>}
  101. </>;
  102. }
  103. render() {
  104. return <>
  105. {this.add()}
  106. </>;
  107. }
  108. }