pdbe-molstar
Version:
Molstar implementation for PDBe
678 lines (677 loc) • 41.9 kB
JavaScript
"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' } })] });
}
}