Skip to content

#4694 - Add Hotkeys in Macro mode similar to Micro mode#8895

Closed
Nyaki1144 wants to merge 6 commits into
masterfrom
4694-Add-Hotkeys-in-Macro-Mode-Similar-to-Micro-Mode
Closed

#4694 - Add Hotkeys in Macro mode similar to Micro mode#8895
Nyaki1144 wants to merge 6 commits into
masterfrom
4694-Add-Hotkeys-in-Macro-Mode-Similar-to-Micro-Mode

Conversation

@Nyaki1144
Copy link
Copy Markdown
Collaborator

Erase Operation with (Del) when hovering on monomer Erase Operation with (Backspace) when hovering on monomer

How the feature works? / How did you fix the issue?

(Screenshots, videos, or GIFs, if applicable)

Check list

  • unit-tests written
  • e2e-tests written
  • documentation updated
  • PR name follows the pattern #1234 – issue name
  • branch name doesn't contain '#'
  • PR is linked with the issue
  • base branch (master or release/xx) is correct
  • task status changed to "Code review"
  • reviewers are notified about the pull request

@AlexeyGirin AlexeyGirin linked an issue Dec 15, 2025 that may be closed by this pull request
@Nyaki1144 Nyaki1144 force-pushed the 4694-Add-Hotkeys-in-Macro-Mode-Similar-to-Micro-Mode branch from 2a243ef to 3b807e5 Compare December 15, 2025 10:21
@Nyaki1144 Nyaki1144 changed the title Select Single Bond Tool: 1 #4694 add hotkeys in Macro mode similar to Micro mode Dec 15, 2025
@AlexeyGirin AlexeyGirin requested review from Copilot and removed request for NataliaLoginova, Zhirnoff and svvald December 23, 2025 11:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds keyboard hotkeys (Delete and Backspace) for deleting monomers on hover in Macro mode, bringing it in line with similar functionality in Micro mode. The implementation introduces a new event subscription system for deleting hovered structures and modifies the entity deletion logic.

Key Changes:

  • Adds global keydown event listener to handle Delete/Backspace keys when hovering over monomers
  • Introduces deleteHoveredStructure event and corresponding handler
  • Adds hoveredEntities getter and deleteHoveredEntities() method to DrawingEntitiesManager

Reviewed changes

Copilot reviewed 5 out of 18 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
EditorEvents.tsx Adds useRef for tracking hovered monomer and useEffect with keydown listener to dispatch deletion events
DrawingEntitiesManager.ts Adds hoveredEntities getter and deleteHoveredEntities method; adds guard in deleteSelectedEntities to prevent deletion when entities are hovered
Erase.ts Adds type cast to deleteSelectedEntities return value
editorEvents.ts Adds deleteHoveredStructure event subscription to IEditorEvents interface
Editor.ts Refactors deleteSelectedStructure handler and adds deleteHoveredStructure handler
Test snapshots (PNG files) Updated test snapshots for sequence mode deletion tests

) {
const modelChanges =
this.editor.drawingEntitiesManager.deleteSelectedEntities();
this.editor.drawingEntitiesManager.deleteSelectedEntities() as Command;
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type cast 'as Command' is redundant because deleteSelectedEntities() already returns a Command type. Consider removing this cast for cleaner code.

Copilot uses AI. Check for mistakes.

window.addEventListener('keydown', onKeyDown);
return () => window.removeEventListener('keydown', onKeyDown);
}, [editor, dispatch]);
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The keydown event listener is missing the 'editor' and 'dispatch' dependencies in the useEffect dependency array. While 'editor' and 'dispatch' are relatively stable, omitting them could lead to stale closures. Consider adding them to the dependency array or documenting why they are intentionally omitted.

Copilot uses AI. Check for mistakes.
Comment on lines +412 to +424
const onKeyDown = (e: KeyboardEvent) => {
if (e.key === '1' && editor?.mode.modeName !== 'sequence-layout-mode') {
dispatch(selectTool('bond-single'));
} else {
if (e.key !== 'Delete' && e.key !== 'Backspace') return;
if (e.ctrlKey || e.metaKey || e.altKey) return;
const monomer = hoveredTargetRef.current;
if (!monomer) return;
if (editor) {
editor.events.deleteHoveredStructure.dispatch();
}
}
};
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The keydown event listener does not check if the user is typing in an input field or text area. This could cause monomers to be deleted while the user is typing "Delete" or "Backspace" in a form field elsewhere in the application. Consider checking if the event target is an input element before processing the deletion.

Copilot uses AI. Check for mistakes.
Comment on lines +759 to +767
this.events.deleteSelectedStructure.add(() => {
const command = new Command();
const history = new EditorHistory(this);
const commandData =
this.drawingEntitiesManager.deleteSelectedEntities() as Command;
command.merge(commandData);
history.update(command);
this.renderersContainer.update(command);
});
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deleteSelectedStructure event handler was completely rewritten and no longer handles SequenceMode separately. The previous implementation included logic to check for SequenceMode and call mode.deleteSelection(). This change may break deletion functionality in Sequence mode. Verify that SequenceMode deletion still works correctly or restore the mode-specific handling.

Copilot uses AI. Check for mistakes.
const command = new Command();
const history = new EditorHistory(this);
const commandData =
this.drawingEntitiesManager.deleteSelectedEntities() as Command;
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type cast 'as Command' is unnecessary because deleteSelectedEntities() already returns a Command type. This cast can be removed to improve code clarity.

Suggested change
this.drawingEntitiesManager.deleteSelectedEntities() as Command;
this.drawingEntitiesManager.deleteSelectedEntities();

Copilot uses AI. Check for mistakes.
Comment on lines +316 to +323
public deleteHoveredEntities() {
const mergedCommand = new Command();
this.hoveredEntities.forEach(([, drawingEntity]) => {
const command = this.deleteDrawingEntity(drawingEntity);
mergedCommand.merge(command);
});
return mergedCommand;
}
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new deleteHoveredEntities method lacks documentation. Consider adding a JSDoc comment explaining its purpose, behavior, and how it differs from deleteSelectedEntities, especially regarding the hover state interactions.

Copilot uses AI. Check for mistakes.
Comment on lines +213 to +217
public get hoveredEntities() {
return this.allEntities.filter(
([, drawingEntity]) => drawingEntity.hovered,
);
}
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new hoveredEntities getter lacks documentation. Consider adding a JSDoc comment explaining what constitutes a "hovered" entity and how this state is managed, to help future maintainers understand the hover state tracking.

Copilot uses AI. Check for mistakes.
Comment on lines +371 to +374
hoveredTargetRef.current =
e.target?.__data__?.monomer ||
e.target?.__data__?.node?.monomer ||
null;
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hoveredTargetRef is updated on every mouse move event. While using a ref avoids re-renders, consider whether this granular tracking is necessary or if there's a more efficient approach. The current implementation may lead to frequent ref updates during mouse movements across the canvas.

Suggested change
hoveredTargetRef.current =
e.target?.__data__?.monomer ||
e.target?.__data__?.node?.monomer ||
null;
const newHoveredTarget =
e.target?.__data__?.monomer ||
e.target?.__data__?.node?.monomer ||
null;
if (hoveredTargetRef.current !== newHoveredTarget) {
hoveredTargetRef.current = newHoveredTarget;
}

Copilot uses AI. Check for mistakes.
Comment on lines +412 to +429
const onKeyDown = (e: KeyboardEvent) => {
if (e.key === '1' && editor?.mode.modeName !== 'sequence-layout-mode') {
dispatch(selectTool('bond-single'));
} else {
if (e.key !== 'Delete' && e.key !== 'Backspace') return;
if (e.ctrlKey || e.metaKey || e.altKey) return;
const monomer = hoveredTargetRef.current;
if (!monomer) return;
if (editor) {
editor.events.deleteHoveredStructure.dispatch();
}
}
};

window.addEventListener('keydown', onKeyDown);
return () => window.removeEventListener('keydown', onKeyDown);
}, [editor, dispatch]);

Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The key '1' handling for bond-single tool selection is mixed with the Delete/Backspace handling in the same event listener. Consider separating these concerns into different useEffect hooks for better code organization and maintainability.

Suggested change
const onKeyDown = (e: KeyboardEvent) => {
if (e.key === '1' && editor?.mode.modeName !== 'sequence-layout-mode') {
dispatch(selectTool('bond-single'));
} else {
if (e.key !== 'Delete' && e.key !== 'Backspace') return;
if (e.ctrlKey || e.metaKey || e.altKey) return;
const monomer = hoveredTargetRef.current;
if (!monomer) return;
if (editor) {
editor.events.deleteHoveredStructure.dispatch();
}
}
};
window.addEventListener('keydown', onKeyDown);
return () => window.removeEventListener('keydown', onKeyDown);
}, [editor, dispatch]);
const onKeyDownForBondSingle = (e: KeyboardEvent) => {
if (e.key === '1' && editor?.mode.modeName !== 'sequence-layout-mode') {
dispatch(selectTool('bond-single'));
}
};
window.addEventListener('keydown', onKeyDownForBondSingle);
return () => window.removeEventListener('keydown', onKeyDownForBondSingle);
}, [editor, dispatch]);
useEffect(() => {
const onKeyDownForDelete = (e: KeyboardEvent) => {
if (e.key !== 'Delete' && e.key !== 'Backspace') return;
if (e.ctrlKey || e.metaKey || e.altKey) return;
const monomer = hoveredTargetRef.current;
if (!monomer) return;
if (editor) {
editor.events.deleteHoveredStructure.dispatch();
}
};
window.addEventListener('keydown', onKeyDownForDelete);
return () => window.removeEventListener('keydown', onKeyDownForDelete);
}, [editor]);

Copilot uses AI. Check for mistakes.
}

public deleteSelectedEntities() {
if (this.hoveredEntities.length !== 0) return;
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deleteSelectedEntities method now returns early when there are hovered entities. This creates a logic conflict where selected entities cannot be deleted if any entity happens to be hovered. This is inconsistent with the typical expectation that Delete/Backspace should delete selected items. Consider removing this guard or clarifying the intended behavior when both selection and hover states are present.

Suggested change
if (this.hoveredEntities.length !== 0) return;

Copilot uses AI. Check for mistakes.
@rrodionov91 rrodionov91 changed the title #4694 add hotkeys in Macro mode similar to Micro mode #4694 - Add Hotkeys in Macro mode similar to Micro mode Dec 23, 2025
@Nyaki1144 Nyaki1144 force-pushed the 4694-Add-Hotkeys-in-Macro-Mode-Similar-to-Micro-Mode branch from f7a5f88 to dca01f1 Compare December 25, 2025 20:46
@Nyaki1144 Nyaki1144 force-pushed the 4694-Add-Hotkeys-in-Macro-Mode-Similar-to-Micro-Mode branch from dca01f1 to f54fc87 Compare December 26, 2025 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Hotkeys in Macro Mode Similar to Micro Mode

4 participants