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

View File

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

View File

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

View File

@ -172,8 +172,7 @@ function MapInteraction({ map, children, controls, selectedToolId }) {
case "pan":
return "move";
case "fog":
case "brush":
case "shape":
case "drawing":
return "crosshair";
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
) {
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 minGrid = Vector2.min(gridSize);
const distance = Vector2.length(Vector2.subtract(snapped, position));

View File

@ -1,6 +1,6 @@
import React from "react";
function ShapeCircleIcon() {
function BrushCircleIcon() {
return (
<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";
function ShapeRectangleIcon() {
function BrushRectangleIcon() {
return (
<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";
function ShapeTriangleIcon() {
function BrushTriangleIcon() {
return (
<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;