From 40df2ebb7d5dcc134d259c16e87208408859baf0 Mon Sep 17 00:00:00 2001 From: Davide Passoni Date: Fri, 12 Apr 2024 17:53:03 +0200 Subject: [PATCH] More work on unit control panel --- .../theme/images/buttons/intensity/1.svg | 52 ++- .../theme/images/buttons/intensity/2.svg | 59 ++- .../theme/images/buttons/threat/evade.svg | 62 ++-- .../theme/images/buttons/threat/manoeuvre.svg | 29 +- .../theme/images/buttons/threat/passive.svg | 55 +-- .../images/buttons/visibility/airbase.svg | 47 +-- .../buttons/visibility/groundunit-sam.svg | 96 ++--- .../images/buttons/visibility/groundunit.svg | 73 ++-- .../theme/images/buttons/visibility/human.svg | 41 +-- .../images/buttons/visibility/olympus.svg | 41 ++- .../theme/images/convertToFontAwesomIcons.py | 36 ++ .../theme/images/markers/target - Copy.svg | 101 ------ .../react/src/ui/components/olbuttongroup.tsx | 23 ++ .../src/ui/components/olcoalitiontoggle.tsx | 11 +- .../react/src/ui/components/oldropdown.tsx | 2 +- frontend/react/src/ui/components/olicons.tsx | 151 ++++++++ .../react/src/ui/components/ollabeltoggle.tsx | 8 +- .../react/src/ui/components/olrangeslider.tsx | 2 +- frontend/react/src/ui/components/oltoggle.tsx | 16 + frontend/react/src/ui/panels/header.tsx | 7 +- frontend/react/src/ui/panels/spawnmenu.tsx | 11 +- .../react/src/ui/panels/unitcontrolmenu.tsx | 339 ++++++++++++++++-- frontend/server/demo.js | 11 +- 23 files changed, 820 insertions(+), 453 deletions(-) create mode 100644 frontend/react/public/resources/theme/images/convertToFontAwesomIcons.py delete mode 100644 frontend/react/public/resources/theme/images/markers/target - Copy.svg create mode 100644 frontend/react/src/ui/components/olbuttongroup.tsx create mode 100644 frontend/react/src/ui/components/olicons.tsx create mode 100644 frontend/react/src/ui/components/oltoggle.tsx diff --git a/frontend/react/public/resources/theme/images/buttons/intensity/1.svg b/frontend/react/public/resources/theme/images/buttons/intensity/1.svg index 428226dc..7c37064b 100644 --- a/frontend/react/public/resources/theme/images/buttons/intensity/1.svg +++ b/frontend/react/public/resources/theme/images/buttons/intensity/1.svg @@ -7,7 +7,7 @@ version="1.1" id="svg4" sodipodi:docname="1.svg" - inkscape:version="1.1 (c68e22c387, 2021-05-23)" + inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" @@ -32,38 +32,30 @@ inkscape:cx="4.2536893" inkscape:cy="-1.2195892" inkscape:window-width="1920" - inkscape:window-height="1017" - inkscape:window-x="-8" + inkscape:window-height="1009" + inkscape:window-x="1912" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="svg4" inkscape:showpageshadow="2" inkscape:deskcolor="#d1d1d1" /> - - - + + + + + + diff --git a/frontend/react/public/resources/theme/images/buttons/intensity/2.svg b/frontend/react/public/resources/theme/images/buttons/intensity/2.svg index 63b73775..de29e50c 100644 --- a/frontend/react/public/resources/theme/images/buttons/intensity/2.svg +++ b/frontend/react/public/resources/theme/images/buttons/intensity/2.svg @@ -7,7 +7,7 @@ version="1.1" id="svg4" sodipodi:docname="2.svg" - inkscape:version="1.1 (c68e22c387, 2021-05-23)" + inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" @@ -32,38 +32,37 @@ inkscape:cx="4.2536893" inkscape:cy="-1.2195892" inkscape:window-width="1920" - inkscape:window-height="1017" - inkscape:window-x="-8" + inkscape:window-height="1009" + inkscape:window-x="1912" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="svg4" inkscape:showpageshadow="2" inkscape:deskcolor="#d1d1d1" /> - - - + + + + + + + + + diff --git a/frontend/react/public/resources/theme/images/buttons/threat/evade.svg b/frontend/react/public/resources/theme/images/buttons/threat/evade.svg index fb5dc6ba..a6b84625 100644 --- a/frontend/react/public/resources/theme/images/buttons/threat/evade.svg +++ b/frontend/react/public/resources/theme/images/buttons/threat/evade.svg @@ -7,13 +7,11 @@ version="1.1" id="svg12" sodipodi:docname="evade.svg" - inkscape:version="1.1 (c68e22c387, 2021-05-23)" + inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> - - + + - - + + + + + - + - + + id="path10" + style="stroke: none" /> diff --git a/frontend/react/public/resources/theme/images/buttons/threat/manoeuvre.svg b/frontend/react/public/resources/theme/images/buttons/threat/manoeuvre.svg index 81fc8534..e12c63e1 100644 --- a/frontend/react/public/resources/theme/images/buttons/threat/manoeuvre.svg +++ b/frontend/react/public/resources/theme/images/buttons/threat/manoeuvre.svg @@ -7,13 +7,11 @@ version="1.1" id="svg12" sodipodi:docname="manoeuvre.svg" - inkscape:version="1.1 (c68e22c387, 2021-05-23)" + inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> - - + + + id="path2" + style="stroke: none" /> + style="color:#000000;fill:#5ca7ff;stroke-linecap:round;stroke-dasharray:2, 2;-inkscape-stroke:none" + d="m 17.644531,0.00390625 -0.242187,0.03125 -0.253907,0.04296875 -0.255859,0.05273437 -0.255859,0.0625 -0.259766,0.0703125 -0.257812,0.078125 -0.259766,0.0859375 -0.253906,0.0917969 a 0.5,0.5 0 0 0 -0.300781,0.64062495 0.5,0.5 0 0 0 0.640625,0.3007813 l 0.242187,-0.087891 0.234375,-0.078125 0.232422,-0.070312 0.230469,-0.0625 0.224609,-0.054687 0.222656,-0.046875 0.21875,-0.035156 0.222656,-0.0292968 A 0.5,0.5 0 0 0 18.205078,0.43554688 0.5,0.5 0 0 0 17.644531,0.00390625 Z m 1.853516,0.27148438 a 0.5,0.5 0 0 0 -0.28125,0.25976562 0.5,0.5 0 0 0 0.242187,0.66406245 l 0.07422,0.033203 0.06445,0.033203 0.06445,0.035156 0.0625,0.037109 0.0625,0.039063 0.06055,0.041016 0.06055,0.042969 0.05859,0.046875 0.115234,0.091797 0.111328,0.097656 0.111328,0.099609 0.107422,0.1015625 0.105469,0.1054688 0.101563,0.1074218 0.101562,0.109375 0.101563,0.1171875 a 0.5,0.5 0 0 0 0.705078,0.050781 0.5,0.5 0 0 0 0.04883,-0.7050782 l -0.109375,-0.1269531 -0.117188,-0.1289062 -0.11914,-0.125 -0.123047,-0.1210938 -0.125,-0.1191406 -0.126953,-0.11523437 -0.13086,-0.11328125 -0.134765,-0.10937501 -0.08398,-0.0644531 -0.08594,-0.0625 -0.08789,-0.0585938 -0.08789,-0.0566406 -0.0918,-0.0527344 -0.0918,-0.0507813 -0.0918,-0.046875 -0.08789,-0.0390625 A 0.5,0.5 0 0 0 19.498047,0.27539063 Z M 14.099609,1.3496094 A 0.5,0.5 0 0 0 13.71875,1.390625 l -0.220703,0.1210937 -0.222656,0.1269532 -0.222657,0.1289062 -0.220703,0.1308594 -0.216797,0.1347656 -0.216796,0.1347657 -0.214844,0.1386718 -0.210938,0.1367188 a 0.5,0.5 0 0 0 -0.142578,0.6933594 0.5,0.5 0 0 0 0.69336,0.1425781 l 0.205078,-0.1347656 0.205078,-0.1328125 0.208984,-0.1289063 0.208985,-0.1289062 0.208984,-0.125 0.212891,-0.1230469 0.210937,-0.1210938 0.216797,-0.1171875 A 0.5,0.5 0 0 0 14.398438,1.5878906 0.5,0.5 0 0 0 14.099609,1.3496094 Z m 7.957032,1.8945312 a 0.5,0.5 0 0 0 -0.273438,0.6503907 l 0.08789,0.2167968 0.07813,0.2109375 0.07227,0.2167969 0.06445,0.2226562 0.05859,0.2265625 0.05273,0.2324219 0.04492,0.2363281 0.03711,0.2480469 a 0.5,0.5 0 0 0 0.572265,0.4179688 0.5,0.5 0 0 0 0.416016,-0.5703125 l -0.04102,-0.265625 -0.05078,-0.2695313 -0.05859,-0.2636719 -0.06641,-0.2578125 -0.07422,-0.2558593 -0.08398,-0.2480469 -0.08984,-0.2441406 -0.09375,-0.2304688 A 0.5,0.5 0 0 0 22.056641,3.2441406 Z M 10.316406,3.6347656 10.099609,3.8046875 9.8867188,3.9765625 9.6796875,4.1445312 9.4785156,4.3105469 9.1015625,4.6328125 8.7597656,4.9375 A 0.5,0.5 0 0 0 8.71875,5.6425781 0.5,0.5 0 0 0 9.4238281,5.6855469 L 9.7597656,5.3867187 10.123047,5.0761719 10.314453,4.9160156 10.513672,4.7539062 10.71875,4.5898437 10.933594,4.4238281 a 0.5,0.5 0 0 0 0.08594,-0.703125 0.5,0.5 0 0 0 -0.703125,-0.085937 z m 12.550781,3.4921875 a 0.5,0.5 0 0 0 -0.546875,0.4492188 l -0.02344,0.2304687 -0.02734,0.2285157 -0.0332,0.2304687 -0.03906,0.2324219 -0.04492,0.2363281 -0.05078,0.2402344 -0.05859,0.2421875 -0.06445,0.2480469 a 0.5,0.5 0 0 0 0.359375,0.6093752 0.5,0.5 0 0 0 0.609375,-0.3574221 l 0.06641,-0.2597656 0.0625,-0.2636719 0.05664,-0.2597656 0.04883,-0.2578125 0.04297,-0.2558594 0.03711,-0.2519531 0.0293,-0.2519532 0.02344,-0.2421875 a 0.5,0.5 0 0 0 -0.447266,-0.546875 z m -1.248046,3.8847659 a 0.5,0.5 0 0 0 -0.275391,0.265625 l -0.09375,0.214844 -0.09766,0.21289 -0.101563,0.214844 -0.105469,0.216797 -0.111328,0.21875 -0.115234,0.21875 -0.119141,0.220703 -0.126953,0.226562 a 0.5,0.5 0 0 0 0.19336,0.679688 0.5,0.5 0 0 0 0.679687,-0.191406 l 0.128906,-0.232422 0.126953,-0.232422 0.121094,-0.232422 0.117188,-0.230469 0.111328,-0.228515 0.109375,-0.228516 0.101562,-0.226562 0.09766,-0.220704 a 0.5,0.5 0 0 0 -0.257813,-0.658203 0.5,0.5 0 0 0 -0.382812,-0.0078 z m -1.488282,3.537109 a 0.5,0.5 0 0 0 -0.697265,0.117188 l -0.277344,0.390625 -0.287109,0.390625 -0.302735,0.392578 -0.318359,0.40039 a 0.5,0.5 0 0 0 0.08008,0.703125 0.5,0.5 0 0 0 0.703125,-0.08008 l 0.324219,-0.40625 0.3125,-0.408203 0.298828,-0.40625 L 20.25,15.244141 a 0.5,0.5 0 0 0 -0.119141,-0.695313 z" + id="path4" /> diff --git a/frontend/react/public/resources/theme/images/buttons/threat/passive.svg b/frontend/react/public/resources/theme/images/buttons/threat/passive.svg index c7a9d0d0..2d4892e5 100644 --- a/frontend/react/public/resources/theme/images/buttons/threat/passive.svg +++ b/frontend/react/public/resources/theme/images/buttons/threat/passive.svg @@ -7,13 +7,11 @@ version="1.1" id="svg14" sodipodi:docname="passive.svg" - inkscape:version="1.1 (c68e22c387, 2021-05-23)" + inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> - - + + - + - - + - + - + + id="path12" + style="stroke: none" /> diff --git a/frontend/react/public/resources/theme/images/buttons/visibility/airbase.svg b/frontend/react/public/resources/theme/images/buttons/visibility/airbase.svg index af684050..d3c97b0f 100644 --- a/frontend/react/public/resources/theme/images/buttons/visibility/airbase.svg +++ b/frontend/react/public/resources/theme/images/buttons/visibility/airbase.svg @@ -1,13 +1,13 @@ - - + diff --git a/frontend/react/public/resources/theme/images/buttons/visibility/groundunit-sam.svg b/frontend/react/public/resources/theme/images/buttons/visibility/groundunit-sam.svg index 3198968b..bb7f9414 100644 --- a/frontend/react/public/resources/theme/images/buttons/visibility/groundunit-sam.svg +++ b/frontend/react/public/resources/theme/images/buttons/visibility/groundunit-sam.svg @@ -7,80 +7,44 @@ version="1.1" id="svg7273" sodipodi:docname="groundunit-sam.svg" - inkscape:version="1.2.2 (732a01da63, 2022-12-09)" + inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> + - - - - - - - - - - - - - - - + + + diff --git a/frontend/react/public/resources/theme/images/buttons/visibility/groundunit.svg b/frontend/react/public/resources/theme/images/buttons/visibility/groundunit.svg index 4070e4ce..c6f11e69 100644 --- a/frontend/react/public/resources/theme/images/buttons/visibility/groundunit.svg +++ b/frontend/react/public/resources/theme/images/buttons/visibility/groundunit.svg @@ -6,59 +6,42 @@ fill="none" version="1.1" id="svg7251" - sodipodi:docname="groundunit-other.svg" - inkscape:version="1.2.2 (732a01da63, 2022-12-09)" + sodipodi:docname="groundunit.svg" + inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> + - - - - - - - - - + + diff --git a/frontend/react/public/resources/theme/images/buttons/visibility/human.svg b/frontend/react/public/resources/theme/images/buttons/visibility/human.svg index 51278e9e..05622e57 100644 --- a/frontend/react/public/resources/theme/images/buttons/visibility/human.svg +++ b/frontend/react/public/resources/theme/images/buttons/visibility/human.svg @@ -1,20 +1,20 @@ + width="12.14064" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> @@ -23,7 +23,7 @@ image/svg+xml - + @@ -39,11 +39,11 @@ inkscape:window-maximized="1" inkscape:window-y="-8" inkscape:window-x="1912" - inkscape:window-height="1017" + inkscape:window-height="1009" inkscape:window-width="1920" - inkscape:cy="3.5052403" - inkscape:cx="-1.3921341" - inkscape:zoom="27.733334" + inkscape:cy="6.71199" + inkscape:cx="5.7558661" + inkscape:zoom="78.441714" showgrid="false" inkscape:pagecheckerboard="0" inkscape:pageopacity="0.0" @@ -51,17 +51,12 @@ borderopacity="1.0" bordercolor="#666666" pagecolor="#ffffff" - id="namedview8" /> - + id="namedview8" + inkscape:showpageshadow="0" + inkscape:deskcolor="#505050" /> diff --git a/frontend/react/public/resources/theme/images/buttons/visibility/olympus.svg b/frontend/react/public/resources/theme/images/buttons/visibility/olympus.svg index c13a36a3..2d781471 100644 --- a/frontend/react/public/resources/theme/images/buttons/visibility/olympus.svg +++ b/frontend/react/public/resources/theme/images/buttons/visibility/olympus.svg @@ -1 +1,40 @@ - \ No newline at end of file + + + + + + + diff --git a/frontend/react/public/resources/theme/images/convertToFontAwesomIcons.py b/frontend/react/public/resources/theme/images/convertToFontAwesomIcons.py new file mode 100644 index 00000000..4c746350 --- /dev/null +++ b/frontend/react/public/resources/theme/images/convertToFontAwesomIcons.py @@ -0,0 +1,36 @@ +from svgpathtools import svg2paths, wsvg +import os +from glob import glob +import svgelements + +result = [y for x in os.walk(".") for y in glob(os.path.join(x[0], '*.svg'))] + +with open(os.path.join( "..", "..", "..", "..", "src", "ui", "components", "olicons.tsx"), "w") as fp: + fp.write('import { IconDefinition, IconName, IconPrefix } from "@fortawesome/fontawesome-svg-core";\n') + for filename in result: + try: + iconName = filename.replace(".", "").replace("\\", "_").removesuffix("svg") + iconName = iconName.replace("-", "_") + temp = iconName.split('_') + iconName = temp[0] + ''.join(ele.capitalize() for ele in temp[1:]) + + svg = svgelements.SVG.parse(filename) + paths, attributes = svg2paths(filename) + + fp.write(f"export const ol{iconName}: IconDefinition = {{") + fp.write(" icon: [") + fp.write(f" {svg.implicit_width}, {svg.implicit_height}, [], \"\",") + fp.write("\"") + + for path in paths: + fp.write(path.d() + " ") + + fp.write("\"") + fp.write("]") + + name = temp[0] + ''.join(ele.lower() + '-' for ele in temp[1:]).removesuffix('-') + fp.write(f', iconName: "olympus-{name}" as IconName') + fp.write(f', prefix: "fas" as IconPrefix') + fp.write("}\n") + except Exception as e: + print(f"Failed to generate path for {iconName}: {e}") \ No newline at end of file diff --git a/frontend/react/public/resources/theme/images/markers/target - Copy.svg b/frontend/react/public/resources/theme/images/markers/target - Copy.svg deleted file mode 100644 index 7afbf612..00000000 --- a/frontend/react/public/resources/theme/images/markers/target - Copy.svg +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/frontend/react/src/ui/components/olbuttongroup.tsx b/frontend/react/src/ui/components/olbuttongroup.tsx new file mode 100644 index 00000000..bd115478 --- /dev/null +++ b/frontend/react/src/ui/components/olbuttongroup.tsx @@ -0,0 +1,23 @@ +import { IconProp } from "@fortawesome/fontawesome-svg-core"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import React from "react"; + +export function OlButtonGroup(props: { + children?: JSX.Element | JSX.Element[] +}) { + + + return
+ {props.children} +
+} + +export function OlButtonGroupItem(props: { + icon: IconProp + active: boolean, + onClick: () => void +}) { + return +} \ No newline at end of file diff --git a/frontend/react/src/ui/components/olcoalitiontoggle.tsx b/frontend/react/src/ui/components/olcoalitiontoggle.tsx index 969233f5..4d28cdcb 100644 --- a/frontend/react/src/ui/components/olcoalitiontoggle.tsx +++ b/frontend/react/src/ui/components/olcoalitiontoggle.tsx @@ -2,18 +2,21 @@ import React from "react"; import { Coalition } from "../../types/types"; export function OlCoalitionToggle(props: { - coalition: Coalition, + coalition: Coalition | undefined, onClick: () => void }) { return
+ + {props.coalition? `Coalition (${props.coalition[0].toLocaleUpperCase() + props.coalition.substring(1)})`: "Different values"} + } \ No newline at end of file diff --git a/frontend/react/src/ui/components/oldropdown.tsx b/frontend/react/src/ui/components/oldropdown.tsx index 75c22868..adcef79c 100644 --- a/frontend/react/src/ui/components/oldropdown.tsx +++ b/frontend/react/src/ui/components/oldropdown.tsx @@ -74,7 +74,7 @@ export function OlDropdown(props: { }) return
- } \ No newline at end of file diff --git a/frontend/react/src/ui/components/olrangeslider.tsx b/frontend/react/src/ui/components/olrangeslider.tsx index 11ebb093..f1e24989 100644 --- a/frontend/react/src/ui/components/olrangeslider.tsx +++ b/frontend/react/src/ui/components/olrangeslider.tsx @@ -21,7 +21,7 @@ export function OlRangeSlider(props: { return void +}) { + return
+
+} \ No newline at end of file diff --git a/frontend/react/src/ui/panels/header.tsx b/frontend/react/src/ui/panels/header.tsx index 4b61e21f..3b88434e 100644 --- a/frontend/react/src/ui/panels/header.tsx +++ b/frontend/react/src/ui/panels/header.tsx @@ -6,6 +6,7 @@ import { StateConsumer } from '../../statecontext'; import { OlDropdownItem, OlDropdown } from '../components/oldropdown'; import { OlLabelToggle } from '../components/ollabeltoggle'; import { getApp } from '../../olympusapp'; +import { olButtonsVisibilityAirbase, olButtonsVisibilityAircraft, olButtonsVisibilityDcs, olButtonsVisibilityGroundunit, olButtonsVisibilityGroundunitSam, olButtonsVisibilityHelicopter, olButtonsVisibilityHuman, olButtonsVisibilityNavyunit, olButtonsVisibilityOlympus } from '../components/olicons'; export function Header() { return @@ -23,7 +24,7 @@ export function Header() {
{ Object.entries({ - 'human': faPerson,'olympus': faBrain, 'dcs': faRobot + 'human': olButtonsVisibilityHuman,'olympus': olButtonsVisibilityOlympus, 'dcs': olButtonsVisibilityDcs }).map((entry) => { return { @@ -38,8 +39,8 @@ export function Header() {
{ Object.entries({ - 'aircraft': faJetFighter,'helicopter': faHelicopter, 'groundunit-sam': faShieldAlt, - 'groundunit': faTruck, 'navyunit': faShip, 'airbase': faPlaneDeparture, 'dead': faSkull + 'aircraft': olButtonsVisibilityAircraft,'helicopter': olButtonsVisibilityHelicopter, 'groundunit-sam': olButtonsVisibilityGroundunitSam, + 'groundunit': olButtonsVisibilityGroundunit, 'navyunit': olButtonsVisibilityNavyunit, 'airbase': olButtonsVisibilityAirbase, 'dead': faSkull }).map((entry) => { return { diff --git a/frontend/react/src/ui/panels/spawnmenu.tsx b/frontend/react/src/ui/panels/spawnmenu.tsx index ff5e08c3..edc4de77 100644 --- a/frontend/react/src/ui/panels/spawnmenu.tsx +++ b/frontend/react/src/ui/panels/spawnmenu.tsx @@ -8,6 +8,7 @@ import { getApp } from "../../olympusapp"; import { OlUnitEntryList } from "../components/olunitlistentry"; import { UnitSpawnMenu } from "./unitspawnmenu"; import { UnitBlueprint } from "../../interfaces"; +import { olButtonsVisibilityAircraft, olButtonsVisibilityGroundunit, olButtonsVisibilityGroundunitSam, olButtonsVisibilityHelicopter, olButtonsVisibilityNavyunit } from "../components/olicons"; library.add(faPlus); @@ -62,7 +63,7 @@ export function SpawnMenu(props: {
{Object.keys(filteredAircraft).map((key) => { const blueprint = getApp().getAircraftDatabase().blueprints[key]; - return setBlueprint(blueprint)} /> + return setBlueprint(blueprint)} /> })}
@@ -70,7 +71,7 @@ export function SpawnMenu(props: {
{Object.keys(filteredHelicopters).map((key) => { const blueprint = getApp().getHelicopterDatabase().blueprints[key]; - return setBlueprint(blueprint)} /> + return setBlueprint(blueprint)} /> })}
@@ -78,7 +79,7 @@ export function SpawnMenu(props: {
{Object.keys(filteredAirDefense).map((key) => { const blueprint = getApp().getGroundUnitDatabase().blueprints[key]; - return setBlueprint(blueprint)} /> + return setBlueprint(blueprint)} /> })}
@@ -86,7 +87,7 @@ export function SpawnMenu(props: {
{Object.keys(filteredGroundUnits).map((key) => { const blueprint = getApp().getGroundUnitDatabase().blueprints[key]; - return setBlueprint(blueprint)} /> + return setBlueprint(blueprint)} /> })}
@@ -94,7 +95,7 @@ export function SpawnMenu(props: {
{Object.keys(filteredNavyUnits).map((key) => { const blueprint = getApp().getNavyUnitDatabase().blueprints[key]; - return setBlueprint(blueprint)} /> + return setBlueprint(blueprint)} /> })}
diff --git a/frontend/react/src/ui/panels/unitcontrolmenu.tsx b/frontend/react/src/ui/panels/unitcontrolmenu.tsx index 54afe927..b50231af 100644 --- a/frontend/react/src/ui/panels/unitcontrolmenu.tsx +++ b/frontend/react/src/ui/panels/unitcontrolmenu.tsx @@ -1,38 +1,57 @@ import React, { useState } from "react"; import { Menu } from "./components/menu"; -import { faGamepad } from '@fortawesome/free-solid-svg-icons'; -import { library } from '@fortawesome/fontawesome-svg-core' import { Unit } from "../../unit/unit"; import { OlLabelToggle } from "../components/ollabeltoggle"; import { OlRangeSlider } from "../components/olrangeslider"; import { getApp } from "../../olympusapp"; - -const defaultUnitControlPanelData = { - desiredAltitude: undefined as undefined | number, - desiredAltitudeType: undefined as undefined | boolean -} +import { OlButtonGroup, OlButtonGroupItem } from "../components/olbuttongroup"; +import { ROEs, emissionsCountermeasures, reactionsToThreat } from "../../constants/constants"; +import { OlToggle } from "../components/oltoggle"; +import { OlCoalitionToggle } from "../components/olcoalitiontoggle"; +import { olButtonsEmissionsAttack, olButtonsEmissionsDefend, olButtonsEmissionsFree, olButtonsEmissionsSilent, olButtonsIntensity1, olButtonsIntensity2, olButtonsIntensity3, olButtonsRoeDesignated, olButtonsRoeFree, olButtonsRoeHold, olButtonsRoeReturn, olButtonsScatter1, olButtonsScatter2, olButtonsScatter3, olButtonsThreatEvade, olButtonsThreatManoeuvre, olButtonsThreatNone, olButtonsThreatPassive } from "../components/olicons"; +import { Coalition } from "../../types/types"; export function UnitControlMenu() { var [open, setOpen] = useState(false); var [selectedUnits, setSelectedUnits] = useState([] as Unit[]); - var [selectedUnitsData, setSelectedUnitsData] = useState(defaultUnitControlPanelData); - var [selectedUnitsRequestedData, setSelectedUnitsRequestedData] = useState(defaultUnitControlPanelData); + var [selectedUnitsData, setSelectedUnitsData] = useState({ + desiredAltitude: undefined as undefined | number, + desiredAltitudeType: undefined as undefined | string, + desiredSpeed: undefined as undefined | number, + desiredSpeedType: undefined as undefined | string, + ROE: undefined as undefined | string, + reactionToThreat: undefined as undefined | string, + emissionsCountermeasures: undefined as undefined | string, + shotsScatter: undefined as undefined | number, + shotsIntensity: undefined as undefined | number, + operateAs: undefined as undefined | string, + followRoads: undefined as undefined | boolean, + isActiveAWACS: undefined as undefined | boolean, + isActiveTanker: undefined as undefined | boolean, + onOff: undefined as undefined | boolean + }); /* */ const minAltitude = 0; - const maxAltitude = 60000; - const altitudeStep = 500; + const maxAltitude = getApp()?.getUnitsManager()?.getSelectedUnitsCategories().every((category) => { return category === 'Helicopter'}) ? 20000 : 60000; + const altitudeStep = getApp()?.getUnitsManager()?.getSelectedUnitsCategories().every((category) => { return category === 'Helicopter'}) ? 100 : 500; + const minSpeed = 0; + const maxSpeed = getApp()?.getUnitsManager()?.getSelectedUnitsCategories().every((category) => { return category === 'Helicopter'}) ? 200 : 800; + const speedStep = getApp()?.getUnitsManager()?.getSelectedUnitsCategories().every((category) => { return category === 'Helicopter'}) ? 5 : 10;; /* When a unit is selected, open the menu */ document.addEventListener("unitsSelection", (ev: CustomEventInit) => { setOpen(true); - setSelectedUnits(ev.detail as Unit[]) + setSelectedUnits(ev.detail as Unit[]); + + updateData(); }) /* When a unit is deselected, refresh the view */ document.addEventListener("unitDeselection", (ev: CustomEventInit) => { - + /* TODO add delay to avoid doing it too many times */ + updateData(); }) /* When all units are selected clean the view */ @@ -41,9 +60,31 @@ export function UnitControlMenu() { setSelectedUnits([]) }) - document.addEventListener("unitUpdated", () => { + /* Update the current values of the shown data */ + function updateData() { + const getters = { + desiredAltitude: (unit: Unit) => { return unit.getDesiredAltitude(); }, + desiredAltitudeType: (unit: Unit) => { return unit.getDesiredAltitudeType(); }, + desiredSpeed: (unit: Unit) => { return unit.getDesiredSpeed(); }, + desiredSpeedType: (unit: Unit) => { return unit.getDesiredSpeedType(); }, + ROE: (unit: Unit) => { return unit.getROE(); }, + reactionToThreat: (unit: Unit) => { return unit.getReactionToThreat(); }, + emissionsCountermeasures: (unit: Unit) => { return unit.getROE(); }, + shotsScatter: (unit: Unit) => { return unit.getShotsScatter(); }, + shotsIntensity: (unit: Unit) => { return unit.getShotsIntensity(); }, + operateAs: (unit: Unit) => { return unit.getOperateAs(); }, + followRoads: (unit: Unit) => { return unit.getFollowRoads(); }, + isActiveAWACS: (unit: Unit) => { return unit.getIsActiveAWACS(); }, + isActiveTanker: (unit: Unit) => { return unit.getIsActiveTanker(); }, + onOff: (unit: Unit) => { return unit.getOnOff(); }, + } as { [key in keyof (typeof selectedUnitsData)]: (unit: Unit) => void } - }) + var updatedData = selectedUnitsData; + Object.entries(getters).forEach(([key, getter]) => { + updatedData[key] = getApp()?.getUnitsManager()?.getSelectedUnitsVariable(getter); + }); + setSelectedUnitsData(updatedData); + } /* Count how many units are selected of each type, divided by coalition */ var unitOccurences = { @@ -51,6 +92,7 @@ export function UnitControlMenu() { red: {}, neutral: {} } + selectedUnits.forEach((unit) => { if (!(unit.getName() in unitOccurences[unit.getCoalition()])) unitOccurences[unit.getCoalition()][unit.getName()] = 1; @@ -58,11 +100,14 @@ export function UnitControlMenu() { unitOccurences[unit.getCoalition()][unit.getName()]++; }) + const selectedCategories = getApp()?.getUnitsManager()?.getSelectedUnitsCategories() ?? []; + return { }} > + {/* Units list */}
{ @@ -85,43 +130,267 @@ export function UnitControlMenu() { }
-
+
+ {/* Altitude selector */ + selectedCategories.every((category) => { return ['Aircraft', 'Helicopter'].includes(category) }) &&
+
+
+ Altitude + {selectedUnitsData.desiredAltitude !== undefined ? (selectedUnitsData.desiredAltitude + " FT") : "Different values"} + +
+ { + selectedUnits.forEach((unit) => { + unit.setAltitudeType((selectedUnitsData.desiredAltitudeType === "ASL") ? "AGL" : "ASL"); + setSelectedUnitsData({ + ...selectedUnitsData, + desiredAltitudeType: (selectedUnitsData.desiredAltitudeType === "ASL") ? "AGL" : "ASL" + }) + }) + }} /> +
+ { + selectedUnits.forEach((unit) => { + unit.setAltitude(Number(ev.target.value)); + setSelectedUnitsData({ + ...selectedUnitsData, + desiredAltitude: Number(ev.target.value) + }) + }) + }} + value={selectedUnitsData.desiredAltitude} + min={minAltitude} + max={maxAltitude} + step={altitudeStep} + /> +
+ } + {/* Airspeed selector */}
- Altitude - {`${selectedUnitsRequestedData.desiredAltitude} FT`} + Speed + {selectedUnitsData.desiredSpeed !== undefined ? (selectedUnitsData.desiredSpeed + " KTS") : "Different values"} +
{ selectedUnits.forEach((unit) => { - unit.setAltitudeType((!selectedUnitsRequestedData.desiredAltitudeType) ? "AGL" : "ASL"); - setSelectedUnitsRequestedData({ - ...selectedUnitsRequestedData, - desiredAltitudeType: !selectedUnitsRequestedData.desiredAltitudeType + unit.setSpeedType((selectedUnitsData.desiredSpeedType === "CAS") ? "GS" : "CAS"); + setSelectedUnitsData({ + ...selectedUnitsData, + desiredSpeedType: (selectedUnitsData.desiredSpeedType === "CAS") ? "GS" : "CAS" }) }) - }} /> + }} + />
{ selectedUnits.forEach((unit) => { - unit.setAltitude(Number(ev.target.value)); - setSelectedUnitsRequestedData({ - ...selectedUnitsRequestedData, - desiredAltitude: Number(ev.target.value) + unit.setSpeed(Number(ev.target.value)); + setSelectedUnitsData({ + ...selectedUnitsData, + desiredSpeed: Number(ev.target.value) }) }) }} - value={selectedUnitsRequestedData.desiredAltitude} - min={minAltitude} - max={maxAltitude} - step={altitudeStep} /> + value={selectedUnitsData.desiredSpeed} + min={minSpeed} + max={maxSpeed} + step={speedStep} + />
-
+
+ Rules of engagement + + { + [olButtonsRoeHold, olButtonsRoeReturn, olButtonsRoeDesignated, olButtonsRoeFree].map((icon, idx) => { + return { + selectedUnits.forEach((unit) => { + unit.setROE(ROEs[idx]); + setSelectedUnitsData({ + ...selectedUnitsData, + ROE: ROEs[idx] + }) + }) + }} + active={selectedUnitsData.ROE === ROEs[idx]} + icon={icon} /> + }) + } + +
+ { + selectedCategories.every((category) => { return ['Aircraft', 'Helicopter'].includes(category) }) && <>
+ Threat reaction + + { + [olButtonsThreatNone, olButtonsThreatPassive, olButtonsThreatManoeuvre, olButtonsThreatEvade].map((icon, idx) => { + return { + selectedUnits.forEach((unit) => { + unit.setReactionToThreat(reactionsToThreat[idx]); + setSelectedUnitsData({ + ...selectedUnitsData, + reactionToThreat: reactionsToThreat[idx] + }) + }) + }} + active={selectedUnitsData.reactionToThreat === reactionsToThreat[idx]} + icon={icon} /> + }) + } + +
+
+ Radar and ECM + + { + [olButtonsEmissionsSilent, olButtonsEmissionsDefend, olButtonsEmissionsAttack, olButtonsEmissionsFree].map((icon, idx) => { + return { + selectedUnits.forEach((unit) => { + unit.setEmissionsCountermeasures(emissionsCountermeasures[idx]); + setSelectedUnitsData({ + ...selectedUnitsData, + emissionsCountermeasures: emissionsCountermeasures[idx] + }) + }) + }} + active={selectedUnitsData.emissionsCountermeasures === emissionsCountermeasures[idx]} + icon={icon} /> + }) + } + +
+ + } + { + getApp()?.getUnitsManager()?.getSelectedUnitsVariable((unit) => { return unit.isTanker() }) && +
+ Act as tanker + { + selectedUnits.forEach((unit) => { + unit.setAdvancedOptions(!selectedUnitsData.isActiveTanker, unit.getIsActiveAWACS(), unit.getTACAN(), unit.getRadio(), unit.getGeneralSettings()); + setSelectedUnitsData({ + ...selectedUnitsData, + isActiveTanker: !selectedUnitsData.isActiveTanker + }) + }) + }} /> +
+ } + { + getApp()?.getUnitsManager()?.getSelectedUnitsVariable((unit) => { return unit.isAWACS() }) && +
+ Act as AWACS + { + selectedUnits.forEach((unit) => { + unit.setAdvancedOptions(unit.getIsActiveTanker(), !selectedUnitsData.isActiveAWACS, unit.getTACAN(), unit.getRadio(), unit.getGeneralSettings()); + setSelectedUnitsData({ + ...selectedUnitsData, + isActiveAWACS: !selectedUnitsData.isActiveAWACS + }) + }) + }} /> +
+ } + { + selectedCategories.every((category) => { return ['GroundUnit', 'NavyUnit'].includes(category) }) && <>
+ Shots scatter + + { + [olButtonsScatter1, olButtonsScatter2, olButtonsScatter3].map((icon, idx) => { + return { + selectedUnits.forEach((unit) => { + unit.setShotsScatter(idx); + setSelectedUnitsData({ + ...selectedUnitsData, + shotsScatter: idx + }) + }) + }} + active={selectedUnitsData.shotsScatter === idx} + icon={icon} /> + }) + } + +
+
+ Shots intensity + + { + [olButtonsIntensity1, olButtonsIntensity2, olButtonsIntensity3].map((icon, idx) => { + return { + selectedUnits.forEach((unit) => { + unit.setShotsIntensity(idx); + setSelectedUnitsData({ + ...selectedUnitsData, + shotsIntensity: idx + }) + }) + }} + active={selectedUnitsData.shotsIntensity === idx} + icon={icon} /> + }) + } + +
+
+ Operate as + { + selectedUnits.forEach((unit) => { + unit.setOperateAs(selectedUnitsData.operateAs === 'blue' ? 'red' : 'blue'); + setSelectedUnitsData({ + ...selectedUnitsData, + operateAs: selectedUnitsData.operateAs === 'blue' ? 'red' : 'blue' + }) + }) + }} /> +
+
+ Follow roads + { + selectedUnits.forEach((unit) => { + unit.setFollowRoads(!selectedUnitsData.followRoads); + setSelectedUnitsData({ + ...selectedUnitsData, + followRoads: !selectedUnitsData.followRoads + }) + }) + }} /> +
+
+ Enabled + { + selectedUnits.forEach((unit) => { + unit.setOnOff(!selectedUnitsData.onOff); + setSelectedUnitsData({ + ...selectedUnitsData, + onOff: !selectedUnitsData.onOff + }) + }) + }} /> +
+ + } +
} \ No newline at end of file diff --git a/frontend/server/demo.js b/frontend/server/demo.js index 741ab307..b8d47664 100644 --- a/frontend/server/demo.js +++ b/frontend/server/demo.js @@ -69,14 +69,14 @@ module.exports = function (configLocation) { // UNCOMMENT TO TEST ALL UNITS **************** - /* + var databases = Object.assign({}, aircraftDatabase, helicopterDatabase, groundUnitDatabase, navyUnitDatabase); var t = Object.keys(databases).length; var l = Math.floor(Math.sqrt(t)); let latIdx = 0; let lngIdx = 0; let idx = 1; - console.log(l) + for (let name in databases) { if (databases[name].enabled) { DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData)); @@ -106,7 +106,7 @@ module.exports = function (configLocation) { } - */ + /* let idx = 1; DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData)); DEMO_UNIT_DATA[idx].name = "S_75M_Volhov"; @@ -140,6 +140,9 @@ module.exports = function (configLocation) { DEMO_UNIT_DATA[idx].category = "Aircraft"; DEMO_UNIT_DATA[idx].isLeader = false; DEMO_UNIT_DATA[idx].coalition = 1; + DEMO_UNIT_DATA[idx].desiredAltitude = 10000; + DEMO_UNIT_DATA[idx].desiredAltitudeType = 0; + idx += 1; DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData)); @@ -168,7 +171,7 @@ module.exports = function (configLocation) { DEMO_UNIT_DATA[idx].position.lat += idx / 100; DEMO_UNIT_DATA[idx].category = "Aircraft"; DEMO_UNIT_DATA[idx].isLeader = true; - + */ this.startTime = Date.now(); }