From bfe3734db87226cc9fceb3e21e7b761ab71531b2 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Fri, 5 May 2023 04:26:30 +0300 Subject: [PATCH 1/4] #2276 - atom tool mousedown, mousemove and mouseup events refactored --- .../src/script/editor/tool/atom.ts | 278 +++++++++--------- 1 file changed, 144 insertions(+), 134 deletions(-) diff --git a/packages/ketcher-react/src/script/editor/tool/atom.ts b/packages/ketcher-react/src/script/editor/tool/atom.ts index e48694ac7c..fbaf762603 100644 --- a/packages/ketcher-react/src/script/editor/tool/atom.ts +++ b/packages/ketcher-react/src/script/editor/tool/atom.ts @@ -65,174 +65,184 @@ class AtomTool { } mousedown(event) { - const struct = this.editor.render.ctab - const sgroups = struct.sgroups - const molecule = struct.molecule - const functionalGroups = molecule.functionalGroups - this.editor.hover(null) - this.editor.selection(null) - const ci = this.editor.findItem(event, ['atoms', 'functionalGroups']) - if ( - ci && - ci.map === 'functionalGroups' && - functionalGroups && - FunctionalGroup.isContractedFunctionalGroup(ci.id, functionalGroups) - ) { - const action = new Action() - const selectedSgroup = sgroups.get(ci.id) - const sGroupAtoms = SGroup.getAtoms(molecule, selectedSgroup?.item) - const [firstAtom, ...atoms] = sGroupAtoms - const atomNeighbours = molecule.atomGetNeighbors(firstAtom) - const extraNeighbour = atomNeighbours?.some( - (atom) => !sGroupAtoms.includes(atom.aid) - ) - if (extraNeighbour) { - action.mergeWith(fromSgroupDeletion(struct, ci.id)) - action.mergeWith(fromFragmentDeletion(struct, { atoms: atoms })) - action.mergeWith( - fromAtomsAttrs(struct, firstAtom, this.atomProps, true) - ) - } else { - const firstAtomPp = struct.atoms.get(firstAtom)?.a.pp - action.mergeWith( - fromFragmentDeletion(struct, { - atoms: SGroup.getAtoms(molecule, selectedSgroup?.item), - bonds: SGroup.getBonds(molecule, selectedSgroup?.item) - }) - ) - action.mergeWith(fromAtomAddition(struct, firstAtomPp, this.atomProps)) + const { + editor, + editor: { + render: { + ctab: { + molecule: { functionalGroups } + } + } } - this.editor.update(action) - } - const atomResult: Array = [] - const result: Array = [] - if (ci && functionalGroups.size && ci.map === 'atoms') { - const atomId = FunctionalGroup.atomsInFunctionalGroup( + } = this + + editor.hover(null) + editor.selection(null) + + const eventMaps = ['atoms', 'functionalGroups'] + const ci = editor.findItem(event, eventMaps) + + if (ci?.map === 'atoms') { + const atomId = ci.id + + const fgId = FunctionalGroup.findFunctionalGroupByAtom( functionalGroups, - ci.id + atomId ) - if (atomId !== null) atomResult.push(atomId) - } - if (atomResult.length > 0) { - for (const id of atomResult) { - const fgId = FunctionalGroup.findFunctionalGroupByAtom( - functionalGroups, - id - ) - if (fgId !== null && !result.includes(fgId)) { - result.push(fgId) - } + + if (fgId !== null) { + editor.event.removeFG.dispatch({ fgIds: [fgId] }) + return } - this.editor.event.removeFG.dispatch({ fgIds: result }) - return } - if (!ci) { - // ci.type == 'Canvas' - this.dragCtx = {} - } else if (ci.map === 'atoms') { - this.dragCtx = { item: ci } + + this.dragCtx = { + item: ci } } mousemove(event) { - const rnd = this.editor.render + const { + dragCtx, + atomProps, + editor, + editor: { + render: rnd, + render: { + ctab: { molecule } + } + } + } = this - if (!this.dragCtx || !this.dragCtx.item) { - this.editor.hoverIcon.show() - this.editor.hoverIcon.updatePosition() + const eventMaps = ['atoms', 'functionalGroups'] + + if (!dragCtx?.item) { + editor.hoverIcon.show() + editor.hoverIcon.updatePosition() + editor.hover(editor.findItem(event, eventMaps), null, event) - this.editor.hover( - this.editor.findItem(event, ['atoms', 'functionalGroups']), - null, - event - ) return - } else { - this.editor.hoverIcon.hide() } - const dragCtx = this.dragCtx - const ci = this.editor.findItem(event, ['atoms']) + editor.hoverIcon.hide() + + const ci = editor.findItem(event, eventMaps) + + if (ci?.map === 'atoms' && ci?.id === dragCtx.item.id) { + editor.hover(editor.findItem(event, eventMaps)) - if (ci && ci.map === 'atoms' && ci.id === dragCtx.item.id) { - // fromAtomsAttrs - this.editor.hover(this.editor.findItem(event, ['atoms'])) return } - // fromAtomAddition - const atom = rnd.ctab.molecule.atoms.get(dragCtx.item.id) - let angle = utils.calcAngle(atom?.pp, rnd.page2obj(event)) - if (!event.ctrlKey) angle = utils.fracAngle(angle, null) - const degrees = utils.degrees(angle) - this.editor.event.message.dispatch({ info: degrees + 'º' }) - const newAtomPos = utils.calcNewAtomPos( - atom?.pp, - rnd.page2obj(event), - event.ctrlKey - ) - if (dragCtx.action) dragCtx.action.perform(rnd.ctab) - - dragCtx.action = fromBondAddition( - rnd.ctab, - this.#bondProps, - dragCtx.item.id, - Object.assign({}, this.atomProps), - undefined, - newAtomPos - )[0] - this.editor.update(dragCtx.action, true) - } + let atomId: number | undefined + if (dragCtx.item.map === 'atoms') { + atomId = dragCtx.item.id + } else if (dragCtx.item.map === 'functionalGroups') { + const sGroup = molecule.sgroups.get(dragCtx.item.id) + const attachmentAtomId = sGroup?.getAttAtomId(molecule) + atomId = attachmentAtomId + } - mouseup(event) { - const struct = this.editor.render.ctab - const molecule = struct.molecule - const functionalGroups = molecule.functionalGroups - const ci = this.editor.findItem(event, ['atoms', 'bonds']) - const atomResult: Array = [] - const result: Array = [] - if (ci && functionalGroups && ci.map === 'atoms') { - const atomId = FunctionalGroup.atomsInFunctionalGroup( - functionalGroups, - ci.id + if (atomId !== undefined) { + const atom = molecule.atoms.get(atomId) + let angle = utils.calcAngle(atom?.pp, rnd.page2obj(event)) + if (!event.ctrlKey) angle = utils.fracAngle(angle, null) + const degrees = utils.degrees(angle) + editor.event.message.dispatch({ info: degrees + 'º' }) + const newAtomPos = utils.calcNewAtomPos( + atom?.pp, + rnd.page2obj(event), + event.ctrlKey ) - if (atomId !== null) atomResult.push(atomId) + if (dragCtx.action) dragCtx.action.perform(rnd.ctab) + + dragCtx.action = fromBondAddition( + rnd.ctab, + this.#bondProps, + atomId, + Object.assign({}, atomProps), + undefined, + newAtomPos + )[0] + + editor.update(dragCtx.action, true) } - if (atomResult.length > 0) { - for (const id of atomResult) { - const fgId = FunctionalGroup.findFunctionalGroupByAtom( - functionalGroups, - id - ) - if (fgId !== null && !result.includes(fgId)) { - result.push(fgId) + } + + mouseup(event) { + const { + dragCtx, + atomProps, + editor, + editor: { + render: rnd, + render: { + ctab: reStruct, + ctab: { + molecule, + molecule: { functionalGroups } + } } } - this.editor.event.removeFG.dispatch({ fgIds: result }) - return - } + } = this - if (this.dragCtx) { - const dragCtx = this.dragCtx - const rnd = this.editor.render + const ci = editor.findItem(event, ['atoms', 'bonds', 'functionalGroups']) + const action = new Action() - this.editor.update( - dragCtx.action || - (dragCtx.item - ? fromAtomsAttrs(rnd.ctab, dragCtx.item.id, this.atomProps, true) - : fromAtomAddition(rnd.ctab, rnd.page2obj(event), this.atomProps)) + if (!dragCtx.item && !ci) { + action.mergeWith( + fromAtomAddition(reStruct, rnd.page2obj(event), atomProps) ) + } else if (dragCtx.item && ci) { + if (dragCtx.item.id === ci.id) { + if ( + ci.map === 'functionalGroups' && + FunctionalGroup.isContractedFunctionalGroup(ci.id, functionalGroups) + ) { + const sGroup = molecule.sgroups.get(ci.id) + const attachmentAtomId = sGroup?.getAttAtomId(molecule) + + if (attachmentAtomId !== undefined) { + const atomsToDelete = [...SGroup.getAtoms(molecule, sGroup)].filter( + (atomId) => atomId !== attachmentAtomId + ) + const bondsToDelete = [...SGroup.getBonds(molecule, sGroup)] + action.mergeWith(fromSgroupDeletion(reStruct, ci.id)) + action.mergeWith( + fromFragmentDeletion(reStruct, { + atoms: atomsToDelete, + bonds: bondsToDelete + }) + ) + action.mergeWith( + fromAtomsAttrs(reStruct, attachmentAtomId, atomProps, true) + ) + } + } else if (ci.map === 'atoms') { + const atomId = ci.id - delete this.dragCtx + if ( + FunctionalGroup.atomsInFunctionalGroup(functionalGroups, atomId) == + null + ) { + action.mergeWith(fromAtomsAttrs(reStruct, atomId, atomProps, true)) + } + } + } } - this.editor.event.message.dispatch({ + + editor.event.message.dispatch({ info: false }) - this.editor.hover( + editor.hover( this.editor.findItem(event, ['atoms', 'functionalGroups']), null, event ) + + delete this.dragCtx + + editor.update(dragCtx.action ? action.mergeWith(dragCtx.action) : action) } } From ad423c198abbdf84cc142d79be46899fd20d76d9 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Fri, 5 May 2023 16:51:06 +0300 Subject: [PATCH 2/4] #2276 - revert bond action if the user hovers over the original target --- .../src/script/editor/tool/atom.ts | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/packages/ketcher-react/src/script/editor/tool/atom.ts b/packages/ketcher-react/src/script/editor/tool/atom.ts index fbaf762603..8888ff7ab0 100644 --- a/packages/ketcher-react/src/script/editor/tool/atom.ts +++ b/packages/ketcher-react/src/script/editor/tool/atom.ts @@ -109,31 +109,33 @@ class AtomTool { editor: { render: rnd, render: { + ctab: reStruct, ctab: { molecule } } } } = this const eventMaps = ['atoms', 'functionalGroups'] + const ci = editor.findItem(event, eventMaps) - if (!dragCtx?.item) { + if (!dragCtx?.item || (ci?.id !== undefined && ci.id === dragCtx.item.id)) { editor.hoverIcon.show() editor.hoverIcon.updatePosition() editor.hover(editor.findItem(event, eventMaps), null, event) - return - } - - editor.hoverIcon.hide() + if (dragCtx?.action) { + const action = dragCtx.action.perform(reStruct) - const ci = editor.findItem(event, eventMaps) + delete dragCtx.action - if (ci?.map === 'atoms' && ci?.id === dragCtx.item.id) { - editor.hover(editor.findItem(event, eventMaps)) + editor.update(action, true) + } return } + editor.hoverIcon.hide() + let atomId: number | undefined if (dragCtx.item.map === 'atoms') { atomId = dragCtx.item.id @@ -154,7 +156,10 @@ class AtomTool { rnd.page2obj(event), event.ctrlKey ) - if (dragCtx.action) dragCtx.action.perform(rnd.ctab) + + if (dragCtx.action) { + dragCtx.action.perform(reStruct) + } dragCtx.action = fromBondAddition( rnd.ctab, @@ -222,8 +227,9 @@ class AtomTool { const atomId = ci.id if ( - FunctionalGroup.atomsInFunctionalGroup(functionalGroups, atomId) == - null + dragCtx.action === undefined && + FunctionalGroup.atomsInFunctionalGroup(functionalGroups, atomId) === + null ) { action.mergeWith(fromAtomsAttrs(reStruct, atomId, atomProps, true)) } From d573d87f168fb59f0f949e5fb91630d70c2b8ac1 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 8 May 2023 12:52:03 +0300 Subject: [PATCH 3/4] #2276 - click and drag action on salt or solvent does not create a bond with atom --- packages/ketcher-react/src/script/editor/tool/atom.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/ketcher-react/src/script/editor/tool/atom.ts b/packages/ketcher-react/src/script/editor/tool/atom.ts index 8888ff7ab0..532e662f41 100644 --- a/packages/ketcher-react/src/script/editor/tool/atom.ts +++ b/packages/ketcher-react/src/script/editor/tool/atom.ts @@ -70,6 +70,7 @@ class AtomTool { editor: { render: { ctab: { + molecule, molecule: { functionalGroups } } } @@ -96,8 +97,16 @@ class AtomTool { } } + const ciFunctionalGroupName = + ci?.map === 'functionalGroups' + ? molecule.functionalGroups.get(ci?.id)?.name + : undefined + const ciIsSaltOrSolvent = ciFunctionalGroupName + ? SGroup.isSaltOrSolvent(ciFunctionalGroupName) + : false + this.dragCtx = { - item: ci + item: ciIsSaltOrSolvent ? undefined : ci } } From 0ea65687a0b78c62795aa4cebba2807f3e23d5af Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Mon, 8 May 2023 14:11:07 +0300 Subject: [PATCH 4/4] #2276 - atom tool click action on salt or solvent fixed --- .../ketcher-react/src/script/editor/tool/atom.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/ketcher-react/src/script/editor/tool/atom.ts b/packages/ketcher-react/src/script/editor/tool/atom.ts index 532e662f41..e92593533f 100644 --- a/packages/ketcher-react/src/script/editor/tool/atom.ts +++ b/packages/ketcher-react/src/script/editor/tool/atom.ts @@ -99,14 +99,15 @@ class AtomTool { const ciFunctionalGroupName = ci?.map === 'functionalGroups' - ? molecule.functionalGroups.get(ci?.id)?.name + ? molecule.sgroups.get(ci?.id)?.data.name : undefined - const ciIsSaltOrSolvent = ciFunctionalGroupName + const isSaltOrSolvent = ciFunctionalGroupName ? SGroup.isSaltOrSolvent(ciFunctionalGroupName) : false this.dragCtx = { - item: ciIsSaltOrSolvent ? undefined : ci + item: ci, + isSaltOrSolvent } } @@ -127,7 +128,11 @@ class AtomTool { const eventMaps = ['atoms', 'functionalGroups'] const ci = editor.findItem(event, eventMaps) - if (!dragCtx?.item || (ci?.id !== undefined && ci.id === dragCtx.item.id)) { + if ( + !dragCtx?.item || + dragCtx?.isSaltOrSolvent || + (ci?.id !== undefined && ci.id === dragCtx.item.id) + ) { editor.hoverIcon.show() editor.hoverIcon.updatePosition() editor.hover(editor.findItem(event, eventMaps), null, event) @@ -203,7 +208,7 @@ class AtomTool { const ci = editor.findItem(event, ['atoms', 'bonds', 'functionalGroups']) const action = new Action() - if (!dragCtx.item && !ci) { + if ((!dragCtx.item || dragCtx?.isSaltOrSolvent) && !ci) { action.mergeWith( fromAtomAddition(reStruct, rnd.page2obj(event), atomProps) )