UNPKG

pdbe-molstar

Version:
678 lines (677 loc) 41.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SegmentTree = void 0; const tslib_1 = require("tslib"); const jsx_runtime_1 = require("react/jsx-runtime"); const transforms_1 = require("molstar/lib/mol-plugin-state/transforms"); const base_1 = require("molstar/lib/mol-plugin-ui/base"); const common_1 = require("molstar/lib/mol-plugin-ui/controls/common"); const icons_1 = require("molstar/lib/mol-plugin-ui/controls/icons"); const parameters_1 = require("molstar/lib/mol-plugin-ui/controls/parameters"); const update_transform_1 = require("molstar/lib/mol-plugin-ui/state/update-transform"); const commands_1 = require("molstar/lib/mol-plugin/commands"); const builder_1 = require("molstar/lib/mol-script/language/builder"); const mol_state_1 = require("molstar/lib/mol-state"); const color_1 = require("molstar/lib/mol-util/color"); const param_definition_1 = require("molstar/lib/mol-util/param-definition"); const rxjs_1 = require("rxjs"); const operators_1 = require("rxjs/operators"); const plugin_custom_state_1 = require("../plugin-custom-state"); const superposition_1 = require("../superposition"); const SuperpositionTag = 'SuperpositionTransform'; class SegmentTree extends base_1.PurePluginUIComponent { constructor() { super(...arguments); this.getSegmentParams = () => { const customState = this.customState; if (!customState.superpositionState || !customState.superpositionState.segmentData) return; const segmentData = customState.superpositionState.segmentData; const segmentArr = segmentData.map((segment, i) => { const segmentLabel = `${i + 1} ( ${segment.segment_start} - ${segment.segment_end} )`; return [segmentLabel, segmentLabel]; }); const segmentOptions = { segment: param_definition_1.ParamDefinition.Select('', segmentArr, { label: 'Select Segment', description: 'Select segment to view its clusters below' }), }; const segmentIndex = customState.superpositionState.activeSegment - 1; this.setState({ segment: { params: segmentOptions, value: { segment: segmentArr[segmentIndex][0] }, }, }); this.setState({ isBusy: false }); }; this.updateSegment = (val) => tslib_1.__awaiter(this, void 0, void 0, function* () { var _a; if (!this.state.segment) return; if (!this.state.segment) return; const customState = this.customState; if (!customState.superpositionState) throw new Error('customState.superpositionState has not been initialized'); (_a = customState.events) === null || _a === void 0 ? void 0 : _a.isBusy.next(true); // Hide pervious segement structures this.hideStructures(customState.superpositionState.activeSegment - 1); // Set current segment params const updatedParams = Object.assign({}, this.state.segment); updatedParams.value = val; this.setState({ segment: updatedParams }); setTimeout(() => tslib_1.__awaiter(this, void 0, void 0, function* () { var _a, _b; const updatedSegmentIndex = parseInt(val.segment.split(' ')[0]); customState.superpositionState.activeSegment = updatedSegmentIndex; // Display current segment visible structures yield this.displayStructures(customState.superpositionState.activeSegment - 1); (_a = customState.events) === null || _a === void 0 ? void 0 : _a.isBusy.next(false); (_b = customState.events) === null || _b === void 0 ? void 0 : _b.segmentUpdate.next(true); }), 100); return false; }); this.hideStructures = (segmentIndex) => { // clear selections this.plugin.managers.interactivity.lociSelects.deselectAll(); // clear Focus this.plugin.managers.structure.focus.clear(); // remove measurements const measurements = this.plugin.managers.structure.measurement.state; const measureTypes = ['labels', 'distances', 'angles', 'dihedrals']; let measurementCell = undefined; measureTypes.forEach((type) => { if (measurementCell) return; if (measurements[type][0]) { measurementCell = this.plugin.state.data.cells.get(measurements[type][0].transform.parent); } }); if (measurementCell) { commands_1.PluginCommands.State.RemoveObject(this.plugin, { state: measurementCell.parent, ref: measurementCell.transform.parent, removeParentGhosts: true }); } // hide structures const customState = this.customState; if (!customState.superpositionState) throw new Error('customState.superpositionState has not been initialized'); customState.superpositionState.visibleRefs[segmentIndex] = []; for (const struct of customState.superpositionState.loadedStructs[segmentIndex]) { const structRef = customState.superpositionState.models[struct]; if (structRef) { const structHierarchy = this.plugin.managers.structure.hierarchy.current.refs.get(structRef); if (structHierarchy && structHierarchy.components) { for (const c of structHierarchy.components) { if (c && c.cell && !c.cell.state.isHidden) { customState.superpositionState.visibleRefs[segmentIndex].push(c.cell.transform.ref); commands_1.PluginCommands.State.ToggleVisibility(this.plugin, { state: c.cell.parent, ref: c.cell.transform.ref }); } } } } } if (customState.superpositionState.alphafold.ref) { const afStr = this.plugin.managers.structure.hierarchy.current.refs.get(customState.superpositionState.alphafold.ref); if (afStr && afStr.components) { for (const c of afStr.components) { if (c && c.cell && !c.cell.state.isHidden) { commands_1.PluginCommands.State.ToggleVisibility(this.plugin, { state: c.cell.parent, ref: c.cell.transform.ref }); } } } } }; this.displayStructures = (segmentIndex) => tslib_1.__awaiter(this, void 0, void 0, function* () { var _a; const customState = this.customState; const spState = customState.superpositionState; if (!spState) throw new Error('customState.superpositionState has not been initialized'); if (spState.visibleRefs[segmentIndex].length === 0) { const loadStrs = []; (_a = spState.segmentData) === null || _a === void 0 ? void 0 : _a[segmentIndex].clusters.forEach(cluster => { var _a, _b; let entryList = [cluster[0]]; if ((_b = (_a = customState.initParams) === null || _a === void 0 ? void 0 : _a.superpositionParams) === null || _b === void 0 ? void 0 : _b.superposeAll) { entryList = cluster; } entryList.forEach((str) => { const structStateId = `${str.pdb_id}_${str.struct_asym_id}`; const structRef = spState.models[structStateId]; if (structRef) { const cell = this.plugin.state.data.cells.get(structRef); const isHidden = cell.state.isHidden ? true : false; if (isHidden) { commands_1.PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent, ref: structRef }); // PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent!, ref: cell.transform.parent }); } } else { loadStrs.push(str); } }); }); commands_1.PluginCommands.Camera.Reset(this.plugin); if (loadStrs.length > 0) { yield (0, superposition_1.renderSuperposition)(this.plugin, segmentIndex, loadStrs); commands_1.PluginCommands.Camera.Reset(this.plugin); } } else { for (const ref of spState.visibleRefs[segmentIndex]) { const cell = this.plugin.state.data.cells.get(ref); if (cell && cell.state.isHidden) { commands_1.PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent, ref }); } } commands_1.PluginCommands.Camera.Reset(this.plugin); } if (spState.alphafold.ref) { (0, superposition_1.superposeAf)(this.plugin, spState.alphafold.traceOnly); commands_1.PluginCommands.Camera.Reset(this.plugin); } if (spState.alphafold.ref && spState.alphafold.visibility[segmentIndex]) { const afStr = this.plugin.managers.structure.hierarchy.current.refs.get(spState.alphafold.ref); if (afStr && afStr.components) { for (const c of afStr.components) { if (c && c.cell && c.cell.state.isHidden) { commands_1.PluginCommands.State.ToggleVisibility(this.plugin, { state: c.cell.parent, ref: c.cell.transform.ref }); } } } } }); } componentDidMount() { this.subscribe((0, plugin_custom_state_1.PluginCustomState)(this.plugin).events.superpositionInit, () => { const customState = this.customState; if (customState && !customState.superpositionError) { this.getSegmentParams(); } this.forceUpdate(); }); this.subscribe((0, plugin_custom_state_1.PluginCustomState)(this.plugin).events.isBusy, (e) => { this.setState({ isBusy: e }); if (e) { commands_1.PluginCommands.Toast.Show(this.plugin, { title: 'Process', message: 'Loading / computing large dataset!', key: 'is-busy-toast', }); } else { commands_1.PluginCommands.Toast.Hide(this.plugin, { key: 'is-busy-toast' }); } }); this.subscribe(this.plugin.behaviors.layout.leftPanelTabName, (e) => { if (e !== 'segments') return; this.getSegmentParams(); this.forceUpdate(); }); } get customState() { return (0, plugin_custom_state_1.PluginCustomState)(this.plugin); } transform(s, matrix) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const r = mol_state_1.StateObjectRef.resolveAndCheck(this.plugin.state.data, s); if (!r) return; // TODO should find any TransformStructureConformation decorator instance const o = mol_state_1.StateSelection.findTagInSubtree(this.plugin.state.data.tree, r.transform.ref, SuperpositionTag); const params = { transform: { name: 'matrix', params: { data: matrix, transpose: false }, }, }; // TODO add .insertOrUpdate to StateBuilder? const b = o ? this.plugin.state.data.build().to(o).update(params) : this.plugin.state.data.build().to(s) .insert(transforms_1.StateTransforms.Model.TransformStructureConformation, params, { tags: SuperpositionTag }); yield this.plugin.runTask(this.plugin.state.data.updateTree(b)); }); } render() { var _a; let sectionHeader = (0, jsx_runtime_1.jsx)(common_1.SectionHeader, { title: `Structure clusters` }); const customState = this.customState; if (customState && customState.initParams && !customState.initParams.superposition) { return (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [sectionHeader, (0, jsx_runtime_1.jsx)("div", { children: "Functionality unavailable!" })] }); } else { if (customState && customState.initParams && customState.initParams.superposition) { sectionHeader = (0, jsx_runtime_1.jsx)(common_1.SectionHeader, { title: `Structure clusters - ${customState.initParams.moleculeId}` }); if (customState.superpositionError) { return (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [sectionHeader, (0, jsx_runtime_1.jsx)("div", { style: { textAlign: 'center' }, children: customState.superpositionError })] }); } else if (!customState.superpositionState || !customState.superpositionState.segmentData) { return (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [sectionHeader, (0, jsx_runtime_1.jsx)("div", { style: { textAlign: 'center' }, children: "Loading Segment Data!" })] }); } } } if (this.state) { const segmentIndex = parseInt(this.state.segment.value.segment.split(' ')[0]) - 1; if (!((_a = customState.superpositionState) === null || _a === void 0 ? void 0 : _a.segmentData)) throw new Error('customState.superpositionState.segmentData has not been initialized'); const segmentData = customState.superpositionState.segmentData; const fullSegmentRange = `( ${segmentData[0].segment_start} - ${segmentData[segmentData.length - 1].segment_end} )`; sectionHeader = (0, jsx_runtime_1.jsx)(common_1.SectionHeader, { title: `Structure clusters ${customState.initParams.moleculeId}`, desc: fullSegmentRange }); return (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [sectionHeader, (0, jsx_runtime_1.jsx)(parameters_1.ParameterControls, { params: this.state.segment.params, values: this.state.segment.value, onChangeValues: this.updateSegment, isDisabled: this.state.isBusy }), segmentData[segmentIndex].clusters.map((c, i) => (0, jsx_runtime_1.jsx)(ClusterNode, { cluster: c, totalClusters: segmentData[segmentIndex].clusters.length, segmentIndex: segmentIndex, clusterIndex: i }, `cluster-${segmentIndex}-${i}`))] }); } return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {}); } } exports.SegmentTree = SegmentTree; class ClusterNode extends base_1.PluginUIComponent { constructor() { super(...arguments); this.state = { isCollapsed: false, showAll: false, showNone: false, showSearch: false, isBusy: false, cluster: this.props.cluster, searchText: '', }; this.inputStream = new rxjs_1.Subject(); this.handleInputStream = (inputStr) => { this.setState({ searchText: inputStr }); const filteredRes = this.props.cluster.filter((item) => { return item.pdb_id.toLowerCase().indexOf(inputStr.toLowerCase()) >= 0; }); this.setState({ cluster: filteredRes }); }; this.toggleExpanded = (e) => { e.preventDefault(); this.setState({ isCollapsed: !this.state.isCollapsed }); e.currentTarget.blur(); }; this.selectAll = (e) => { e.preventDefault(); this.setState({ showAll: !this.state.showAll, showNone: false }); e.currentTarget.blur(); }; this.selectNone = (e) => { e.preventDefault(); this.setState({ showAll: false, showNone: !this.state.showNone }); e.currentTarget.blur(); }; this.applyAction = (e) => tslib_1.__awaiter(this, void 0, void 0, function* () { var _a; e.preventDefault(); e.currentTarget.blur(); const customState = this.customState; (_a = customState.events) === null || _a === void 0 ? void 0 : _a.isBusy.next(true); const currentState = Object.assign({}, this.state); this.setState({ showAll: false, showNone: false }); setTimeout(() => tslib_1.__awaiter(this, void 0, void 0, function* () { var _a, e_1, _b, _c; var _d; const loadStrs = []; try { for (var _e = true, _f = tslib_1.__asyncValues(this.state.cluster), _g; _g = yield _f.next(), _a = _g.done, !_a; _e = true) { _c = _g.value; _e = false; const str = _c; const structStateId = `${str.pdb_id}_${str.struct_asym_id}`; let structRef = undefined; if (customState && customState.superpositionState && customState.superpositionState.models[structStateId]) { structRef = customState.superpositionState.models[structStateId]; } if (structRef) { const cell = this.plugin.state.data.cells.get(structRef); if (cell) { const isHidden = cell.state.isHidden ? true : false; if ((isHidden && currentState.showAll) || (!isHidden && currentState.showNone)) { yield commands_1.PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent, ref: structRef }); // await PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent!, ref: cell.transform.parent }); } } } else { if (currentState.showAll) loadStrs.push(str); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_e && !_a && (_b = _f.return)) yield _b.call(_f); } finally { if (e_1) throw e_1.error; } } ; commands_1.PluginCommands.Camera.Reset(this.plugin); if (loadStrs.length > 0) { yield (0, superposition_1.renderSuperposition)(this.plugin, this.props.segmentIndex, loadStrs); } (_d = customState.events) === null || _d === void 0 ? void 0 : _d.isBusy.next(false); })); }); this.cancelAction = (e) => { e.preventDefault(); this.setState({ showAll: false, showNone: false }); e.currentTarget.blur(); }; this.clearSearch = (e) => { e.preventDefault(); this.setState({ searchText: '' }); this.inputStream.next(''); e.currentTarget.blur(); }; } componentDidMount() { this.subscribe((0, plugin_custom_state_1.PluginCustomState)(this.plugin).events.isBusy, (e) => { this.setState({ isBusy: e, showAll: false, showNone: false }); }); this.subscribe(this.inputStream.pipe((0, operators_1.debounceTime)(1000 / 24)), (e) => this.handleInputStream(e)); } get customState() { return (0, plugin_custom_state_1.PluginCustomState)(this.plugin); } render() { const customState = this.customState; if (!customState.superpositionState || !customState.superpositionState.segmentData) return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {}); const expand = (0, jsx_runtime_1.jsx)(common_1.IconButton, { svg: this.state.isCollapsed ? icons_1.ArrowRightSvg : icons_1.ArrowDropDownSvg, flex: '20px', onClick: this.toggleExpanded, transparent: true, disabled: this.state.isBusy, className: 'msp-no-hover-outline' }); const title = `Segment ${customState.superpositionState.activeSegment} Cluster ${this.props.clusterIndex + 1}`; const label = (0, jsx_runtime_1.jsxs)(common_1.Button, { className: `msp-btn-tree-label`, noOverflow: true, title: title, disabled: this.state.isBusy, children: [(0, jsx_runtime_1.jsxs)("span", { children: ["Cluster ", this.props.clusterIndex + 1] }), " ", (0, jsx_runtime_1.jsxs)("small", { children: [this.state.cluster.length < this.props.cluster.length ? `${this.state.cluster.length} / ` : '', this.props.cluster.length, " chain", this.props.cluster.length > 1 ? 's' : ''] })] }); const selectionControls = (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(common_1.Button, { icon: icons_1.CheckSvg, flex: true, onClick: this.selectAll, style: { flex: '0 0 50px', textAlign: 'center', fontSize: '80%', color: '#9cacc3', padding: 0 }, disabled: this.state.isBusy, title: `Show all chains`, children: "All" }), (0, jsx_runtime_1.jsx)(common_1.Button, { icon: icons_1.CloseSvg, flex: true, onClick: this.selectNone, style: { flex: '0 0 50px', textAlign: 'center', fontSize: '80%', color: '#9cacc3', padding: 0 }, disabled: this.state.isBusy, title: `Hide all chains`, children: "None" })] }); const mainRow = (0, jsx_runtime_1.jsxs)("div", { className: `msp-flex-row msp-tree-row`, style: { marginTop: '10px' }, children: [expand, label, this.props.cluster.length > 1 && selectionControls] }); const searchControls = (0, jsx_runtime_1.jsxs)("div", { className: 'msp-mapped-parameter-group', style: { fontSize: '90%' }, children: [(0, jsx_runtime_1.jsxs)("div", { className: 'msp-control-row msp-transform-header-brand-gray', style: { height: '33px', marginLeft: '30px' }, children: [(0, jsx_runtime_1.jsx)("span", { className: 'msp-control-row-label', children: "Search PDB ID" }), (0, jsx_runtime_1.jsx)("div", { className: 'msp-control-row-ctrl', children: (0, jsx_runtime_1.jsx)("input", { type: 'text', placeholder: 'Enter PDB ID..', disabled: this.state.isBusy, onChange: e => this.inputStream.next(e.target.value), value: this.state.searchText, maxLength: 4 }) })] }), (0, jsx_runtime_1.jsx)(common_1.IconButton, { svg: icons_1.CloseSvg, flex: true, onClick: this.clearSearch, style: { flex: '0 0 24px', padding: 0 }, disabled: this.state.isBusy || this.state.searchText === '', toggleState: this.state.searchText !== '', title: 'Clear search input' })] }); return (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [mainRow, (this.state.showAll || this.state.showNone) && (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsxs)("div", { className: `msp-control-row msp-transform-header-brand-${this.state.showAll ? 'green' : 'red'}`, style: { display: 'flex', marginLeft: '20px', height: '35px' }, children: [(0, jsx_runtime_1.jsxs)("span", { className: 'msp-control-row-label', style: { flex: '1 1 auto', textAlign: 'left', fontSize: '85%' }, children: [this.state.showAll ? 'Display' : 'Hide', " ", this.state.cluster.length < this.props.cluster.length ? `${this.state.cluster.length} / ` : 'all ', this.props.cluster.length, " chains"] }), (0, jsx_runtime_1.jsx)(common_1.Button, { icon: icons_1.CheckSvg, flex: true, onClick: this.applyAction, style: { flex: '0 0 60px', textAlign: 'center', fontSize: '78%', color: '#9cacc3', padding: 0, margin: '0 1px' }, title: `Apply action`, children: "Apply" }), (0, jsx_runtime_1.jsx)(common_1.Button, { icon: icons_1.CloseSvg, flex: true, onClick: this.cancelAction, style: { flex: '0 0 60px', textAlign: 'center', fontSize: '78%', color: '#9cacc3', padding: 0, margin: '0 1px' }, title: `Cancel action`, children: "Cancel" })] }) }), (!this.state.isCollapsed && this.props.cluster.length > 5) && searchControls, !this.state.isCollapsed && (0, jsx_runtime_1.jsx)("div", { className: 'msp-tree-updates-wrapper', style: { maxHeight: (this.props.totalClusters > 1) ? '330px' : '87%', overflowY: 'auto' }, children: this.state.cluster.map((s, i) => (0, jsx_runtime_1.jsx)(StructureNode, { segmentIndex: this.props.segmentIndex, structure: s, isRep: i === 0 ? true : false }, `str-${s.pdb_id}${s.struct_asym_id}${i}`)) })] }); } } class StructureNode extends base_1.PluginUIComponent { constructor() { super(...arguments); this.state = { showControls: false, isBusy: false, isProcessing: false, isHidden: true, }; this.toggleVisible = (e) => tslib_1.__awaiter(this, void 0, void 0, function* () { e.preventDefault(); e.currentTarget.blur(); this.setState({ isProcessing: true, showControls: false }); if (this.ref) { const structHierarchy = this.plugin.managers.structure.hierarchy.current.refs.get(this.ref); if (structHierarchy && structHierarchy.components) { for (const c of structHierarchy.components) { const currentHiddenState = c.cell.state.isHidden ? true : false; if (currentHiddenState === this.state.isHidden) { commands_1.PluginCommands.State.ToggleVisibility(this.plugin, { state: c.cell.parent, ref: c.cell.transform.ref }); } } this.setState({ isHidden: !this.state.isHidden }); } } else { yield (0, superposition_1.renderSuperposition)(this.plugin, this.props.segmentIndex, [this.props.structure]); } this.setState({ isProcessing: false }); commands_1.PluginCommands.Camera.Reset(this.plugin); }); this.selectAction = item => { if (!item) return; this.setState({ showControls: false }); (item === null || item === void 0 ? void 0 : item.value)(); }; this.highlight = (e) => { e.preventDefault(); if (this.ref) { const cell = this.plugin.state.data.cells.get(this.ref); commands_1.PluginCommands.Interactivity.Object.Highlight(this.plugin, { state: cell.parent, ref: this.ref }); } e.currentTarget.blur(); }; this.clearHighlight = (e) => { e.preventDefault(); commands_1.PluginCommands.Interactivity.ClearHighlights(this.plugin); e.currentTarget.blur(); }; this.toggleControls = (e) => { e.preventDefault(); this.setState({ showControls: !this.state.showControls }); e.currentTarget.blur(); }; } get customState() { return (0, plugin_custom_state_1.PluginCustomState)(this.plugin); } get ref() { if (this.customState && this.customState.superpositionState && this.customState.superpositionState.models[`${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`]) { return this.customState.superpositionState.models[`${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`]; } else { return undefined; } } get modelCell() { if (this.ref) { return this.plugin.state.data.cells.get(this.ref); } else { return undefined; } } get isAllHidden() { let isHidden = true; if (this.ref) { const structHierarchy = this.plugin.managers.structure.hierarchy.current.refs.get(this.ref); if (structHierarchy && structHierarchy.components) { for (const c of structHierarchy.components) { if (c && c.cell && !c.cell.state.isHidden) { isHidden = false; break; } } } else { isHidden = false; } } return isHidden; } checkRelation(ref) { let isRelated = false; const cell = this.plugin.state.data.cells.get(ref); if (cell && cell.transform.parent) { if (cell && cell.transform.parent === this.ref) { isRelated = true; } else { const pcell = this.plugin.state.data.cells.get(cell.transform.parent); if (pcell && pcell.transform.parent === this.ref) isRelated = true; } } else { const currentNodeCell = this.plugin.state.data.cells.get(this.ref); if (currentNodeCell && currentNodeCell.transform.parent === cell.transform.parent) { isRelated = true; } } return isRelated; } is(e) { var _a, _b; if (!this.ref) return false; let isRelated = false; if (this.ref && e.ref !== this.ref) { isRelated = this.checkRelation(e.ref); } if (e.ref === this.ref || isRelated) { return true; } else { const id = `${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`; const invalidStruct = (_b = (_a = this.customState.superpositionState) === null || _a === void 0 ? void 0 : _a.invalidStruct.includes(id)) !== null && _b !== void 0 ? _b : false; return invalidStruct; } } componentDidMount() { this.setState({ isHidden: this.isAllHidden }); this.subscribe((0, plugin_custom_state_1.PluginCustomState)(this.plugin).events.isBusy, (e) => { this.setState({ isBusy: e, showControls: false }); }); this.subscribe(this.plugin.state.events.cell.stateUpdated.pipe((0, operators_1.filter)(e => this.is(e)), (0, operators_1.debounceTime)(33)), e => { this.setState({ isHidden: this.isAllHidden }); // this.forceUpdate(); }); } getTagRefs(tags) { const TagSet = new Set(tags); const tree = this.plugin.state.data.tree; return mol_state_1.StateSelection.findUniqueTagsInSubtree(tree, this.modelCell.transform.ref, TagSet); } ; addChainRepr() { return tslib_1.__awaiter(this, void 0, void 0, function* () { const uniformColor1 = (0, superposition_1.getNextColor)(this.plugin, this.props.segmentIndex); const strInstance = this.plugin.state.data.select(this.ref)[0]; const query = builder_1.MolScriptBuilder.struct.generator.atomGroups({ 'chain-test': builder_1.MolScriptBuilder.core.rel.eq([builder_1.MolScriptBuilder.struct.atomProperty.macromolecular.label_asym_id(), this.props.structure.struct_asym_id]), }); const chainSel = yield this.plugin.builders.structure.tryCreateComponentFromExpression(strInstance, query, `Chain-${this.props.segmentIndex}`, { label: `Chain`, tags: [`superposition-sel`] }); if (chainSel) { yield this.plugin.builders.structure.representation.addRepresentation(chainSel, { type: 'cartoon', color: 'uniform', colorParams: { value: uniformColor1 } }, { tag: `superposition-visual` }); } }); } updates() { var _a; const structHierarchy = this.plugin.managers.structure.hierarchy.current.refs.get(this.ref); if (structHierarchy && structHierarchy.components) { const representations = []; let showAddChainBtn = true; structHierarchy.components.forEach((comps) => { const gKeys = comps.key.split(','); const cId1Arr = gKeys[0].split('-'); if (cId1Arr[2] === 'Chain') showAddChainBtn = false; if (comps.representations) { comps.representations.forEach((repr) => { representations.push(repr); }); } }); const customState = (0, plugin_custom_state_1.PluginCustomState)(this.plugin); if (((_a = customState.initParams) === null || _a === void 0 ? void 0 : _a.superpositionParams) && !customState.initParams.superpositionParams.ligandView) { showAddChainBtn = false; } if (representations.length > 0) { return (0, jsx_runtime_1.jsxs)("div", { className: 'msp-accent-offset', style: { marginLeft: '40px' }, children: [representations.length > 0 && representations.map((r, i) => (0, jsx_runtime_1.jsx)(StructureRepresentationEntry, { group: [structHierarchy], representation: r }, `${r.cell.transform.ref}-${i}`)), showAddChainBtn && (0, jsx_runtime_1.jsx)("div", { className: 'msp-control-group-header', style: { marginTop: '1px' }, children: (0, jsx_runtime_1.jsxs)(common_1.Button, { noOverflow: true, className: 'msp-control-button-label', title: `Click to add chain representaion`, onClick: () => this.addChainRepr(), children: ["\u00A0\u00A0Add Chain ", this.props.structure.struct_asym_id, " Representation"] }) })] }); } } return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {}); } getSubtitle() { if (!this.customState.superpositionState) throw new Error('customState.superpositionState has not been initialized'); const hetList = this.customState.superpositionState.hets[`${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`]; let subtitle; if (hetList) { const hetLimit = this.props.structure.is_representative ? 1 : 4; const totalHets = hetList.length; let hetStr = hetList.join(', '); if (totalHets > hetLimit) { hetStr = hetList.slice(0, hetLimit).join(', '); hetStr += ` + ${totalHets - hetLimit}`; } subtitle = ` ( ${hetStr} )`; if (this.props.structure.is_representative) subtitle = ` ${subtitle} ( Representative )`; } else if (this.props.structure.is_representative) { subtitle = ' ( Representative )'; } return subtitle; } get panelColor() { let panelColor = '#808080'; if (!this.state.isHidden) { if (this.modelCell) { const refs = this.getTagRefs([`superposition-visual`, `superposition-ligand-visual`]); const visualRef = refs[`superposition-ligand-visual`] ? refs[`superposition-ligand-visual`] : refs[`superposition-visual`] ? refs[`superposition-visual`] : undefined; if (visualRef) { const visualCell = this.plugin.state.data.cells.get(visualRef); if (visualCell.params && visualCell.params.values && visualCell.params.values.colorTheme) { const colorTheme = visualCell.params.values.colorTheme; if (colorTheme.params && colorTheme.params.value) { panelColor = `${color_1.Color.toStyle(colorTheme.params.value)}`; } else if (colorTheme.params && colorTheme.params.palette) { const colorList1 = colorTheme.params.palette.params.list.colors; panelColor = `${color_1.Color.toStyle(colorList1[0])}`; } else if (colorTheme.params && colorTheme.params.list) { const colorList2 = colorTheme.params.list.colors; panelColor = `${color_1.Color.toStyle(colorList2[0])}`; } } } } } return panelColor; } render() { var _a, _b; const superpositionParams = this.customState.initParams.superpositionParams; const strutStateId = `${this.props.structure.pdb_id}_${this.props.structure.struct_asym_id}`; const invalidStruct = (_a = this.customState.superpositionState) === null || _a === void 0 ? void 0 : _a.invalidStruct.includes(strutStateId); const noMatrixStruct = (_b = this.customState.superpositionState) === null || _b === void 0 ? void 0 : _b.noMatrixStruct.includes(strutStateId); const subTitle = invalidStruct ? noMatrixStruct ? ` Matrix not available!` : ` No Ligand found!` : this.getSubtitle(); let strTitle = `${this.props.structure.pdb_id} chain ${this.props.structure.auth_asym_id}`; if (superpositionParams && superpositionParams.ligandView) { strTitle = `${this.props.structure.pdb_id} ${this.props.structure.struct_asym_id}`; } const label = (0, jsx_runtime_1.jsxs)(common_1.Button, { className: `msp-btn-tree-label`, style: { borderLeftColor: this.panelColor }, noOverflow: true, title: strTitle, disabled: (invalidStruct || this.state.isBusy || this.state.isProcessing) ? true : false, onMouseEnter: this.highlight, onMouseLeave: this.clearHighlight, children: [(0, jsx_runtime_1.jsx)("span", { children: strTitle }), subTitle && (0, jsx_runtime_1.jsx)("small", { children: subTitle })] }); const expand = (0, jsx_runtime_1.jsx)(common_1.IconButton, { svg: !this.state.showControls ? icons_1.ArrowRightSvg : icons_1.ArrowDropDownSvg, flex: '20px', onClick: this.toggleControls, transparent: true, className: 'msp-no-hover-outline', disabled: (invalidStruct || this.state.isBusy || this.state.isProcessing) ? true : false }); const visibility = (0, jsx_runtime_1.jsx)(common_1.IconButton, { svg: this.state.isHidden ? icons_1.VisibilityOffOutlinedSvg : icons_1.VisibilityOutlinedSvg, toggleState: false, small: true, onClick: this.toggleVisible, disabled: (invalidStruct || this.state.isBusy || this.state.isProcessing) ? true : false, title: this.state.isHidden ? `Show chain` : `Hide chain` }); const row = (0, jsx_runtime_1.jsxs)("div", { className: `msp-flex-row msp-tree-row`, style: { marginLeft: !this.state.isHidden ? '10px' : '31px' }, children: [!this.state.isHidden && expand, label, visibility] }); return (0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: '1px' }, children: [row, this.state.showControls && this.updates()] }); } } class StructureRepresentationEntry extends base_1.PurePluginUIComponent { constructor() { super(...arguments); this.toggleVisible = (e) => { e.preventDefault(); e.currentTarget.blur(); const cell = this.props.representation.cell; commands_1.PluginCommands.State.ToggleVisibility(this.plugin, { state: cell.parent, ref: cell.transform.parent }); }; } componentDidMount() { this.subscribe(this.plugin.state.events.cell.stateUpdated, e => { if (mol_state_1.State.ObjectEvent.isCell(e, this.props.representation.cell)) this.forceUpdate(); }); } render() { var _a, _b, _c, _d, _e, _f, _g; const repr = this.props.representation.cell; let label = (_a = repr.obj) === null || _a === void 0 ? void 0 : _a.label; if (((_b = repr.obj) === null || _b === void 0 ? void 0 : _b.data.repr) && ((_c = repr.obj) === null || _c === void 0 ? void 0 : _c.data.repr.label)) { let sourceLabel = (((_d = repr.obj) === null || _d === void 0 ? void 0 : _d.data.repr.label.indexOf('[Focus]')) >= 0) ? '[Focus]' : (_e = repr.obj) === null || _e === void 0 ? void 0 : _e.data.repr.label; const isLargeLabel = sourceLabel.length > 10 ? true : false; sourceLabel = `${isLargeLabel ? `${sourceLabel.substring(0, 28)}...` : sourceLabel}`; if (isLargeLabel) { label = sourceLabel; } else { label = `${sourceLabel} ${(label && label.length < 21) ? ' - ' + label : ''}`; } } if (((_f = repr.obj) === null || _f === void 0 ? void 0 : _f.data.repr) && ((_g = repr.obj) === null || _g === void 0 ? void 0 : _g.data.repr.label) === 'Custom Selection') label = 'Custom Selection'; return (0, jsx_runtime_1.jsxs)("div", { className: 'msp-representation-entry', children: [repr.parent && (0, jsx_runtime_1.jsx)(common_1.ExpandGroup, { header: `${label || 'Representation'}`, noOffset: true, headerStyle: { overflow: 'hidden' }, children: (0, jsx_runtime_1.jsx)(update_transform_1.UpdateTransformControl, { state: repr.parent, transform: repr.transform, customHeader: 'none', noMargin: true }) }), (0, jsx_runtime_1.jsx)(common_1.IconButton, { svg: this.props.representation.cell.state.isHidden ? icons_1.VisibilityOffOutlinedSvg : icons_1.VisibilityOutlinedSvg, toggleState: false, onClick: this.toggleVisible, title: this.props.representation.cell.state.isHidden ? `Show representation` : `Hide representation`, small: true, className: 'msp-default-bg', style: { position: 'absolute', top: 0, right: 0, lineHeight: '24px', height: '24px', textAlign: 'right', width: '32px', paddingRight: '6px', background: 'none' } })] }); } }