forked from enviPath/enviPy
255 lines
8.2 KiB
JavaScript
255 lines
8.2 KiB
JavaScript
/****************************************************************************
|
|
* Copyright 2017 EPAM Systems
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
***************************************************************************/
|
|
|
|
var Set = require('../../util/set');
|
|
|
|
var Action = require('../action');
|
|
var Struct = require('../../chem/struct');
|
|
|
|
var LassoHelper = require('./helper/lasso');
|
|
|
|
var SGroup = require('./sgroup');
|
|
var Atom = require('./atom');
|
|
|
|
function SelectTool(editor, mode) {
|
|
if (!(this instanceof SelectTool))
|
|
return new SelectTool(editor, mode);
|
|
|
|
this.editor = editor;
|
|
|
|
this.lassoHelper = new LassoHelper(mode === 'lasso' ? 0 : 1, editor, mode === 'fragment');
|
|
}
|
|
|
|
SelectTool.prototype.mousedown = function (event) { // eslint-disable-line max-statements
|
|
var rnd = this.editor.render;
|
|
var ctab = rnd.ctab;
|
|
var struct = ctab.molecule;
|
|
this.editor.hover(null); // TODO review hovering for touch devicess
|
|
var selectFragment = (this.lassoHelper.fragment || event.ctrlKey);
|
|
var ci = this.editor.findItem(
|
|
event,
|
|
selectFragment ?
|
|
['frags', 'sgroups', 'sgroupData', 'rgroups', 'rxnArrows', 'rxnPluses', 'chiralFlags'] :
|
|
['atoms', 'bonds', 'sgroups', 'sgroupData', 'rgroups', 'rxnArrows', 'rxnPluses', 'chiralFlags']
|
|
);
|
|
this.dragCtx = {
|
|
item: ci,
|
|
xy0: rnd.page2obj(event)
|
|
};
|
|
if (!ci) { // ci.type == 'Canvas'
|
|
Atom.atomLongtapEvent(this, rnd);
|
|
delete this.dragCtx.item;
|
|
|
|
if (!this.lassoHelper.fragment)
|
|
this.lassoHelper.begin(event);
|
|
} else {
|
|
this.editor.hover(null);
|
|
if (!isSelected(rnd, this.editor.selection(), ci)) {
|
|
var sel = closestToSel(ci);
|
|
if (ci.map === 'frags') {
|
|
var frag = ctab.frags.get(ci.id);
|
|
sel = {
|
|
atoms: frag.fragGetAtoms(rnd, ci.id),
|
|
bonds: frag.fragGetBonds(rnd, ci.id)
|
|
};
|
|
} else if (ci.map === 'sgroups') {
|
|
var sgroup = ctab.sgroups.get(ci.id).item;
|
|
sel = {
|
|
atoms: Struct.SGroup.getAtoms(struct, sgroup),
|
|
bonds: Struct.SGroup.getBonds(struct, sgroup)
|
|
};
|
|
} else if (ci.map === 'rgroups') {
|
|
var rgroup = ctab.rgroups.get(ci.id);
|
|
sel = {
|
|
atoms: rgroup.getAtoms(rnd),
|
|
bonds: rgroup.getBonds(rnd)
|
|
};
|
|
}
|
|
this.editor.selection(!event.shiftKey ? sel :
|
|
selMerge(sel, this.editor.selection()));
|
|
}
|
|
if (ci.map === 'atoms')
|
|
// this event has to be stopped in others events by `tool.dragCtx.stopTapping()`
|
|
Atom.atomLongtapEvent(this, rnd);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
SelectTool.prototype.mousemove = function (event) {
|
|
var rnd = this.editor.render;
|
|
if (this.dragCtx && this.dragCtx.stopTapping)
|
|
this.dragCtx.stopTapping();
|
|
|
|
if (this.dragCtx && this.dragCtx.item) {
|
|
// moving selected objects
|
|
if (this.dragCtx.action) {
|
|
this.dragCtx.action.perform(rnd.ctab);
|
|
this.editor.update(this.dragCtx.action, true); // redraw the elements in unshifted position, lest the have different offset
|
|
}
|
|
this.dragCtx.action = Action.fromMultipleMove(
|
|
rnd.ctab,
|
|
this.editor.explicitSelected(),
|
|
rnd.page2obj(event).sub(this.dragCtx.xy0));
|
|
// finding & highlighting object to stick to
|
|
if (['atoms'/* , 'bonds'*/].indexOf(this.dragCtx.item.map) >= 0) {
|
|
// TODO add bond-to-bond fusing
|
|
var ci = this.editor.findItem(event, [this.dragCtx.item.map], this.dragCtx.item);
|
|
this.editor.hover((ci && ci.map == this.dragCtx.item.map) ? ci : null);
|
|
}
|
|
this.editor.update(this.dragCtx.action, true);
|
|
} else if (this.lassoHelper.running()) {
|
|
var sel = this.lassoHelper.addPoint(event);
|
|
this.editor.selection(!event.shiftKey ? sel :
|
|
selMerge(sel, this.editor.selection()));
|
|
} else {
|
|
this.editor.hover(
|
|
this.editor.findItem(event,
|
|
(this.lassoHelper.fragment || event.ctrlKey) ?
|
|
['frags', 'sgroups', 'sgroupData', 'rgroups', 'rxnArrows', 'rxnPluses', 'chiralFlags'] :
|
|
['atoms', 'bonds', 'sgroups', 'sgroupData', 'rgroups', 'rxnArrows', 'rxnPluses', 'chiralFlags']
|
|
)
|
|
);
|
|
}
|
|
return true;
|
|
};
|
|
SelectTool.prototype.mouseup = function (event) { // eslint-disable-line max-statements
|
|
if (this.dragCtx && this.dragCtx.stopTapping)
|
|
this.dragCtx.stopTapping();
|
|
|
|
if (this.dragCtx && this.dragCtx.item) {
|
|
if (['atoms'/* , 'bonds'*/].indexOf(this.dragCtx.item.map) >= 0) {
|
|
// TODO add bond-to-bond fusing
|
|
var ci = this.editor.findItem(event, [this.dragCtx.item.map], this.dragCtx.item);
|
|
if (ci && ci.map == this.dragCtx.item.map) {
|
|
var restruct = this.editor.render.ctab;
|
|
this.editor.hover(null);
|
|
this.editor.selection(null);
|
|
this.dragCtx.action = this.dragCtx.action ?
|
|
Action.fromAtomMerge(restruct, this.dragCtx.item.id, ci.id).mergeWith(this.dragCtx.action) :
|
|
Action.fromAtomMerge(restruct, this.dragCtx.item.id, ci.id);
|
|
}
|
|
}
|
|
if (this.dragCtx.action)
|
|
this.editor.update(this.dragCtx.action);
|
|
delete this.dragCtx;
|
|
} else if (this.lassoHelper.running()) { // TODO it catches more events than needed, to be re-factored
|
|
var sel = this.lassoHelper.end();
|
|
this.editor.selection(!event.shiftKey ? sel :
|
|
selMerge(sel, this.editor.selection()));
|
|
} else if (this.lassoHelper.fragment) {
|
|
this.editor.selection(null);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
SelectTool.prototype.dblclick = function (event) { // eslint-disable-line max-statements
|
|
var editor = this.editor;
|
|
var rnd = this.editor.render;
|
|
var ci = this.editor.findItem(event, ['atoms', 'bonds', 'sgroups', 'sgroupData']);
|
|
if (!ci) return;
|
|
|
|
var struct = rnd.ctab.molecule;
|
|
if (ci.map === 'atoms') {
|
|
this.editor.selection(closestToSel(ci));
|
|
var atom = struct.atoms.get(ci.id);
|
|
var ra = editor.event.elementEdit.dispatch(atom);
|
|
Promise.resolve(ra).then(function (newatom) {
|
|
// TODO: deep compare to not produce dummy, e.g.
|
|
// atom.label != attrs.label || !atom.atomList.equals(attrs.atomList)
|
|
editor.update(Action.fromAtomsAttrs(rnd.ctab, ci.id, newatom));
|
|
});
|
|
} else if (ci.map === 'bonds') {
|
|
this.editor.selection(closestToSel(ci));
|
|
var bond = rnd.ctab.bonds.get(ci.id).b;
|
|
var rb = editor.event.bondEdit.dispatch(bond);
|
|
Promise.resolve(rb).then(function (newbond) {
|
|
editor.update(Action.fromBondAttrs(rnd.ctab, ci.id, newbond));
|
|
});
|
|
} else if (ci.map === 'sgroups' || ci.map === 'sgroupData') {
|
|
this.editor.selection(closestToSel(ci));
|
|
SGroup.dialog(this.editor, ci.id);
|
|
// } else if (ci.map == 'sgroupData') {
|
|
// SGroup.dialog(this.editor, ci.sgid);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
SelectTool.prototype.cancel = SelectTool.prototype.mouseleave = function () {
|
|
if (this.dragCtx && this.dragCtx.stopTapping)
|
|
this.dragCtx.stopTapping();
|
|
|
|
if (this.dragCtx && this.dragCtx.action) {
|
|
var action = this.dragCtx.action;
|
|
this.editor.update(action);
|
|
}
|
|
if (this.lassoHelper.running())
|
|
this.editor.selection(this.lassoHelper.end());
|
|
|
|
delete this.dragCtx;
|
|
|
|
this.editor.hover(null);
|
|
};
|
|
|
|
function closestToSel(ci) {
|
|
var res = {};
|
|
res[ci.map] = [ci.id];
|
|
return res;
|
|
}
|
|
|
|
// TODO: deep-merge?
|
|
function selMerge(selection, add) {
|
|
if (add) {
|
|
for (var item in add) {
|
|
if (add.hasOwnProperty(item)) {
|
|
if (!selection[item]) {
|
|
selection[item] = add[item].slice();
|
|
} else {
|
|
selection[item] = uniqArray(selection[item],
|
|
add[item]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return selection;
|
|
}
|
|
|
|
function uniqArray(dest, add) {
|
|
for (var i = 0; i < add.length; i++) {
|
|
if (dest.indexOf(add[i]) < 0)
|
|
dest.push(add[i]);
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
function isSelected(render, selection, item) {
|
|
if (!selection)
|
|
return false;
|
|
var ctab = render.ctab;
|
|
if (item.map === 'frags' || item.map === 'rgroups') {
|
|
var atoms = item.map === 'frags' ?
|
|
ctab.frags.get(item.id).fragGetAtoms(render, item.id) :
|
|
ctab.rgroups.get(item.id).getAtoms(render);
|
|
|
|
return !!selection['atoms'] &&
|
|
Set.subset(Set.fromList(atoms), Set.fromList(selection['atoms']));
|
|
}
|
|
|
|
return !!selection[item.map] &&
|
|
selection[item.map].indexOf(item.id) > -1;
|
|
}
|
|
|
|
module.exports = SelectTool;
|