Skip to content

Commit

Permalink
Merge pull request #12 from RianM/feature/duplicate-selected
Browse files Browse the repository at this point in the history
Duplicate selected Square
  • Loading branch information
plateupplanner committed Oct 26, 2022
2 parents dad342b + 9bdb52a commit 2b607f3
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 4 deletions.
26 changes: 22 additions & 4 deletions src/components/grids/PlanGrid.tsx
Expand Up @@ -5,6 +5,7 @@ import {
IconRotateClockwise2,
IconTrash,
IconTrashX,
IconCopy,
} from '@tabler/icons';
import { useState, SyntheticEvent, MouseEvent, DragEvent } from 'react';
import shallow from 'zustand/shallow';
Expand Down Expand Up @@ -249,6 +250,14 @@ const PlanGrid = () => {
}
};

const handleDuplicateSelected = () => {
if (selectedCell === undefined) return;

const newLayout = layout.clone();
newLayout.duplicateElement(selectedCell, hoveredCell);
setLayout(newLayout);
};

useHotkeys([
['Backspace', () => handleDelete()],
['Delete', () => handleDelete()],
Expand All @@ -262,6 +271,7 @@ const PlanGrid = () => {
['ArrowLeft', () => handleSelectionMove(-1, 0)],
['ArrowDown', () => handleSelectionMove(0, 1)],
['ArrowRight', () => handleSelectionMove(1, 0)],
['CTRL+D', () => handleDuplicateSelected()],
]);

const getPlanGridElements = () => {
Expand Down Expand Up @@ -410,20 +420,28 @@ const PlanGrid = () => {
<IconRotate2 stroke='2.5' size={20} />
</ActionIcon>
<ActionIcon
onClick={() => handleDelete()}
onClick={() => handleRotateRight()}
size='xl'
radius='xl'
disabled={selectedCell === undefined}
>
<IconTrashX stroke='2.5' size={20} />
<IconRotateClockwise2 stroke='2.5' size={20} />
</ActionIcon>
<ActionIcon
onClick={() => handleRotateRight()}
onClick={() => handleDuplicateSelected()}
size='xl'
radius='xl'
disabled={selectedCell === undefined}
>
<IconRotateClockwise2 stroke='2.5' size={20} />
<IconCopy stroke='2.5' size={20} />
</ActionIcon>
<ActionIcon
onClick={() => handleDelete()}
size='xl'
radius='xl'
disabled={selectedCell === undefined}
>
<IconTrashX stroke='2.5' size={20} />
</ActionIcon>
<Button
onClick={() => handleRemoveSquares()}
Expand Down
34 changes: 34 additions & 0 deletions src/components/layout/Layout.ts
Expand Up @@ -136,6 +136,40 @@ export class Layout {
}
this.elements = [];
}

// Duplicate element in the selected cell
// It will either be placed in the hoveredCell, if it is not a wall and not already occupied
// Or it will be placed in the first empty cell
duplicateElement(
selectedCell: [number, number],
hoveredCell: [number, number] | undefined,
) {
if (
!(this.layout[selectedCell[0]][selectedCell[1]] instanceof SquareType)
) {
throw new Error('Cannot duplicate a wall element');
}

const square = this.layout[selectedCell[0]][selectedCell[1]] as SquareType;

if (hoveredCell && this.isEmptySquare(hoveredCell[0], hoveredCell[1])) {
this.setElement(hoveredCell[0], hoveredCell[1], square.clone());
} else {
for (let i = 0; i < this.height * 2 - 1; i++) {
for (let j = 0; j < this.width * 2 - 1; j++) {
if (this.isEmptySquare(i, j)) {
this.setElement(i, j, square.clone());
return;
}
}
}
}
}

isEmptySquare(i: number, j: number): boolean {
const square = this.layout[i][j] as SquareType;
return square && square === SquareType.Empty;
}
}

export function encodeLayoutString(layout: Layout) {
Expand Down
4 changes: 4 additions & 0 deletions src/components/modals/infoModal/InfoModal.tsx
Expand Up @@ -68,6 +68,10 @@ const InfoModal = ({ className }: Props) => {
<kbd>Q</kbd> <kbd>E</kbd>
</div>
<span>rotate selected item left/right</span>
<div>
<kbd>Ctrl</kbd>+<kbd>D</kbd>
</div>
<span>duplicate selected item</span>
<div>
<kbd>?</kbd>
</div>
Expand Down

0 comments on commit 2b607f3

Please sign in to comment.