mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Completed first iteration of drawings management on v2
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Menu } from "./components/menu";
|
||||
import { FaArrowDown, FaArrowUp, FaTrash } from "react-icons/fa";
|
||||
import { FaArrowDown, FaArrowUp, FaChevronRight, FaTrash } from "react-icons/fa";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { OlStateButton } from "../components/olstatebutton";
|
||||
import { faDrawPolygon } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faDrawPolygon, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faCircle } from "@fortawesome/free-regular-svg-icons";
|
||||
import { CoalitionPolygon } from "../../map/coalitionarea/coalitionpolygon";
|
||||
import { OlCoalitionToggle } from "../components/olcoalitiontoggle";
|
||||
@@ -13,9 +13,12 @@ import { Coalition } from "../../types/types";
|
||||
import { OlRangeSlider } from "../components/olrangeslider";
|
||||
import { CoalitionCircle } from "../../map/coalitionarea/coalitioncircle";
|
||||
import { DrawSubState, ERAS_ORDER, IADSTypes, NO_SUBSTATE, OlympusState, OlympusSubState } from "../../constants/constants";
|
||||
import { AppStateChangedEvent, CoalitionAreasChangedEvent, CoalitionAreaSelectedEvent } from "../../events";
|
||||
import { AppStateChangedEvent, CoalitionAreasChangedEvent, CoalitionAreaSelectedEvent, DrawingsInitEvent, DrawingsUpdatedEvent } from "../../events";
|
||||
import { FaXmark } from "react-icons/fa6";
|
||||
import { deepCopyTable } from "../../other/utils";
|
||||
import { DCSDrawingsContainer, DCSEmptyLayer } from "../../map/drawings/drawingsmanager";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { OlSearchBar } from "../components/olsearchbar";
|
||||
|
||||
export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
const [appState, setAppState] = useState(OlympusState.NOT_INITIALIZED);
|
||||
@@ -30,11 +33,21 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
const [erasSelection, setErasSelection] = useState({});
|
||||
const [rangesSelection, setRangesSelection] = useState({});
|
||||
|
||||
const [openContainers, setOpenContainers] = useState([] as DCSDrawingsContainer[]);
|
||||
const [mainDrawingsContainer, setDrawingsContainer] = useState({ container: null } as { container: null | DCSDrawingsContainer });
|
||||
const [searchString, setSearchString] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
AppStateChangedEvent.on((state, subState) => {
|
||||
setAppState(state);
|
||||
setAppSubState(subState);
|
||||
});
|
||||
DrawingsInitEvent.on((drawingContainer) => {
|
||||
setDrawingsContainer({ container: drawingContainer });
|
||||
});
|
||||
DrawingsUpdatedEvent.on(() => {
|
||||
setDrawingsContainer({ container: getApp().getDrawingsManager().getDrawingsContainer() });
|
||||
});
|
||||
}, []);
|
||||
|
||||
/* Get all the unique types and eras for groundunits */
|
||||
@@ -50,6 +63,85 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
CoalitionAreasChangedEvent.on((coalitionAreas) => setCoalitionAreas([...coalitionAreas]));
|
||||
}, []);
|
||||
|
||||
function renderDrawingsContainerControls(container: DCSDrawingsContainer) {
|
||||
if (container.hasSearchString(searchString)) {
|
||||
return (
|
||||
<div className="ml-2 flex flex-col gap-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex justify-between gap-2">
|
||||
<FaChevronRight
|
||||
className={`
|
||||
my-auto
|
||||
${openContainers.includes(container) && `rotate-90`}
|
||||
cursor-pointer text-gray-400 transition-transform
|
||||
`}
|
||||
onClick={() => {
|
||||
if (openContainers.includes(container)) {
|
||||
let index = openContainers.indexOf(container);
|
||||
openContainers.splice(index, 1);
|
||||
} else {
|
||||
openContainers.push(container);
|
||||
}
|
||||
setOpenContainers([...openContainers]);
|
||||
}}
|
||||
></FaChevronRight>
|
||||
<FontAwesomeIcon
|
||||
icon={container.getVisibility() ? faEye : faEyeSlash}
|
||||
className={`
|
||||
my-auto w-6 cursor-pointer text-gray-400 transition-transform
|
||||
hover:scale-125 hover:text-gray-200
|
||||
`}
|
||||
onClick={() => {
|
||||
container.setVisibility(!container.getVisibility(), true);
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className={`
|
||||
w-40 w-max-40 overflow-hidden text-ellipsis text-nowrap bg-
|
||||
`}
|
||||
>
|
||||
{container.getName()}
|
||||
</div>
|
||||
|
||||
<OlRangeSlider
|
||||
value={container.getOpacity() * 100}
|
||||
min={0}
|
||||
max={100}
|
||||
onChange={(ev) => {
|
||||
container.setOpacity(Number(ev.currentTarget.value) / 100);
|
||||
}}
|
||||
className={`my-auto ml-auto max-w-32`}
|
||||
></OlRangeSlider>
|
||||
</div>
|
||||
</div>
|
||||
{openContainers.includes(container) && container.getSubContainers().map((container) => renderDrawingsContainerControls(container))}
|
||||
{openContainers.includes(container) &&
|
||||
container.getDrawings().map((drawing) => {
|
||||
if (drawing instanceof DCSEmptyLayer) return <></>;
|
||||
return (
|
||||
<div className="ml-4 flex justify-start gap-2">
|
||||
<FontAwesomeIcon
|
||||
icon={drawing.getVisibility() ? faEye : faEyeSlash}
|
||||
className={`
|
||||
my-auto w-6 cursor-pointer text-gray-400
|
||||
transition-transform
|
||||
hover:scale-125 hover:text-gray-200
|
||||
`}
|
||||
onClick={() => {
|
||||
drawing.setVisibility(!drawing.getVisibility());
|
||||
}}
|
||||
/>
|
||||
<div className={`overflow-hidden text-ellipsis text-nowrap`}>{drawing.getName()}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return <></>;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Menu
|
||||
open={props.open}
|
||||
@@ -132,6 +224,14 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
<div className="text-sm">Add circle</div>
|
||||
</OlStateButton>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex flex-col gap-2 p-6">
|
||||
<div className="text-sm text-gray-400">Mission drawings</div>
|
||||
<OlSearchBar onChange={(search) => setSearchString(search)} text={searchString || ""}></OlSearchBar>
|
||||
<div className="flex flex-col gap-2">{mainDrawingsContainer.container && renderDrawingsContainerControls(mainDrawingsContainer.container)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { OlRoundStateButton, OlStateButton, OlLockStateButton } from "../components/olstatebutton";
|
||||
import { faSkull, faCamera, faFlag, faVolumeHigh, faDownload, faUpload } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faSkull, faCamera, faFlag, faVolumeHigh, faDownload, faUpload, faDrawPolygon } from "@fortawesome/free-solid-svg-icons";
|
||||
import { OlDropdownItem, OlDropdown } from "../components/oldropdown";
|
||||
import { OlLabelToggle } from "../components/ollabeltoggle";
|
||||
import { getApp, IP } from "../../olympusapp";
|
||||
@@ -16,8 +16,24 @@ import {
|
||||
olButtonsVisibilityOlympus,
|
||||
} from "../components/olicons";
|
||||
import { FaChevronLeft, FaChevronRight, FaFloppyDisk } from "react-icons/fa6";
|
||||
import { CommandModeOptionsChangedEvent, ConfigLoadedEvent, HiddenTypesChangedEvent, MapOptionsChangedEvent, MapSourceChangedEvent, SessionDataChangedEvent, SessionDataSavedEvent } from "../../events";
|
||||
import { BLUE_COMMANDER, COMMAND_MODE_OPTIONS_DEFAULTS, ImportExportSubstate, MAP_HIDDEN_TYPES_DEFAULTS, MAP_OPTIONS_DEFAULTS, OlympusState, RED_COMMANDER } from "../../constants/constants";
|
||||
import {
|
||||
CommandModeOptionsChangedEvent,
|
||||
ConfigLoadedEvent,
|
||||
HiddenTypesChangedEvent,
|
||||
MapOptionsChangedEvent,
|
||||
MapSourceChangedEvent,
|
||||
SessionDataChangedEvent,
|
||||
SessionDataSavedEvent,
|
||||
} from "../../events";
|
||||
import {
|
||||
BLUE_COMMANDER,
|
||||
COMMAND_MODE_OPTIONS_DEFAULTS,
|
||||
ImportExportSubstate,
|
||||
MAP_HIDDEN_TYPES_DEFAULTS,
|
||||
MAP_OPTIONS_DEFAULTS,
|
||||
OlympusState,
|
||||
RED_COMMANDER,
|
||||
} from "../../constants/constants";
|
||||
import { OlympusConfig } from "../../interfaces";
|
||||
import { FaCheck, FaSave, FaSpinner } from "react-icons/fa";
|
||||
|
||||
@@ -116,15 +132,40 @@ export function Header() {
|
||||
{IP}
|
||||
</div>
|
||||
</div>
|
||||
{savingSessionData ? <div className="text-white"><FaSpinner className={`
|
||||
animate-spin text-2xl
|
||||
`}/></div> : <div className={`relative text-white`}><FaFloppyDisk className={`
|
||||
absolute -top-3 text-2xl
|
||||
`}/><FaCheck className={`
|
||||
absolute left-[9px] top-[-6px] text-2xl text-olympus-900
|
||||
`}/><FaCheck className={`absolute left-3 top-0 text-green-500`}/></div>}
|
||||
<OlStateButton className="ml-8" icon={faDownload} onClick={() => {getApp().setState(OlympusState.IMPORT_EXPORT, ImportExportSubstate.EXPORT)}} checked={false}/>
|
||||
<OlStateButton icon={faUpload} onClick={() => {getApp().setState(OlympusState.IMPORT_EXPORT, ImportExportSubstate.IMPORT)}} checked={false}/>
|
||||
{savingSessionData ? (
|
||||
<div className="text-white">
|
||||
<FaSpinner
|
||||
className={`animate-spin text-2xl`}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className={`relative text-white`}>
|
||||
<FaFloppyDisk
|
||||
className={`absolute -top-3 text-2xl`}
|
||||
/>
|
||||
<FaCheck
|
||||
className={`
|
||||
absolute left-[9px] top-[-6px] text-2xl text-olympus-900
|
||||
`}
|
||||
/>
|
||||
<FaCheck className={`absolute left-3 top-0 text-green-500`} />
|
||||
</div>
|
||||
)}
|
||||
<OlStateButton
|
||||
className="ml-8"
|
||||
icon={faDownload}
|
||||
onClick={() => {
|
||||
getApp().setState(OlympusState.IMPORT_EXPORT, ImportExportSubstate.EXPORT);
|
||||
}}
|
||||
checked={false}
|
||||
/>
|
||||
<OlStateButton
|
||||
icon={faUpload}
|
||||
onClick={() => {
|
||||
getApp().setState(OlympusState.IMPORT_EXPORT, ImportExportSubstate.IMPORT);
|
||||
}}
|
||||
checked={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{commandModeOptions.commandMode === BLUE_COMMANDER && (
|
||||
@@ -138,6 +179,14 @@ export function Header() {
|
||||
</div>
|
||||
)}
|
||||
<div className={`flex h-fit flex-row items-center justify-start gap-1`}>
|
||||
<OlRoundStateButton
|
||||
icon={faDrawPolygon}
|
||||
checked={mapOptions.showMissionDrawings}
|
||||
onClick={() => {
|
||||
getApp().getMap().setOption("showMissionDrawings", !mapOptions.showMissionDrawings);
|
||||
}}
|
||||
tooltip="Show/Hide mission drawings"
|
||||
/>
|
||||
<OlLockStateButton
|
||||
checked={!mapOptions.protectDCSUnits}
|
||||
onClick={() => {
|
||||
|
||||
Reference in New Issue
Block a user