Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#3648 - Macro: Displaying unmodified nucleotide chains in sequence representation #4100

Merged
merged 21 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
takeEditorScreenshot,
waitForPageInit,
waitForRender,
selectSnakeLayoutModeTool,
} from '@utils';

test.describe('Import-Saving-Files', () => {
Expand Down Expand Up @@ -327,7 +328,7 @@ test.describe('Import-Saving-Files', () => {
Description: Sequence of Peptides displaying according to snake view mockup.
*/
await openFileAndAddToCanvas('KET/snake-mode-peptides.ket', page);
await page.getByTestId('snake-mode').click();
await selectSnakeLayoutModeTool(page);
await takeEditorScreenshot(page);
});

Expand All @@ -342,7 +343,7 @@ test.describe('Import-Saving-Files', () => {
'Molfiles-V3000/snake-mode-peptides.mol',
page,
);
await page.getByTestId('snake-mode').click();
await selectSnakeLayoutModeTool(page);
await takeEditorScreenshot(page);
});

Expand All @@ -357,7 +358,7 @@ test.describe('Import-Saving-Files', () => {
'Molfiles-V3000/snake-mode-peptides.mol',
page,
);
await page.getByTestId('snake-mode').click();
await selectSnakeLayoutModeTool(page);
const expectedFile = await getMolfile(page);
await saveToFile(
'Molfiles-V3000/snake-mode-peptides-expected.mol',
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import {
clickRedo,
clickUndo,
selectSingleBondTool,
selectSnakeBondTool,
selectSnakeLayoutModeTool,
takeEditorScreenshot,
waitForPageInit,
addBondedMonomersToCanvas,
selectFlexLayoutModeTool,
waitForRender,
} from '@utils';
import { turnOnMacromoleculesEditor } from '@utils/macromolecules';
import { bondTwoMonomers } from '@utils/macromolecules/polymerBond';
Expand Down Expand Up @@ -70,7 +72,7 @@ test.describe('Snake Bond Tool', () => {
Description: Snake bond tool
*/

await selectSnakeBondTool(page);
await selectSnakeLayoutModeTool(page);
const [, peptide2] = await addBondedMonomersToCanvas(
page,
MONOMER_NAME_TZA,
Expand Down Expand Up @@ -123,7 +125,7 @@ test.describe('Snake Bond Tool', () => {
12,
);

await selectSnakeBondTool(page);
await selectSnakeLayoutModeTool(page);

await takeEditorScreenshot(page);
});
Expand All @@ -137,28 +139,33 @@ test.describe('Snake Bond Tool', () => {
*/
await createBondedMonomers(page);
await takeEditorScreenshot(page);
await selectSnakeBondTool(page);
await selectSnakeLayoutModeTool(page);
await takeEditorScreenshot(page);
});

test('Button is not active after undo', async ({ page }) => {
const snakeModeButton = page.getByTestId('snake-mode');
test('Mode returns back/forth after undo/redo', async ({ page }) => {
const flexModeButton = page.getByTestId('flex-layout-mode');
const snakeModeButton = page.getByTestId('snake-layout-mode');
await createBondedMonomers(page);
await expect(snakeModeButton).not.toHaveClass(/active/);
await expect(flexModeButton).toHaveClass(/active/);

await selectSnakeBondTool(page);
await selectSnakeLayoutModeTool(page);
await expect(snakeModeButton).toHaveClass(/active/);

await clickUndo(page);
await expect(snakeModeButton).not.toHaveClass(/active/);
await waitForRender(page);
await expect(snakeModeButton).not.toBeVisible();
await expect(flexModeButton).toHaveClass(/active/);

await clickRedo(page);
await waitForRender(page);
await expect(flexModeButton).not.toBeVisible();
await expect(snakeModeButton).toHaveClass(/active/);
});

test('Create snake bond between RNA nucleotides', async ({ page }) => {
await page.getByText('RNA').click();
await selectSnakeBondTool(page);
await selectSnakeLayoutModeTool(page);

const { phosphate } = await addRnaPresetOnCanvas(
page,
Expand Down Expand Up @@ -244,7 +251,7 @@ test.describe('Snake Bond Tool', () => {
await bondTwoMonomers(page, phosphate2, sugar3);
await bondTwoMonomers(page, phosphate3, sugar4);

await selectSnakeBondTool(page);
await selectSnakeLayoutModeTool(page);
await takeEditorScreenshot(page);
});

Expand Down Expand Up @@ -307,16 +314,16 @@ test.describe('Snake Bond Tool', () => {

await takeEditorScreenshot(page);

await selectSnakeBondTool(page);
await selectSnakeLayoutModeTool(page);
await takeEditorScreenshot(page);

await selectSnakeBondTool(page);
await selectFlexLayoutModeTool(page);
await takeEditorScreenshot(page);
});

test('Create snake bond for chain with nucleoside', async ({ page }) => {
await page.getByText('RNA').click();
await selectSnakeBondTool(page);
await selectSnakeLayoutModeTool(page);

const { phosphate } = await addRnaPresetOnCanvas(
page,
Expand Down Expand Up @@ -361,10 +368,10 @@ test.describe('Snake Bond Tool', () => {

await takeEditorScreenshot(page);

await selectSnakeBondTool(page);
await selectFlexLayoutModeTool(page);
await takeEditorScreenshot(page);

await selectSnakeBondTool(page);
await selectSnakeLayoutModeTool(page);
await takeEditorScreenshot(page);
});

Expand Down Expand Up @@ -468,7 +475,7 @@ test.describe('Snake Bond Tool', () => {
await bondTwoMonomers(page, hcyPeptide1, balPeptide1, undefined, 'R1');
await takeEditorScreenshot(page);

await selectSnakeBondTool(page);
await selectSnakeLayoutModeTool(page);
await takeEditorScreenshot(page);
});

Expand Down Expand Up @@ -508,7 +515,7 @@ test.describe('Snake Bond Tool', () => {

await takeEditorScreenshot(page);

await selectSnakeBondTool(page);
await selectSnakeLayoutModeTool(page);
await takeEditorScreenshot(page);
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
selectSingleBondTool,
takeEditorScreenshot,
waitForPageInit,
selectSnakeLayoutModeTool,
} from '@utils';
import { turnOnMacromoleculesEditor } from '@utils/macromolecules';
import { bondTwoMonomers } from '@utils/macromolecules/polymerBond';
Expand Down Expand Up @@ -397,7 +398,7 @@ test.describe('Rectangle Selection Tool', () => {
const x = 900;
const y = 500;
await openFileAndAddToCanvas('KET/snake-mode-peptides.ket', page);
await page.getByTestId('snake-mode').click();
await selectSnakeLayoutModeTool(page);
await page.keyboard.press('Control+a');
await page.getByText('Hhs').locator('..').first().hover();
await dragMouseTo(x, y, page);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
openFileAndAddToCanvas,
selectRectangleArea,
selectSingleBondTool,
selectSnakeBondTool,
selectSnakeLayoutModeTool,
takeEditorScreenshot,
waitForPageInit,
} from '@utils';
Expand Down Expand Up @@ -94,7 +94,7 @@ test.describe('Undo Redo', () => {
Description: Add monomers and bonds, activate snake mode and do undo redo
*/

await selectSnakeBondTool(page);
await selectSnakeLayoutModeTool(page);
await clickUndo(page);
await takeEditorScreenshot(page);
});
Expand Down
22 changes: 19 additions & 3 deletions ketcher-autotests/tests/utils/canvas/tools/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,25 @@ export async function selectSingleBondTool(page: Page) {
await bondToolButton.click();
}

export async function selectSnakeBondTool(page: Page) {
const bondToolButton = page.getByTestId('snake-mode');
await bondToolButton.click();
export async function openLayoutModeMenu(page: Page) {
const modeSelectorButton = await page.getByTestId('layout-mode');
await modeSelectorButton.click();
}

export async function selectSnakeLayoutModeTool(page: Page) {
await openLayoutModeMenu(page);
const snakeModeButton = page.getByTestId('snake-layout-mode');

await snakeModeButton.waitFor({ state: 'visible' });
await snakeModeButton.click();
}

export async function selectFlexLayoutModeTool(page: Page) {
await openLayoutModeMenu(page);
const flexModeButton = page.getByTestId('flex-layout-mode');

await flexModeButton.waitFor({ state: 'visible' });
await flexModeButton.click();
}

export async function selectEraseTool(page: Page) {
Expand Down
36 changes: 22 additions & 14 deletions packages/ketcher-core/src/application/editor/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ import { Editor } from 'application/editor/editor.types';
import { MacromoleculesConverter } from 'application/editor/MacromoleculesConverter';
import { BaseMonomer } from 'domain/entities/BaseMonomer';
import { ketcherProvider } from 'application/utils';
import { SnakeMode } from './modes/internal';
import { initHotKeys, keyNorm } from '../../utilities/keynorm';

import { initHotKeys, keyNorm } from 'utilities';
import { FlexMode, LayoutMode, modesMap } from 'application/editor/modes/';
import { BaseMode } from 'application/editor/modes/internal';
import assert from 'assert';
interface ICoreEditorConstructorParams {
theme;
canvas: SVGSVGElement;
Expand All @@ -52,6 +53,7 @@ export class CoreEditor {
public zoomTool: ZoomTool;
// private lastEvent: Event | undefined;
private tool?: Tool | BaseTool;
public mode: BaseMode = new FlexMode();
private micromoleculesEditor: Editor;
private hotKeyEventHandler: (event: unknown) => void = () => {};

Expand Down Expand Up @@ -147,19 +149,25 @@ export class CoreEditor {
}
}

// todo we need to create abstraction layer for modes in future similar to the tools layer
private onSelectMode(isSnakeMode: boolean) {
const command = SnakeMode.setSnakeMode(editor, isSnakeMode);
const modelChanges = this.drawingEntitiesManager.reArrangeChains(
this.canvas.width.baseVal.value,
isSnakeMode,
private onSelectMode(
data:
| LayoutMode
| { mode: LayoutMode; mergeWithLatestHistoryCommand: boolean },
) {
const mode = typeof data === 'object' ? data.mode : data;
const ModeConstructor = modesMap[mode];
assert(ModeConstructor);
const history = new EditorHistory(this);
this.mode = new ModeConstructor(this.mode.modeName);
const command = this.mode.initialize();
history.update(
command,
typeof data === 'object' ? data?.mergeWithLatestHistoryCommand : false,
);
}

command.merge(modelChanges);

const history = new EditorHistory(this);
history.update(command);
this.renderersContainer.update(command);
public setMode(mode: BaseMode) {
this.mode = mode;
}

public onSelectHistory(name: HistoryOperationType) {
Expand Down
15 changes: 10 additions & 5 deletions packages/ketcher-core/src/application/editor/EditorHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,17 @@ export class EditorHistory {
return this;
}

update(command: Command) {
this.historyStack.splice(this.historyPointer, HISTORY_SIZE + 1, command);
if (this.historyStack.length > HISTORY_SIZE) {
this.historyStack.shift();
update(command: Command, megreWithLatestHistoryCommand?: boolean) {
const latestCommand = this.historyStack[this.historyStack.length - 1];
if (megreWithLatestHistoryCommand && latestCommand) {
latestCommand.merge(command);
} else {
this.historyStack.splice(this.historyPointer, HISTORY_SIZE + 1, command);
if (this.historyStack.length > HISTORY_SIZE) {
this.historyStack.shift();
}
this.historyPointer = this.historyStack.length;
}
this.historyPointer = this.historyStack.length;
}

undo() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function resetEditorEvents() {
createBondViaModal: new Subscription(),
cancelBondCreationViaModal: new Subscription(),
selectMode: new Subscription(),
snakeModeChange: new Subscription(),
layoutModeChange: new Subscription(),
selectHistory: new Subscription(),
error: new Subscription(),
openMonomerConnectionModal: new Subscription(),
Expand Down
4 changes: 4 additions & 0 deletions packages/ketcher-core/src/application/editor/internal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './Editor';
export * from './EditorHistory';
export * from './shared/coordinates';
export * from './editor.types';
34 changes: 34 additions & 0 deletions packages/ketcher-core/src/application/editor/modes/BaseMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Command } from 'domain/entities/Command';
import { SelectLayoutModeOperation } from '../operations/polymerBond';
import { CoreEditor } from '../internal';
import { LayoutMode, modesMap } from 'application/editor/modes';

export abstract class BaseMode {
protected constructor(
public modeName: LayoutMode,
public previousMode: LayoutMode = 'flex-layout-mode',
) {}

private changeMode(editor: CoreEditor, modeName: LayoutMode) {
editor.events.layoutModeChange.dispatch(modeName);
const ModeConstructor = modesMap[modeName];
editor.setMode(new ModeConstructor());
editor.mode.initialize();
}

public initialize() {
const command = new Command();
const editor = CoreEditor.provideEditorInstance();

command.addOperation(
new SelectLayoutModeOperation(
this.changeMode.bind(this, editor, this.modeName),
this.changeMode.bind(this, editor, this.previousMode),
this.modeName,
this.previousMode,
),
);

return command;
}
}
19 changes: 19 additions & 0 deletions packages/ketcher-core/src/application/editor/modes/FlexMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { CoreEditor } from 'application/editor/internal';
import { LayoutMode } from 'application/editor/modes/types';
import { BaseMode } from 'application/editor/modes/internal';
export class FlexMode extends BaseMode {
constructor(previousMode?: LayoutMode) {
super('flex-layout-mode', previousMode);
}

initialize() {
const command = super.initialize();
const editor = CoreEditor.provideEditorInstance();

editor.drawingEntitiesManager.applyFlexLayoutMode();

editor.renderersContainer.update();

return command;
}
}
Loading
Loading