Add shortcut for disabling grid snapping

This commit is contained in:
Mitchell McCaffrey 2021-08-04 08:32:27 +10:00
parent 9e5eb9d258
commit 6eb1f71bc2
6 changed files with 100 additions and 17 deletions

View File

@ -3,7 +3,10 @@ import { Transform } from "konva/lib/Util";
import { useEffect, useMemo, useRef } from "react"; import { useEffect, useMemo, useRef } from "react";
import { Transformer as KonvaTransformer } from "react-konva"; import { Transformer as KonvaTransformer } from "react-konva";
import { useGridCellPixelSize } from "../../contexts/GridContext"; import {
useGridCellPixelSize,
useGridSnappingSensitivity,
} from "../../contexts/GridContext";
import { useSetPreventMapInteraction } from "../../contexts/MapInteractionContext"; import { useSetPreventMapInteraction } from "../../contexts/MapInteractionContext";
import { roundTo } from "../../helpers/shared"; import { roundTo } from "../../helpers/shared";
import Vector2 from "../../helpers/Vector2"; import Vector2 from "../../helpers/Vector2";
@ -56,6 +59,10 @@ function Transformer({
}, [active, nodeRef, gridCellPixelSize]); }, [active, nodeRef, gridCellPixelSize]);
const scale = parseGridScale(gridScale); const scale = parseGridScale(gridScale);
const snappingSensitivity = useGridSnappingSensitivity();
// Clamp snapping to 0 to accound for -1 snapping override
const gridSnappingSensitivity = Math.max(snappingSensitivity, 0);
const anchorScale = useMemo(() => getAnchorImage(192, scaleDark), []); const anchorScale = useMemo(() => getAnchorImage(192, scaleDark), []);
const anchorRotate = useMemo(() => getAnchorImage(192, rotateDark), []); const anchorRotate = useMemo(() => getAnchorImage(192, rotateDark), []);
@ -192,8 +199,10 @@ function Transformer({
); );
const distanceToSnap = Math.abs(snapBox.width - nearestCellWidth); const distanceToSnap = Math.abs(snapBox.width - nearestCellWidth);
let snapping = false; let snapping = false;
if (distanceToSnap < gridCellAbsoluteSize.x * 0.1) { if (
// TODO: use global grid snapping value distanceToSnap <
gridCellAbsoluteSize.x * gridSnappingSensitivity
) {
snapBox.width = nearestCellWidth; snapBox.width = nearestCellWidth;
snapping = true; snapping = true;
} }

View File

@ -20,6 +20,7 @@ import {
useGridStrokeWidth, useGridStrokeWidth,
useGridCellPixelOffset, useGridCellPixelOffset,
useGridOffset, useGridOffset,
useGridSnappingSensitivity,
} from "../../contexts/GridContext"; } from "../../contexts/GridContext";
import { useKeyboard } from "../../contexts/KeyboardContext"; import { useKeyboard } from "../../contexts/KeyboardContext";
@ -93,9 +94,10 @@ function FogTool({
const gridCellPixelOffset = useGridCellPixelOffset(); const gridCellPixelOffset = useGridCellPixelOffset();
const gridOffset = useGridOffset(); const gridOffset = useGridOffset();
const [gridSnappingSensitivity] = useSetting<number>( const snappingSensitivity = useGridSnappingSensitivity();
"map.gridSnappingSensitivity" // Clamp snapping to 0 to accound for -1 snapping override
); const gridSnappingSensitivity = Math.max(snappingSensitivity, 0);
const [showFogGuides] = useSetting<boolean>("fog.showGuides"); const [showFogGuides] = useSetting<boolean>("fog.showGuides");
const [editOpacity] = useSetting<number>("fog.editOpacity"); const [editOpacity] = useSetting<number>("fog.editOpacity");
const mapStageRef = useMapStage(); const mapStageRef = useMapStage();

View File

@ -3,8 +3,15 @@ import React, { useContext, useState, useEffect } from "react";
import Vector2 from "../helpers/Vector2"; import Vector2 from "../helpers/Vector2";
import Size from "../helpers/Size"; import Size from "../helpers/Size";
import { getGridPixelSize, getCellPixelSize } from "../helpers/grid"; import { getGridPixelSize, getCellPixelSize } from "../helpers/grid";
import { Grid } from "../types/Grid"; import { Grid } from "../types/Grid";
import useSetting from "../hooks/useSetting";
import shortcuts from "../shortcuts";
import { useBlur, useKeyboard } from "./KeyboardContext";
/** /**
* @typedef GridContextValue * @typedef GridContextValue
* @property {Grid} grid Base grid value * @property {Grid} grid Base grid value
@ -23,6 +30,7 @@ type GridContextValue = {
gridOffset: Vector2; gridOffset: Vector2;
gridStrokeWidth: number; gridStrokeWidth: number;
gridCellPixelOffset: Vector2; gridCellPixelOffset: Vector2;
gridSnappingSensitivity: number;
}; };
/** /**
@ -44,6 +52,7 @@ const defaultValue: GridContextValue = {
gridOffset: new Vector2(0, 0), gridOffset: new Vector2(0, 0),
gridStrokeWidth: 0, gridStrokeWidth: 0,
gridCellPixelOffset: new Vector2(0, 0), gridCellPixelOffset: new Vector2(0, 0),
gridSnappingSensitivity: 0,
}; };
export const GridContext = React.createContext(defaultValue.grid); export const GridContext = React.createContext(defaultValue.grid);
@ -63,6 +72,9 @@ export const GridStrokeWidthContext = React.createContext(
export const GridCellPixelOffsetContext = React.createContext( export const GridCellPixelOffsetContext = React.createContext(
defaultValue.gridCellPixelOffset defaultValue.gridCellPixelOffset
); );
export const GridSnappingSensitivityContext = React.createContext(
defaultValue.gridSnappingSensitivity
);
const defaultStrokeWidth = 1 / 10; const defaultStrokeWidth = 1 / 10;
@ -138,6 +150,40 @@ export function GridProvider({
setGridCellPixelOffset(_gridCellPixelOffset); setGridCellPixelOffset(_gridCellPixelOffset);
}, [grid, width, height]); }, [grid, width, height]);
const [gridSnappingSensitivity, setGridSnappingSensitivity] = useState(
defaultValue.gridSnappingSensitivity
);
const [defaultSnappingSensitivity] = useSetting<number>(
"map.gridSnappingSensitivity"
);
useEffect(() => {
if (
gridSnappingSensitivity !== defaultSnappingSensitivity &&
gridSnappingSensitivity !== -1 // Snapping not disabled
) {
setGridSnappingSensitivity(defaultSnappingSensitivity);
}
}, [defaultSnappingSensitivity, gridSnappingSensitivity]);
function handleKeyDown(event: KeyboardEvent) {
if (shortcuts.disableSnapping(event)) {
setGridSnappingSensitivity(-1);
}
}
function handleKeyUp(event: KeyboardEvent) {
if (shortcuts.disableSnapping(event)) {
setGridSnappingSensitivity(defaultSnappingSensitivity);
}
}
function handleBlur() {
setGridSnappingSensitivity(defaultSnappingSensitivity);
}
useKeyboard(handleKeyDown, handleKeyUp);
useBlur(handleBlur);
return ( return (
<GridContext.Provider value={grid}> <GridContext.Provider value={grid}>
<GridPixelSizeContext.Provider value={gridPixelSize}> <GridPixelSizeContext.Provider value={gridPixelSize}>
@ -150,7 +196,11 @@ export function GridProvider({
<GridCellPixelOffsetContext.Provider <GridCellPixelOffsetContext.Provider
value={gridCellPixelOffset} value={gridCellPixelOffset}
> >
{children} <GridSnappingSensitivityContext.Provider
value={gridSnappingSensitivity}
>
{children}
</GridSnappingSensitivityContext.Provider>
</GridCellPixelOffsetContext.Provider> </GridCellPixelOffsetContext.Provider>
</GridStrokeWidthContext.Provider> </GridStrokeWidthContext.Provider>
</GridOffsetContext.Provider> </GridOffsetContext.Provider>
@ -220,3 +270,13 @@ export function useGridCellPixelOffset() {
} }
return context; return context;
} }
export function useGridSnappingSensitivity() {
const context = useContext(GridSnappingSensitivityContext);
if (context === undefined) {
throw new Error(
"useGridSnappingSensitivity must be used within a GridProvider"
);
}
return context;
}

View File

@ -35,6 +35,7 @@ import {
useGridCellPixelOffset, useGridCellPixelOffset,
useGridOffset, useGridOffset,
useGridPixelSize, useGridPixelSize,
useGridSnappingSensitivity,
GridContext, GridContext,
GridPixelSizeContext, GridPixelSizeContext,
GridCellPixelSizeContext, GridCellPixelSizeContext,
@ -42,6 +43,7 @@ import {
GridOffsetContext, GridOffsetContext,
GridStrokeWidthContext, GridStrokeWidthContext,
GridCellPixelOffsetContext, GridCellPixelOffsetContext,
GridSnappingSensitivityContext,
} from "../contexts/GridContext"; } from "../contexts/GridContext";
import DatabaseContext, { useDatabase } from "../contexts/DatabaseContext"; import DatabaseContext, { useDatabase } from "../contexts/DatabaseContext";
@ -83,6 +85,7 @@ function KonvaBridge({
const gridStrokeWidth = useGridStrokeWidth(); const gridStrokeWidth = useGridStrokeWidth();
const gridCellPixelOffset = useGridCellPixelOffset(); const gridCellPixelOffset = useGridCellPixelOffset();
const gridOffset = useGridOffset(); const gridOffset = useGridOffset();
const gridSnappingSensitivity = useGridSnappingSensitivity();
const database = useDatabase(); const database = useDatabase();
@ -128,7 +131,13 @@ function KonvaBridge({
<GridCellPixelOffsetContext.Provider <GridCellPixelOffsetContext.Provider
value={gridCellPixelOffset} value={gridCellPixelOffset}
> >
{children} <GridSnappingSensitivityContext.Provider
value={
gridSnappingSensitivity
}
>
{children}
</GridSnappingSensitivityContext.Provider>
</GridCellPixelOffsetContext.Provider> </GridCellPixelOffsetContext.Provider>
</GridStrokeWidthContext.Provider> </GridStrokeWidthContext.Provider>
</GridOffsetContext.Provider> </GridOffsetContext.Provider>

View File

@ -5,13 +5,12 @@ import {
getCellCorners, getCellCorners,
} from "../helpers/grid"; } from "../helpers/grid";
import useSetting from "./useSetting";
import { import {
useGrid, useGrid,
useGridOffset, useGridOffset,
useGridCellPixelSize, useGridCellPixelSize,
useGridCellPixelOffset, useGridCellPixelOffset,
useGridSnappingSensitivity,
} from "../contexts/GridContext"; } from "../contexts/GridContext";
/** /**
@ -23,13 +22,16 @@ function useGridSnapping(
snappingSensitivity: number | undefined = undefined, snappingSensitivity: number | undefined = undefined,
useCorners: boolean = true useCorners: boolean = true
) { ) {
const [defaultSnappingSensitivity] = useSetting<number>( const defaultSnappingSensitivity = useGridSnappingSensitivity();
"map.gridSnappingSensitivity" let gridSnappingSensitivity: number;
); if (defaultSnappingSensitivity === -1) {
let gridSnappingSensitivity = // Snapping disabled via shortcut
snappingSensitivity === undefined gridSnappingSensitivity = 0;
? defaultSnappingSensitivity } else if (snappingSensitivity === undefined) {
: snappingSensitivity; gridSnappingSensitivity = defaultSnappingSensitivity;
} else {
gridSnappingSensitivity = snappingSensitivity;
}
const grid = useGrid(); const grid = useGrid();
const gridOffset = useGridOffset(); const gridOffset = useGridOffset();

View File

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