import React, { useCallback, useEffect, useRef, useState } from "react"; import { BLUE_COMMANDER, colors, COMMAND_MODE_OPTIONS_DEFAULTS, GAME_MASTER, NO_SUBSTATE, OlympusState, OlympusSubState } from "../../constants/constants"; import { LatLng } from "leaflet"; import { AppStateChangedEvent, CommandModeOptionsChangedEvent, SpawnContextMenuRequestEvent, StarredSpawnsChangedEvent, UnitDatabaseLoadedEvent, } from "../../events"; import { getApp } from "../../olympusapp"; import { SpawnRequestTable, UnitBlueprint } from "../../interfaces"; import { faEllipsisVertical, faExplosion, faSearch, faSmog, faStar } from "@fortawesome/free-solid-svg-icons"; import { EffectSpawnMenu } from "../panels/effectspawnmenu"; import { UnitSpawnMenu } from "../panels/unitspawnmenu"; import { OlEffectListEntry } from "../components/oleffectlistentry"; import { olButtonsVisibilityAircraft, olButtonsVisibilityGroundunit, olButtonsVisibilityGroundunitSam, olButtonsVisibilityHelicopter, olButtonsVisibilityNavyunit, olIconsApc, olIconsArtillery, olIconsEwr, olIconsInfantry, olIconsRadar, olIconsTactical, olIconsTank, olIconsTruck, } from "../components/olicons"; import { OlUnitListEntry } from "../components/olunitlistentry"; import { OlSearchBar } from "../components/olsearchbar"; import { OlStateButton } from "../components/olstatebutton"; import { OlDropdownItem } from "../components/oldropdown"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { OlCoalitionToggle } from "../components/olcoalitiontoggle"; import { Coalition } from "../../types/types"; import { spawn } from "child_process"; enum CategoryGroup { NONE, AIRCRAFT, HELICOPTER, AIR_DEFENCE, GROUND_UNIT, NAVY_UNIT, EFFECT, SEARCH, STARRED, } export function SpawnContextMenu(props: {}) { const [appState, setAppState] = useState(OlympusState.NOT_INITIALIZED); const [appSubState, setAppSubState] = useState(NO_SUBSTATE as OlympusSubState); const [xPosition, setXPosition] = useState(0); const [yPosition, setYPosition] = useState(0); const [latlng, setLatLng] = useState(null as null | LatLng); const [starredSpawns, setStarredSpawns] = useState({} as { [key: string]: SpawnRequestTable }); const [openAccordion, setOpenAccordion] = useState(CategoryGroup.NONE); const [blueprint, setBlueprint] = useState(null as null | UnitBlueprint); const [effect, setEffect] = useState(null as null | string); const [filterString, setFilterString] = useState(""); const [selectedRole, setSelectedRole] = useState(null as null | string); const [selectedType, setSelectedType] = useState(null as null | string); const [blueprints, setBlueprints] = useState([] as UnitBlueprint[]); const [roles, setRoles] = useState({ aircraft: [] as string[], helicopter: [] as string[] }); const [types, setTypes] = useState({ groundunit: [] as string[], navyunit: [] as string[] }); const [tags, setTags] = useState({ aircraft: [] as string[], helicopter: [] as string[], groundunit: [] as string[], navyunit: [] as string[] }); const [commandModeOptions, setCommandModeOptions] = useState(COMMAND_MODE_OPTIONS_DEFAULTS); const [showCost, setShowCost] = useState(false); const [spawnCoalition, setSpawnCoalition] = useState("blue" as Coalition); const [showMore, setShowMore] = useState(false); const [height, setHeight] = useState(0); const [translated, setTranslated] = useState(false); useEffect(() => { if (selectedRole) setBlueprints(getApp()?.getUnitsManager().getDatabase().getByRole(selectedRole)); else if (selectedType) setBlueprints(getApp()?.getUnitsManager().getDatabase().getByType(selectedType)); else setBlueprints(getApp()?.getUnitsManager().getDatabase().getBlueprints()); }, [selectedRole, selectedType, openAccordion]); useEffect(() => { UnitDatabaseLoadedEvent.on(() => { setRoles({ aircraft: getApp() ?.getUnitsManager() .getDatabase() .getRoles((unit) => unit.category === "aircraft"), helicopter: getApp() ?.getUnitsManager() .getDatabase() .getRoles((unit) => unit.category === "helicopter"), }); setTypes({ groundunit: getApp() ?.getUnitsManager() .getDatabase() .getTypes((unit) => unit.category === "groundunit"), navyunit: getApp() ?.getUnitsManager() .getDatabase() .getTypes((unit) => unit.category === "navyunit"), }); setTags({ aircraft: getApp() ?.getUnitsManager() .getDatabase() .getTags((unit) => unit.category === "aircraft"), helicopter: getApp() ?.getUnitsManager() .getDatabase() .getTags((unit) => unit.category === "helicopter"), groundunit: getApp() ?.getUnitsManager() .getDatabase() .getTags((unit) => unit.category === "groundunit"), navyunit: getApp() ?.getUnitsManager() .getDatabase() .getTags((unit) => unit.category === "navyunit"), }); }); CommandModeOptionsChangedEvent.on((commandModeOptions) => { setCommandModeOptions(commandModeOptions); setShowCost(!(commandModeOptions.commandMode == GAME_MASTER || !commandModeOptions.restrictSpawns)); setOpenAccordion(CategoryGroup.NONE); }); StarredSpawnsChangedEvent.on((starredSpawns) => setStarredSpawns({ ...starredSpawns })); }, []); useEffect(() => { setBlueprint(null); setEffect(null); setSelectedType(null); setSelectedRole(null); }, [openAccordion]); const translateMenu = useCallback(() => { if (blueprint && !translated) { setTranslated(true); setXPosition(xPosition + 60); setYPosition(yPosition + 40); } else if (!blueprint && translated) { setTranslated(false); setXPosition(xPosition - 60); setYPosition(yPosition - 40); } }, [blueprint, translated]); useEffect(translateMenu, [blueprint, translated]); /* Filter the blueprints according to the label */ const filteredBlueprints: UnitBlueprint[] = []; if (blueprints && filterString !== "") { blueprints.forEach((blueprint) => { if (blueprint.enabled && (filterString === "" || blueprint.label.toLowerCase().includes(filterString.toLowerCase()))) filteredBlueprints.push(blueprint); }); } var contentRef = useRef(null); useEffect(() => { AppStateChangedEvent.on((state, subState) => { setAppState(state); setAppSubState(subState); }); StarredSpawnsChangedEvent.on((starredSpawns) => setStarredSpawns({ ...starredSpawns })); SpawnContextMenuRequestEvent.on((latlng) => { setLatLng(latlng); const containerPoint = getApp().getMap().latLngToContainerPoint(latlng); setXPosition(getApp().getMap().getContainer().offsetLeft + containerPoint.x); setYPosition(getApp().getMap().getContainer().offsetTop + containerPoint.y); setTranslated(false); }); }, []); useEffect(() => { if (contentRef.current) { const content = contentRef.current as HTMLDivElement; content.style.left = `${xPosition}px`; content.style.top = `${yPosition}px`; let newXPosition = xPosition; let newYposition = yPosition; let [cxr, cyb] = [content.getBoundingClientRect().x + content.clientWidth, content.getBoundingClientRect().y + content.clientHeight]; /* Try and move the content so it is inside the screen */ if (cxr > window.innerWidth) newXPosition -= cxr - window.innerWidth; if (cyb > window.innerHeight) newYposition -= cyb - window.innerHeight; content.style.left = `${newXPosition}px`; content.style.top = `${newYposition}px`; const resizeObserver = new ResizeObserver(() => { setHeight(content.clientHeight); }); resizeObserver.observe(content); return () => resizeObserver.disconnect(); // clean up } }); // TODO fix button being moved if overflowing return ( <>