Moved drawing tools into one section

This commit is contained in:
Mitchell McCaffrey 2020-06-21 11:01:03 +10:00
parent aa4ba33a0b
commit 3ba7c8809c
14 changed files with 152 additions and 246 deletions

View File

@ -49,14 +49,9 @@ function Map({
const [selectedToolId, setSelectedToolId] = useState("pan"); const [selectedToolId, setSelectedToolId] = useState("pan");
const [toolSettings, setToolSettings] = useState({ const [toolSettings, setToolSettings] = useState({
fog: { type: "polygon", useEdgeSnapping: false, useFogCut: false }, fog: { type: "polygon", useEdgeSnapping: false, useFogCut: false },
brush: { drawing: {
color: "darkGray",
type: "stroke",
useBlending: false,
},
shape: {
color: "red", color: "red",
type: "rectangle", type: "brush",
useBlending: true, useBlending: true,
}, },
}); });
@ -189,33 +184,27 @@ function Map({
const disabledControls = []; const disabledControls = [];
if (!allowMapDrawing) { if (!allowMapDrawing) {
disabledControls.push("brush"); disabledControls.push("drawing");
disabledControls.push("shape");
disabledControls.push("erase");
} }
if (!map) { if (!map) {
disabledControls.push("pan"); disabledControls.push("pan");
} }
if (mapShapes.length === 0) {
disabledControls.push("erase");
}
if (!allowFogDrawing) { if (!allowFogDrawing) {
disabledControls.push("fog"); disabledControls.push("fog");
} }
const disabledSettings = { fog: [], brush: [], shape: [], erase: [] }; const disabledSettings = { fog: [], drawing: [] };
if (mapShapes.length === 0) {
disabledSettings.drawing.push("erase");
}
if (!mapState || mapState.mapDrawActionIndex < 0) { if (!mapState || mapState.mapDrawActionIndex < 0) {
disabledSettings.brush.push("undo"); disabledSettings.drawing.push("undo");
disabledSettings.shape.push("undo");
disabledSettings.erase.push("undo");
} }
if ( if (
!mapState || !mapState ||
mapState.mapDrawActionIndex === mapState.mapDrawActions.length - 1 mapState.mapDrawActionIndex === mapState.mapDrawActions.length - 1
) { ) {
disabledSettings.brush.push("redo"); disabledSettings.drawing.push("redo");
disabledSettings.shape.push("redo");
disabledSettings.erase.push("redo");
} }
if (!mapState || mapState.fogDrawActionIndex < 0) { if (!mapState || mapState.fogDrawActionIndex < 0) {
disabledSettings.fog.push("undo"); disabledSettings.fog.push("undo");

View File

@ -7,15 +7,11 @@ import Divider from "../Divider";
import SelectMapButton from "./SelectMapButton"; import SelectMapButton from "./SelectMapButton";
import FogToolSettings from "./controls/FogToolSettings"; import FogToolSettings from "./controls/FogToolSettings";
import BrushToolSettings from "./controls/BrushToolSettings"; import DrawingToolSettings from "./controls/DrawingToolSettings";
import ShapeToolSettings from "./controls/ShapeToolSettings";
import EraseToolSettings from "./controls/EraseToolSettings";
import PanToolIcon from "../../icons/PanToolIcon"; import PanToolIcon from "../../icons/PanToolIcon";
import FogToolIcon from "../../icons/FogToolIcon"; import FogToolIcon from "../../icons/FogToolIcon";
import BrushToolIcon from "../../icons/BrushToolIcon"; import BrushToolIcon from "../../icons/BrushToolIcon";
import ShapeToolIcon from "../../icons/ShapeToolIcon";
import EraseToolIcon from "../../icons/EraseToolIcon";
import ExpandMoreIcon from "../../icons/ExpandMoreIcon"; import ExpandMoreIcon from "../../icons/ExpandMoreIcon";
function MapContols({ function MapContols({
@ -45,26 +41,14 @@ function MapContols({
title: "Fog Tool", title: "Fog Tool",
SettingsComponent: FogToolSettings, SettingsComponent: FogToolSettings,
}, },
brush: { drawing: {
id: "brush", id: "brush",
icon: <BrushToolIcon />, icon: <BrushToolIcon />,
title: "Brush Tool", title: "Brush Tool",
SettingsComponent: BrushToolSettings, SettingsComponent: DrawingToolSettings,
},
shape: {
id: "shape",
icon: <ShapeToolIcon />,
title: "Shape Tool",
SettingsComponent: ShapeToolSettings,
},
erase: {
id: "erase",
icon: <EraseToolIcon />,
title: "Erase tool",
SettingsComponent: EraseToolSettings,
}, },
}; };
const tools = ["pan", "fog", "brush", "shape", "erase"]; const tools = ["pan", "fog", "drawing"];
const sections = [ const sections = [
{ {

View File

@ -29,11 +29,18 @@ function MapDrawing({
const [isBrushDown, setIsBrushDown] = useState(false); const [isBrushDown, setIsBrushDown] = useState(false);
const [erasingShapes, setErasingShapes] = useState([]); const [erasingShapes, setErasingShapes] = useState([]);
const shouldHover = selectedToolId === "erase"; const shouldHover =
const isEditing = selectedToolSettings && selectedToolSettings.type === "erase";
selectedToolId === "brush" || const isEditing = selectedToolId === "drawing";
selectedToolId === "shape" || const isBrush =
selectedToolId === "erase"; selectedToolSettings &&
(selectedToolSettings.type === "brush" ||
selectedToolSettings.type === "paint");
const isShape =
selectedToolSettings &&
(selectedToolSettings.type === "rectangle" ||
selectedToolSettings.type === "circle" ||
selectedToolSettings.type === "triangle");
const handleBrushUp = useCallback(() => { const handleBrushUp = useCallback(() => {
setIsBrushDown(false); setIsBrushDown(false);
@ -58,15 +65,15 @@ function MapDrawing({
blend: selectedToolSettings && selectedToolSettings.useBlending, blend: selectedToolSettings && selectedToolSettings.useBlending,
id: shortid.generate(), id: shortid.generate(),
}; };
if (selectedToolId === "brush") { if (isBrush) {
setDrawingShape({ setDrawingShape({
type: "path", type: "path",
pathType: selectedToolSettings.type, pathType: selectedToolSettings.type === "brush" ? "stroke" : "fill",
data: { points: [brushPosition] }, data: { points: [brushPosition] },
strokeWidth: selectedToolSettings.type === "stroke" ? 1 : 0, strokeWidth: selectedToolSettings.type === "brush" ? 1 : 0,
...commonShapeData, ...commonShapeData,
}); });
} else if (selectedToolId === "shape") { } else if (isShape) {
setDrawingShape({ setDrawingShape({
type: "shape", type: "shape",
shapeType: selectedToolSettings.type, shapeType: selectedToolSettings.type,
@ -86,7 +93,7 @@ function MapDrawing({
gridSize, gridSize,
shapes shapes
); );
if (selectedToolId === "brush") { if (isBrush) {
setDrawingShape((prevShape) => { setDrawingShape((prevShape) => {
const prevPoints = prevShape.data.points; const prevPoints = prevShape.data.points;
if ( if (
@ -108,7 +115,7 @@ function MapDrawing({
data: { points: simplified }, data: { points: simplified },
}; };
}); });
} else if (selectedToolId === "shape") { } else if (isShape) {
setDrawingShape((prevShape) => ({ setDrawingShape((prevShape) => ({
...prevShape, ...prevShape,
data: getUpdatedShapeData( data: getUpdatedShapeData(
@ -122,11 +129,11 @@ function MapDrawing({
} }
function endShape() { function endShape() {
if (selectedToolId === "brush" && drawingShape) { if (isBrush && drawingShape) {
if (drawingShape.data.points.length > 1) { if (drawingShape.data.points.length > 1) {
onShapeAdd(drawingShape); onShapeAdd(drawingShape);
} }
} else if (selectedToolId === "shape" && drawingShape) { } else if (isShape && drawingShape) {
onShapeAdd(drawingShape); onShapeAdd(drawingShape);
} }
setDrawingShape(null); setDrawingShape(null);
@ -156,6 +163,8 @@ function MapDrawing({
shapes, shapes,
drawingShape, drawingShape,
handleBrushUp, handleBrushUp,
isBrush,
isShape,
] ]
); );

View File

@ -172,8 +172,7 @@ function MapInteraction({ map, children, controls, selectedToolId }) {
case "pan": case "pan":
return "move"; return "move";
case "fog": case "fog":
case "brush": case "drawing":
case "shape":
return "crosshair"; return "crosshair";
default: default:
return "default"; return "default";

View File

@ -1,61 +0,0 @@
import React from "react";
import { Flex } from "theme-ui";
import ColorControl from "./ColorControl";
import AlphaBlendToggle from "./AlphaBlendToggle";
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,
onToolAction,
disabledActions,
}) {
return (
<Flex sx={{ alignItems: "center" }}>
<ColorControl
color={settings.color}
onColorChange={(color) => onSettingChange({ color })}
/>
<Divider vertical />
<RadioIconButton
title="Brush Type Stroke"
onClick={() => onSettingChange({ type: "stroke" })}
isSelected={settings.type === "stroke"}
>
<BrushStrokeIcon />
</RadioIconButton>
<RadioIconButton
title="Brush Type Fill"
onClick={() => onSettingChange({ type: "fill" })}
isSelected={settings.type === "fill"}
>
<BrushFillIcon />
</RadioIconButton>
<Divider vertical />
<AlphaBlendToggle
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>
);
}
export default BrushToolSettings;

View File

@ -0,0 +1,104 @@
import React from "react";
import { Flex, IconButton } from "theme-ui";
import ColorControl from "./ColorControl";
import AlphaBlendToggle from "./AlphaBlendToggle";
import RadioIconButton from "./RadioIconButton";
import BrushIcon from "../../../icons/BrushToolIcon";
import BrushFillIcon from "../../../icons/BrushPaintIcon";
import BrushRectangleIcon from "../../../icons/BrushRectangleIcon";
import BrushCircleIcon from "../../../icons/BrushCircleIcon";
import BrushTriangleIcon from "../../../icons/BrushTriangleIcon";
import EraseAllIcon from "../../../icons/EraseAllIcon";
import EraseIcon from "../../../icons/EraseToolIcon";
import UndoButton from "./UndoButton";
import RedoButton from "./RedoButton";
import Divider from "../../Divider";
function DrawingToolSettings({
settings,
onSettingChange,
onToolAction,
disabledActions,
}) {
return (
<Flex sx={{ alignItems: "center" }}>
<ColorControl
color={settings.color}
onColorChange={(color) => onSettingChange({ color })}
/>
<Divider vertical />
<RadioIconButton
title="Brush"
onClick={() => onSettingChange({ type: "brush" })}
isSelected={settings.type === "brush"}
>
<BrushIcon />
</RadioIconButton>
<RadioIconButton
title="Paint"
onClick={() => onSettingChange({ type: "paint" })}
isSelected={settings.type === "paint"}
>
<BrushFillIcon />
</RadioIconButton>
<RadioIconButton
title="Rectangle"
onClick={() => onSettingChange({ type: "rectangle" })}
isSelected={settings.type === "rectangle"}
>
<BrushRectangleIcon />
</RadioIconButton>
<RadioIconButton
title="Circle"
onClick={() => onSettingChange({ type: "circle" })}
isSelected={settings.type === "circle"}
>
<BrushCircleIcon />
</RadioIconButton>
<RadioIconButton
title="Triangle"
onClick={() => onSettingChange({ type: "triangle" })}
isSelected={settings.type === "triangle"}
>
<BrushTriangleIcon />
</RadioIconButton>
<Divider vertical />
<RadioIconButton
title="Erase"
onClick={() => onSettingChange({ type: "erase" })}
isSelected={settings.type === "erase"}
disabled={disabledActions.includes("erase")}
>
<EraseIcon />
</RadioIconButton>
<IconButton
aria-label="Erase All"
title="Erase All"
onClick={() => onToolAction("eraseAll")}
disabled={disabledActions.includes("erase")}
>
<EraseAllIcon />
</IconButton>
<Divider vertical />
<AlphaBlendToggle
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>
);
}
export default DrawingToolSettings;

View File

@ -1,34 +0,0 @@
import React from "react";
import { Flex, IconButton } from "theme-ui";
import EraseAllIcon from "../../../icons/EraseAllIcon";
import UndoButton from "./UndoButton";
import RedoButton from "./RedoButton";
import Divider from "../../Divider";
function EraseToolSettings({ onToolAction, disabledActions }) {
return (
<Flex sx={{ alignItems: "center" }}>
<IconButton
aria-label="Erase All"
title="Erase All"
onClick={() => onToolAction("eraseAll")}
>
<EraseAllIcon />
</IconButton>
<Divider vertical />
<UndoButton
onClick={() => onToolAction("mapUndo")}
disabled={disabledActions.includes("undo")}
/>
<RedoButton
onClick={() => onToolAction("mapRedo")}
disabled={disabledActions.includes("redo")}
/>
</Flex>
);
}
export default EraseToolSettings;

View File

@ -1,69 +0,0 @@
import React from "react";
import { Flex } from "theme-ui";
import ColorControl from "./ColorControl";
import AlphaBlendToggle from "./AlphaBlendToggle";
import RadioIconButton from "./RadioIconButton";
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,
onToolAction,
disabledActions,
}) {
return (
<Flex sx={{ alignItems: "center" }}>
<ColorControl
color={settings.color}
onColorChange={(color) => onSettingChange({ color })}
/>
<Divider vertical />
<RadioIconButton
title="Shape Type Rectangle"
onClick={() => onSettingChange({ type: "rectangle" })}
isSelected={settings.type === "rectangle"}
>
<ShapeRectangleIcon />
</RadioIconButton>
<RadioIconButton
title="Shape Type Circle"
onClick={() => onSettingChange({ type: "circle" })}
isSelected={settings.type === "circle"}
>
<ShapeCircleIcon />
</RadioIconButton>
<RadioIconButton
title="Shape Type Triangle"
onClick={() => onSettingChange({ type: "triangle" })}
isSelected={settings.type === "triangle"}
>
<ShapeTriangleIcon />
</RadioIconButton>
<Divider vertical />
<AlphaBlendToggle
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>
);
}
export default ShapeToolSettings;

View File

@ -12,7 +12,12 @@ export function getBrushPositionForTool(
shapes shapes
) { ) {
let position = brushPosition; let position = brushPosition;
if (tool === "shape") { if (
tool === "drawing" &&
(toolSettings.type === "rectangle" ||
toolSettings.type === "circle" ||
toolSettings.type === "triangle")
) {
const snapped = Vector2.roundTo(position, gridSize); const snapped = Vector2.roundTo(position, gridSize);
const minGrid = Vector2.min(gridSize); const minGrid = Vector2.min(gridSize);
const distance = Vector2.length(Vector2.subtract(snapped, position)); const distance = Vector2.length(Vector2.subtract(snapped, position));

View File

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
function ShapeCircleIcon() { function BrushCircleIcon() {
return ( return (
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -15,4 +15,4 @@ function ShapeCircleIcon() {
); );
} }
export default ShapeCircleIcon; export default BrushCircleIcon;

View File

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
function ShapeRectangleIcon() { function BrushRectangleIcon() {
return ( return (
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -15,4 +15,4 @@ function ShapeRectangleIcon() {
); );
} }
export default ShapeRectangleIcon; export default BrushRectangleIcon;

View File

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
function ShapeTriangleIcon() { function BrushTriangleIcon() {
return ( return (
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -15,4 +15,4 @@ function ShapeTriangleIcon() {
); );
} }
export default ShapeTriangleIcon; export default BrushTriangleIcon;

View File

@ -1,20 +0,0 @@
import React from "react";
function ShapeToolIcon() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
height="24"
viewBox="0 0 24 24"
width="24"
fill="currentcolor"
>
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M11.15 3.4L7.43 9.48c-.41.66.07 1.52.85 1.52h7.43c.78 0 1.26-.86.85-1.52L12.85 3.4c-.39-.64-1.31-.64-1.7 0z" />
<circle cx="17.5" cy="17.5" r="4.5" />
<path d="M4 21.5h6c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1z" />
</svg>
);
}
export default ShapeToolIcon;