2021-07-16 14:55:33 +10:00
|
|
|
import { useState, Fragment } from "react";
|
2020-04-27 17:29:46 +10:00
|
|
|
import { IconButton, Flex, Box } from "theme-ui";
|
|
|
|
|
|
2020-10-01 22:32:21 +10:00
|
|
|
import RadioIconButton from "../RadioIconButton";
|
2020-05-26 14:47:37 +10:00
|
|
|
import Divider from "../Divider";
|
2020-04-18 23:31:40 +10:00
|
|
|
|
2020-04-23 21:54:58 +10:00
|
|
|
import SelectMapButton from "./SelectMapButton";
|
2020-04-27 17:29:46 +10:00
|
|
|
|
2021-07-20 20:41:26 +10:00
|
|
|
import FogToolSettings from "../controls/FogToolSettings";
|
|
|
|
|
import DrawingToolSettings from "../controls/DrawingToolSettings";
|
|
|
|
|
import PointerToolSettings from "../controls/PointerToolSettings";
|
|
|
|
|
import SelectToolSettings from "../controls/SelectToolSettings";
|
2020-04-27 17:29:46 +10:00
|
|
|
|
2021-02-22 15:32:35 +11:00
|
|
|
import MoveToolIcon from "../../icons/MoveToolIcon";
|
2020-04-27 17:29:46 +10:00
|
|
|
import FogToolIcon from "../../icons/FogToolIcon";
|
2020-04-23 10:09:12 +10:00
|
|
|
import BrushToolIcon from "../../icons/BrushToolIcon";
|
2020-06-26 12:23:06 +10:00
|
|
|
import MeasureToolIcon from "../../icons/MeasureToolIcon";
|
2020-04-27 17:29:46 +10:00
|
|
|
import ExpandMoreIcon from "../../icons/ExpandMoreIcon";
|
2020-07-28 17:59:26 +10:00
|
|
|
import PointerToolIcon from "../../icons/PointerToolIcon";
|
2020-09-06 15:18:05 +10:00
|
|
|
import FullScreenIcon from "../../icons/FullScreenIcon";
|
|
|
|
|
import FullScreenExitIcon from "../../icons/FullScreenExitIcon";
|
2020-11-03 16:21:39 +11:00
|
|
|
import NoteToolIcon from "../../icons/NoteToolIcon";
|
2021-07-22 16:05:54 +10:00
|
|
|
import SelectToolIcon from "../../icons/SelectToolIcon";
|
2020-09-06 15:18:05 +10:00
|
|
|
|
2021-07-20 21:45:18 +10:00
|
|
|
import UndoButton from "../controls/shared/UndoButton";
|
|
|
|
|
import RedoButton from "../controls/shared/RedoButton";
|
|
|
|
|
|
2021-02-04 15:06:34 +11:00
|
|
|
import useSetting from "../../hooks/useSetting";
|
2021-07-19 10:56:14 +10:00
|
|
|
|
2021-07-16 14:55:33 +10:00
|
|
|
import { Map, MapTool, MapToolId } from "../../types/Map";
|
2021-07-13 08:59:28 +10:00
|
|
|
import { MapState } from "../../types/MapState";
|
2021-07-16 14:55:33 +10:00
|
|
|
import {
|
|
|
|
|
MapChangeEventHandler,
|
|
|
|
|
MapResetEventHandler,
|
|
|
|
|
} from "../../types/Events";
|
|
|
|
|
import { Settings } from "../../types/Settings";
|
2021-07-13 08:59:28 +10:00
|
|
|
|
2021-07-19 10:56:14 +10:00
|
|
|
import { useKeyboard } from "../../contexts/KeyboardContext";
|
|
|
|
|
|
|
|
|
|
import shortcuts from "../../shortcuts";
|
2021-07-21 17:12:49 +10:00
|
|
|
import { useUserId } from "../../contexts/UserIdContext";
|
|
|
|
|
import { isEmpty } from "../../helpers/shared";
|
|
|
|
|
import { MapActions } from "../../hooks/useMapActions";
|
2021-07-19 10:56:14 +10:00
|
|
|
|
2021-07-13 08:59:28 +10:00
|
|
|
type MapControlsProps = {
|
2021-07-16 14:55:33 +10:00
|
|
|
onMapChange: MapChangeEventHandler;
|
|
|
|
|
onMapReset: MapResetEventHandler;
|
2021-07-21 17:12:49 +10:00
|
|
|
map: Map | null;
|
|
|
|
|
mapState: MapState | null;
|
|
|
|
|
mapActions: MapActions;
|
|
|
|
|
allowMapChange: boolean;
|
2021-07-16 14:55:33 +10:00
|
|
|
selectedToolId: MapToolId;
|
|
|
|
|
onSelectedToolChange: (toolId: MapToolId) => void;
|
|
|
|
|
toolSettings: Settings;
|
|
|
|
|
onToolSettingChange: (change: Partial<Settings>) => void;
|
|
|
|
|
onToolAction: (actionId: string) => void;
|
2021-07-20 21:45:18 +10:00
|
|
|
onUndo: () => void;
|
|
|
|
|
onRedo: () => void;
|
2021-07-13 08:59:28 +10:00
|
|
|
};
|
2020-04-20 11:56:56 +10:00
|
|
|
|
2020-04-27 17:29:46 +10:00
|
|
|
function MapContols({
|
2020-04-19 00:24:06 +10:00
|
|
|
onMapChange,
|
2021-02-22 17:14:12 +11:00
|
|
|
onMapReset,
|
2021-07-21 17:12:49 +10:00
|
|
|
map,
|
|
|
|
|
mapState,
|
|
|
|
|
mapActions,
|
|
|
|
|
allowMapChange,
|
2020-04-27 17:29:46 +10:00
|
|
|
selectedToolId,
|
|
|
|
|
onSelectedToolChange,
|
|
|
|
|
toolSettings,
|
|
|
|
|
onToolSettingChange,
|
2020-04-29 20:55:52 +10:00
|
|
|
onToolAction,
|
2021-07-20 21:45:18 +10:00
|
|
|
onUndo,
|
|
|
|
|
onRedo,
|
2021-07-13 08:59:28 +10:00
|
|
|
}: MapControlsProps) {
|
2020-06-30 19:19:33 +10:00
|
|
|
const [isExpanded, setIsExpanded] = useState(true);
|
2020-09-06 15:18:05 +10:00
|
|
|
const [fullScreen, setFullScreen] = useSetting("map.fullScreen");
|
2020-04-19 13:33:31 +10:00
|
|
|
|
2021-07-21 17:12:49 +10:00
|
|
|
const userId = useUserId();
|
|
|
|
|
|
|
|
|
|
const isOwner = map && map.owner === userId;
|
|
|
|
|
|
|
|
|
|
const allowMapDrawing = isOwner || mapState?.editFlags.includes("drawing");
|
|
|
|
|
const allowFogDrawing = isOwner || mapState?.editFlags.includes("fog");
|
|
|
|
|
const allowNoteEditing = isOwner || mapState?.editFlags.includes("notes");
|
|
|
|
|
|
|
|
|
|
const disabledControls: MapToolId[] = [];
|
|
|
|
|
if (!allowMapDrawing) {
|
|
|
|
|
disabledControls.push("drawing");
|
|
|
|
|
}
|
|
|
|
|
if (!map) {
|
|
|
|
|
disabledControls.push("move");
|
|
|
|
|
disabledControls.push("measure");
|
|
|
|
|
disabledControls.push("pointer");
|
|
|
|
|
disabledControls.push("select");
|
|
|
|
|
}
|
|
|
|
|
if (!allowFogDrawing) {
|
|
|
|
|
disabledControls.push("fog");
|
|
|
|
|
}
|
|
|
|
|
if (!allowMapChange) {
|
|
|
|
|
disabledControls.push("map");
|
|
|
|
|
}
|
|
|
|
|
if (!allowNoteEditing) {
|
|
|
|
|
disabledControls.push("note");
|
|
|
|
|
}
|
|
|
|
|
if (!map || mapActions.actionIndex < 0) {
|
|
|
|
|
disabledControls.push("undo");
|
|
|
|
|
}
|
|
|
|
|
if (!map || mapActions.actionIndex === mapActions.actions.length - 1) {
|
|
|
|
|
disabledControls.push("redo");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const disabledSettings: Partial<Record<keyof Settings, string[]>> = {
|
|
|
|
|
drawing: [],
|
|
|
|
|
};
|
|
|
|
|
if (mapState && isEmpty(mapState.drawShapes)) {
|
|
|
|
|
disabledSettings.drawing?.push("erase");
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 14:55:33 +10:00
|
|
|
const toolsById: Record<string, MapTool> = {
|
2021-02-22 15:32:35 +11:00
|
|
|
move: {
|
|
|
|
|
id: "move",
|
|
|
|
|
icon: <MoveToolIcon />,
|
|
|
|
|
title: "Move Tool (W)",
|
2020-04-27 17:29:46 +10:00
|
|
|
},
|
2021-07-19 10:56:14 +10:00
|
|
|
select: {
|
|
|
|
|
id: "select",
|
|
|
|
|
icon: <SelectToolIcon />,
|
2021-07-19 11:37:41 +10:00
|
|
|
title: "Select Tool (L)",
|
2021-07-19 10:56:14 +10:00
|
|
|
SettingsComponent: SelectToolSettings,
|
|
|
|
|
},
|
2020-04-27 17:29:46 +10:00
|
|
|
fog: {
|
|
|
|
|
id: "fog",
|
|
|
|
|
icon: <FogToolIcon />,
|
2020-10-17 09:37:39 +11:00
|
|
|
title: "Fog Tool (F)",
|
2020-04-27 17:29:46 +10:00
|
|
|
SettingsComponent: FogToolSettings,
|
|
|
|
|
},
|
2020-06-21 11:01:03 +10:00
|
|
|
drawing: {
|
2020-06-22 09:24:45 +10:00
|
|
|
id: "drawing",
|
2020-04-27 17:29:46 +10:00
|
|
|
icon: <BrushToolIcon />,
|
2020-10-17 09:37:39 +11:00
|
|
|
title: "Drawing Tool (D)",
|
2020-06-21 11:01:03 +10:00
|
|
|
SettingsComponent: DrawingToolSettings,
|
2020-04-27 17:29:46 +10:00
|
|
|
},
|
2020-06-26 12:23:06 +10:00
|
|
|
measure: {
|
|
|
|
|
id: "measure",
|
|
|
|
|
icon: <MeasureToolIcon />,
|
2020-10-17 09:37:39 +11:00
|
|
|
title: "Measure Tool (M)",
|
2020-06-26 12:23:06 +10:00
|
|
|
},
|
2020-07-28 17:59:26 +10:00
|
|
|
pointer: {
|
|
|
|
|
id: "pointer",
|
|
|
|
|
icon: <PointerToolIcon />,
|
2020-10-17 09:37:39 +11:00
|
|
|
title: "Pointer Tool (Q)",
|
2021-01-28 15:12:30 +11:00
|
|
|
SettingsComponent: PointerToolSettings,
|
2020-07-28 17:59:26 +10:00
|
|
|
},
|
2020-11-03 16:21:39 +11:00
|
|
|
note: {
|
|
|
|
|
id: "note",
|
|
|
|
|
icon: <NoteToolIcon />,
|
|
|
|
|
title: "Note Tool (N)",
|
|
|
|
|
},
|
2020-04-20 11:56:56 +10:00
|
|
|
};
|
2021-07-16 14:55:33 +10:00
|
|
|
const tools: MapToolId[] = [
|
|
|
|
|
"move",
|
2021-07-19 10:56:14 +10:00
|
|
|
"select",
|
2021-07-16 14:55:33 +10:00
|
|
|
"fog",
|
|
|
|
|
"drawing",
|
|
|
|
|
"measure",
|
|
|
|
|
"pointer",
|
|
|
|
|
"note",
|
|
|
|
|
];
|
2020-04-20 17:25:40 +10:00
|
|
|
|
2020-04-29 21:32:23 +10:00
|
|
|
const sections = [
|
|
|
|
|
{
|
2020-04-26 14:34:27 +10:00
|
|
|
id: "map",
|
|
|
|
|
component: (
|
|
|
|
|
<SelectMapButton
|
|
|
|
|
onMapChange={onMapChange}
|
2021-02-22 17:14:12 +11:00
|
|
|
onMapReset={onMapReset}
|
2021-07-21 17:12:49 +10:00
|
|
|
currentMap={map}
|
|
|
|
|
currentMapState={mapState}
|
2020-07-17 15:57:52 +10:00
|
|
|
disabled={disabledControls.includes("map")}
|
2020-04-26 14:34:27 +10:00
|
|
|
/>
|
|
|
|
|
),
|
2020-04-29 21:32:23 +10:00
|
|
|
},
|
|
|
|
|
{
|
2020-06-26 12:23:06 +10:00
|
|
|
id: "tools",
|
2020-04-27 17:29:46 +10:00
|
|
|
component: tools.map((tool) => (
|
|
|
|
|
<RadioIconButton
|
|
|
|
|
key={tool}
|
|
|
|
|
title={toolsById[tool].title}
|
|
|
|
|
onClick={() => onSelectedToolChange(tool)}
|
|
|
|
|
isSelected={selectedToolId === tool}
|
|
|
|
|
disabled={disabledControls.includes(tool)}
|
|
|
|
|
>
|
|
|
|
|
{toolsById[tool].icon}
|
|
|
|
|
</RadioIconButton>
|
|
|
|
|
)),
|
2020-04-29 21:32:23 +10:00
|
|
|
},
|
2021-07-20 21:45:18 +10:00
|
|
|
{
|
|
|
|
|
id: "history",
|
|
|
|
|
component: (
|
|
|
|
|
<>
|
2021-07-21 17:12:49 +10:00
|
|
|
<UndoButton
|
|
|
|
|
onClick={onUndo}
|
|
|
|
|
disabled={disabledControls.includes("undo")}
|
|
|
|
|
/>
|
|
|
|
|
<RedoButton
|
|
|
|
|
onClick={onRedo}
|
|
|
|
|
disabled={disabledControls.includes("redo")}
|
|
|
|
|
/>
|
2021-07-20 21:45:18 +10:00
|
|
|
</>
|
|
|
|
|
),
|
|
|
|
|
},
|
2020-04-29 21:32:23 +10:00
|
|
|
];
|
2020-04-26 14:34:27 +10:00
|
|
|
|
|
|
|
|
let controls = null;
|
|
|
|
|
if (sections.length === 1 && sections[0].id === "map") {
|
|
|
|
|
controls = (
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
display: "block",
|
|
|
|
|
backgroundColor: "overlay",
|
|
|
|
|
borderRadius: "4px",
|
|
|
|
|
}}
|
|
|
|
|
m={2}
|
|
|
|
|
>
|
|
|
|
|
{sections[0].component}
|
|
|
|
|
</Box>
|
|
|
|
|
);
|
|
|
|
|
} else if (sections.length > 0) {
|
|
|
|
|
controls = (
|
|
|
|
|
<>
|
|
|
|
|
<IconButton
|
|
|
|
|
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",
|
|
|
|
|
backgroundColor: "overlay",
|
|
|
|
|
borderRadius: "50%",
|
|
|
|
|
}}
|
|
|
|
|
m={2}
|
|
|
|
|
>
|
|
|
|
|
<ExpandMoreIcon />
|
|
|
|
|
</IconButton>
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
display: isExpanded ? "flex" : "none",
|
|
|
|
|
backgroundColor: "overlay",
|
|
|
|
|
borderRadius: "4px",
|
|
|
|
|
}}
|
|
|
|
|
p={2}
|
|
|
|
|
>
|
|
|
|
|
{sections.map((section, index) => (
|
2020-04-26 18:33:28 +10:00
|
|
|
<Fragment key={section.id}>
|
2020-04-26 14:34:27 +10:00
|
|
|
{section.component}
|
2020-04-27 17:29:46 +10:00
|
|
|
{index !== sections.length - 1 && <Divider />}
|
2020-04-26 18:33:28 +10:00
|
|
|
</Fragment>
|
2020-04-26 14:34:27 +10:00
|
|
|
))}
|
2020-04-20 11:56:56 +10:00
|
|
|
</Box>
|
2020-04-26 14:34:27 +10:00
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 17:29:46 +10:00
|
|
|
function getToolSettings() {
|
|
|
|
|
const Settings = toolsById[selectedToolId].SettingsComponent;
|
2021-07-16 14:55:33 +10:00
|
|
|
if (
|
|
|
|
|
!Settings ||
|
2021-07-21 17:12:49 +10:00
|
|
|
(selectedToolId !== "fog" &&
|
|
|
|
|
selectedToolId !== "drawing" &&
|
|
|
|
|
selectedToolId !== "pointer" &&
|
|
|
|
|
selectedToolId !== "select")
|
2021-07-16 14:55:33 +10:00
|
|
|
) {
|
2020-04-27 17:29:46 +10:00
|
|
|
return null;
|
|
|
|
|
}
|
2021-07-16 14:55:33 +10:00
|
|
|
return (
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
position: "absolute",
|
|
|
|
|
top: "4px",
|
|
|
|
|
left: "50%",
|
|
|
|
|
transform: "translateX(-50%)",
|
|
|
|
|
backgroundColor: "overlay",
|
|
|
|
|
borderRadius: "4px",
|
|
|
|
|
}}
|
|
|
|
|
p={1}
|
|
|
|
|
>
|
|
|
|
|
<Settings
|
|
|
|
|
settings={toolSettings[selectedToolId]}
|
2021-07-16 18:59:29 +10:00
|
|
|
onSettingChange={(
|
2021-07-19 10:56:14 +10:00
|
|
|
change: Partial<Settings["fog" | "drawing" | "pointer" | "select"]>
|
2021-07-16 18:59:29 +10:00
|
|
|
) =>
|
2021-07-16 14:55:33 +10:00
|
|
|
onToolSettingChange({
|
|
|
|
|
[selectedToolId]: {
|
|
|
|
|
...toolSettings[selectedToolId],
|
|
|
|
|
...change,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
onToolAction={onToolAction}
|
|
|
|
|
disabledActions={disabledSettings[selectedToolId]}
|
|
|
|
|
/>
|
|
|
|
|
</Box>
|
|
|
|
|
);
|
2020-04-27 17:29:46 +10:00
|
|
|
}
|
|
|
|
|
|
2021-07-19 10:56:14 +10:00
|
|
|
function handleKeyDown(event: KeyboardEvent) {
|
|
|
|
|
if (shortcuts.moveTool(event) && !disabledControls.includes("move")) {
|
|
|
|
|
onSelectedToolChange("move");
|
|
|
|
|
}
|
|
|
|
|
if (shortcuts.selectTool(event) && !disabledControls.includes("select")) {
|
|
|
|
|
onSelectedToolChange("select");
|
|
|
|
|
}
|
|
|
|
|
if (shortcuts.drawingTool(event) && !disabledControls.includes("drawing")) {
|
|
|
|
|
onSelectedToolChange("drawing");
|
|
|
|
|
}
|
|
|
|
|
if (shortcuts.fogTool(event) && !disabledControls.includes("fog")) {
|
|
|
|
|
onSelectedToolChange("fog");
|
|
|
|
|
}
|
|
|
|
|
if (shortcuts.measureTool(event) && !disabledControls.includes("measure")) {
|
|
|
|
|
onSelectedToolChange("measure");
|
|
|
|
|
}
|
|
|
|
|
if (shortcuts.pointerTool(event) && !disabledControls.includes("pointer")) {
|
|
|
|
|
onSelectedToolChange("pointer");
|
|
|
|
|
}
|
|
|
|
|
if (shortcuts.noteTool(event) && !disabledControls.includes("note")) {
|
|
|
|
|
onSelectedToolChange("note");
|
|
|
|
|
}
|
2021-07-21 17:12:49 +10:00
|
|
|
if (shortcuts.redo(event) && !disabledControls.includes("redo")) {
|
|
|
|
|
onRedo();
|
|
|
|
|
}
|
|
|
|
|
if (shortcuts.undo(event) && !disabledControls.includes("undo")) {
|
|
|
|
|
onUndo();
|
|
|
|
|
}
|
2021-07-19 10:56:14 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
useKeyboard(handleKeyDown);
|
|
|
|
|
|
2020-04-26 14:34:27 +10:00
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<Flex
|
|
|
|
|
sx={{
|
|
|
|
|
position: "absolute",
|
|
|
|
|
top: 0,
|
|
|
|
|
right: 0,
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
}}
|
|
|
|
|
mx={1}
|
|
|
|
|
>
|
|
|
|
|
{controls}
|
2020-04-20 11:56:56 +10:00
|
|
|
</Flex>
|
2020-04-27 17:29:46 +10:00
|
|
|
{getToolSettings()}
|
2020-09-06 15:18:05 +10:00
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
position: "absolute",
|
2020-09-08 12:34:03 +10:00
|
|
|
right: "4px",
|
2020-09-06 15:18:05 +10:00
|
|
|
bottom: 0,
|
|
|
|
|
backgroundColor: "overlay",
|
|
|
|
|
borderRadius: "50%",
|
|
|
|
|
}}
|
|
|
|
|
m={2}
|
|
|
|
|
>
|
|
|
|
|
<IconButton
|
|
|
|
|
onClick={() => setFullScreen(!fullScreen)}
|
|
|
|
|
aria-label={fullScreen ? "Exit Full Screen" : "Enter Full Screen"}
|
|
|
|
|
title={fullScreen ? "Exit Full Screen" : "Enter Full Screen"}
|
|
|
|
|
>
|
|
|
|
|
{fullScreen ? <FullScreenExitIcon /> : <FullScreenIcon />}
|
|
|
|
|
</IconButton>
|
|
|
|
|
</Box>
|
2020-04-20 11:56:56 +10:00
|
|
|
</>
|
2020-04-18 23:31:40 +10:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 17:29:46 +10:00
|
|
|
export default MapContols;
|