diff --git a/src/components/map/Map.js b/src/components/map/Map.js index 33fa62d..af5e9bc 100644 --- a/src/components/map/Map.js +++ b/src/components/map/Map.js @@ -1,5 +1,6 @@ import React, { useState } from "react"; import { Box } from "theme-ui"; +import { useToasts } from "react-toast-notifications"; import MapControls from "./MapControls"; import MapInteraction from "./MapInteraction"; @@ -49,6 +50,8 @@ function Map({ disabledTokens, session, }) { + const { addToast } = useToasts(); + const { tokensById } = useTokenData(); const [selectedToolId, setSelectedToolId] = useState("move"); @@ -232,6 +235,7 @@ function Map({ onShapesCut={handleFogShapesCut} onShapesRemove={handleFogShapesRemove} onShapesEdit={handleFogShapesEdit} + onShapeError={addToast} active={selectedToolId === "fog"} toolSettings={settings.fog} editable={allowFogDrawing && !settings.fog.preview} diff --git a/src/components/map/MapFog.js b/src/components/map/MapFog.js index 3e94081..f62fadf 100644 --- a/src/components/map/MapFog.js +++ b/src/components/map/MapFog.js @@ -38,8 +38,10 @@ import { Tick, getRelativePointerPosition, } from "../../helpers/konva"; +import { keyBy } from "../../helpers/shared"; import SubtractShapeAction from "../../actions/SubtractShapeAction"; +import CutShapeAction from "../../actions/CutShapeAction"; import useSetting from "../../hooks/useSetting"; @@ -52,6 +54,7 @@ function MapFog({ onShapesCut, onShapesRemove, onShapesEdit, + onShapeError, active, toolSettings, editable, @@ -214,6 +217,8 @@ function MapFog({ ) { const cut = toolSettings.useFogCut; let drawingShapes = [drawingShape]; + + // Filter out hidden or visible shapes if single layer enabled if (!toolSettings.multilayer) { const shapesToSubtract = shapes.filter((shape) => cut ? !shape.visible : shape.visible @@ -228,22 +233,32 @@ function MapFog({ } if (drawingShapes.length > 0) { - drawingShapes = drawingShapes.map((shape) => { - if (cut) { - return { - id: shape.id, - type: shape.type, - data: shape.data, - }; - } else { - return { ...shape, color: "black" }; - } - }); - if (cut) { - onShapesCut(drawingShapes); + // Run a pre-emptive cut action to check whether we've cut anything + const cutAction = new CutShapeAction(drawingShapes); + const state = cutAction.execute(keyBy(shapes, "id")); + + if (Object.keys(state).length === shapes.length) { + onShapeError("No fog found to cut"); + } else { + onShapesCut( + drawingShapes.map((shape) => ({ + id: shape.id, + type: shape.type, + data: shape.data, + })) + ); + } } else { - onShapesAdd(drawingShapes); + onShapesAdd( + drawingShapes.map((shape) => ({ ...shape, color: "black" })) + ); + } + } else { + if (cut) { + onShapeError("Fog already cut"); + } else { + onShapeError("Fog already placed"); } } setDrawingShape(null); @@ -373,6 +388,7 @@ function MapFog({ }; let polygonShapes = [polygonShape]; + // Filter out hidden or visible shapes if single layer enabled if (!toolSettings.multilayer) { const shapesToSubtract = shapes.filter((shape) => cut ? !shape.visible : shape.visible @@ -388,7 +404,15 @@ function MapFog({ if (polygonShapes.length > 0) { if (cut) { - onShapesCut(polygonShapes); + // Run a pre-emptive cut action to check whether we've cut anything + const cutAction = new CutShapeAction(polygonShapes); + const state = cutAction.execute(keyBy(shapes, "id")); + + if (Object.keys(state).length === shapes.length) { + onShapeError("No fog found to cut"); + } else { + onShapesCut(polygonShapes); + } } else { onShapesAdd( polygonShapes.map((shape) => ({ @@ -399,6 +423,12 @@ function MapFog({ })) ); } + } else { + if (cut) { + onShapeError("Fog already cut"); + } else { + onShapeError("Fog already placed"); + } } setDrawingShape(null);