Moved undo and redo into tool settings and implemented it for fog
This commit is contained in:
parent
ccaa51fe84
commit
88b4785307
@ -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 (
|
||||
|
@ -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({
|
||||
</RadioIconButton>
|
||||
)),
|
||||
},
|
||||
{
|
||||
id: "history",
|
||||
component: (
|
||||
<>
|
||||
<IconButton
|
||||
onClick={onUndo}
|
||||
disabled={disabledControls.includes("undo")}
|
||||
>
|
||||
<UndoIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={onRedo}
|
||||
disabled={disabledControls.includes("redo")}
|
||||
>
|
||||
<RedoIcon />
|
||||
</IconButton>
|
||||
</>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
let controls = null;
|
||||
@ -191,6 +169,7 @@ function MapContols({
|
||||
onToolSettingChange(selectedToolId, change)
|
||||
}
|
||||
onToolAction={onToolAction}
|
||||
disabledActions={disabledSettings[selectedToolId]}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
@ -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(() => {
|
||||
|
@ -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 (
|
||||
<Flex sx={{ alignItems: "center" }}>
|
||||
<ColorControl
|
||||
@ -37,6 +45,15 @@ function BrushToolSettings({ settings, onSettingChange }) {
|
||||
useBlending={settings.useBlending}
|
||||
onBlendingChange={(useBlending) => onSettingChange({ useBlending })}
|
||||
/>
|
||||
<Divider vertical />
|
||||
<UndoButton
|
||||
onClick={() => onToolAction("mapUndo")}
|
||||
disabled={disabledActions.includes("undo")}
|
||||
/>
|
||||
<RedoButton
|
||||
onClick={() => onToolAction("mapRedo")}
|
||||
disabled={disabledActions.includes("redo")}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
@ -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 (
|
||||
<Flex sx={{ alignItems: "center" }}>
|
||||
<IconButton
|
||||
@ -13,6 +18,15 @@ function EraseToolSettings({ onToolAction }) {
|
||||
>
|
||||
<EraseAllIcon />
|
||||
</IconButton>
|
||||
<Divider vertical />
|
||||
<UndoButton
|
||||
onClick={() => onToolAction("mapUndo")}
|
||||
disabled={disabledActions.includes("undo")}
|
||||
/>
|
||||
<RedoButton
|
||||
onClick={() => onToolAction("mapRedo")}
|
||||
disabled={disabledActions.includes("redo")}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
@ -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 (
|
||||
<Flex sx={{ alignItems: "center" }}>
|
||||
<RadioIconButton
|
||||
@ -48,6 +56,15 @@ function BrushToolSettings({ settings, onSettingChange }) {
|
||||
onSettingChange({ useGridSnapping })
|
||||
}
|
||||
/>
|
||||
<Divider vertical />
|
||||
<UndoButton
|
||||
onClick={() => onToolAction("fogUndo")}
|
||||
disabled={disabledActions.includes("undo")}
|
||||
/>
|
||||
<RedoButton
|
||||
onClick={() => onToolAction("fogRedo")}
|
||||
disabled={disabledActions.includes("redo")}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
14
src/components/map/controls/RedoButton.js
Normal file
14
src/components/map/controls/RedoButton.js
Normal file
@ -0,0 +1,14 @@
|
||||
import React from "react";
|
||||
import { IconButton } from "theme-ui";
|
||||
|
||||
import RedoIcon from "../../../icons/RedoIcon";
|
||||
|
||||
function RedoButton({ onClick, disabled }) {
|
||||
return (
|
||||
<IconButton onClick={onClick} disabled={disabled}>
|
||||
<RedoIcon />
|
||||
</IconButton>
|
||||
);
|
||||
}
|
||||
|
||||
export default RedoButton;
|
@ -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 (
|
||||
<Flex sx={{ alignItems: "center" }}>
|
||||
<ColorControl
|
||||
@ -45,6 +53,15 @@ function ShapeToolSettings({ settings, onSettingChange }) {
|
||||
useBlending={settings.useBlending}
|
||||
onBlendingChange={(useBlending) => onSettingChange({ useBlending })}
|
||||
/>
|
||||
<Divider vertical />
|
||||
<UndoButton
|
||||
onClick={() => onToolAction("mapUndo")}
|
||||
disabled={disabledActions.includes("undo")}
|
||||
/>
|
||||
<RedoButton
|
||||
onClick={() => onToolAction("mapRedo")}
|
||||
disabled={disabledActions.includes("redo")}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
14
src/components/map/controls/UndoButton.js
Normal file
14
src/components/map/controls/UndoButton.js
Normal file
@ -0,0 +1,14 @@
|
||||
import React from "react";
|
||||
import { IconButton } from "theme-ui";
|
||||
|
||||
import UndoIcon from "../../../icons/UndoIcon";
|
||||
|
||||
function UndoButton({ onClick, disabled }) {
|
||||
return (
|
||||
<IconButton onClick={onClick} disabled={disabled}>
|
||||
<UndoIcon />
|
||||
</IconButton>
|
||||
);
|
||||
}
|
||||
|
||||
export default UndoButton;
|
@ -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}
|
||||
|
Loading…
Reference in New Issue
Block a user