diff --git a/src/components/map/Map.js b/src/components/map/Map.js
index c0a4907..46e2609 100644
--- a/src/components/map/Map.js
+++ b/src/components/map/Map.js
@@ -26,9 +26,11 @@ function Map({
onMapChange,
onMapStateChange,
onMapDraw,
+ onMapDrawUndo,
+ onMapDrawRedo,
onFogDraw,
- onMapUndo,
- onMapRedo,
+ onFogDrawUndo,
+ onFogDrawRedo,
allowMapDrawing,
allowFogDrawing,
allowTokenChange,
@@ -82,28 +84,40 @@ function Map({
timestamp: Date.now(),
});
}
+ if (action === "mapUndo") {
+ onMapDrawUndo();
+ }
+ if (action === "mapRedo") {
+ onMapDrawRedo();
+ }
+ if (action === "fogUndo") {
+ onFogDrawUndo();
+ }
+ if (action === "fogRedo") {
+ onFogDrawRedo();
+ }
}
const [mapShapes, setMapShapes] = useState([]);
function handleMapShapeAdd(shape) {
- onMapDraw({ type: "add", shapes: [shape], timestamp: Date.now() });
+ onMapDraw({ type: "add", shapes: [shape] });
}
function handleMapShapeRemove(shapeId) {
- onMapDraw({ type: "remove", shapeIds: [shapeId], timestamp: Date.now() });
+ onMapDraw({ type: "remove", shapeIds: [shapeId] });
}
const [fogShapes, setFogShapes] = useState([]);
function handleFogShapeAdd(shape) {
- onFogDraw({ type: "add", shapes: [shape], timestamp: Date.now() });
+ onFogDraw({ type: "add", shapes: [shape] });
}
function handleFogShapeRemove(shapeId) {
- onFogDraw({ type: "remove", shapeIds: [shapeId], timestamp: Date.now() });
+ onFogDraw({ type: "remove", shapeIds: [shapeId] });
}
function handleFogShapeEdit(shape) {
- onFogDraw({ type: "edit", shapes: [shape], timestamp: Date.now() });
+ onFogDraw({ type: "edit", shapes: [shape] });
}
// Replay the draw actions and convert them to shapes for the map drawing
@@ -141,28 +155,38 @@ function Map({
disabledControls.push("shape");
disabledControls.push("erase");
}
- // If no actions that can be undone
- if (!allowFogDrawing && !allowMapDrawing) {
- disabledControls.push("undo");
- disabledControls.push("redo");
- }
if (!map) {
disabledControls.push("pan");
}
if (mapShapes.length === 0) {
disabledControls.push("erase");
}
- if (!mapState || mapState.mapDrawActionIndex < 0) {
- disabledControls.push("undo");
- }
if (!allowFogDrawing) {
disabledControls.push("fog");
}
+
+ const disabledSettings = { fog: [], brush: [], shape: [], erase: [] };
+ if (!mapState || mapState.mapDrawActionIndex < 0) {
+ disabledSettings.brush.push("undo");
+ disabledSettings.shape.push("undo");
+ disabledSettings.erase.push("undo");
+ }
if (
!mapState ||
mapState.mapDrawActionIndex === mapState.mapDrawActions.length - 1
) {
- disabledControls.push("redo");
+ disabledSettings.brush.push("redo");
+ disabledSettings.shape.push("redo");
+ disabledSettings.erase.push("redo");
+ }
+ if (fogShapes.length === 0) {
+ disabledSettings.fog.push("undo");
+ }
+ if (
+ !mapState ||
+ mapState.fogDrawActionIndex === mapState.fogDrawActions.length - 1
+ ) {
+ disabledSettings.fog.push("redo");
}
/**
@@ -262,8 +286,7 @@ function Map({
onToolSettingChange={handleToolSettingChange}
onToolAction={handleToolAction}
disabledControls={disabledControls}
- onUndo={onMapUndo}
- onRedo={onMapRedo}
+ disabledSettings={disabledSettings}
/>
);
return (
diff --git a/src/components/map/MapControls.js b/src/components/map/MapControls.js
index 2431054..7399798 100644
--- a/src/components/map/MapControls.js
+++ b/src/components/map/MapControls.js
@@ -16,8 +16,6 @@ import FogToolIcon from "../../icons/FogToolIcon";
import BrushToolIcon from "../../icons/BrushToolIcon";
import ShapeToolIcon from "../../icons/ShapeToolIcon";
import EraseToolIcon from "../../icons/EraseToolIcon";
-import UndoIcon from "../../icons/UndoIcon";
-import RedoIcon from "../../icons/RedoIcon";
import ExpandMoreIcon from "../../icons/ExpandMoreIcon";
function MapContols({
@@ -30,8 +28,7 @@ function MapContols({
onToolSettingChange,
onToolAction,
disabledControls,
- onUndo,
- onRedo,
+ disabledSettings,
}) {
const [isExpanded, setIsExpanded] = useState(false);
@@ -93,25 +90,6 @@ function MapContols({
)),
},
- {
- id: "history",
- component: (
- <>
-
-
-
-
-
-
- >
- ),
- },
];
let controls = null;
@@ -191,6 +169,7 @@ function MapContols({
onToolSettingChange(selectedToolId, change)
}
onToolAction={onToolAction}
+ disabledActions={disabledSettings[selectedToolId]}
/>
);
@@ -199,13 +178,6 @@ function MapContols({
}
}
- // Move back to pan tool if selected tool becomes disabled
- useEffect(() => {
- if (disabledControls.includes(selectedToolId)) {
- onSelectedToolChange("pan");
- }
- }, [disabledControls]);
-
// Stop map drawing from happening when selecting controls
// Not using react events as they seem to trigger after dom events
useEffect(() => {
diff --git a/src/components/map/controls/BrushToolSettings.js b/src/components/map/controls/BrushToolSettings.js
index b503972..df24bb1 100644
--- a/src/components/map/controls/BrushToolSettings.js
+++ b/src/components/map/controls/BrushToolSettings.js
@@ -8,9 +8,17 @@ import RadioIconButton from "./RadioIconButton";
import BrushStrokeIcon from "../../../icons/BrushStrokeIcon";
import BrushFillIcon from "../../../icons/BrushFillIcon";
+import UndoButton from "./UndoButton";
+import RedoButton from "./RedoButton";
+
import Divider from "./Divider";
-function BrushToolSettings({ settings, onSettingChange }) {
+function BrushToolSettings({
+ settings,
+ onSettingChange,
+ onToolAction,
+ disabledActions,
+}) {
return (
onSettingChange({ useBlending })}
/>
+
+ onToolAction("mapUndo")}
+ disabled={disabledActions.includes("undo")}
+ />
+ onToolAction("mapRedo")}
+ disabled={disabledActions.includes("redo")}
+ />
);
}
diff --git a/src/components/map/controls/EraseToolSettings.js b/src/components/map/controls/EraseToolSettings.js
index 01a2aeb..0660570 100644
--- a/src/components/map/controls/EraseToolSettings.js
+++ b/src/components/map/controls/EraseToolSettings.js
@@ -3,7 +3,12 @@ import { Flex, IconButton } from "theme-ui";
import EraseAllIcon from "../../../icons/EraseAllIcon";
-function EraseToolSettings({ onToolAction }) {
+import UndoButton from "./UndoButton";
+import RedoButton from "./RedoButton";
+
+import Divider from "./Divider";
+
+function EraseToolSettings({ onToolAction, disabledActions }) {
return (
+
+ onToolAction("mapUndo")}
+ disabled={disabledActions.includes("undo")}
+ />
+ onToolAction("mapRedo")}
+ disabled={disabledActions.includes("redo")}
+ />
);
}
diff --git a/src/components/map/controls/FogToolSettings.js b/src/components/map/controls/FogToolSettings.js
index 43cba40..04183d3 100644
--- a/src/components/map/controls/FogToolSettings.js
+++ b/src/components/map/controls/FogToolSettings.js
@@ -9,9 +9,17 @@ import FogAddIcon from "../../../icons/FogAddIcon";
import FogRemoveIcon from "../../../icons/FogRemoveIcon";
import FogToggleIcon from "../../../icons/FogToggleIcon";
+import UndoButton from "./UndoButton";
+import RedoButton from "./RedoButton";
+
import Divider from "./Divider";
-function BrushToolSettings({ settings, onSettingChange }) {
+function BrushToolSettings({
+ settings,
+ onSettingChange,
+ onToolAction,
+ disabledActions,
+}) {
return (
+
+ onToolAction("fogUndo")}
+ disabled={disabledActions.includes("undo")}
+ />
+ onToolAction("fogRedo")}
+ disabled={disabledActions.includes("redo")}
+ />
);
}
diff --git a/src/components/map/controls/RedoButton.js b/src/components/map/controls/RedoButton.js
new file mode 100644
index 0000000..e233143
--- /dev/null
+++ b/src/components/map/controls/RedoButton.js
@@ -0,0 +1,14 @@
+import React from "react";
+import { IconButton } from "theme-ui";
+
+import RedoIcon from "../../../icons/RedoIcon";
+
+function RedoButton({ onClick, disabled }) {
+ return (
+
+
+
+ );
+}
+
+export default RedoButton;
diff --git a/src/components/map/controls/ShapeToolSettings.js b/src/components/map/controls/ShapeToolSettings.js
index b332ca9..e4a8328 100644
--- a/src/components/map/controls/ShapeToolSettings.js
+++ b/src/components/map/controls/ShapeToolSettings.js
@@ -9,9 +9,17 @@ import ShapeRectangleIcon from "../../../icons/ShapeRectangleIcon";
import ShapeCircleIcon from "../../../icons/ShapeCircleIcon";
import ShapeTriangleIcon from "../../../icons/ShapeTriangleIcon";
+import UndoButton from "./UndoButton";
+import RedoButton from "./RedoButton";
+
import Divider from "./Divider";
-function ShapeToolSettings({ settings, onSettingChange }) {
+function ShapeToolSettings({
+ settings,
+ onSettingChange,
+ onToolAction,
+ disabledActions,
+}) {
return (
onSettingChange({ useBlending })}
/>
+
+ onToolAction("mapUndo")}
+ disabled={disabledActions.includes("undo")}
+ />
+ onToolAction("mapRedo")}
+ disabled={disabledActions.includes("redo")}
+ />
);
}
diff --git a/src/components/map/controls/UndoButton.js b/src/components/map/controls/UndoButton.js
new file mode 100644
index 0000000..88d0d26
--- /dev/null
+++ b/src/components/map/controls/UndoButton.js
@@ -0,0 +1,14 @@
+import React from "react";
+import { IconButton } from "theme-ui";
+
+import UndoIcon from "../../../icons/UndoIcon";
+
+function UndoButton({ onClick, disabled }) {
+ return (
+
+
+
+ );
+}
+
+export default UndoButton;
diff --git a/src/routes/Game.js b/src/routes/Game.js
index 4691e19..e2ee57e 100644
--- a/src/routes/Game.js
+++ b/src/routes/Game.js
@@ -118,82 +118,92 @@ function Game() {
}
}
- function addNewMapDrawActions(actions) {
+ function addMapDrawActions(actions, indexKey, actionsKey) {
setMapState((prevMapState) => {
const newActions = [
- ...prevMapState.mapDrawActions.slice(
- 0,
- prevMapState.mapDrawActionIndex + 1
- ),
+ ...prevMapState[actionsKey].slice(0, prevMapState[indexKey] + 1),
...actions,
];
const newIndex = newActions.length - 1;
return {
...prevMapState,
- mapDrawActions: newActions,
- mapDrawActionIndex: newIndex,
+ [actionsKey]: newActions,
+ [indexKey]: newIndex,
};
});
}
+ function updateDrawActionIndex(change, indexKey, actionsKey, peerId) {
+ const newIndex = Math.min(
+ Math.max(mapState[indexKey] + change, -1),
+ mapState[actionsKey].length - 1
+ );
+
+ setMapState((prevMapState) => ({
+ ...prevMapState,
+ [indexKey]: newIndex,
+ }));
+ return newIndex;
+ }
+
function handleMapDraw(action) {
- addNewMapDrawActions([action]);
+ addMapDrawActions([action], "mapDrawActionIndex", "mapDrawActions");
for (let peer of Object.values(peers)) {
peer.connection.send({ id: "mapDraw", data: [action] });
}
}
- function handleMapUndo() {
- // TODO: Check whether to pull from draw actions or fog actions
- const newIndex = Math.max(mapState.mapDrawActionIndex - 1, -1);
- setMapState((prevMapState) => ({
- ...prevMapState,
- mapDrawActionIndex: newIndex,
- }));
- for (let peer of Object.values(peers)) {
- peer.connection.send({ id: "mapDrawIndex", data: newIndex });
- }
- }
-
- function handleMapRedo() {
- const newIndex = Math.min(
- mapState.mapDrawActionIndex + 1,
- mapState.mapDrawActions.length - 1
+ function handleMapDrawUndo() {
+ const index = updateDrawActionIndex(
+ -1,
+ "mapDrawActionIndex",
+ "mapDrawActions"
);
- setMapState((prevMapState) => ({
- ...prevMapState,
- mapDrawActionIndex: newIndex,
- }));
for (let peer of Object.values(peers)) {
- peer.connection.send({ id: "mapDrawIndex", data: newIndex });
+ peer.connection.send({ id: "mapDrawIndex", data: index });
}
}
- function addNewFogDrawActions(actions) {
- setMapState((prevMapState) => {
- const newActions = [
- ...prevMapState.fogDrawActions.slice(
- 0,
- prevMapState.fogDrawActionIndex + 1
- ),
- ...actions,
- ];
- const newIndex = newActions.length - 1;
- return {
- ...prevMapState,
- fogDrawActions: newActions,
- fogDrawActionIndex: newIndex,
- };
- });
+ function handleMapDrawRedo() {
+ const index = updateDrawActionIndex(
+ 1,
+ "mapDrawActionIndex",
+ "mapDrawActions"
+ );
+ for (let peer of Object.values(peers)) {
+ peer.connection.send({ id: "mapDrawIndex", data: index });
+ }
}
function handleFogDraw(action) {
- addNewFogDrawActions([action]);
+ addMapDrawActions([action], "fogDrawActionIndex", "fogDrawActions");
for (let peer of Object.values(peers)) {
peer.connection.send({ id: "mapFog", data: [action] });
}
}
+ function handleFogDrawUndo() {
+ const index = updateDrawActionIndex(
+ -1,
+ "fogDrawActionIndex",
+ "fogDrawActions"
+ );
+ for (let peer of Object.values(peers)) {
+ peer.connection.send({ id: "fogDrawIndex", data: index });
+ }
+ }
+
+ function handleFogDrawRedo() {
+ const index = updateDrawActionIndex(
+ 1,
+ "fogDrawActionIndex",
+ "fogDrawActions"
+ );
+ for (let peer of Object.values(peers)) {
+ peer.connection.send({ id: "fogDrawIndex", data: index });
+ }
+ }
+
/**
* Party state
*/
@@ -261,7 +271,7 @@ function Game() {
}));
}
if (data.id === "mapDraw") {
- addNewMapDrawActions(data.data);
+ addMapDrawActions(data.data, "mapDrawActionIndex", "mapDrawActions");
}
if (data.id === "mapDrawIndex") {
setMapState((prevMapState) => ({
@@ -270,7 +280,7 @@ function Game() {
}));
}
if (data.id === "mapFog") {
- addNewFogDrawActions(data.data);
+ addMapDrawActions(data.data, "fogDrawActionIndex", "fogDrawActions");
}
if (data.id === "mapFogIndex") {
setMapState((prevMapState) => ({
@@ -412,9 +422,11 @@ function Game() {
onMapChange={handleMapChange}
onMapStateChange={handleMapStateChange}
onMapDraw={handleMapDraw}
- onMapUndo={handleMapUndo}
- onMapRedo={handleMapRedo}
+ onMapDrawUndo={handleMapDrawUndo}
+ onMapDrawRedo={handleMapDrawRedo}
onFogDraw={handleFogDraw}
+ onFogDrawUndo={handleFogDrawUndo}
+ onFogDrawRedo={handleFogDrawRedo}
allowMapDrawing={canEditMapDrawing}
allowFogDrawing={canEditFogDrawing}
allowTokenChange={canEditTokens}