Skip to content

Commit

Permalink
Paste elements at current cursor position
Browse files Browse the repository at this point in the history
  • Loading branch information
hlxid committed Oct 21, 2023
1 parent 5026248 commit 482f7fa
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 7 deletions.
16 changes: 13 additions & 3 deletions src/features/copyPaste/keyListener.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { injectable } from "inversify";
import { inject, injectable } from "inversify";
import { PasteElementsAction } from "./pasteCommand";
import { CommitModelAction, KeyListener, SModelElementImpl, SModelRootImpl, isSelected } from "sprotty";
import {
CommitModelAction,
KeyListener,
MousePositionTracker,
SModelElementImpl,
SModelRootImpl,
isSelected,
} from "sprotty";
import { Action } from "sprotty-protocol";
import { matchesKeystroke } from "sprotty/lib/utils/keyboard";

Expand All @@ -14,6 +21,8 @@ import { matchesKeystroke } from "sprotty/lib/utils/keyboard";
export class CopyPasteKeyListener implements KeyListener {
private copyElements: SModelElementImpl[] = [];

constructor(@inject(MousePositionTracker) private readonly mousePositionTracker: MousePositionTracker) {}

keyUp(_element: SModelElementImpl, _event: KeyboardEvent): Action[] {
return [];
}
Expand Down Expand Up @@ -48,6 +57,7 @@ export class CopyPasteKeyListener implements KeyListener {
* This is done inside a command, so that it can be undone/redone.
*/
private paste(): Action[] {
return [PasteElementsAction.create(this.copyElements), CommitModelAction.create()];
const targetPosition = this.mousePositionTracker.lastPositionOnDiagram ?? { x: 0, y: 0 };
return [PasteElementsAction.create(this.copyElements, targetPosition), CommitModelAction.create()];
}
}
41 changes: 37 additions & 4 deletions src/features/copyPaste/pasteCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,21 @@ import {
import { DynamicChildrenProcessor } from "../dfdElements/dynamicChildren";
import { generateRandomSprottyId } from "../../utils";
import { DfdNode, DfdNodeImpl } from "../dfdElements/nodes";
import { Action, SPort } from "sprotty-protocol";
import { Action, Point, SPort } from "sprotty-protocol";
import { ArrowEdge, ArrowEdgeImpl } from "../dfdElements/edges";

export interface PasteElementsAction extends Action {
kind: typeof PasteElementsAction.KIND;
copyElements: SModelElementImpl[];
targetPosition: Point;
}
export namespace PasteElementsAction {
export const KIND = "paste-clipboard-elements";
export function create(copyElements: SModelElementImpl[]): PasteElementsAction {
export function create(copyElements: SModelElementImpl[], targetPosition: Point): PasteElementsAction {
return {
kind: KIND,
copyElements,
targetPosition,
};
}
}
Expand All @@ -51,7 +53,7 @@ export class PasteElementsCommand extends Command {
}

/**
* Selectes the newly created copy and deselects the copy source.
* Selects the newly created copy and deselects the copy source.
*/
private setSelection(context: CommandExecutionContext, selection: "old" | "new"): void {
Object.entries(this.copyElementIdMapping).forEach(([oldId, newId]) => {
Expand All @@ -67,8 +69,39 @@ export class PasteElementsCommand extends Command {
});
}

/**
* Calculates the offset between the copy source elements and the set paste target position.
* Does this by finding the top left position of the copy source elements and subtracting it from the target position.
*
* @returns The offset between the top left position of the copy source elements and the target position.
*/
private computeElementOffset(): Point {
const sourcePosition = { x: Infinity, y: Infinity };

this.action.copyElements.forEach((element) => {
if (!(element instanceof SNodeImpl)) {
return;
}

if (element.position.x < sourcePosition.x) {
sourcePosition.x = element.position.x;
}
if (element.position.y < sourcePosition.y) {
sourcePosition.y = element.position.y;
}
});

if (sourcePosition.x === Infinity || sourcePosition.y === Infinity) {
return { x: 0, y: 0 };
}

// Compute delta between top left position of copy source elements and the target position
return Point.subtract(this.action.targetPosition, sourcePosition);
}

execute(context: CommandExecutionContext): CommandReturn {
// Step 1: copy nodes and their ports
const positionOffset = this.computeElementOffset();
this.action.copyElements.forEach((element) => {
if (!(element instanceof SNodeImpl)) {
return;
Expand All @@ -77,7 +110,7 @@ export class PasteElementsCommand extends Command {
const schema = {
id: generateRandomSprottyId(),
type: element.type,
position: { x: element.position.x + 30, y: element.position.y + 30 },
position: Point.add(element.position, positionOffset),
size: { height: -1, width: -1 },
text: "",
labels: [],
Expand Down

0 comments on commit 482f7fa

Please sign in to comment.