molstar
Version:
A comprehensive macromolecular library.
233 lines • 11.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StructureFocusControls = void 0;
var tslib_1 = require("tslib");
var jsx_runtime_1 = require("react/jsx-runtime");
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
var int_1 = require("../../mol-data/int");
var structure_1 = require("../../mol-model/structure");
var representation_1 = require("../../mol-plugin/behavior/dynamic/representation");
var label_1 = require("../../mol-theme/label");
var binding_1 = require("../../mol-util/binding");
var memoize_1 = require("../../mol-util/memoize");
var base_1 = require("../base");
var action_menu_1 = require("../controls/action-menu");
var common_1 = require("../controls/common");
var icons_1 = require("../controls/icons");
function addSymmetryGroupEntries(entries, location, unitSymmetryGroup, granularity) {
var idx = int_1.SortedArray.indexOf(location.unit.elements, location.element);
var base = structure_1.StructureElement.Loci(location.structure, [
{ unit: location.unit, indices: int_1.OrderedSet.ofSingleton(idx) }
]);
var extended = granularity === 'residue'
? structure_1.StructureElement.Loci.extendToWholeResidues(base)
: structure_1.StructureElement.Loci.extendToWholeChains(base);
var name = structure_1.StructureProperties.entity.pdbx_description(location).join(', ');
for (var _i = 0, _a = unitSymmetryGroup.units; _i < _a.length; _i++) {
var u = _a[_i];
var loci = structure_1.StructureElement.Loci(extended.structure, [
{ unit: u, indices: extended.elements[0].indices }
]);
var label = (0, label_1.lociLabel)(loci, { reverse: true, hidePrefix: true, htmlStyling: false, granularity: granularity });
if (!label)
label = (0, label_1.lociLabel)(loci, { hidePrefix: false, htmlStyling: false });
if (unitSymmetryGroup.units.length > 1) {
label += " | " + loci.elements[0].unit.conformation.operator.name;
}
var item = { label: label, category: name, loci: loci };
if (entries.has(name))
entries.get(name).push(item);
else
entries.set(name, [item]);
}
}
function getFocusEntries(structure) {
var entityEntries = new Map();
var l = structure_1.StructureElement.Location.create(structure);
for (var _i = 0, _a = structure.unitSymmetryGroups; _i < _a.length; _i++) {
var ug = _a[_i];
if (!structure_1.Unit.isAtomic(ug.units[0]))
continue;
l.unit = ug.units[0];
l.element = ug.elements[0];
var isMultiChain = structure_1.Unit.Traits.is(l.unit.traits, 1 /* MultiChain */);
var entityType = structure_1.StructureProperties.entity.type(l);
var isNonPolymer = entityType === 'non-polymer';
var isBranched = entityType === 'branched';
var isBirdMolecule = !!structure_1.StructureProperties.entity.prd_id(l);
if (isBirdMolecule) {
addSymmetryGroupEntries(entityEntries, l, ug, 'chain');
}
else if (isNonPolymer && !isMultiChain) {
addSymmetryGroupEntries(entityEntries, l, ug, 'residue');
}
else if (isBranched || (isNonPolymer && isMultiChain)) {
var u = l.unit;
var residueIndex = u.model.atomicHierarchy.residueAtomSegments.index;
var prev = -1;
for (var i = 0, il = u.elements.length; i < il; ++i) {
var eI = u.elements[i];
var rI = residueIndex[eI];
if (rI !== prev) {
l.element = eI;
addSymmetryGroupEntries(entityEntries, l, ug, 'residue');
prev = rI;
}
}
}
}
var entries = [];
entityEntries.forEach(function (e, name) {
if (e.length === 1) {
entries.push({ label: name + ": " + e[0].label, loci: e[0].loci });
}
else if (e.length < 2000) {
entries.push.apply(entries, e);
}
});
return entries;
}
var StructureFocusControls = /** @class */ (function (_super) {
(0, tslib_1.__extends)(StructureFocusControls, _super);
function StructureFocusControls() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.state = { isBusy: false, showAction: false };
_this.getSelectionItems = (0, memoize_1.memoizeLatest)(function (structures) {
var _a;
var presetItems = [];
for (var _i = 0, structures_1 = structures; _i < structures_1.length; _i++) {
var s = structures_1[_i];
var d = (_a = s.cell.obj) === null || _a === void 0 ? void 0 : _a.data;
if (d) {
var entries = getFocusEntries(d);
if (entries.length > 0) {
presetItems.push((0, tslib_1.__spreadArray)([
action_menu_1.ActionMenu.Header(d.label, { description: d.label })
], action_menu_1.ActionMenu.createItems(entries, {
label: function (f) { return f.label; },
category: function (f) { return f.category; },
description: function (f) { return f.label; }
}), true));
}
}
}
return presetItems;
});
_this.selectAction = function (item, e) {
if (!item || !_this.state.showAction) {
_this.setState({ showAction: false });
return;
}
var f = item.value;
if (e === null || e === void 0 ? void 0 : e.shiftKey) {
_this.plugin.managers.structure.focus.addFromLoci(f.loci);
}
else {
_this.plugin.managers.structure.focus.set(f);
}
_this.focusCamera();
};
_this.toggleAction = function () { return _this.setState({ showAction: !_this.state.showAction }); };
_this.focusCamera = function () {
var current = _this.plugin.managers.structure.focus.current;
if (current)
_this.plugin.managers.camera.focusLoci(current.loci);
};
_this.clear = function () {
_this.plugin.managers.structure.focus.clear();
_this.plugin.managers.camera.reset();
};
_this.highlightCurrent = function () {
var current = _this.plugin.managers.structure.focus.current;
if (current)
_this.plugin.managers.interactivity.lociHighlights.highlightOnly({ loci: current.loci }, false);
};
_this.clearHighlights = function () {
_this.plugin.managers.interactivity.lociHighlights.clearHighlights();
};
return _this;
}
StructureFocusControls.prototype.componentDidMount = function () {
var _this = this;
this.subscribe(this.plugin.managers.structure.focus.behaviors.current, function (c) {
// clear the memo cache
_this.getSelectionItems([]);
_this.forceUpdate();
});
this.subscribe(this.plugin.managers.structure.focus.events.historyUpdated, function (c) {
_this.forceUpdate();
});
this.subscribe(this.plugin.behaviors.state.isBusy, function (v) {
_this.setState({ isBusy: v, showAction: false });
});
};
Object.defineProperty(StructureFocusControls.prototype, "isDisabled", {
get: function () {
return this.state.isBusy || this.actionItems.length === 0;
},
enumerable: false,
configurable: true
});
Object.defineProperty(StructureFocusControls.prototype, "actionItems", {
get: function () {
var historyItems = [];
var history = this.plugin.managers.structure.focus.history;
if (history.length > 0) {
historyItems.push((0, tslib_1.__spreadArray)([
action_menu_1.ActionMenu.Header('History', { description: 'Previously focused on items.' })
], action_menu_1.ActionMenu.createItems(history, {
label: function (f) { return f.label; },
description: function (f) {
return f.category && f.label !== f.category
? f.category + " | " + f.label
: f.label;
}
}), true));
}
var presetItems = this.getSelectionItems(this.plugin.managers.structure.hierarchy.selection.structures);
if (presetItems.length === 1) {
var item = presetItems[0];
var header = item[0];
header.initiallyExpanded = true;
}
var items = [];
if (presetItems.length > 0)
items.push.apply(items, presetItems);
if (historyItems.length > 0)
items.push.apply(items, historyItems);
return items;
},
enumerable: false,
configurable: true
});
StructureFocusControls.prototype.getToggleBindingLabel = function () {
var _a;
var t = this.plugin.state.behaviors.transforms.get(representation_1.FocusLoci.id);
if (!t)
return '';
var binding = (_a = t.params) === null || _a === void 0 ? void 0 : _a.bindings.clickFocus;
if (!binding || binding_1.Binding.isEmpty(binding))
return '';
return binding_1.Binding.formatTriggers(binding);
};
StructureFocusControls.prototype.render = function () {
var current = this.plugin.managers.structure.focus.current;
var label = (current === null || current === void 0 ? void 0 : current.label) || 'Nothing Focused';
var title = 'Click to Center Camera';
if (!current) {
title = 'Select focus using the menu';
var binding = this.getToggleBindingLabel();
if (binding) {
title += "\nor use '" + binding + "' on element";
}
}
return (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", (0, tslib_1.__assign)({ className: 'msp-flex-row' }, { children: [(0, jsx_runtime_1.jsx)(common_1.Button, (0, tslib_1.__assign)({ noOverflow: true, onClick: this.focusCamera, title: title, onMouseEnter: this.highlightCurrent, onMouseLeave: this.clearHighlights, disabled: this.isDisabled || !current, style: { textAlignLast: current ? 'left' : void 0 } }, { children: label }), void 0), current && (0, jsx_runtime_1.jsx)(common_1.IconButton, { svg: icons_1.CancelOutlinedSvg, onClick: this.clear, title: 'Clear', className: 'msp-form-control', flex: true, disabled: this.isDisabled }, void 0), (0, jsx_runtime_1.jsx)(common_1.ToggleButton, { icon: icons_1.CenterFocusStrongSvg, title: 'Select a focus target to center on an show its surroundings. Hold shift to focus on multiple targets.', toggle: this.toggleAction, isSelected: this.state.showAction, disabled: this.isDisabled, style: { flex: '0 0 40px', padding: 0 } }, void 0)] }), void 0), this.state.showAction && (0, jsx_runtime_1.jsx)(action_menu_1.ActionMenu, { items: this.actionItems, onSelect: this.selectAction }, void 0)] }, void 0);
};
return StructureFocusControls;
}(base_1.PluginUIComponent));
exports.StructureFocusControls = StructureFocusControls;
//# sourceMappingURL=focus.js.map