diff --git a/frontend/react/src/constants/constants.ts b/frontend/react/src/constants/constants.ts index 9d97ac45..a01141bb 100644 --- a/frontend/react/src/constants/constants.ts +++ b/frontend/react/src/constants/constants.ts @@ -259,6 +259,10 @@ export const NO_SUBSTATE = "No substate"; export enum UnitControlSubState { NO_SUBSTATE = "No substate", FORMATION = "Formation", + PROTECTION = "Protection", + MAP_CONTEXT_MENU = "Map context menu", + UNIT_CONTEXT_MENU = "Unit context menu", + UNIT_EXPLOSION_MENU = "Unit explosion menu" } export enum DrawSubState { diff --git a/frontend/react/src/map/map.ts b/frontend/react/src/map/map.ts index b20e14b3..5ee02085 100644 --- a/frontend/react/src/map/map.ts +++ b/frontend/react/src/map/map.ts @@ -19,6 +19,7 @@ import { SpawnSubState, DrawSubState, JTACSubState, + UnitControlSubState, } from "../constants/constants"; import { CoalitionPolygon } from "./coalitionarea/coalitionpolygon"; import { MapHiddenTypes, MapOptions } from "../types/types"; @@ -354,12 +355,12 @@ export class Map extends L.Map { setContextActionSet(contextActionSet: ContextActionSet | null) { this.#contextActionSet = contextActionSet; - ContextActionSetChangedEvent.dispatch(this.#contextActionSet) + ContextActionSetChangedEvent.dispatch(this.#contextActionSet); } setContextAction(contextAction: ContextAction | null) { this.#contextAction = contextAction; - ContextActionChangedEvent.dispatch(this.#contextAction) + ContextActionChangedEvent.dispatch(this.#contextAction); } getCurrentControls() { @@ -571,8 +572,10 @@ export class Map extends L.Map { } deselectAllCoalitionAreas() { - CoalitionAreaSelectedEvent.dispatch(null); - this.#coalitionAreas.forEach((coalitionArea: CoalitionPolygon | CoalitionCircle) => coalitionArea.setSelected(false)); + if (this.getSelectedCoalitionArea() !== null) { + CoalitionAreaSelectedEvent.dispatch(null); + this.#coalitionAreas.forEach((coalitionArea: CoalitionPolygon | CoalitionCircle) => coalitionArea.setSelected(false)); + } } deleteCoalitionArea(coalitionArea: CoalitionPolygon | CoalitionCircle) { @@ -915,9 +918,6 @@ export class Map extends L.Map { console.log(`Short press at ${pressLocation}`); - document.dispatchEvent(new CustomEvent("hideMapContextMenu")); - document.dispatchEvent(new CustomEvent("hideUnitContextMenu")); - /* Execute the short click action */ if (getApp().getState() === OlympusState.IDLE) { /* Do nothing */ @@ -1040,7 +1040,7 @@ export class Map extends L.Map { else document.dispatchEvent(new CustomEvent("forceboxselect", { detail: e.originalEvent })); } else if (getApp().getState() === OlympusState.UNIT_CONTROL) { if (e.originalEvent.button === 2) { - document.dispatchEvent(new CustomEvent("showMapContextMenu", { detail: e })); // TODP + getApp().setState(OlympusState.UNIT_CONTROL, UnitControlSubState.MAP_CONTEXT_MENU); } else { if (e.type === "touchstart") document.dispatchEvent(new CustomEvent("forceboxselect", { detail: e })); else document.dispatchEvent(new CustomEvent("forceboxselect", { detail: e.originalEvent })); diff --git a/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx b/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx index b5394a2a..90ebd904 100644 --- a/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx +++ b/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx @@ -1,17 +1,17 @@ import React, { useEffect, useRef, useState } from "react"; import { Unit } from "../../unit/unit"; -import { ContextActionSet } from "../../unit/contextactionset"; -import { getApp } from "../../olympusapp"; import { ContextAction } from "../../unit/contextaction"; -import { CONTEXT_ACTION_COLORS } from "../../constants/constants"; +import { CONTEXT_ACTION_COLORS, NO_SUBSTATE, OlympusState, OlympusSubState, UnitControlSubState } from "../../constants/constants"; import { OlDropdownItem } from "../components/oldropdown"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { LatLng } from "leaflet"; -import { SelectionClearedEvent } from "../../events"; +import { AppStateChangedEvent, ContextActionChangedEvent, ContextActionSetChangedEvent, SelectionClearedEvent } from "../../events"; +import { ContextActionSet } from "../../unit/contextactionset"; export function MapContextMenu(props: {}) { - const [open, setOpen] = useState(false); - const [contextActionsSet, setContextActionsSet] = useState(new ContextActionSet()); + const [appState, setAppState] = useState(OlympusState.NOT_INITIALIZED); + const [appSubState, setAppSubState] = useState(NO_SUBSTATE as OlympusSubState); + const [contextActionSet, setContextActionsSet] = useState(null as ContextActionSet | null); const [xPosition, setXPosition] = useState(0); const [yPosition, setYPosition] = useState(0); const [latLng, setLatLng] = useState(null as null | LatLng); @@ -19,6 +19,16 @@ export function MapContextMenu(props: {}) { var contentRef = useRef(null); + // TODO show at correct position + + useEffect(() => { + AppStateChangedEvent.on((state, subState) => { + setAppState(state); + setAppSubState(subState); + }); + ContextActionSetChangedEvent.on((contextActionSet) => setContextActionsSet(contextActionSet)); + }, []); + useEffect(() => { if (contentRef.current) { const content = contentRef.current as HTMLDivElement; @@ -40,69 +50,18 @@ export function MapContextMenu(props: {}) { } }); - useEffect(() => { - document.addEventListener("showMapContextMenu", (ev: CustomEventInit) => { - setOpen(true); - - updateData(); - - setXPosition(ev.detail.originalEvent.clientX); - setYPosition(ev.detail.originalEvent.clientY); - setLatLng(ev.detail.latlng); - setUnit(null); - }); - - document.addEventListener("showUnitContextMenu", (ev: CustomEventInit) => { - setOpen(true); - - updateData(); - - setXPosition(ev.detail.originalEvent.clientX); - setYPosition(ev.detail.originalEvent.clientY); - setLatLng(null); - setUnit(ev.detail.sourceTarget); - }); - - document.addEventListener("hideMapContextMenu", (ev: CustomEventInit) => { - setOpen(false); - }); - - document.addEventListener("hideUnitContextMenu", (ev: CustomEventInit) => { - setOpen(false); - }); - - SelectionClearedEvent.on(() => { - setOpen(false); - }); - }, []); - - /* Update the current values of the shown data */ - function updateData() { - var newContextActionSet = new ContextActionSet(); - - getApp() - .getUnitsManager() - .getSelectedUnits() - .filter((unit) => !unit.getHuman()) - .forEach((unit: Unit) => { - unit.appendContextActions(newContextActionSet); - }); - - setContextActionsSet(newContextActionSet); - return newContextActionSet; - } - let reorderedActions: ContextAction[] = []; CONTEXT_ACTION_COLORS.forEach((color) => { - Object.values(contextActionsSet.getContextActions()).forEach((contextAction: ContextAction) => { - if (color === null && contextAction.getOptions().buttonColor === undefined) reorderedActions.push(contextAction); - else if (color === contextAction.getOptions().buttonColor) reorderedActions.push(contextAction); - }); + if (contextActionSet) + Object.values(contextActionSet.getContextActions()).forEach((contextAction: ContextAction) => { + if (color === null && contextAction.getOptions().buttonColor === undefined) reorderedActions.push(contextAction); + else if (color === contextAction.getOptions().buttonColor) reorderedActions.push(contextAction); + }); }); return ( <> - {open && ( + {appState === OlympusState.UNIT_CONTROL && appSubState === UnitControlSubState.UNIT_CONTEXT_MENU && ( <>
- {Object.values(contextActionsSet.getContextActions(latLng ? "position" : "unit")).map((contextAction) => { - const colorString = contextAction.getOptions().buttonColor - ? ` + {contextActionSet && + Object.values(contextActionSet.getContextActions(latLng ? "position" : "unit")).map((contextActionIt) => { + const colorString = contextActionIt.getOptions().buttonColor + ? ` border-2 - border-${contextAction.getOptions().buttonColor}-500 + border-${contextActionIt.getOptions().buttonColor}-500 ` - : ""; + : ""; return ( { - if (contextAction.getOptions().executeImmediately) { - contextAction.executeCallback(null, null); + if (contextActionIt.getOptions().executeImmediately) { + contextActionIt.executeCallback(null, null); } else { if (latLng !== null) { - contextAction.executeCallback(null, latLng); - setOpen(false); + contextActionIt.executeCallback(null, latLng); } else if (unit !== null) { - contextAction.executeCallback(unit, null); - setOpen(false); + contextActionIt.executeCallback(unit, null); } } + }} - > - -
{contextAction.getLabel()}
-
- ); - })} + > + +
{contextActionIt.getLabel()}
+ + ); + })}
diff --git a/frontend/react/src/ui/modals/protectionprompt.tsx b/frontend/react/src/ui/modals/protectionprompt.tsx index 83fe2986..c0ee3515 100644 --- a/frontend/react/src/ui/modals/protectionprompt.tsx +++ b/frontend/react/src/ui/modals/protectionprompt.tsx @@ -4,8 +4,10 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faArrowRight } from "@fortawesome/free-solid-svg-icons"; import { Unit } from "../../unit/unit"; import { FaLock } from "react-icons/fa6"; +import { getApp } from "../../olympusapp"; +import { OlympusState } from "../../constants/constants"; -export function ProtectionPrompt(props: {onContinue: () => void, onBack: () => void }) { +export function ProtectionPrompt(props: { }) { return ( void, onBack: () => v