diff --git a/frontend/react/src/constants/constants.ts b/frontend/react/src/constants/constants.ts
index c8bb298d..b5f7117c 100644
--- a/frontend/react/src/constants/constants.ts
+++ b/frontend/react/src/constants/constants.ts
@@ -259,7 +259,11 @@ export const NO_SUBSTATE = "No substate";
export enum UnitControlSubState {
NO_SUBSTATE = "No substate",
- FORMATION = "Formation"
+ 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/events.ts b/frontend/react/src/events.ts
index f5409271..af8753d4 100644
--- a/frontend/react/src/events.ts
+++ b/frontend/react/src/events.ts
@@ -48,8 +48,8 @@ export class AppStateChangedEvent {
static dispatch(state: OlympusState, subState: OlympusSubState) {
const detail = { state, subState };
document.dispatchEvent(new CustomEvent(this.name, { detail }));
- console.log(`Event ${this.name} dispatched with detail:`);
- console.log(detail);
+ console.log(`Event ${this.name} dispatched`);
+ console.log(`State: ${state} Substate: ${subState}`);
}
}
@@ -160,26 +160,26 @@ export class ContactsUpdatedEvent {
}
export class ContextActionSetChangedEvent {
- static on(callback: (contextActionSet: ContextActionSet) => void) {
+ static on(callback: (contextActionSet: ContextActionSet | null) => void) {
document.addEventListener(this.name, (ev: CustomEventInit) => {
callback(ev.detail.contextActionSet);
});
}
- static dispatch(contextActionSet: ContextActionSet) {
+ static dispatch(contextActionSet: ContextActionSet | null) {
document.dispatchEvent(new CustomEvent(this.name, {detail: {contextActionSet}}));
console.log(`Event ${this.name} dispatched`);
}
}
export class ContextActionChangedEvent {
- static on(callback: (contextAction: ContextAction) => void) {
+ static on(callback: (contextAction: ContextAction | null) => void) {
document.addEventListener(this.name, (ev: CustomEventInit) => {
- callback(ev.detail.contextActionSet);
+ callback(ev.detail.contextAction);
});
}
- static dispatch(contextAction: ContextAction) {
+ static dispatch(contextAction: ContextAction | null) {
document.dispatchEvent(new CustomEvent(this.name, {detail: {contextAction}}));
console.log(`Event ${this.name} dispatched`);
}
diff --git a/frontend/react/src/map/map.ts b/frontend/react/src/map/map.ts
index cd9d00ad..ccaf3dc2 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";
@@ -37,7 +38,16 @@ import { faDrawPolygon, faHandPointer, faJetFighter, faMap } from "@fortawesome/
import { ExplosionMarker } from "./markers/explosionmarker";
import { TextMarker } from "./markers/textmarker";
import { TargetMarker } from "./markers/targetmarker";
-import { AppStateChangedEvent, CoalitionAreaSelectedEvent, ConfigLoadedEvent, HiddenTypesChangedEvent, MapOptionsChangedEvent, MapSourceChangedEvent } from "../events";
+import {
+ AppStateChangedEvent,
+ CoalitionAreaSelectedEvent,
+ ConfigLoadedEvent,
+ ContextActionChangedEvent,
+ ContextActionSetChangedEvent,
+ HiddenTypesChangedEvent,
+ MapOptionsChangedEvent,
+ MapSourceChangedEvent,
+} from "../events";
import { ContextActionSet } from "../unit/contextactionset";
/* Register the handler for the box selection */
@@ -349,10 +359,12 @@ export class Map extends L.Map {
setContextActionSet(contextActionSet: ContextActionSet | null) {
this.#contextActionSet = contextActionSet;
+ ContextActionSetChangedEvent.dispatch(contextActionSet);
}
setContextAction(contextAction: ContextAction | null) {
this.#contextAction = contextAction;
+ ContextActionChangedEvent.dispatch(contextAction);
}
#onStateChanged(state: OlympusState, subState: OlympusSubState) {
@@ -614,8 +626,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) {
@@ -916,9 +930,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 */
@@ -1041,7 +1052,7 @@ export class Map extends L.Map {
else document.dispatchEvent(new CustomEvent("mapForceBoxSelect", { detail: e.originalEvent }));
} else if (getApp().getState() === OlympusState.UNIT_CONTROL) {
if (e.originalEvent.button === 2) {
- document.dispatchEvent(new CustomEvent("showMapContextMenu", { detail: e }));
+ getApp().setState(OlympusState.UNIT_CONTROL, UnitControlSubState.MAP_CONTEXT_MENU);
} else {
if (e.type === "touchstart") document.dispatchEvent(new CustomEvent("mapForceBoxSelect", { detail: e }));
else document.dispatchEvent(new CustomEvent("mapForceBoxSelect", { detail: e.originalEvent }));
diff --git a/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx b/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx
index 351571a4..53e6e81d 100644
--- a/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx
+++ b/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx
@@ -1,18 +1,18 @@
-import React, { useEffect, useRef, useState } from "react";
+import React, { useContext, 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, OlympusState, UnitControlSubState } from "../../constants/constants";
import { OlDropdownItem } from "../components/oldropdown";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { LatLng } from "leaflet";
import { SelectionClearedEvent } from "../../events";
+import { StateContext } from "../../statecontext";
export function MapContextMenu(props: {}) {
- const [open, setOpen] = useState(false);
- const [contextActionsSet, setContextActionsSet] = useState(new ContextActionSet());
- const [activeContextAction, setActiveContextAction] = useState(null as null | ContextAction);
+ const appState = useContext(StateContext);
+
const [xPosition, setXPosition] = useState(0);
const [yPosition, setYPosition] = useState(0);
const [latLng, setLatLng] = useState(null as null | LatLng);
@@ -41,69 +41,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 (appState.contextActionSet)
+ Object.values(appState.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.appState === OlympusState.UNIT_CONTROL && appState.appSubState === UnitControlSubState.UNIT_CONTEXT_MENU && (
<>
- {Object.values(contextActionsSet.getContextActions(latLng ? "position" : "unit")).map((contextAction) => {
- const colorString = contextAction.getOptions().buttonColor
- ? `
+ {appState.contextActionSet &&
+ Object.values(appState.contextActionSet.getContextActions(latLng ? "position" : "unit")).map((contextAction) => {
+ const colorString = contextAction.getOptions().buttonColor
+ ? `
border-2
border-${contextAction.getOptions().buttonColor}-500
`
- : "";
- return (
-
{
- if (contextAction.getOptions().executeImmediately) {
- contextAction.executeCallback(null, null);
- } else {
- if (latLng !== null) {
- contextAction.executeCallback(null, latLng);
- setOpen(false);
- } else if (unit !== null) {
- contextAction.executeCallback(unit, null);
- setOpen(false);
+ : "";
+ return (
+ {
+ if (contextAction.getOptions().executeImmediately) {
+ contextAction.executeCallback(null, null);
+ } else {
+ if (latLng !== null) {
+ contextAction.executeCallback(null, latLng);
+
+ } else if (unit !== null) {
+ contextAction.executeCallback(unit, null);
+ }
}
- }
- }}
- >
-
- {contextAction.getLabel()}
-
- );
- })}
+ }}
+ >
+
+ {contextAction.getLabel()}
+
+ );
+ })}
>
diff --git a/frontend/react/src/ui/modals/protectionprompt.tsx b/frontend/react/src/ui/modals/protectionprompt.tsx
index 69002077..83fe2986 100644
--- a/frontend/react/src/ui/modals/protectionprompt.tsx
+++ b/frontend/react/src/ui/modals/protectionprompt.tsx
@@ -5,7 +5,7 @@ import { faArrowRight } from "@fortawesome/free-solid-svg-icons";
import { Unit } from "../../unit/unit";
import { FaLock } from "react-icons/fa6";
-export function ProtectionPrompt(props: {onContinue: (units: Unit[]) => void, onBack: () => void, units: Unit[] }) {
+export function ProtectionPrompt(props: {onContinue: () => void, onBack: () => void }) {
return (
void, on