mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Readded context menus
This commit is contained in:
@@ -6,7 +6,7 @@ import { OlTooltip } from "./oltooltip";
|
||||
|
||||
export function OlStateButton(props: {
|
||||
className?: string;
|
||||
borderColor?: string | null;
|
||||
buttonColor?: string | null;
|
||||
checked: boolean;
|
||||
icon: IconProp;
|
||||
tooltip: string;
|
||||
@@ -21,10 +21,13 @@ export function OlStateButton(props: {
|
||||
`
|
||||
h-[40px] w-[40px] flex-none rounded-md text-lg font-medium
|
||||
dark:bg-olympus-600 dark:text-gray-300 dark:hover:bg-olympus-300
|
||||
dark:data-[checked='true']:bg-blue-500
|
||||
dark:data-[checked='true']:text-white
|
||||
`;
|
||||
|
||||
let textColor = "white";
|
||||
if (props.checked && props.buttonColor == "white") {
|
||||
textColor = "#243141"
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
@@ -37,7 +40,8 @@ export function OlStateButton(props: {
|
||||
type="button"
|
||||
className={className}
|
||||
style={{
|
||||
border: props.borderColor ? "2px solid " + props.borderColor : "0px solid transparent"
|
||||
border: props.buttonColor ? "2px solid " + props.buttonColor : "0px solid transparent",
|
||||
background: props.checked ? (props.buttonColor? props.buttonColor: "#3b82f6"): "#243141",
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
setHover(true);
|
||||
@@ -47,7 +51,7 @@ export function OlStateButton(props: {
|
||||
}}
|
||||
>
|
||||
<div className="m-auto flex w-fit content-center justify-center gap-2">
|
||||
<FontAwesomeIcon icon={props.icon} className="m-auto" />
|
||||
<FontAwesomeIcon icon={props.icon} className="m-auto" style={{color: textColor}} />
|
||||
{props.children}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -5,13 +5,21 @@ import { CONTEXT_ACTION_COLORS, NO_SUBSTATE, OlympusState, OlympusSubState, Unit
|
||||
import { OlDropdownItem } from "../components/oldropdown";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { LatLng } from "leaflet";
|
||||
import { AppStateChangedEvent, ContextActionChangedEvent, ContextActionSetChangedEvent, SelectionClearedEvent } from "../../events";
|
||||
import {
|
||||
AppStateChangedEvent,
|
||||
ContextActionChangedEvent,
|
||||
ContextActionSetChangedEvent,
|
||||
MapContextMenuRequestEvent,
|
||||
SelectionClearedEvent,
|
||||
UnitContextMenuRequestEvent,
|
||||
} from "../../events";
|
||||
import { ContextActionSet } from "../../unit/contextactionset";
|
||||
import { getApp } from "../../olympusapp";
|
||||
|
||||
export function MapContextMenu(props: {}) {
|
||||
const [appState, setAppState] = useState(OlympusState.NOT_INITIALIZED);
|
||||
const [appSubState, setAppSubState] = useState(NO_SUBSTATE as OlympusSubState);
|
||||
const [contextActionSet, setContextActionsSet] = useState(null as ContextActionSet | null);
|
||||
const [contextActionSet, setcontextActionSet] = useState(null as ContextActionSet | null);
|
||||
const [xPosition, setXPosition] = useState(0);
|
||||
const [yPosition, setYPosition] = useState(0);
|
||||
const [latLng, setLatLng] = useState(null as null | LatLng);
|
||||
@@ -19,14 +27,24 @@ 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));
|
||||
ContextActionSetChangedEvent.on((contextActionSet) => setcontextActionSet(contextActionSet));
|
||||
MapContextMenuRequestEvent.on((latlng) => {
|
||||
setLatLng(latlng);
|
||||
const containerPoint = getApp().getMap().latLngToContainerPoint(latlng);
|
||||
setXPosition(getApp().getMap().getContainer().offsetLeft + containerPoint.x);
|
||||
setYPosition(getApp().getMap().getContainer().offsetTop + containerPoint.y);
|
||||
});
|
||||
UnitContextMenuRequestEvent.on((unit) => {
|
||||
setUnit(unit);
|
||||
const containerPoint = getApp().getMap().latLngToContainerPoint(unit.getPosition());
|
||||
setXPosition(getApp().getMap().getContainer().offsetLeft + containerPoint.x);
|
||||
setYPosition(getApp().getMap().getContainer().offsetTop + containerPoint.y);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -50,64 +68,63 @@ export function MapContextMenu(props: {}) {
|
||||
}
|
||||
});
|
||||
|
||||
let reorderedActions: ContextAction[] = [];
|
||||
CONTEXT_ACTION_COLORS.forEach((color) => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
let reorderedActions: ContextAction[] = contextActionSet
|
||||
? Object.values(contextActionSet.getContextActions(appSubState === UnitControlSubState.MAP_CONTEXT_MENU ? "position" : "unit")).sort(
|
||||
(a: ContextAction, b: ContextAction) => (a.getOptions().type < b.getOptions().type ? -1 : 1)
|
||||
)
|
||||
: [];
|
||||
|
||||
return (
|
||||
<>
|
||||
{appState === OlympusState.UNIT_CONTROL && appSubState === UnitControlSubState.UNIT_CONTEXT_MENU && (
|
||||
<>
|
||||
<div
|
||||
ref={contentRef}
|
||||
className={`absolute flex min-w-80 gap-2 rounded-md bg-olympus-600`}
|
||||
>
|
||||
{appState === OlympusState.UNIT_CONTROL &&
|
||||
(appSubState === UnitControlSubState.MAP_CONTEXT_MENU || appSubState === UnitControlSubState.UNIT_CONTEXT_MENU) && (
|
||||
<>
|
||||
<div
|
||||
ref={contentRef}
|
||||
className={`
|
||||
flex w-full flex-col gap-2 overflow-x-auto no-scrollbar p-2
|
||||
`}
|
||||
absolute flex min-w-80 gap-2 rounded-md bg-olympus-600
|
||||
`}
|
||||
>
|
||||
{contextActionSet &&
|
||||
Object.values(contextActionSet.getContextActions(latLng ? "position" : "unit")).map((contextActionIt) => {
|
||||
const colorString = contextActionIt.getOptions().buttonColor
|
||||
? `
|
||||
<div
|
||||
className={`
|
||||
flex w-full flex-col gap-2 overflow-x-auto no-scrollbar p-2
|
||||
`}
|
||||
>
|
||||
{contextActionSet &&
|
||||
reorderedActions.map((contextActionIt) => {
|
||||
const colorString = `
|
||||
border-2
|
||||
border-${contextActionIt.getOptions().buttonColor}-500
|
||||
`
|
||||
: "";
|
||||
return (
|
||||
<OlDropdownItem
|
||||
className={`
|
||||
flex w-full content-center gap-2 text-white
|
||||
${colorString}
|
||||
`}
|
||||
onClick={() => {
|
||||
if (contextActionIt.getOptions().executeImmediately) {
|
||||
contextActionIt.executeCallback(null, null);
|
||||
} else {
|
||||
if (latLng !== null) {
|
||||
contextActionIt.executeCallback(null, latLng);
|
||||
} else if (unit !== null) {
|
||||
contextActionIt.executeCallback(unit, null);
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon className="my-auto" icon={contextActionIt.getIcon()} />
|
||||
<div>{contextActionIt.getLabel()}</div>
|
||||
</OlDropdownItem>
|
||||
);
|
||||
})}
|
||||
border-${CONTEXT_ACTION_COLORS[contextActionIt.getOptions().type]}-500
|
||||
`;
|
||||
|
||||
return (
|
||||
<OlDropdownItem
|
||||
className={`
|
||||
flex w-full content-center gap-2 text-white
|
||||
${colorString}
|
||||
`}
|
||||
onClick={() => {
|
||||
if (contextActionIt.getOptions().executeImmediately) {
|
||||
contextActionIt.executeCallback(null, null);
|
||||
} else {
|
||||
if (appSubState === UnitControlSubState.MAP_CONTEXT_MENU ) {
|
||||
contextActionIt.executeCallback(null, latLng);
|
||||
} else if (unit !== null) {
|
||||
contextActionIt.executeCallback(unit, null);
|
||||
}
|
||||
}
|
||||
getApp().setState(OlympusState.UNIT_CONTROL)
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon className="my-auto" icon={contextActionIt.getIcon()} />
|
||||
<div>{contextActionIt.getLabel()}</div>
|
||||
</OlDropdownItem>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,9 @@ import { OlAccordion } from "../components/olaccordion";
|
||||
import { OlUnitListEntry } from "../components/olunitlistentry";
|
||||
import { olButtonsVisibilityAircraft, olButtonsVisibilityHelicopter } from "../components/olicons";
|
||||
import { UnitSpawnMenu } from "./unitspawnmenu";
|
||||
import { AirbaseSelectedEvent, UnitDatabaseLoadedEvent } from "../../events";
|
||||
import { AirbaseSelectedEvent, CommandModeOptionsChangedEvent, UnitDatabaseLoadedEvent } from "../../events";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { BLUE_COMMANDER, COMMAND_MODE_OPTIONS_DEFAULTS, GAME_MASTER, RED_COMMANDER } from "../../constants/constants";
|
||||
|
||||
enum CategoryAccordion {
|
||||
NONE,
|
||||
@@ -27,6 +28,8 @@ export function AirbaseMenu(props: { open: boolean; onClose: () => void; childre
|
||||
const [blueprints, setBlueprints] = useState([] as UnitBlueprint[]);
|
||||
const [roles, setRoles] = useState({ aircraft: [] as string[], helicopter: [] as string[] });
|
||||
const [openAccordion, setOpenAccordion] = useState(CategoryAccordion.NONE);
|
||||
const [commandModeOptions, setCommandModeOptions] = useState(COMMAND_MODE_OPTIONS_DEFAULTS);
|
||||
const [showCost, setShowCost] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
AirbaseSelectedEvent.on((airbase) => {
|
||||
@@ -45,6 +48,12 @@ export function AirbaseMenu(props: { open: boolean; onClose: () => void; childre
|
||||
.getRoles((unit) => unit.category === "helicopter"),
|
||||
});
|
||||
});
|
||||
|
||||
CommandModeOptionsChangedEvent.on((commandModeOptions) => {
|
||||
setCommandModeOptions(commandModeOptions);
|
||||
setShowCost(!(commandModeOptions.commandMode === GAME_MASTER || !commandModeOptions.restrictSpawns));
|
||||
setOpenAccordion(CategoryAccordion.NONE);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -132,112 +141,137 @@ export function AirbaseMenu(props: { open: boolean; onClose: () => void; childre
|
||||
</div>
|
||||
</OlAccordion>
|
||||
</div>
|
||||
<div className="mt-5 flex gap-2 px-5 text-white bold">
|
||||
{blueprint && (
|
||||
<FaArrowLeft
|
||||
className={`
|
||||
my-auto h-8 w-8 cursor-pointer rounded-md p-2
|
||||
dark:text-gray-500 dark:hover:bg-gray-700 dark:hover:text-white
|
||||
`}
|
||||
onClick={() => setBlueprint(null)}
|
||||
/>
|
||||
)}
|
||||
<span className="my-auto">Spawn units at airbase</span>
|
||||
</div>
|
||||
{blueprint === null && (
|
||||
<div className="p-5">
|
||||
<OlSearchBar onChange={(value) => setFilterString(value)} text={filterString} />
|
||||
<OlAccordion
|
||||
title={`Aircraft`}
|
||||
open={openAccordion == CategoryAccordion.AIRCRAFT}
|
||||
onClick={() => {
|
||||
setOpenAccordion(openAccordion === CategoryAccordion.AIRCRAFT ? CategoryAccordion.NONE : CategoryAccordion.AIRCRAFT);
|
||||
setSelectedRole(null);
|
||||
}}
|
||||
>
|
||||
<div className="mb-2 flex flex-wrap gap-1">
|
||||
{roles.aircraft.sort().map((role) => {
|
||||
return (
|
||||
<div
|
||||
key={role}
|
||||
data-selected={selectedRole === role}
|
||||
className={`
|
||||
cursor-pointer rounded-full bg-olympus-800 px-2 py-0.5
|
||||
text-xs font-bold text-olympus-50
|
||||
data-[selected='true']:bg-blue-500
|
||||
data-[selected='true']:text-gray-200
|
||||
`}
|
||||
onClick={() => {
|
||||
selectedRole === role ? setSelectedRole(null) : setSelectedRole(role);
|
||||
}}
|
||||
>
|
||||
{role}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{(commandModeOptions.commandMode === GAME_MASTER ||
|
||||
(commandModeOptions.commandMode === BLUE_COMMANDER && airbase?.getCoalition() === "blue") ||
|
||||
(commandModeOptions.commandMode === RED_COMMANDER && airbase?.getCoalition() === "red")) && (
|
||||
<>
|
||||
<div className="mt-5 flex gap-2 px-5 text-white bold">
|
||||
{blueprint && (
|
||||
<FaArrowLeft
|
||||
className={`
|
||||
my-auto h-8 w-8 cursor-pointer rounded-md p-2
|
||||
dark:text-gray-500 dark:hover:bg-gray-700
|
||||
dark:hover:text-white
|
||||
`}
|
||||
onClick={() => setBlueprint(null)}
|
||||
/>
|
||||
)}
|
||||
<span className="my-auto">Spawn units at airbase</span>
|
||||
</div>
|
||||
{blueprint === null && (
|
||||
<div className="p-5">
|
||||
<OlSearchBar onChange={(value) => setFilterString(value)} text={filterString} />
|
||||
<OlAccordion
|
||||
title={`Aircraft`}
|
||||
open={openAccordion == CategoryAccordion.AIRCRAFT}
|
||||
onClick={() => {
|
||||
setOpenAccordion(openAccordion === CategoryAccordion.AIRCRAFT ? CategoryAccordion.NONE : CategoryAccordion.AIRCRAFT);
|
||||
setSelectedRole(null);
|
||||
}}
|
||||
>
|
||||
<div className="mb-2 flex flex-wrap gap-1">
|
||||
{roles.aircraft.sort().map((role) => {
|
||||
return (
|
||||
<div
|
||||
key={role}
|
||||
data-selected={selectedRole === role}
|
||||
className={`
|
||||
cursor-pointer rounded-full bg-olympus-800 px-2
|
||||
py-0.5 text-xs font-bold text-olympus-50
|
||||
data-[selected='true']:bg-blue-500
|
||||
data-[selected='true']:text-gray-200
|
||||
`}
|
||||
onClick={() => {
|
||||
selectedRole === role ? setSelectedRole(null) : setSelectedRole(role);
|
||||
}}
|
||||
>
|
||||
{role}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
flex max-h-[450px] flex-col gap-1 overflow-y-scroll
|
||||
no-scrollbar
|
||||
`}
|
||||
>
|
||||
{filteredBlueprints
|
||||
.filter((blueprint) => blueprint.category === "aircraft")
|
||||
.map((blueprint) => {
|
||||
return (
|
||||
<OlUnitListEntry
|
||||
key={blueprint.name}
|
||||
icon={olButtonsVisibilityAircraft}
|
||||
blueprint={blueprint}
|
||||
onClick={() => setBlueprint(blueprint)}
|
||||
showCost={showCost}
|
||||
cost={getApp().getUnitsManager().getDatabase().getSpawnPointsByName(blueprint.name)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion
|
||||
title={`Helicopters`}
|
||||
open={openAccordion == CategoryAccordion.HELICOPTER}
|
||||
onClick={() => {
|
||||
setOpenAccordion(openAccordion === CategoryAccordion.HELICOPTER ? CategoryAccordion.NONE : CategoryAccordion.HELICOPTER);
|
||||
setSelectedRole(null);
|
||||
}}
|
||||
>
|
||||
<div className="mb-2 flex flex-wrap gap-1">
|
||||
{roles.helicopter.sort().map((role) => {
|
||||
return (
|
||||
<div
|
||||
key={role}
|
||||
data-selected={selectedRole === role}
|
||||
className={`
|
||||
cursor-pointer rounded-full bg-olympus-800 px-2
|
||||
py-0.5 text-xs font-bold text-olympus-50
|
||||
data-[selected='true']:bg-blue-500
|
||||
data-[selected='true']:text-gray-200
|
||||
`}
|
||||
onClick={() => {
|
||||
selectedRole === role ? setSelectedRole(null) : setSelectedRole(role);
|
||||
}}
|
||||
>
|
||||
{role}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
flex max-h-[450px] flex-col gap-1 overflow-y-scroll
|
||||
no-scrollbar
|
||||
`}
|
||||
>
|
||||
{filteredBlueprints
|
||||
.filter((blueprint) => blueprint.category === "helicopter")
|
||||
.map((blueprint) => {
|
||||
return (
|
||||
<OlUnitListEntry
|
||||
key={blueprint.name}
|
||||
icon={olButtonsVisibilityHelicopter}
|
||||
blueprint={blueprint}
|
||||
onClick={() => setBlueprint(blueprint)}
|
||||
showCost={showCost}
|
||||
cost={getApp().getUnitsManager().getDatabase().getSpawnPointsByName(blueprint.name)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
flex max-h-[450px] flex-col gap-1 overflow-y-scroll
|
||||
no-scrollbar
|
||||
`}
|
||||
>
|
||||
{filteredBlueprints
|
||||
.filter((blueprint) => blueprint.category === "aircraft")
|
||||
.map((entry) => {
|
||||
return <OlUnitListEntry key={entry.name} icon={olButtonsVisibilityAircraft} blueprint={entry} onClick={() => setBlueprint(entry)} />;
|
||||
})}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
<OlAccordion
|
||||
title={`Helicopters`}
|
||||
open={openAccordion == CategoryAccordion.HELICOPTER}
|
||||
onClick={() => {
|
||||
setOpenAccordion(openAccordion === CategoryAccordion.HELICOPTER ? CategoryAccordion.NONE : CategoryAccordion.HELICOPTER);
|
||||
setSelectedRole(null);
|
||||
}}
|
||||
>
|
||||
<div className="mb-2 flex flex-wrap gap-1">
|
||||
{roles.helicopter.sort().map((role) => {
|
||||
return (
|
||||
<div
|
||||
key={role}
|
||||
data-selected={selectedRole === role}
|
||||
className={`
|
||||
cursor-pointer rounded-full bg-olympus-800 px-2 py-0.5
|
||||
text-xs font-bold text-olympus-50
|
||||
data-[selected='true']:bg-blue-500
|
||||
data-[selected='true']:text-gray-200
|
||||
`}
|
||||
onClick={() => {
|
||||
selectedRole === role ? setSelectedRole(null) : setSelectedRole(role);
|
||||
}}
|
||||
>
|
||||
{role}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
flex max-h-[450px] flex-col gap-1 overflow-y-scroll
|
||||
no-scrollbar
|
||||
`}
|
||||
>
|
||||
{filteredBlueprints
|
||||
.filter((blueprint) => blueprint.category === "helicopter")
|
||||
.map((entry) => {
|
||||
return <OlUnitListEntry key={entry.name} icon={olButtonsVisibilityHelicopter} blueprint={entry} onClick={() => setBlueprint(entry)} />;
|
||||
})}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
</div>
|
||||
)}
|
||||
<>
|
||||
{!(blueprint === null) && (
|
||||
<UnitSpawnMenu blueprint={blueprint} spawnAtLocation={false} airbase={airbase} coalition={(airbase?.getCoalition() ?? "blue") as Coalition} />
|
||||
)}
|
||||
</>
|
||||
</>
|
||||
)}
|
||||
<>
|
||||
{!(blueprint === null) && (
|
||||
<UnitSpawnMenu blueprint={blueprint} spawnAtLocation={false} airbase={airbase} coalition={(airbase?.getCoalition() ?? "blue") as Coalition} />
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
@@ -4,19 +4,21 @@ import { OlDropdown, OlDropdownItem } from "../components/oldropdown";
|
||||
import { useDrag } from "../libs/useDrag";
|
||||
import { Unit } from "../../unit/unit";
|
||||
import { OlRangeSlider } from "../components/olrangeslider";
|
||||
import { FormationCreationRequestEvent } from "../../events";
|
||||
|
||||
export function FormationMenu(props: {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
leader: Unit | null;
|
||||
wingmen: Unit[] | null;
|
||||
children?: JSX.Element | JSX.Element[];
|
||||
}) {
|
||||
const [leader, setLeader] = useState(null as Unit | null)
|
||||
const [wingmen, setWingmen] = useState(null as Unit[] | null)
|
||||
|
||||
/* The useDrag custom hook used to handle the dragging of the units requires that the number of hooks remains unchanged.
|
||||
The units array is therefore initialized to 128 units maximum. */
|
||||
let units = Array(128).fill(null) as (Unit | null)[];
|
||||
units[0] = props.leader;
|
||||
props.wingmen?.forEach((unit, idx) => {
|
||||
units[0] = leader;
|
||||
wingmen?.forEach((unit, idx) => {
|
||||
if (idx < units.length) units[idx + 1] = unit;
|
||||
});
|
||||
|
||||
@@ -53,6 +55,13 @@ export function FormationMenu(props: {
|
||||
});
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
FormationCreationRequestEvent.on((leader, wingmen) => {
|
||||
setLeader(leader);
|
||||
setWingmen(wingmen);
|
||||
})
|
||||
})
|
||||
|
||||
/* When the formation type is changed, reset the position to the center and the position of the silhouettes depending on the aircraft */
|
||||
useEffect(() => {
|
||||
if (scrollRef.current && containerRef.current) {
|
||||
|
||||
@@ -1,132 +1,52 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { ContextActionSet } from "../../unit/contextactionset";
|
||||
import { OlStateButton } from "../components/olstatebutton";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { ContextAction } from "../../unit/contextaction";
|
||||
import { CONTEXT_ACTION_COLORS } from "../../constants/constants";
|
||||
import { FaInfoCircle } from "react-icons/fa";
|
||||
import { FaChevronLeft, FaChevronRight } from "react-icons/fa6";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { AppStateChangedEvent, ContextActionChangedEvent, InfoPopupEvent } from "../../events";
|
||||
import { OlympusState } from "../../constants/constants";
|
||||
import { AppStateChangedEvent, ContextActionChangedEvent, ContextActionSetChangedEvent } from "../../events";
|
||||
import { ContextAction } from "../../unit/contextaction";
|
||||
|
||||
export function InfoBar(props: {}) {
|
||||
const [messages, setMessages] = useState([] as string[]);
|
||||
const [appState, setAppState] = useState(OlympusState.NOT_INITIALIZED);
|
||||
const [contextActionSet, setContextActionsSet] = useState(null as ContextActionSet | null);
|
||||
const [contextAction, setContextAction] = useState(null as ContextAction | null);
|
||||
const [scrolledLeft, setScrolledLeft] = useState(true);
|
||||
const [scrolledRight, setScrolledRight] = useState(false);
|
||||
|
||||
/* Initialize the "scroll" position of the element */
|
||||
var scrollRef = useRef(null);
|
||||
useEffect(() => {
|
||||
if (scrollRef.current) onScroll(scrollRef.current);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
InfoPopupEvent.on((messages) => setMessages([...messages]));
|
||||
AppStateChangedEvent.on((state, subState) => setAppState(state));
|
||||
ContextActionSetChangedEvent.on((contextActionSet) => setContextActionsSet(contextActionSet));
|
||||
ContextActionChangedEvent.on((contextAction) => setContextAction(contextAction));
|
||||
}, []);
|
||||
|
||||
function onScroll(el) {
|
||||
const sl = el.scrollLeft;
|
||||
const sr = el.scrollWidth - el.scrollLeft - el.clientWidth;
|
||||
|
||||
sl < 1 && !scrolledLeft && setScrolledLeft(true);
|
||||
sl > 1 && scrolledLeft && setScrolledLeft(false);
|
||||
|
||||
sr < 1 && !scrolledRight && setScrolledRight(true);
|
||||
sr > 1 && scrolledRight && setScrolledRight(false);
|
||||
let topString = "";
|
||||
if (appState === OlympusState.UNIT_CONTROL) {
|
||||
if (contextAction === null) {
|
||||
topString = "top-32";
|
||||
} else {
|
||||
topString = "top-48";
|
||||
}
|
||||
} else {
|
||||
topString = "top-16";
|
||||
}
|
||||
|
||||
let reorderedActions: ContextAction[] = [];
|
||||
CONTEXT_ACTION_COLORS.forEach((color) => {
|
||||
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 (
|
||||
<>
|
||||
{appState === OlympusState.UNIT_CONTROL && contextActionSet && Object.keys(contextActionSet.getContextActions()).length > 0 && (
|
||||
<>
|
||||
<div
|
||||
className={`
|
||||
absolute left-[50%]
|
||||
${topString}
|
||||
flex w-[400px] max-w-[80%] translate-x-[calc(-50%+2rem)]
|
||||
`}
|
||||
>
|
||||
{messages.map((message, idx) => {
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
absolute left-[50%] top-16 flex max-w-[80%]
|
||||
translate-x-[calc(-50%+2rem)] gap-2 rounded-md bg-gray-200
|
||||
dark:bg-olympus-900
|
||||
absolute left-0 w-full gap-2 rounded-md bg-olympus-800/90 px-4
|
||||
py-2 text-center text-sm text-white backdrop-blur-lg
|
||||
backdrop-grayscale
|
||||
`}
|
||||
style={{ top: `${idx * 20}px` }}
|
||||
>
|
||||
{!scrolledLeft && (
|
||||
<FaChevronLeft
|
||||
className={`
|
||||
absolute left-0 h-full w-6 rounded-lg px-2 py-3.5
|
||||
text-gray-200
|
||||
dark:bg-olympus-900
|
||||
`}
|
||||
/>
|
||||
)}
|
||||
<div className="flex gap-2 overflow-x-auto no-scrollbar p-2" onScroll={(ev) => onScroll(ev.target)} ref={scrollRef}>
|
||||
{reorderedActions.map((contextActionIt: ContextAction) => {
|
||||
return (
|
||||
<OlStateButton
|
||||
key={contextActionIt.getId()}
|
||||
checked={contextActionIt === contextAction}
|
||||
icon={contextActionIt.getIcon()}
|
||||
tooltip={contextActionIt.getLabel()}
|
||||
borderColor={contextActionIt.getOptions().buttonColor}
|
||||
onClick={() => {
|
||||
if (contextActionIt.getOptions().executeImmediately) {
|
||||
contextActionIt.executeCallback(null, null);
|
||||
} else {
|
||||
contextActionIt !== contextAction ? getApp().getMap().setContextAction(contextActionIt) : getApp().getMap().setContextAction(null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{!scrolledRight && (
|
||||
<FaChevronRight
|
||||
className={`
|
||||
absolute right-0 h-full w-6 rounded-lg px-2 py-3.5
|
||||
text-gray-200
|
||||
dark:bg-olympus-900
|
||||
`}
|
||||
/>
|
||||
)}
|
||||
{message}
|
||||
</div>
|
||||
{contextAction && (
|
||||
<div
|
||||
className={`
|
||||
absolute left-[50%] top-32 flex min-w-[300px]
|
||||
translate-x-[calc(-50%+2rem)] items-center gap-2 rounded-md
|
||||
bg-gray-200 p-4
|
||||
dark:bg-olympus-800
|
||||
`}
|
||||
>
|
||||
<FaInfoCircle
|
||||
className={`
|
||||
mr-2 hidden min-w-8 text-sm text-blue-500
|
||||
md:block
|
||||
`}
|
||||
/>
|
||||
<div
|
||||
className={`
|
||||
px-2
|
||||
dark:text-gray-400
|
||||
md:border-l-[1px] md:px-5
|
||||
`}
|
||||
>
|
||||
{contextAction.getDescription()}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Menu } from "./components/menu";
|
||||
import { OlCheckbox } from "../components/olcheckbox";
|
||||
import { OlRangeSlider } from "../components/olrangeslider";
|
||||
import { OlNumberInput } from "../components/olnumberinput";
|
||||
import { MapOptions } from "../../types/types";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { MAP_OPTIONS_DEFAULTS } from "../../constants/constants";
|
||||
import { MapOptionsChangedEvent } from "../../events";
|
||||
|
||||
export function OptionsMenu(props: { open: boolean; onClose: () => void; children?: JSX.Element | JSX.Element[] }) {
|
||||
const [mapOptions, setMapOptions] = useState(MAP_OPTIONS_DEFAULTS);
|
||||
|
||||
useEffect(() => {
|
||||
MapOptionsChangedEvent.on((mapOptions) => setMapOptions({ ...mapOptions }));
|
||||
}, []);
|
||||
|
||||
export function OptionsMenu(props: { open: boolean; onClose: () => void; options: MapOptions; children?: JSX.Element | JSX.Element[] }) {
|
||||
return (
|
||||
<Menu title="User preferences" open={props.open} showBackButton={false} onClose={props.onClose}>
|
||||
<div
|
||||
@@ -22,10 +29,10 @@ export function OptionsMenu(props: { open: boolean; onClose: () => void; options
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp().getMap().setOption("showUnitLabels", !props.options.showUnitLabels);
|
||||
getApp().getMap().setOption("showUnitLabels", !mapOptions.showUnitLabels);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox checked={props.options.showUnitLabels} onChange={() => {}}></OlCheckbox>
|
||||
<OlCheckbox checked={mapOptions.showUnitLabels} onChange={() => {}}></OlCheckbox>
|
||||
<span>Show Unit Labels</span>
|
||||
<kbd
|
||||
className={`
|
||||
@@ -44,10 +51,10 @@ export function OptionsMenu(props: { open: boolean; onClose: () => void; options
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp().getMap().setOption("showUnitsEngagementRings", !props.options.showUnitsEngagementRings);
|
||||
getApp().getMap().setOption("showUnitsEngagementRings", !mapOptions.showUnitsEngagementRings);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox checked={props.options.showUnitsEngagementRings} onChange={() => {}}></OlCheckbox>
|
||||
<OlCheckbox checked={mapOptions.showUnitsEngagementRings} onChange={() => {}}></OlCheckbox>
|
||||
<span>Show Threat Rings</span>
|
||||
<kbd
|
||||
className={`
|
||||
@@ -66,10 +73,10 @@ export function OptionsMenu(props: { open: boolean; onClose: () => void; options
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp().getMap().setOption("showUnitsAcquisitionRings", !props.options.showUnitsAcquisitionRings);
|
||||
getApp().getMap().setOption("showUnitsAcquisitionRings", !mapOptions.showUnitsAcquisitionRings);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox checked={props.options.showUnitsAcquisitionRings} onChange={() => {}}></OlCheckbox>
|
||||
<OlCheckbox checked={mapOptions.showUnitsAcquisitionRings} onChange={() => {}}></OlCheckbox>
|
||||
<span>Show Detection rings</span>
|
||||
<kbd
|
||||
className={`
|
||||
@@ -88,10 +95,10 @@ export function OptionsMenu(props: { open: boolean; onClose: () => void; options
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp().getMap().setOption("showUnitTargets", !props.options.showUnitTargets);
|
||||
getApp().getMap().setOption("showUnitTargets", !mapOptions.showUnitTargets);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox checked={props.options.showUnitTargets} onChange={() => {}}></OlCheckbox>
|
||||
<OlCheckbox checked={mapOptions.showUnitTargets} onChange={() => {}}></OlCheckbox>
|
||||
<span>Show Detection lines</span>
|
||||
<kbd
|
||||
className={`
|
||||
@@ -110,10 +117,10 @@ export function OptionsMenu(props: { open: boolean; onClose: () => void; options
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp().getMap().setOption("hideUnitsShortRangeRings", !props.options.hideUnitsShortRangeRings);
|
||||
getApp().getMap().setOption("hideUnitsShortRangeRings", !mapOptions.hideUnitsShortRangeRings);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox checked={props.options.hideUnitsShortRangeRings} onChange={() => {}}></OlCheckbox>
|
||||
<OlCheckbox checked={mapOptions.hideUnitsShortRangeRings} onChange={() => {}}></OlCheckbox>
|
||||
<span>Hide Short range Rings</span>
|
||||
<kbd
|
||||
className={`
|
||||
@@ -132,10 +139,32 @@ export function OptionsMenu(props: { open: boolean; onClose: () => void; options
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp().getMap().setOption("hideGroupMembers", !props.options.hideGroupMembers);
|
||||
getApp().getMap().setOption("keepRelativePositions", !mapOptions.keepRelativePositions);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox checked={props.options.hideGroupMembers} onChange={() => {}}></OlCheckbox>
|
||||
<OlCheckbox checked={mapOptions.keepRelativePositions} onChange={() => {}}></OlCheckbox>
|
||||
<span>Keep units relative positions</span>
|
||||
<kbd
|
||||
className={`
|
||||
ml-auto rounded-lg border border-gray-200 bg-gray-100 px-2 py-1.5
|
||||
text-xs font-semibold text-gray-800
|
||||
dark:border-gray-500 dark:bg-gray-600 dark:text-gray-100
|
||||
`}
|
||||
>
|
||||
P
|
||||
</kbd>
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
group flex flex-row rounded-md justify-content cursor-pointer gap-4
|
||||
p-2
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp().getMap().setOption("hideGroupMembers", !mapOptions.hideGroupMembers);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox checked={mapOptions.hideGroupMembers} onChange={() => {}}></OlCheckbox>
|
||||
<span>Hide Group members</span>
|
||||
<kbd
|
||||
className={`
|
||||
@@ -154,10 +183,10 @@ export function OptionsMenu(props: { open: boolean; onClose: () => void; options
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp().getMap().setOption("showMinimap", !props.options.showMinimap);
|
||||
getApp().getMap().setOption("showMinimap", !mapOptions.showMinimap);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox checked={props.options.showMinimap} onChange={() => {}}></OlCheckbox>
|
||||
<OlCheckbox checked={mapOptions.showMinimap} onChange={() => {}}></OlCheckbox>
|
||||
<span>Show minimap</span>
|
||||
<kbd
|
||||
className={`
|
||||
|
||||
@@ -167,7 +167,7 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
blueprint={blueprint}
|
||||
onClick={() => setBlueprint(blueprint)}
|
||||
showCost={showCost}
|
||||
cost={blueprint.cost ?? 10}
|
||||
cost={getApp().getUnitsManager().getDatabase().getSpawnPointsByName(blueprint.name)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -219,7 +219,7 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
blueprint={blueprint}
|
||||
onClick={() => setBlueprint(blueprint)}
|
||||
showCost={showCost}
|
||||
cost={blueprint.cost ?? 10}
|
||||
cost={getApp().getUnitsManager().getDatabase().getSpawnPointsByName(blueprint.name)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -250,7 +250,7 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
blueprint={blueprint}
|
||||
onClick={() => setBlueprint(blueprint)}
|
||||
showCost={showCost}
|
||||
cost={blueprint.cost ?? 10}
|
||||
cost={getApp().getUnitsManager().getDatabase().getSpawnPointsByName(blueprint.name)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -281,7 +281,7 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
blueprint={blueprint}
|
||||
onClick={() => setBlueprint(blueprint)}
|
||||
showCost={showCost}
|
||||
cost={blueprint.cost ?? 10}
|
||||
cost={getApp().getUnitsManager().getDatabase().getSpawnPointsByName(blueprint.name)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -336,7 +336,7 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
blueprint={blueprint}
|
||||
onClick={() => setBlueprint(blueprint)}
|
||||
showCost={showCost}
|
||||
cost={blueprint.cost ?? 10}
|
||||
cost={getApp().getUnitsManager().getDatabase().getSpawnPointsByName(blueprint.name)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -388,7 +388,7 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
|
||||
blueprint={blueprint}
|
||||
onClick={() => setBlueprint(blueprint)}
|
||||
showCost={showCost}
|
||||
cost={blueprint.cost ?? 10}
|
||||
cost={getApp().getUnitsManager().getDatabase().getSpawnPointsByName(blueprint.name)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { AppStateChangedEvent, ContextActionChangedEvent, ContextActionSetChange
|
||||
|
||||
export function UnitControlBar(props: {}) {
|
||||
const [appState, setAppState] = useState(OlympusState.NOT_INITIALIZED);
|
||||
const [contextActionSet, setContextActionsSet] = useState(null as ContextActionSet | null);
|
||||
const [contextActionSet, setcontextActionSet] = useState(null as ContextActionSet | null);
|
||||
const [contextAction, setContextAction] = useState(null as ContextAction | null);
|
||||
const [scrolledLeft, setScrolledLeft] = useState(true);
|
||||
const [scrolledRight, setScrolledRight] = useState(false);
|
||||
@@ -24,7 +24,7 @@ export function UnitControlBar(props: {}) {
|
||||
|
||||
useEffect(() => {
|
||||
AppStateChangedEvent.on((state, subState) => setAppState(state));
|
||||
ContextActionSetChangedEvent.on((contextActionSet) => setContextActionsSet(contextActionSet));
|
||||
ContextActionSetChangedEvent.on((contextActionSet) => setcontextActionSet(contextActionSet));
|
||||
ContextActionChangedEvent.on((contextAction) => setContextAction(contextAction));
|
||||
}, []);
|
||||
|
||||
@@ -39,15 +39,9 @@ export function UnitControlBar(props: {}) {
|
||||
sr > 1 && scrolledRight && setScrolledRight(false);
|
||||
}
|
||||
|
||||
let reorderedActions: ContextAction[] = [];
|
||||
CONTEXT_ACTION_COLORS.forEach((color) => {
|
||||
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);
|
||||
});
|
||||
}
|
||||
});
|
||||
let reorderedActions: ContextAction[] = contextActionSet
|
||||
? Object.values(contextActionSet.getContextActions()).sort((a: ContextAction, b: ContextAction) => (a.getOptions().type < b.getOptions().type ? -1 : 1))
|
||||
: [];
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -77,7 +71,7 @@ export function UnitControlBar(props: {}) {
|
||||
checked={contextActionIt === contextAction}
|
||||
icon={contextActionIt.getIcon()}
|
||||
tooltip={contextActionIt.getLabel()}
|
||||
borderColor={contextActionIt.getOptions().buttonColor}
|
||||
buttonColor={CONTEXT_ACTION_COLORS[contextActionIt.getOptions().type ?? 0]}
|
||||
onClick={() => {
|
||||
if (contextActionIt.getOptions().executeImmediately) {
|
||||
contextActionIt.executeCallback(null, null);
|
||||
@@ -99,6 +93,7 @@ export function UnitControlBar(props: {}) {
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{/*}
|
||||
{contextAction && (
|
||||
<div
|
||||
className={`
|
||||
@@ -125,6 +120,7 @@ export function UnitControlBar(props: {}) {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{*/}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Menu } from "./components/menu";
|
||||
import { OlDropdown, OlDropdownItem } from "../components/oldropdown";
|
||||
import { Unit } from "../../unit/unit";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { UnitExplosionRequestEvent } from "../../events";
|
||||
|
||||
export function UnitExplosionMenu(props: { open: boolean; onClose: () => void; units: Unit[] | null; children?: JSX.Element | JSX.Element[] }) {
|
||||
export function UnitExplosionMenu(props: { open: boolean; onClose: () => void; children?: JSX.Element | JSX.Element[] }) {
|
||||
const [units, setUnits] = useState(null as null | Unit[])
|
||||
const [explosionType, setExplosionType] = useState("High explosive");
|
||||
|
||||
useEffect(() => {
|
||||
UnitExplosionRequestEvent.on((units) => setUnits(units))
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Menu title="Unit explosion menu" open={props.open} showBackButton={false} onClose={props.onClose}>
|
||||
<div className="flex h-full flex-col gap-4 p-4">
|
||||
@@ -26,16 +32,16 @@ export function UnitExplosionMenu(props: { open: boolean; onClose: () => void; u
|
||||
);
|
||||
})}
|
||||
</OlDropdown>
|
||||
{props.units !== null && (
|
||||
{units !== null && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (explosionType === "High explosive") {
|
||||
getApp()?.getUnitsManager().delete(true, "normal", props.units);
|
||||
getApp()?.getUnitsManager().delete(true, "normal", units);
|
||||
} else if (explosionType === "Napalm") {
|
||||
getApp()?.getUnitsManager().delete(true, "napalm", props.units);
|
||||
getApp()?.getUnitsManager().delete(true, "napalm", units);
|
||||
} else if (explosionType === "White phosphorous") {
|
||||
getApp()?.getUnitsManager().delete(true, "phosphorous", props.units);
|
||||
getApp()?.getUnitsManager().delete(true, "phosphorous", units);
|
||||
}
|
||||
props.onClose();
|
||||
}}
|
||||
|
||||
@@ -36,6 +36,7 @@ import { UnitExplosionMenu } from "./panels/unitexplosionmenu";
|
||||
import { JTACMenu } from "./panels/jtacmenu";
|
||||
import { AppStateChangedEvent, MapOptionsChangedEvent } from "../events";
|
||||
import { GameMasterMenu } from "./panels/gamemastermenu";
|
||||
import { InfoBar } from "./panels/infobar";
|
||||
|
||||
export type OlympusUIState = {
|
||||
mainMenuVisible: boolean;
|
||||
@@ -52,23 +53,16 @@ export type OlympusUIState = {
|
||||
export function UI() {
|
||||
const [appState, setAppState] = useState(OlympusState.NOT_INITIALIZED);
|
||||
const [appSubState, setAppSubState] = useState(NO_SUBSTATE as OlympusSubState);
|
||||
const [mapOptions, setMapOptions] = useState(MAP_OPTIONS_DEFAULTS);
|
||||
|
||||
|
||||
const [checkingPassword, setCheckingPassword] = useState(false);
|
||||
const [loginError, setLoginError] = useState(false);
|
||||
const [commandMode, setCommandMode] = useState(null as null | string);
|
||||
|
||||
const [formationLeader, setFormationLeader] = useState(null as null | Unit);
|
||||
const [formationWingmen, setFormationWingmen] = useState(null as null | Unit[]);
|
||||
|
||||
const [unitExplosionUnits, setUnitExplosionUnits] = useState([] as Unit[]);
|
||||
|
||||
useEffect(() => {
|
||||
AppStateChangedEvent.on((state, subState) => {
|
||||
setAppState(state);
|
||||
setAppSubState(subState);
|
||||
});
|
||||
MapOptionsChangedEvent.on((mapOptions) => setMapOptions({ ...mapOptions }));
|
||||
}, []);
|
||||
|
||||
function checkPassword(password: string) {
|
||||
@@ -142,16 +136,14 @@ export function UI() {
|
||||
<div id="map-container" className="z-0 h-full w-screen" />
|
||||
<MainMenu open={appState === OlympusState.MAIN_MENU} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<SpawnMenu open={appState === OlympusState.SPAWN} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<OptionsMenu open={appState === OlympusState.OPTIONS} onClose={() => getApp().setState(OlympusState.IDLE)} options={mapOptions} /* TODO remove */ />
|
||||
<OptionsMenu open={appState === OlympusState.OPTIONS} onClose={() => getApp().setState(OlympusState.IDLE)}/>
|
||||
|
||||
<UnitControlMenu
|
||||
open={appState === OlympusState.UNIT_CONTROL && appSubState !== UnitControlSubState.FORMATION}
|
||||
open={appState === OlympusState.UNIT_CONTROL && ![UnitControlSubState.FORMATION, UnitControlSubState.UNIT_EXPLOSION_MENU].includes(appSubState as UnitControlSubState)}
|
||||
onClose={() => getApp().setState(OlympusState.IDLE)}
|
||||
/>
|
||||
<FormationMenu
|
||||
open={appState === OlympusState.UNIT_CONTROL && appSubState === UnitControlSubState.FORMATION}
|
||||
leader={formationLeader}
|
||||
wingmen={formationWingmen}
|
||||
onClose={() => getApp().setState(OlympusState.IDLE)}
|
||||
/>
|
||||
|
||||
@@ -160,7 +152,7 @@ export function UI() {
|
||||
<AudioMenu open={appState === OlympusState.AUDIO} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<GameMasterMenu open={appState === OlympusState.GAME_MASTER} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
|
||||
{/* TODO} <UnitExplosionMenu open={appState === OlympusState.MAIN_MENU} units={unitExplosionUnits} onClose={() => getApp().setState(OlympusState.IDLE)} /> {*/}
|
||||
<UnitExplosionMenu open={appState === OlympusState.UNIT_CONTROL && appSubState === UnitControlSubState.UNIT_EXPLOSION_MENU} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<JTACMenu open={appState === OlympusState.JTAC} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
|
||||
<MiniMapPanel />
|
||||
@@ -168,6 +160,7 @@ export function UI() {
|
||||
<UnitControlBar />
|
||||
<MapContextMenu />
|
||||
<SideBar />
|
||||
<InfoBar />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user