Add alt drag duplicate shortcut for tokens, notes and selection
This commit is contained in:
parent
27bcc127bc
commit
d6d8ee2f11
@ -40,6 +40,7 @@ import {
|
|||||||
SelectionItemsChangeEventHandler,
|
SelectionItemsChangeEventHandler,
|
||||||
SelectionItemsRemoveEventHandler,
|
SelectionItemsRemoveEventHandler,
|
||||||
SelectionItemsCreateEventHandler,
|
SelectionItemsCreateEventHandler,
|
||||||
|
TokensStateCreateHandler,
|
||||||
} from "../../types/Events";
|
} from "../../types/Events";
|
||||||
|
|
||||||
import useMapTokens from "../../hooks/useMapTokens";
|
import useMapTokens from "../../hooks/useMapTokens";
|
||||||
@ -53,6 +54,7 @@ type MapProps = {
|
|||||||
mapActions: MapActions;
|
mapActions: MapActions;
|
||||||
onMapTokenStateChange: TokenStateChangeEventHandler;
|
onMapTokenStateChange: TokenStateChangeEventHandler;
|
||||||
onMapTokenStateRemove: TokenStateRemoveHandler;
|
onMapTokenStateRemove: TokenStateRemoveHandler;
|
||||||
|
onMapTokensStateCreate: TokensStateCreateHandler;
|
||||||
onSelectionItemsChange: SelectionItemsChangeEventHandler;
|
onSelectionItemsChange: SelectionItemsChangeEventHandler;
|
||||||
onSelectionItemsRemove: SelectionItemsRemoveEventHandler;
|
onSelectionItemsRemove: SelectionItemsRemoveEventHandler;
|
||||||
onSelectionItemsCreate: SelectionItemsCreateEventHandler;
|
onSelectionItemsCreate: SelectionItemsCreateEventHandler;
|
||||||
@ -75,6 +77,7 @@ function Map({
|
|||||||
mapActions,
|
mapActions,
|
||||||
onMapTokenStateChange,
|
onMapTokenStateChange,
|
||||||
onMapTokenStateRemove,
|
onMapTokenStateRemove,
|
||||||
|
onMapTokensStateCreate,
|
||||||
onSelectionItemsChange,
|
onSelectionItemsChange,
|
||||||
onSelectionItemsRemove,
|
onSelectionItemsRemove,
|
||||||
onSelectionItemsCreate,
|
onSelectionItemsCreate,
|
||||||
@ -142,6 +145,7 @@ function Map({
|
|||||||
mapState,
|
mapState,
|
||||||
onMapTokenStateChange,
|
onMapTokenStateChange,
|
||||||
onMapTokenStateRemove,
|
onMapTokenStateRemove,
|
||||||
|
onMapTokensStateCreate,
|
||||||
selectedToolId
|
selectedToolId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import Konva from "konva";
|
import Konva from "konva";
|
||||||
import { KonvaEventObject } from "konva/lib/Node";
|
import { KonvaEventObject } from "konva/lib/Node";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { v4 as uuid } from "uuid";
|
||||||
|
|
||||||
import Note from "../components/konva/Note";
|
import Note from "../components/konva/Note";
|
||||||
import NoteDragOverlay from "../components/note/NoteDragOverlay";
|
import NoteDragOverlay from "../components/note/NoteDragOverlay";
|
||||||
import NoteMenu from "../components/note/NoteMenu";
|
import NoteMenu from "../components/note/NoteMenu";
|
||||||
import NoteTool from "../components/tools/NoteTool";
|
import NoteTool from "../components/tools/NoteTool";
|
||||||
|
import { useBlur, useKeyboard } from "../contexts/KeyboardContext";
|
||||||
import { useUserId } from "../contexts/UserIdContext";
|
import { useUserId } from "../contexts/UserIdContext";
|
||||||
|
import shortcuts from "../shortcuts";
|
||||||
import {
|
import {
|
||||||
NoteChangeEventHandler,
|
NoteChangeEventHandler,
|
||||||
NoteCreateEventHander,
|
NoteCreateEventHander,
|
||||||
@ -47,6 +51,12 @@ function useMapNotes(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleNoteDragStart(_: KonvaEventObject<DragEvent>, noteId: string) {
|
function handleNoteDragStart(_: KonvaEventObject<DragEvent>, noteId: string) {
|
||||||
|
if (duplicateNote) {
|
||||||
|
const note = mapState?.notes[noteId];
|
||||||
|
if (note) {
|
||||||
|
onNoteCreate([{ ...note, id: uuid() }]);
|
||||||
|
}
|
||||||
|
}
|
||||||
setNoteDraggingOptions({ dragging: true, noteId });
|
setNoteDraggingOptions({ dragging: true, noteId });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +70,26 @@ function useMapNotes(
|
|||||||
setNoteDraggingOptions(undefined);
|
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 = (
|
const notes = (
|
||||||
<NoteTool
|
<NoteTool
|
||||||
map={map}
|
map={map}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { v4 as uuid } from "uuid";
|
||||||
|
|
||||||
import SelectionDragOverlay from "../components/selection/SelectionDragOverlay";
|
import SelectionDragOverlay from "../components/selection/SelectionDragOverlay";
|
||||||
import SelectionMenu from "../components/selection/SelectionMenu";
|
import SelectionMenu from "../components/selection/SelectionMenu";
|
||||||
import SelectTool from "../components/tools/SelectTool";
|
import SelectTool from "../components/tools/SelectTool";
|
||||||
|
import { useBlur, useKeyboard } from "../contexts/KeyboardContext";
|
||||||
import { useUserId } from "../contexts/UserIdContext";
|
import { useUserId } from "../contexts/UserIdContext";
|
||||||
|
import shortcuts from "../shortcuts";
|
||||||
import {
|
import {
|
||||||
SelectionItemsChangeEventHandler,
|
SelectionItemsChangeEventHandler,
|
||||||
SelectionItemsCreateEventHandler,
|
SelectionItemsCreateEventHandler,
|
||||||
@ -10,8 +14,10 @@ import {
|
|||||||
} from "../types/Events";
|
} from "../types/Events";
|
||||||
import { Map, MapToolId } from "../types/Map";
|
import { Map, MapToolId } from "../types/Map";
|
||||||
import { MapState } from "../types/MapState";
|
import { MapState } from "../types/MapState";
|
||||||
|
import { Note } from "../types/Note";
|
||||||
import { Selection } from "../types/Select";
|
import { Selection } from "../types/Select";
|
||||||
import { SelectToolSettings } from "../types/Select";
|
import { SelectToolSettings } from "../types/Select";
|
||||||
|
import { TokenState } from "../types/TokenState";
|
||||||
|
|
||||||
function useMapSelection(
|
function useMapSelection(
|
||||||
map: Map | null,
|
map: Map | null,
|
||||||
@ -66,6 +72,24 @@ function useMapSelection(
|
|||||||
}, [map]);
|
}, [map]);
|
||||||
|
|
||||||
function handleSelectionDragStart() {
|
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);
|
setIsSelectionDragging(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +105,26 @@ function useMapSelection(
|
|||||||
onSelectionItemsRemove(tokenStateIds, noteIds);
|
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 ? (
|
const selectionTool = map ? (
|
||||||
<SelectTool
|
<SelectTool
|
||||||
active={active}
|
active={active}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Group } from "react-konva";
|
import { Group } from "react-konva";
|
||||||
|
import { v4 as uuid } from "uuid";
|
||||||
|
|
||||||
import { Map, MapToolId } from "../types/Map";
|
import { Map, MapToolId } from "../types/Map";
|
||||||
import { MapState } from "../types/MapState";
|
import { MapState } from "../types/MapState";
|
||||||
@ -11,6 +12,7 @@ import { TokenState } from "../types/TokenState";
|
|||||||
import {
|
import {
|
||||||
TokenStateRemoveHandler,
|
TokenStateRemoveHandler,
|
||||||
TokenStateChangeEventHandler,
|
TokenStateChangeEventHandler,
|
||||||
|
TokensStateCreateHandler,
|
||||||
} from "../types/Events";
|
} from "../types/Events";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import Konva from "konva";
|
import Konva from "konva";
|
||||||
@ -19,12 +21,15 @@ import { KonvaEventObject } from "konva/lib/Node";
|
|||||||
import TokenMenu from "../components/token/TokenMenu";
|
import TokenMenu from "../components/token/TokenMenu";
|
||||||
import TokenDragOverlay from "../components/token/TokenDragOverlay";
|
import TokenDragOverlay from "../components/token/TokenDragOverlay";
|
||||||
import { useUserId } from "../contexts/UserIdContext";
|
import { useUserId } from "../contexts/UserIdContext";
|
||||||
|
import { useBlur, useKeyboard } from "../contexts/KeyboardContext";
|
||||||
|
import shortcuts from "../shortcuts";
|
||||||
|
|
||||||
function useMapTokens(
|
function useMapTokens(
|
||||||
map: Map | null,
|
map: Map | null,
|
||||||
mapState: MapState | null,
|
mapState: MapState | null,
|
||||||
onTokenStateChange: TokenStateChangeEventHandler,
|
onTokenStateChange: TokenStateChangeEventHandler,
|
||||||
onTokenStateRemove: TokenStateRemoveHandler,
|
onTokenStateRemove: TokenStateRemoveHandler,
|
||||||
|
onTokensStateCreate: TokensStateCreateHandler,
|
||||||
selectedToolId: MapToolId
|
selectedToolId: MapToolId
|
||||||
) {
|
) {
|
||||||
const userId = useUserId();
|
const userId = useUserId();
|
||||||
@ -57,6 +62,12 @@ function useMapTokens(
|
|||||||
_: KonvaEventObject<DragEvent>,
|
_: KonvaEventObject<DragEvent>,
|
||||||
tokenStateId: string
|
tokenStateId: string
|
||||||
) {
|
) {
|
||||||
|
if (duplicateToken) {
|
||||||
|
const state = mapState?.tokens[tokenStateId];
|
||||||
|
if (state) {
|
||||||
|
onTokensStateCreate([{ ...state, id: uuid() }]);
|
||||||
|
}
|
||||||
|
}
|
||||||
setTokenDraggingOptions({
|
setTokenDraggingOptions({
|
||||||
dragging: true,
|
dragging: true,
|
||||||
tokenStateId,
|
tokenStateId,
|
||||||
@ -76,6 +87,26 @@ function useMapTokens(
|
|||||||
setTokenDraggingOptions(undefined);
|
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) {
|
function tokenFromTokenState(tokenState: TokenState) {
|
||||||
return (
|
return (
|
||||||
map && (
|
map && (
|
||||||
|
@ -417,6 +417,7 @@ function NetworkedMapAndTokens({ session }: { session: Session }) {
|
|||||||
mapActions={mapActions}
|
mapActions={mapActions}
|
||||||
onMapTokenStateChange={handleMapTokenStateChange}
|
onMapTokenStateChange={handleMapTokenStateChange}
|
||||||
onMapTokenStateRemove={handleMapTokenStateRemove}
|
onMapTokenStateRemove={handleMapTokenStateRemove}
|
||||||
|
onMapTokensStateCreate={handleMapTokensStateCreate}
|
||||||
onSelectionItemsChange={handleSelectionItemsChange}
|
onSelectionItemsChange={handleSelectionItemsChange}
|
||||||
onSelectionItemsRemove={handleSelectionItemsRemove}
|
onSelectionItemsRemove={handleSelectionItemsRemove}
|
||||||
onSelectionItemsCreate={handleSelectionItemsCreate}
|
onSelectionItemsCreate={handleSelectionItemsCreate}
|
||||||
|
@ -104,6 +104,7 @@ const shortcuts: Record<string, Shortcut> = {
|
|||||||
paste,
|
paste,
|
||||||
delete: ({ key }) => key === "Backspace" || key === "Delete",
|
delete: ({ key }) => key === "Backspace" || key === "Delete",
|
||||||
disableSnapping: ({ key }) => key === "Control" || key === "Meta",
|
disableSnapping: ({ key }) => key === "Control" || key === "Meta",
|
||||||
|
duplicate: ({ key }) => key === "Alt",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default shortcuts;
|
export default shortcuts;
|
||||||
|
Loading…
Reference in New Issue
Block a user