diff --git a/packages/ketcher-react/src/script/editor/tool/template.ts b/packages/ketcher-react/src/script/editor/tool/template.ts index e5b2959944..1d20dccdc0 100644 --- a/packages/ketcher-react/src/script/editor/tool/template.ts +++ b/packages/ketcher-react/src/script/editor/tool/template.ts @@ -26,21 +26,27 @@ import { SGroup, ReStruct, Struct, - fromFragmentDeletion + fromFragmentDeletion, + fromPaste } from 'ketcher-core' import utils from '../shared/utils' import Editor from '../Editor' import { getGroupIdsFromItemArrays } from './helper/getGroupIdsFromItems' +import { getMergeItems } from './helper/getMergeItems' + +type MergeItems = Record> | null class TemplateTool { editor: Editor mode: any template: any findItems: Array + mergeItems: MergeItems = null dragCtx: any targetGroupsIds: Array = [] isSaltOrSolvent: boolean + followAction: any constructor(editor, tmpl) { this.editor = editor @@ -85,6 +91,11 @@ class TemplateTool { } mousedown(event) { + if (this.followAction) { + this.followAction.perform(this.editor.render.ctab) + delete this.followAction + } + const closestItem = this.editor.findItem(event, [ 'atoms', 'bonds', @@ -113,9 +124,17 @@ class TemplateTool { this.editor.hover(null) + const dragCtxItem = getDragCtxItem( + this.editor, + event, + this.mode, + this.mergeItems, + this.findItems + ) + this.dragCtx = { xy0: this.editor.render.page2obj(event), - item: this.editor.findItem(event, this.findItems) + item: dragCtxItem } const dragCtx = this.dragCtx @@ -177,22 +196,42 @@ class TemplateTool { } mousemove(event) { - const restruct = this.editor.render.ctab - if (!this.dragCtx) { - this.editor.hover( - this.editor.findItem(event, this.findItems), - null, - event + if (this.followAction) { + this.followAction.perform(this.editor.render.ctab) + } + + const [followAction, pasteItems] = fromPaste( + this.editor.render.ctab, + this.template.molecule, + this.editor.render.page2obj(event) ) - return true + + this.followAction = followAction + this.editor.update(followAction, true) + + if (this.mode === 'fg') { + const skip = getIgnoredGroupItem(this.editor.struct(), pasteItems) + const ci = this.editor.findItem(event, this.findItems, skip) + + if (ci) { + this.editor.hover(ci) + } else { + this.editor.hover(null) + } + } else { + this.mergeItems = getMergeItems(this.editor, pasteItems) + this.editor.hover(getHoverToFuse(this.mergeItems)) + } + + return } const dragCtx = this.dragCtx const ci = dragCtx.item let targetPos: Vec2 | null | undefined = null const eventPos = this.editor.render.page2obj(event) - const struct = restruct.molecule + const struct = this.editor.render.ctab.molecule /* moving when attached to bond */ if (ci && ci.map === 'bonds' && this.mode !== 'fg') { @@ -205,12 +244,12 @@ class TemplateTool { if (sign !== dragCtx.sign2 || !dragCtx.action) { if (dragCtx.action) { - dragCtx.action.perform(restruct) + dragCtx.action.perform(this.editor.render.ctab) } // undo previous action dragCtx.sign2 = sign const [action, pasteItems] = fromTemplateOnBondAction( - restruct, + this.editor.render.ctab, this.template, ci.id, this.editor.event, @@ -275,7 +314,7 @@ class TemplateTool { // undo previous action if (dragCtx.action) { - dragCtx.action.perform(restruct) + dragCtx.action.perform(this.editor.render.ctab) } // create new action @@ -298,7 +337,7 @@ class TemplateTool { } else if (ci?.map === 'atoms' || ci?.map === 'functionalGroups') { const atomId = getTargetAtomId(struct, ci) ;[action, pasteItems] = fromTemplateOnAtom( - restruct, + this.editor.render.ctab, this.template, atomId, angle, @@ -431,12 +470,10 @@ class TemplateTool { } else if (ci.map === 'atoms') { const degree = restruct.atoms.get(ci.id)?.a.neighbors.length let angle - let extraBond if (degree && degree > 1) { // common case angle = null - extraBond = true } else if (degree === 1) { // on chain end const atom = struct.atoms.get(ci.id) @@ -446,11 +483,9 @@ class TemplateTool { angle = event.ctrlKey ? utils.calcAngle(nei?.pp, atom?.pp) : utils.fracAngle(utils.calcAngle(nei.pp, atom?.pp), null) - extraBond = false } else { // on single atom angle = 0 - extraBond = false } ;[action, pasteItems] = fromTemplateOnAtom( @@ -458,7 +493,7 @@ class TemplateTool { this.template, ci.id, angle, - extraBond + this.mode === 'fg' ) dragCtx.action = action } else if (ci.map === 'bonds' && this.mode !== 'fg') { @@ -496,16 +531,19 @@ class TemplateTool { if (completeAction && !completeAction.isDummy()) { this.editor.update(completeAction) } - this.editor.event.showInfo.dispatch(null) - this.editor.event.message.dispatch({ - info: false - }) this.editor.hover(this.editor.findItem(event, this.findItems), null, event) + this.editor.event.showInfo.dispatch(null) + this.editor.event.message.dispatch({ info: false }) return true } cancel(e) { + if (this.followAction) { + this.followAction.perform(this.editor.render.ctab) + delete this.followAction + } + this.mouseup(e) } @@ -564,4 +602,24 @@ function getTargetAtomId(struct: Struct, ci): number | void { } } +function getIgnoredGroupItem(struct: Struct, pasteItems) { + const groupId = struct.getGroupIdFromAtomId(pasteItems.atoms[0]) + return { map: 'functionalGroups', id: groupId } +} + +function getDragCtxItem( + editor: Editor, + event, + mode: string, + mergeItems: MergeItems, + findItems +): { map: string; id: number } | null { + if (mode === 'fg') return editor.findItem(event, findItems) + if (mergeItems?.atoms.size === 1 && mergeItems.bonds.size === 0) { + // get ID of single dst (target) atom we are hovering over + return { map: 'atoms', id: mergeItems.atoms.values().next().value } + } + return null +} + export default TemplateTool