2020-04-20 17:25:40 +10:00
|
|
|
import React, { useState, useEffect, useRef } from "react";
|
2020-04-20 15:26:36 +10:00
|
|
|
import { Flex, Box, IconButton, Label } from "theme-ui";
|
2020-04-18 23:31:40 +10:00
|
|
|
|
2020-04-23 21:54:58 +10:00
|
|
|
import SelectMapButton from "./SelectMapButton";
|
2020-04-23 10:09:12 +10:00
|
|
|
import ExpandMoreIcon from "../../icons/ExpandMoreIcon";
|
|
|
|
|
import PanToolIcon from "../../icons/PanToolIcon";
|
|
|
|
|
import BrushToolIcon from "../../icons/BrushToolIcon";
|
|
|
|
|
import EraseToolIcon from "../../icons/EraseToolIcon";
|
|
|
|
|
import UndoIcon from "../../icons/UndoIcon";
|
|
|
|
|
import RedoIcon from "../../icons/RedoIcon";
|
|
|
|
|
import GridOnIcon from "../../icons/GridOnIcon";
|
|
|
|
|
import GridOffIcon from "../../icons/GridOffIcon";
|
|
|
|
|
import BlendOnIcon from "../../icons/BlendOnIcon";
|
|
|
|
|
import BlendOffIcon from "../../icons/BlendOffIcon";
|
|
|
|
|
import GestureOnIcon from "../../icons/GestureOnIcon";
|
|
|
|
|
import GestureOffIcon from "../../icons/GestureOffIcon";
|
2020-04-18 23:31:40 +10:00
|
|
|
|
2020-04-23 10:09:12 +10:00
|
|
|
import colors, { colorOptions } from "../../helpers/colors";
|
2020-04-20 11:56:56 +10:00
|
|
|
|
|
|
|
|
import MapMenu from "./MapMenu";
|
2020-04-23 10:09:12 +10:00
|
|
|
import EraseAllIcon from "../../icons/EraseAllIcon";
|
2020-04-20 11:56:56 +10:00
|
|
|
|
2020-04-19 00:24:06 +10:00
|
|
|
function MapControls({
|
|
|
|
|
onMapChange,
|
2020-04-23 21:54:58 +10:00
|
|
|
onMapStateChange,
|
|
|
|
|
currentMap,
|
2020-04-19 00:24:06 +10:00
|
|
|
onToolChange,
|
|
|
|
|
selectedTool,
|
2020-04-19 13:33:31 +10:00
|
|
|
disabledTools,
|
2020-04-19 00:24:06 +10:00
|
|
|
onUndo,
|
|
|
|
|
onRedo,
|
2020-04-19 13:33:31 +10:00
|
|
|
undoDisabled,
|
|
|
|
|
redoDisabled,
|
2020-04-20 11:56:56 +10:00
|
|
|
brushColor,
|
|
|
|
|
onBrushColorChange,
|
|
|
|
|
onEraseAll,
|
2020-04-20 15:17:56 +10:00
|
|
|
useBrushGridSnapping,
|
|
|
|
|
onBrushGridSnappingChange,
|
2020-04-20 23:52:21 +10:00
|
|
|
useBrushBlending,
|
|
|
|
|
onBrushBlendingChange,
|
|
|
|
|
useBrushGesture,
|
|
|
|
|
onBrushGestureChange,
|
2020-04-19 00:24:06 +10:00
|
|
|
}) {
|
2020-04-19 13:33:31 +10:00
|
|
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
|
|
|
|
2020-04-20 11:56:56 +10:00
|
|
|
const subMenus = {
|
|
|
|
|
brush: (
|
|
|
|
|
<Box sx={{ width: "104px" }} p={1}>
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexWrap: "wrap",
|
|
|
|
|
justifyContent: "space-between",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{colorOptions.map((color) => (
|
|
|
|
|
<Box
|
|
|
|
|
key={color}
|
|
|
|
|
sx={{
|
|
|
|
|
width: "25%",
|
|
|
|
|
paddingTop: "25%",
|
|
|
|
|
borderRadius: "50%",
|
|
|
|
|
transform: "scale(0.75)",
|
|
|
|
|
backgroundColor: colors[color],
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
}}
|
|
|
|
|
onClick={() => onBrushColorChange(color)}
|
2020-04-20 23:54:07 +10:00
|
|
|
aria-label={`Brush Color ${color}`}
|
2020-04-20 11:56:56 +10:00
|
|
|
>
|
|
|
|
|
{brushColor === color && (
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
width: "100%",
|
|
|
|
|
height: "100%",
|
|
|
|
|
border: "2px solid white",
|
|
|
|
|
position: "absolute",
|
|
|
|
|
top: 0,
|
|
|
|
|
borderRadius: "50%",
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Box>
|
|
|
|
|
))}
|
|
|
|
|
</Box>
|
2020-04-20 23:52:21 +10:00
|
|
|
<Flex sx={{ justifyContent: "space-between" }}>
|
|
|
|
|
<IconButton
|
|
|
|
|
aria-label={
|
|
|
|
|
useBrushGridSnapping
|
|
|
|
|
? "Disable Brush Grid Snapping"
|
|
|
|
|
: "Enable Brush Grid Snapping"
|
|
|
|
|
}
|
|
|
|
|
title={
|
|
|
|
|
useBrushGridSnapping
|
|
|
|
|
? "Disable Brush Grid Snapping"
|
|
|
|
|
: "Enable Brush Grid Snapping"
|
|
|
|
|
}
|
|
|
|
|
onClick={() => onBrushGridSnappingChange(!useBrushGridSnapping)}
|
2020-04-20 15:17:56 +10:00
|
|
|
>
|
2020-04-20 23:52:21 +10:00
|
|
|
{useBrushGridSnapping ? <GridOnIcon /> : <GridOffIcon />}
|
|
|
|
|
</IconButton>
|
|
|
|
|
<IconButton
|
|
|
|
|
aria-label={
|
|
|
|
|
useBrushBlending
|
|
|
|
|
? "Disable Brush Blending"
|
|
|
|
|
: "Enable Brush Blending"
|
|
|
|
|
}
|
|
|
|
|
title={
|
|
|
|
|
useBrushBlending
|
|
|
|
|
? "Disable Brush Blending"
|
|
|
|
|
: "Enable Brush Blending"
|
|
|
|
|
}
|
|
|
|
|
onClick={() => onBrushBlendingChange(!useBrushBlending)}
|
|
|
|
|
>
|
|
|
|
|
{useBrushBlending ? <BlendOnIcon /> : <BlendOffIcon />}
|
|
|
|
|
</IconButton>
|
|
|
|
|
<IconButton
|
|
|
|
|
aria-label={
|
|
|
|
|
useBrushGesture
|
|
|
|
|
? "Disable Gesture Detection"
|
|
|
|
|
: "Enable Gesture Detection"
|
|
|
|
|
}
|
|
|
|
|
title={
|
|
|
|
|
useBrushGesture
|
|
|
|
|
? "Disable Gesture Detection"
|
|
|
|
|
: "Enable Gesture Detection"
|
|
|
|
|
}
|
|
|
|
|
onClick={() => onBrushGestureChange(!useBrushGesture)}
|
|
|
|
|
>
|
|
|
|
|
{useBrushGesture ? <GestureOnIcon /> : <GestureOffIcon />}
|
|
|
|
|
</IconButton>
|
|
|
|
|
</Flex>
|
2020-04-20 11:56:56 +10:00
|
|
|
</Box>
|
|
|
|
|
),
|
|
|
|
|
erase: (
|
2020-04-20 15:26:36 +10:00
|
|
|
<Box p={1} pr={3}>
|
|
|
|
|
<Label
|
|
|
|
|
sx={{
|
|
|
|
|
fontSize: 1,
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
":hover": { color: "primary", cursor: "pointer" },
|
|
|
|
|
":active": { color: "secondary" },
|
2020-04-20 11:56:56 +10:00
|
|
|
}}
|
|
|
|
|
>
|
2020-04-20 15:26:36 +10:00
|
|
|
<IconButton
|
|
|
|
|
aria-label="Erase All"
|
|
|
|
|
title="Erase All"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
onEraseAll();
|
|
|
|
|
setCurrentSubmenu(null);
|
|
|
|
|
setCurrentSubmenuOptions({});
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<EraseAllIcon />
|
|
|
|
|
</IconButton>
|
2020-04-20 11:56:56 +10:00
|
|
|
Erase All
|
2020-04-20 15:26:36 +10:00
|
|
|
</Label>
|
2020-04-20 11:56:56 +10:00
|
|
|
</Box>
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const [currentSubmenu, setCurrentSubmenu] = useState(null);
|
|
|
|
|
const [currentSubmenuOptions, setCurrentSubmenuOptions] = useState({});
|
|
|
|
|
|
|
|
|
|
function handleToolClick(event, tool) {
|
|
|
|
|
if (tool !== selectedTool) {
|
|
|
|
|
onToolChange(tool);
|
2020-04-20 17:25:40 +10:00
|
|
|
} else if (currentSubmenu) {
|
|
|
|
|
setCurrentSubmenu(null);
|
|
|
|
|
setCurrentSubmenuOptions({});
|
2020-04-20 11:56:56 +10:00
|
|
|
} else if (subMenus[tool]) {
|
|
|
|
|
const toolRect = event.target.getBoundingClientRect();
|
|
|
|
|
setCurrentSubmenu(tool);
|
|
|
|
|
setCurrentSubmenuOptions({
|
|
|
|
|
// Align the right of the submenu to the left of the tool and center vertically
|
2020-04-20 15:47:52 +10:00
|
|
|
left: `${toolRect.left - 16}px`,
|
2020-04-20 11:56:56 +10:00
|
|
|
top: `${toolRect.bottom - toolRect.height / 2}px`,
|
|
|
|
|
style: { transform: "translate(-100%, -50%)" },
|
2020-04-20 17:25:40 +10:00
|
|
|
// Exclude this node from the sub menus auto close
|
|
|
|
|
excludeNode: event.target,
|
2020-04-20 11:56:56 +10:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-20 15:31:54 +10:00
|
|
|
// Detect when a tool becomes disabled and switch to to the pan tool
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (disabledTools.includes(selectedTool)) {
|
|
|
|
|
onToolChange("pan");
|
|
|
|
|
}
|
|
|
|
|
}, [selectedTool, disabledTools, onToolChange]);
|
|
|
|
|
|
2020-04-18 23:31:40 +10:00
|
|
|
const divider = (
|
|
|
|
|
<Box
|
|
|
|
|
my={2}
|
|
|
|
|
bg="text"
|
|
|
|
|
sx={{ height: "2px", width: "24px", borderRadius: "2px", opacity: 0.5 }}
|
|
|
|
|
></Box>
|
|
|
|
|
);
|
2020-04-20 17:25:40 +10:00
|
|
|
|
|
|
|
|
const expanedMenuRef = useRef();
|
|
|
|
|
|
2020-04-18 23:31:40 +10:00
|
|
|
return (
|
2020-04-20 11:56:56 +10:00
|
|
|
<>
|
|
|
|
|
<Flex
|
2020-04-19 13:33:31 +10:00
|
|
|
sx={{
|
2020-04-20 11:56:56 +10:00
|
|
|
position: "absolute",
|
|
|
|
|
top: 0,
|
2020-04-20 17:30:59 +10:00
|
|
|
right: 0,
|
2020-04-19 13:33:31 +10:00
|
|
|
flexDirection: "column",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
}}
|
2020-04-20 17:30:59 +10:00
|
|
|
mx={1}
|
2020-04-19 00:24:06 +10:00
|
|
|
>
|
2020-04-19 13:33:31 +10:00
|
|
|
<IconButton
|
2020-04-20 11:56:56 +10:00
|
|
|
aria-label={isExpanded ? "Hide Map Controls" : "Show Map Controls"}
|
|
|
|
|
title={isExpanded ? "Hide Map Controls" : "Show Map Controls"}
|
|
|
|
|
onClick={() => setIsExpanded(!isExpanded)}
|
|
|
|
|
sx={{
|
|
|
|
|
transform: `rotate(${isExpanded ? "0" : "180deg"})`,
|
|
|
|
|
display: "block",
|
2020-04-20 15:47:52 +10:00
|
|
|
backgroundColor: "overlay",
|
|
|
|
|
borderRadius: "50%",
|
2020-04-20 11:56:56 +10:00
|
|
|
}}
|
2020-04-20 15:47:52 +10:00
|
|
|
m={2}
|
2020-04-19 13:33:31 +10:00
|
|
|
>
|
2020-04-20 11:56:56 +10:00
|
|
|
<ExpandMoreIcon />
|
2020-04-19 13:33:31 +10:00
|
|
|
</IconButton>
|
2020-04-20 11:56:56 +10:00
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
display: isExpanded ? "flex" : "none",
|
2020-04-20 15:47:52 +10:00
|
|
|
backgroundColor: "overlay",
|
|
|
|
|
borderRadius: "4px",
|
2020-04-20 11:56:56 +10:00
|
|
|
}}
|
2020-04-20 15:47:52 +10:00
|
|
|
p={2}
|
2020-04-20 17:25:40 +10:00
|
|
|
ref={expanedMenuRef}
|
2020-04-19 13:33:31 +10:00
|
|
|
>
|
2020-04-23 21:54:58 +10:00
|
|
|
<SelectMapButton
|
|
|
|
|
onMapChange={onMapChange}
|
|
|
|
|
onMapStateChange={onMapStateChange}
|
|
|
|
|
currentMap={currentMap}
|
|
|
|
|
/>
|
2020-04-20 11:56:56 +10:00
|
|
|
{divider}
|
|
|
|
|
<IconButton
|
|
|
|
|
aria-label="Pan Tool"
|
|
|
|
|
title="Pan Tool"
|
|
|
|
|
onClick={(e) => handleToolClick(e, "pan")}
|
|
|
|
|
sx={{ color: selectedTool === "pan" ? "primary" : "text" }}
|
|
|
|
|
disabled={disabledTools.includes("pan")}
|
|
|
|
|
>
|
|
|
|
|
<PanToolIcon />
|
|
|
|
|
</IconButton>
|
|
|
|
|
<IconButton
|
|
|
|
|
aria-label="Brush Tool"
|
|
|
|
|
title="Brush Tool"
|
|
|
|
|
onClick={(e) => handleToolClick(e, "brush")}
|
|
|
|
|
sx={{ color: selectedTool === "brush" ? "primary" : "text" }}
|
|
|
|
|
disabled={disabledTools.includes("brush")}
|
|
|
|
|
>
|
|
|
|
|
<BrushToolIcon />
|
|
|
|
|
</IconButton>
|
|
|
|
|
<IconButton
|
|
|
|
|
aria-label="Erase Tool"
|
|
|
|
|
title="Erase Tool"
|
|
|
|
|
onClick={(e) => handleToolClick(e, "erase")}
|
|
|
|
|
sx={{ color: selectedTool === "erase" ? "primary" : "text" }}
|
|
|
|
|
disabled={disabledTools.includes("erase")}
|
|
|
|
|
>
|
|
|
|
|
<EraseToolIcon />
|
|
|
|
|
</IconButton>
|
|
|
|
|
{divider}
|
|
|
|
|
<IconButton
|
|
|
|
|
aria-label="Undo"
|
|
|
|
|
title="Undo"
|
|
|
|
|
onClick={() => onUndo()}
|
|
|
|
|
disabled={undoDisabled}
|
|
|
|
|
>
|
|
|
|
|
<UndoIcon />
|
|
|
|
|
</IconButton>
|
|
|
|
|
<IconButton
|
|
|
|
|
aria-label="Redo"
|
|
|
|
|
title="Redo"
|
|
|
|
|
onClick={() => onRedo()}
|
|
|
|
|
disabled={redoDisabled}
|
|
|
|
|
>
|
|
|
|
|
<RedoIcon />
|
|
|
|
|
</IconButton>
|
|
|
|
|
</Box>
|
|
|
|
|
</Flex>
|
|
|
|
|
<MapMenu
|
|
|
|
|
isOpen={!!currentSubmenu}
|
|
|
|
|
onRequestClose={() => {
|
|
|
|
|
setCurrentSubmenu(null);
|
|
|
|
|
setCurrentSubmenuOptions({});
|
|
|
|
|
}}
|
|
|
|
|
{...currentSubmenuOptions}
|
|
|
|
|
>
|
|
|
|
|
{currentSubmenu && subMenus[currentSubmenu]}
|
|
|
|
|
</MapMenu>
|
|
|
|
|
</>
|
2020-04-18 23:31:40 +10:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default MapControls;
|