Add alt drag duplicate shortcut for tokens, notes and selection

This commit is contained in:
Mitchell McCaffrey 2021-08-06 12:04:22 +10:00
parent 27bcc127bc
commit d6d8ee2f11
6 changed files with 111 additions and 0 deletions

View File

@ -40,6 +40,7 @@ import {
SelectionItemsChangeEventHandler,
SelectionItemsRemoveEventHandler,
SelectionItemsCreateEventHandler,
TokensStateCreateHandler,
} from "../../types/Events";
import useMapTokens from "../../hooks/useMapTokens";
@ -53,6 +54,7 @@ type MapProps = {
mapActions: MapActions;
onMapTokenStateChange: TokenStateChangeEventHandler;
onMapTokenStateRemove: TokenStateRemoveHandler;
onMapTokensStateCreate: TokensStateCreateHandler;
onSelectionItemsChange: SelectionItemsChangeEventHandler;
onSelectionItemsRemove: SelectionItemsRemoveEventHandler;
onSelectionItemsCreate: SelectionItemsCreateEventHandler;
@ -75,6 +77,7 @@ function Map({
mapActions,
onMapTokenStateChange,
onMapTokenStateRemove,
onMapTokensStateCreate,
onSelectionItemsChange,
onSelectionItemsRemove,
onSelectionItemsCreate,
@ -142,6 +145,7 @@ function Map({
mapState,
onMapTokenStateChange,
onMapTokenStateRemove,
onMapTokensStateCreate,
selectedToolId
);

View File

@ -1,11 +1,15 @@
import Konva from "konva";
import { KonvaEventObject } from "konva/lib/Node";
import { useState } from "react";
import { v4 as uuid } from "uuid";
import Note from "../components/konva/Note";
import NoteDragOverlay from "../components/note/NoteDragOverlay";
import NoteMenu from "../components/note/NoteMenu";
import NoteTool from "../components/tools/NoteTool";
import { useBlur, useKeyboard } from "../contexts/KeyboardContext";
import { useUserId } from "../contexts/UserIdContext";
import shortcuts from "../shortcuts";
import {
NoteChangeEventHandler,
NoteCreateEventHander,
@ -47,6 +51,12 @@ function useMapNotes(
}
function handleNoteDragStart(_: KonvaEventObject<DragEvent>, noteId: string) {
if (duplicateNote) {
const note = mapState?.notes[noteId];
if (note) {
onNoteCreate([{ ...note, id: uuid() }]);
}
}
setNoteDraggingOptions({ dragging: true, noteId });
}
@ -60,6 +70,26 @@ function useMapNotes(
setNoteDraggingOptions(undefined);
}
const [duplicateNote, setDuplicateNote] = useState(false);
function handleKeyDown(event: KeyboardEvent) {
if (shortcuts.duplicate(event)) {
setDuplicateNote(true);
}
}
function handleKeyUp(event: KeyboardEvent) {
if (shortcuts.duplicate(event)) {
setDuplicateNote(false);
}
}
function handleBlur() {
setDuplicateNote(false);
}
useKeyboard(handleKeyDown, handleKeyUp);
useBlur(handleBlur);
const notes = (
<NoteTool
map={map}

View File

@ -1,8 +1,12 @@
import { useEffect, useState } from "react";
import { v4 as uuid } from "uuid";
import SelectionDragOverlay from "../components/selection/SelectionDragOverlay";
import SelectionMenu from "../components/selection/SelectionMenu";
import SelectTool from "../components/tools/SelectTool";
import { useBlur, useKeyboard } from "../contexts/KeyboardContext";
import { useUserId } from "../contexts/UserIdContext";
import shortcuts from "../shortcuts";
import {
SelectionItemsChangeEventHandler,
SelectionItemsCreateEventHandler,
@ -10,8 +14,10 @@ import {
} from "../types/Events";
import { Map, MapToolId } from "../types/Map";
import { MapState } from "../types/MapState";
import { Note } from "../types/Note";
import { Selection } from "../types/Select";
import { SelectToolSettings } from "../types/Select";
import { TokenState } from "../types/TokenState";
function useMapSelection(
map: Map | null,
@ -66,6 +72,24 @@ function useMapSelection(
}, [map]);
function handleSelectionDragStart() {
if (duplicateSelection && selection) {
const tokenStates: TokenState[] = [];
const notes: Note[] = [];
for (let item of selection.items) {
if (item.type === "token") {
const token = mapState?.tokens[item.id];
if (token && !token.locked) {
tokenStates.push({ ...token, id: uuid() });
}
} else {
const note = mapState?.notes[item.id];
if (note && !note.locked) {
notes.push({ ...note, id: uuid() });
}
}
}
onSelectionItemsCreate(tokenStates, notes);
}
setIsSelectionDragging(true);
}
@ -81,6 +105,26 @@ function useMapSelection(
onSelectionItemsRemove(tokenStateIds, noteIds);
}
const [duplicateSelection, setDuplicateSelection] = useState(false);
function handleKeyDown(event: KeyboardEvent) {
if (shortcuts.duplicate(event)) {
setDuplicateSelection(true);
}
}
function handleKeyUp(event: KeyboardEvent) {
if (shortcuts.duplicate(event)) {
setDuplicateSelection(false);
}
}
function handleBlur() {
setDuplicateSelection(false);
}
useKeyboard(handleKeyDown, handleKeyUp);
useBlur(handleBlur);
const selectionTool = map ? (
<SelectTool
active={active}

View File

@ -1,4 +1,5 @@
import { Group } from "react-konva";
import { v4 as uuid } from "uuid";
import { Map, MapToolId } from "../types/Map";
import { MapState } from "../types/MapState";
@ -11,6 +12,7 @@ import { TokenState } from "../types/TokenState";
import {
TokenStateRemoveHandler,
TokenStateChangeEventHandler,
TokensStateCreateHandler,
} from "../types/Events";
import { useState } from "react";
import Konva from "konva";
@ -19,12 +21,15 @@ import { KonvaEventObject } from "konva/lib/Node";
import TokenMenu from "../components/token/TokenMenu";
import TokenDragOverlay from "../components/token/TokenDragOverlay";
import { useUserId } from "../contexts/UserIdContext";
import { useBlur, useKeyboard } from "../contexts/KeyboardContext";
import shortcuts from "../shortcuts";
function useMapTokens(
map: Map | null,
mapState: MapState | null,
onTokenStateChange: TokenStateChangeEventHandler,
onTokenStateRemove: TokenStateRemoveHandler,
onTokensStateCreate: TokensStateCreateHandler,
selectedToolId: MapToolId
) {
const userId = useUserId();
@ -57,6 +62,12 @@ function useMapTokens(
_: KonvaEventObject<DragEvent>,
tokenStateId: string
) {
if (duplicateToken) {
const state = mapState?.tokens[tokenStateId];
if (state) {
onTokensStateCreate([{ ...state, id: uuid() }]);
}
}
setTokenDraggingOptions({
dragging: true,
tokenStateId,
@ -76,6 +87,26 @@ function useMapTokens(
setTokenDraggingOptions(undefined);
}
const [duplicateToken, setDuplicateToken] = useState(false);
function handleKeyDown(event: KeyboardEvent) {
if (shortcuts.duplicate(event)) {
setDuplicateToken(true);
}
}
function handleKeyUp(event: KeyboardEvent) {
if (shortcuts.duplicate(event)) {
setDuplicateToken(false);
}
}
function handleBlur() {
setDuplicateToken(false);
}
useKeyboard(handleKeyDown, handleKeyUp);
useBlur(handleBlur);
function tokenFromTokenState(tokenState: TokenState) {
return (
map && (

View File

@ -417,6 +417,7 @@ function NetworkedMapAndTokens({ session }: { session: Session }) {
mapActions={mapActions}
onMapTokenStateChange={handleMapTokenStateChange}
onMapTokenStateRemove={handleMapTokenStateRemove}
onMapTokensStateCreate={handleMapTokensStateCreate}
onSelectionItemsChange={handleSelectionItemsChange}
onSelectionItemsRemove={handleSelectionItemsRemove}
onSelectionItemsCreate={handleSelectionItemsCreate}

View File

@ -104,6 +104,7 @@ const shortcuts: Record<string, Shortcut> = {
paste,
delete: ({ key }) => key === "Backspace" || key === "Delete",
disableSnapping: ({ key }) => key === "Control" || key === "Meta",
duplicate: ({ key }) => key === "Alt",
};
export default shortcuts;