From 5cd566c7ca4a8f067bab95ca64d673f0fe14a290 Mon Sep 17 00:00:00 2001 From: MarcoJayUsai Date: Mon, 11 Nov 2024 12:19:05 +0100 Subject: [PATCH 01/11] feat(map): added an option to show human controlled unit original callsign --- backend/core/include/datatypes.h | 1 + backend/core/include/unit.h | 3 +++ backend/core/src/unit.cpp | 4 ++++ .../server/public/stylesheets/markers/units.css | 10 ++++++++-- frontend/website/src/constants/constants.ts | 2 ++ frontend/website/src/interfaces.ts | 2 ++ frontend/website/src/map/map.ts | 7 ++++++- frontend/website/src/unit/unit.ts | 17 +++++++++++++++-- scripts/lua/backend/OlympusCommand.lua | 2 ++ 9 files changed, 43 insertions(+), 5 deletions(-) diff --git a/backend/core/include/datatypes.h b/backend/core/include/datatypes.h index c0e1c86e..fec3cb5b 100644 --- a/backend/core/include/datatypes.h +++ b/backend/core/include/datatypes.h @@ -13,6 +13,7 @@ namespace DataIndex { country, name, unitName, + callsign, groupName, state, task, diff --git a/backend/core/include/unit.h b/backend/core/include/unit.h index 5ba64e7c..a4ded619 100644 --- a/backend/core/include/unit.h +++ b/backend/core/include/unit.h @@ -71,6 +71,7 @@ public: virtual void setCountry(unsigned char newValue) { updateValue(country, newValue, DataIndex::country); } virtual void setName(string newValue) { updateValue(name, newValue, DataIndex::name); } virtual void setUnitName(string newValue) { updateValue(unitName, newValue, DataIndex::unitName); } + virtual void setCallsign(string newValue) { updateValue(callsign, newValue, DataIndex::callsign); } virtual void setGroupName(string newValue) { updateValue(groupName, newValue, DataIndex::groupName); } virtual void setState(unsigned char newValue) { updateValue(state, newValue, DataIndex::state); }; virtual void setTask(string newValue) { updateValue(task, newValue, DataIndex::task); } @@ -117,6 +118,7 @@ public: virtual unsigned char getCoalition() { return coalition; } virtual unsigned char getCountry() { return country; } virtual string getName() { return name; } + virtual string getCallsign() { return callsign; } virtual string getUnitName() { return unitName; } virtual string getGroupName() { return groupName; } virtual unsigned char getState() { return state; } @@ -167,6 +169,7 @@ protected: unsigned char country = NULL; string name = ""; string unitName = ""; + string callsign = ""; string groupName = ""; unsigned char state = State::NONE; string task = ""; diff --git a/backend/core/src/unit.cpp b/backend/core/src/unit.cpp index f35c5c1f..4bd03fba 100644 --- a/backend/core/src/unit.cpp +++ b/backend/core/src/unit.cpp @@ -37,6 +37,9 @@ void Unit::initialize(json::value json) if (json.has_string_field(L"groupName")) setGroupName(to_string(json[L"groupName"])); + if (json.has_string_field(L"callsign")) + setCallsign(to_string(json[L"callsign"])); + if (json.has_number_field(L"coalitionID")) setCoalition(json[L"coalitionID"].as_number().to_int32()); @@ -255,6 +258,7 @@ void Unit::getData(stringstream& ss, unsigned long long time) case DataIndex::country: appendNumeric(ss, datumIndex, country); break; case DataIndex::name: appendString(ss, datumIndex, name); break; case DataIndex::unitName: appendString(ss, datumIndex, unitName); break; + case DataIndex::callsign: appendString(ss, datumIndex, callsign); break; case DataIndex::groupName: appendString(ss, datumIndex, groupName); break; case DataIndex::state: appendNumeric(ss, datumIndex, state); break; case DataIndex::task: appendString(ss, datumIndex, task); break; diff --git a/frontend/server/public/stylesheets/markers/units.css b/frontend/server/public/stylesheets/markers/units.css index e2cba54d..119150c9 100644 --- a/frontend/server/public/stylesheets/markers/units.css +++ b/frontend/server/public/stylesheets/markers/units.css @@ -160,6 +160,8 @@ column-gap: 6px; display: flex; flex-wrap: wrap; + flex-direction: column; + align-items: flex-end; font-size: 11px; font-weight: bold; justify-content: right; @@ -173,18 +175,22 @@ -1px 1px 0 #000, 1px 1px 0 #000; right: 100%; - width: fit-content; + width: max-content; } [data-hide-labels] [data-object|="unit"] .unit-summary { display: none; } +[data-hide-original-callsign] [data-object|="unit"] .unit-original-callsign { + display: none; +} + [data-object|="unit"] .unit-summary>* { padding: 1px; } -[data-object|="unit"] .unit-summary .unit-callsign { +[data-object|="unit"] .unit-summary .unit-callsign .unit-group { color: white; overflow: hidden; text-align: right; diff --git a/frontend/website/src/constants/constants.ts b/frontend/website/src/constants/constants.ts index 7d411761..fddb20b6 100644 --- a/frontend/website/src/constants/constants.ts +++ b/frontend/website/src/constants/constants.ts @@ -251,6 +251,7 @@ export const SHOW_UNIT_PATHS = "Show selected unit paths"; export const SHOW_UNIT_TARGETS = "Show selected unit targets"; export const DCS_LINK_PORT = "DCS Camera link port"; export const DCS_LINK_RATIO = "DCS Camera zoom"; +export const SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN = "Show human controlled unit original callsign"; export enum DataIndexes { startOfData = 0, @@ -262,6 +263,7 @@ export enum DataIndexes { country, name, unitName, + callsign, groupName, state, task, diff --git a/frontend/website/src/interfaces.ts b/frontend/website/src/interfaces.ts index ef60bd07..fc38ff01 100644 --- a/frontend/website/src/interfaces.ts +++ b/frontend/website/src/interfaces.ts @@ -90,6 +90,7 @@ export interface ObjectIconOptions { showAmmo: boolean, showSummary: boolean, showCallsign: boolean, + showOriginalCallsign?: boolean, rotateToHeading: boolean } @@ -144,6 +145,7 @@ export interface UnitData { country: number; name: string; unitName: string; + callsign: string; groupName: string; state: string; task: string; diff --git a/frontend/website/src/map/map.ts b/frontend/website/src/map/map.ts index 35c240e8..39e6c0d4 100644 --- a/frontend/website/src/map/map.ts +++ b/frontend/website/src/map/map.ts @@ -12,7 +12,7 @@ import { DestinationPreviewMarker } from "./markers/destinationpreviewmarker"; import { TemporaryUnitMarker } from "./markers/temporaryunitmarker"; import { ClickableMiniMap } from "./clickableminimap"; import { SVGInjector } from '@tanem/svg-injector' -import { defaultMapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, MOVE_UNIT, SHOW_UNIT_CONTACTS, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, SHOW_UNIT_LABELS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING, MAP_MARKER_CONTROLS, DCS_LINK_PORT, DCS_LINK_RATIO, defaultMapMirrors } from "../constants/constants"; +import { defaultMapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, MOVE_UNIT, SHOW_UNIT_CONTACTS, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, SHOW_UNIT_LABELS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING, MAP_MARKER_CONTROLS, DCS_LINK_PORT, DCS_LINK_RATIO, defaultMapMirrors, SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN } from "../constants/constants"; import { CoalitionArea } from "./coalitionarea/coalitionarea"; import { CoalitionAreaContextMenu } from "../contextmenus/coalitionareacontextmenu"; import { DrawingCursor } from "./coalitionarea/drawingcursor"; @@ -152,6 +152,9 @@ export class Map extends L.Map { /* Init the state machine */ this.#state = IDLE; + /* By default let's hide human controlled unit original callsign */ + this.getContainer().toggleAttribute("data-hide-original-callsign", !this.getVisibilityOptions()[SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN]); + /* Register event handles */ this.on("click", (e: any) => this.#onClick(e)); this.on("dblclick", (e: any) => this.#onDoubleClick(e)); @@ -212,6 +215,7 @@ export class Map extends L.Map { document.addEventListener("mapOptionsChanged", () => { this.getContainer().toggleAttribute("data-hide-labels", !this.getVisibilityOptions()[SHOW_UNIT_LABELS]); + this.getContainer().toggleAttribute("data-hide-original-callsign", !this.getVisibilityOptions()[SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN]); this.#cameraControlPort = this.getVisibilityOptions()[DCS_LINK_PORT] as number; this.#cameraZoomRatio = 50 / (20 + (this.getVisibilityOptions()[DCS_LINK_RATIO] as number)); @@ -303,6 +307,7 @@ export class Map extends L.Map { this.addVisibilityOption(SHOW_UNITS_ENGAGEMENT_RINGS, true); this.addVisibilityOption(SHOW_UNITS_ACQUISITION_RINGS, true); this.addVisibilityOption(HIDE_UNITS_SHORT_RANGE_RINGS, true); + this.addVisibilityOption(SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN, false); /* this.addVisibilityOption(FILL_SELECTED_RING, false); Removed since currently broken: TODO fix!*/ } diff --git a/frontend/website/src/unit/unit.ts b/frontend/website/src/unit/unit.ts index ab8f8b9a..a85a1eaa 100644 --- a/frontend/website/src/unit/unit.ts +++ b/frontend/website/src/unit/unit.ts @@ -5,7 +5,7 @@ import { CustomMarker } from '../map/markers/custommarker'; import { SVGInjector } from '@tanem/svg-injector'; import { UnitDatabase } from './databases/unitdatabase'; import { TargetMarker } from '../map/markers/targetmarker'; -import { DLINK, DataIndexes, GAME_MASTER, HIDE_GROUP_MEMBERS, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, ROEs, RWR, SHOW_UNIT_CONTACTS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, VISUAL, emissionsCountermeasures, reactionsToThreat, states, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING, GROUPING_ZOOM_TRANSITION, MAX_SHOTS_SCATTER, SHOTS_SCATTER_DEGREES, GROUND_UNIT_AIR_DEFENCE_REGEX } from '../constants/constants'; +import { DLINK, DataIndexes, GAME_MASTER, HIDE_GROUP_MEMBERS, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, ROEs, RWR, SHOW_UNIT_CONTACTS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, VISUAL, emissionsCountermeasures, reactionsToThreat, states, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING, GROUPING_ZOOM_TRANSITION, MAX_SHOTS_SCATTER, SHOTS_SCATTER_DEGREES, GROUND_UNIT_AIR_DEFENCE_REGEX, SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN } from '../constants/constants'; import { DataExtractor } from '../server/dataextractor'; import { groundUnitDatabase } from './databases/groundunitdatabase'; import { navyUnitDatabase } from './databases/navyunitdatabase'; @@ -36,6 +36,7 @@ export abstract class Unit extends CustomMarker { #country: number = 0; #name: string = ""; #unitName: string = ""; + #callsign: string = ""; #groupName: string = ""; #state: string = states[0]; #task: string = "" @@ -119,6 +120,7 @@ export abstract class Unit extends CustomMarker { getCountry() { return this.#country }; getName() { return this.#name }; getUnitName() { return this.#unitName }; + getCallsign() { return this.#callsign }; getGroupName() { return this.#groupName }; getState() { return this.#state }; getTask() { return this.#task }; @@ -279,6 +281,7 @@ export abstract class Unit extends CustomMarker { case DataIndexes.country: this.#country = dataExtractor.extractUInt8(); break; case DataIndexes.name: this.#name = dataExtractor.extractString(); break; case DataIndexes.unitName: this.#unitName = dataExtractor.extractString(); break; + case DataIndexes.callsign: this.#callsign = dataExtractor.extractString(); break; case DataIndexes.groupName: this.#groupName = dataExtractor.extractString(); updateMarker = true; break; case DataIndexes.state: this.#state = enumToState(dataExtractor.extractUInt8()); updateMarker = true; break; case DataIndexes.task: this.#task = dataExtractor.extractString(); break; @@ -358,6 +361,7 @@ export abstract class Unit extends CustomMarker { country: this.#country, name: this.#name, unitName: this.#unitName, + callsign: this.#callsign, groupName: this.#groupName, state: this.#state, task: this.#task, @@ -423,7 +427,7 @@ export abstract class Unit extends CustomMarker { setSelected(selected: boolean) { /* Only alive units can be selected that belong to the commanded coalition can be selected */ if ((this.#alive || !selected) && this.belongsToCommandedCoalition() && this.getSelected() != selected) { - this.#selected = selected; + this.#selected = selected; /* If selected, update the marker to show the selected effects, else clear all the drawings that are only shown for selected units. */ if (selected) { @@ -678,13 +682,20 @@ export abstract class Unit extends CustomMarker { if (iconOptions.showSummary) { var summary = document.createElement("div"); summary.classList.add("unit-summary"); + + var originalCallsign = document.createElement("div"); + originalCallsign.classList.add("unit-original-callsign"); + originalCallsign.innerText = this.#callsign; + var callsign = document.createElement("div"); callsign.classList.add("unit-callsign"); callsign.innerText = this.#unitName; + var altitude = document.createElement("div"); altitude.classList.add("unit-altitude"); var speed = document.createElement("div"); speed.classList.add("unit-speed"); + if (this.#human) summary.appendChild(originalCallsign); if (iconOptions.showCallsign) summary.appendChild(callsign); summary.appendChild(altitude); summary.appendChild(speed); @@ -1485,6 +1496,7 @@ export abstract class Unit extends CustomMarker { export abstract class AirUnit extends Unit { getIconOptions() { var belongsToCommandedCoalition = this.belongsToCommandedCoalition(); + var showHumanControlledUnitGroup = getApp().getMap().getVisibilityOptions()[SHOW_HUMAN_CONTROLLED_UNIT_ORIGINAL_CALLSIGN] as boolean; return { showState: belongsToCommandedCoalition, showVvi: (belongsToCommandedCoalition || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))), @@ -1496,6 +1508,7 @@ export abstract class AirUnit extends Unit { showAmmo: belongsToCommandedCoalition, showSummary: (belongsToCommandedCoalition || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))), showCallsign: belongsToCommandedCoalition, + showOriginalCallsign: showHumanControlledUnitGroup, rotateToHeading: false }; } diff --git a/scripts/lua/backend/OlympusCommand.lua b/scripts/lua/backend/OlympusCommand.lua index 390abf57..e1615965 100644 --- a/scripts/lua/backend/OlympusCommand.lua +++ b/scripts/lua/backend/OlympusCommand.lua @@ -1074,6 +1074,8 @@ function Olympus.setUnitsData(arg, time) else table["unitName"] = unit:getName() end + -- In case of AI units the callSign and the unitName will be the same + table["callsign"] = unit:getName() table["groupName"] = group:getName() table["isHuman"] = (unit:getPlayerName() ~= nil) table["hasTask"] = controller:hasTask() From 5e5ee30b8f34559a2bc4158ee9518aa63ef21871 Mon Sep 17 00:00:00 2001 From: MarcoJayUsai Date: Mon, 11 Nov 2024 18:56:29 +0100 Subject: [PATCH 02/11] feat(mouse info panel): added selected unit coordinates displaying The coordinates are only shown if one unit has been selected. --- .../public/stylesheets/panels/mouseinfo.css | 19 ++++++ frontend/server/views/panels/mouseinfo.ejs | 37 +++++++++++ frontend/website/src/panels/mouseinfopanel.ts | 66 ++++++++++++++++++- 3 files changed, 120 insertions(+), 2 deletions(-) diff --git a/frontend/server/public/stylesheets/panels/mouseinfo.css b/frontend/server/public/stylesheets/panels/mouseinfo.css index c82b25e4..384933cc 100644 --- a/frontend/server/public/stylesheets/panels/mouseinfo.css +++ b/frontend/server/public/stylesheets/panels/mouseinfo.css @@ -107,4 +107,23 @@ #coordinates-tool[data-location-system="MGRS"] [data-location-system="MGRS"], #coordinates-tool[data-location-system="UTM"] [data-location-system="UTM"] { display:flex; +} + +/* Unit Coordinates */ +#unit-coordinates .elevation::after { + content: attr(data-value) +} + +#unit-coordinates[data-location-system] [data-location-system] { + display:none; +} + +#unit-coordinates[data-location-system="LatLng"] [data-location-system="LatLng"], +#unit-coordinates[data-location-system="MGRS"] [data-location-system="MGRS"], +#unit-coordinates[data-location-system="UTM"] [data-location-system="UTM"] { + display:flex; +} + +#unit-coordinates-title { + font-size: 10px; } \ No newline at end of file diff --git a/frontend/server/views/panels/mouseinfo.ejs b/frontend/server/views/panels/mouseinfo.ejs index 990258e7..a9ac7410 100644 --- a/frontend/server/views/panels/mouseinfo.ejs +++ b/frontend/server/views/panels/mouseinfo.ejs @@ -60,4 +60,41 @@ + Selected Unit Coordinates: + +
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+ \ No newline at end of file diff --git a/frontend/website/src/panels/mouseinfopanel.ts b/frontend/website/src/panels/mouseinfopanel.ts index 82dba41e..0f8bfd48 100644 --- a/frontend/website/src/panels/mouseinfopanel.ts +++ b/frontend/website/src/panels/mouseinfopanel.ts @@ -5,9 +5,11 @@ import { Unit } from "../unit/unit"; import { Panel } from "./panel"; import formatcoords from "formatcoords"; import { MGRS_PRECISION_100M, MGRS_PRECISION_10KM, MGRS_PRECISION_10M, MGRS_PRECISION_1KM, MGRS_PRECISION_1M } from "../constants/constants"; +import { log } from "console"; export class MouseInfoPanel extends Panel { #coordinatesElement:HTMLElement; + #unitCoordinatesElement:HTMLElement; #locationSystems = [ "LatLng", "MGRS", "UTM" ]; #measureMarker: Marker; #measurePoint: LatLng | null = null; @@ -18,6 +20,9 @@ export class MouseInfoPanel extends Panel { #selectedMGRSPrecisionIndex = 3; #selectedLocationSystemIndex = 0; #elevationRequest: XMLHttpRequest | null = null; + #unitElevationRequest: XMLHttpRequest | null = null; + #unitElevation: any = null; + constructor(ID: string) { super( ID ); @@ -38,6 +43,7 @@ export class MouseInfoPanel extends Panel { document.addEventListener('clearSelection', () => this.#update()); this.#coordinatesElement = this.getElement().querySelector( '#coordinates-tool' ); + this.#unitCoordinatesElement = this.getElement().querySelector( '#unit-coordinates' ); this.#coordinatesElement.addEventListener( "click", ( ev:MouseEvent ) => { this.#changeLocationSystem(); @@ -79,9 +85,18 @@ export class MouseInfoPanel extends Panel { const mousePosition = getApp().getMap().getMouseCoordinates(); var selectedUnitPosition = null; + var selectedUnits = getApp().getUnitsManager().getSelectedUnits(); - if (selectedUnits && selectedUnits.length == 1) + if (selectedUnits && selectedUnits.length == 1) { + this.getElement().querySelector(`#unit-coordinates`)?.classList.remove('hide'); + this.getElement().querySelector(`#unit-coordinates-title`)?.classList.remove('hide'); selectedUnitPosition = new LatLng(selectedUnits[0].getPosition().lat, selectedUnits[0].getPosition().lng); + } else { + selectedUnitPosition = null; + this.#unitElevation = null; + this.getElement().querySelector(`#unit-coordinates`)?.classList.add('hide'); + this.getElement().querySelector(`#unit-coordinates-title`)?.classList.add('hide'); + } /* Draw measures from selected unit, from pin location, and from bullseyes */ this.#drawMeasure("ref-measure-position", "measure-position", this.#measurePoint, mousePosition); @@ -110,6 +125,24 @@ export class MouseInfoPanel extends Panel { this.#drawCoordinates("ref-mouse-position-longitude", "mouse-position-longitude", coordString.split(" ")[1]); } + /* Draw selected unit coordinates */ + if (selectedUnitPosition) { + var unitCoords = formatcoords(selectedUnitPosition.lat, selectedUnitPosition.lng); + var unitCoordString = unitCoords.format('XDDMMss', {decimalPlaces: 4}); + + if ( this.#getLocationSystem() === "MGRS" ) { + const mgrs = latLngToMGRS( selectedUnitPosition.lat, selectedUnitPosition.lng, this.#MGRSPrecisions[ this.#selectedMGRSPrecisionIndex ] ); + this.#drawCoordinates("ref-unit-position-mgrs", "unit-position-mgrs", "M"+mgrs.groups.join(" ") ); + } else if ( this.#getLocationSystem() === "UTM" ) { + const utm = latLngToUTM( selectedUnitPosition.lat, selectedUnitPosition.lng ); + this.#drawCoordinates("ref-unit-position-utm-northing", "unit-position-utm-northing", "N"+utm.northing); + this.#drawCoordinates("ref-unit-position-utm-easting", "unit-position-utm-easting", "E"+utm.easting); + } else { + this.#drawCoordinates("ref-unit-position-latitude", "unit-position-latitude", unitCoordString.split(" ")[0]); + this.#drawCoordinates("ref-unit-position-longitude", "unit-position-longitude", unitCoordString.split(" ")[1]); + } + } + /* Get the ground elevation from the server endpoint */ if (this.#elevationRequest == null) { this.#elevationRequest = new XMLHttpRequest(); @@ -133,6 +166,35 @@ export class MouseInfoPanel extends Panel { this.#elevationRequest.onabort = () => {this.#elevationRequest = null;} this.#elevationRequest.send(); } + + /* Get the ground elevation from the server endpoint for the unit */ + if (this.#unitElevationRequest == null && this.#unitElevation == null && selectedUnitPosition !== null) { + + this.#unitElevationRequest = new XMLHttpRequest(); + this.#unitElevationRequest.open('GET', `api/elevation/${selectedUnitPosition.lat}/${selectedUnitPosition.lng}`, true); + this.#unitElevationRequest.timeout = 500; // ms + this.#unitElevationRequest.responseType = 'json'; + this.#unitElevationRequest.onload = () => { + var status = this.#unitElevationRequest?.status; + if (status === 200) { + this.#unitElevation = this.#unitElevationRequest?.response; + + const el = this.getElement().querySelector(`#unit-position-elevation`) as HTMLElement; + try { + el.dataset.value = `${Math.floor(mToFt(parseFloat(this.#unitElevation)))} ft`; + } catch { + el.dataset.value = `N/A`; + } + } else { + this.#unitElevation = null; + } + this.#unitElevationRequest = null; + }; + this.#unitElevationRequest.ontimeout = () => {this.#unitElevationRequest = null;} + this.#unitElevationRequest.onerror = () => {this.#unitElevationRequest = null;} + this.#unitElevationRequest.onabort = () => {this.#unitElevationRequest = null;} + this.#unitElevationRequest.send(); + } } #onMapClick(e: any) { @@ -273,10 +335,10 @@ export class MouseInfoPanel extends Panel { } this.#coordinatesElement.setAttribute( "data-location-system", this.#getLocationSystem() ); + this.#unitCoordinatesElement.setAttribute( "data-location-system", this.#getLocationSystem() ); this.#update(); } - #getLocationSystem() { const x = this.#locationSystems; const y = this.#selectedLocationSystemIndex; From e2732036292c2b450318e5f7b58764999976aa2c Mon Sep 17 00:00:00 2001 From: MarcoJayUsai Date: Sat, 16 Nov 2024 18:33:59 +0100 Subject: [PATCH 03/11] feat(map): selected unit coordinates panel moved to top; coords are now copy-able --- .../public/stylesheets/panels/mouseinfo.css | 49 ++++++++++++- frontend/server/views/panels/mouseinfo.ejs | 70 ++++++++++--------- frontend/website/src/panels/mouseinfopanel.ts | 65 +++++++++++++++-- 3 files changed, 145 insertions(+), 39 deletions(-) diff --git a/frontend/server/public/stylesheets/panels/mouseinfo.css b/frontend/server/public/stylesheets/panels/mouseinfo.css index 384933cc..2917847e 100644 --- a/frontend/server/public/stylesheets/panels/mouseinfo.css +++ b/frontend/server/public/stylesheets/panels/mouseinfo.css @@ -124,6 +124,53 @@ display:flex; } -#unit-coordinates-title { +#unit-coordinates-container { + box-sizing: border-box; + background-color: var(--background-steel); + border-radius: var(--border-radius-sm); + box-shadow: 0px 2px 5px #000A; + padding: 10px; + position: absolute; + top: -48px; + right: 0; + display: flex; + flex-direction: column; + align-items: center; + gap: 0px; + transition: all 200ms ease-in-out; +} + +#unit-coordinates-container[data-open="true"] { + gap: 4px; + top: -140px; +} + +#unit-coordinates-container > #unit-coordinates { + width: 170px; + height: 0; + padding: 0 6px; + overflow: hidden; + flex-grow: 1; + transition: all 200ms ease-in-out; +} + +#unit-coordinates-container[data-open="true"] > #unit-coordinates { + height: 90px; + padding: 6px; +} + +#unit-coordinates-container > #unit-coordinates-toggle { font-size: 10px; + flex-shrink: 1; + cursor: pointer; +} + +#unit-coordinates-container > #unit-coordinates-toggle> #unit-coordinates-toggle-icon::after { + margin-top: 8px; + font-size: 12px; + content: "↑"; +} + +#unit-coordinates-container[data-open="true"] > #unit-coordinates-toggle > #unit-coordinates-toggle-icon::after { + content: "↓"; } \ No newline at end of file diff --git a/frontend/server/views/panels/mouseinfo.ejs b/frontend/server/views/panels/mouseinfo.ejs index a9ac7410..20981dec 100644 --- a/frontend/server/views/panels/mouseinfo.ejs +++ b/frontend/server/views/panels/mouseinfo.ejs @@ -60,40 +60,44 @@ - Selected Unit Coordinates: - -
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
+
+
+ +
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+ +
+ Unit Coordinates
diff --git a/frontend/website/src/panels/mouseinfopanel.ts b/frontend/website/src/panels/mouseinfopanel.ts index 0f8bfd48..1b3a0d05 100644 --- a/frontend/website/src/panels/mouseinfopanel.ts +++ b/frontend/website/src/panels/mouseinfopanel.ts @@ -22,6 +22,7 @@ export class MouseInfoPanel extends Panel { #elevationRequest: XMLHttpRequest | null = null; #unitElevationRequest: XMLHttpRequest | null = null; #unitElevation: any = null; + #updateInterval: any = null; constructor(ID: string) { @@ -43,7 +44,6 @@ export class MouseInfoPanel extends Panel { document.addEventListener('clearSelection', () => this.#update()); this.#coordinatesElement = this.getElement().querySelector( '#coordinates-tool' ); - this.#unitCoordinatesElement = this.getElement().querySelector( '#unit-coordinates' ); this.#coordinatesElement.addEventListener( "click", ( ev:MouseEvent ) => { this.#changeLocationSystem(); @@ -79,6 +79,63 @@ export class MouseInfoPanel extends Panel { }, "code": "Period" }); + + /* Selected unit coordinates panel interaction */ + this.#unitCoordinatesElement = this.getElement().querySelector( '#unit-coordinates' ); + + const unitCoordsToggleEl = this.getElement().querySelector('#unit-coordinates-toggle'); + const unitCoordsContainer = this.getElement().querySelector('#unit-coordinates-container'); + unitCoordsToggleEl.addEventListener("click", (ev: MouseEvent) => { + if (unitCoordsContainer.getAttribute('data-open') === 'true') { + unitCoordsContainer.setAttribute('data-open', 'false'); + } else { + unitCoordsContainer.setAttribute('data-open', 'true'); + } + }); + + /* Let's update selected unit coordinates every second, useful for moving units */ + this.#updateInterval = setInterval(() => { + var selectedUnits = getApp().getUnitsManager().getSelectedUnits(); + if (selectedUnits && selectedUnits.length == 1) { + this.#update() + } else { + } + }, 1000); + + /* Let's make coordinates copy-able */ + this.#listenForCopyableElements(); + } + + #listenForCopyableElements() { + const copyableElements = document.getElementsByClassName('copyable'); + + for (const element of copyableElements) { + element.addEventListener('click', (ev) => { + if (!ev.target) return; + + const el = ev.target as HTMLElement; + + let text = null; + + if (el.innerText !== "") { + text = el.innerText; + } + + if (el.getAttribute('data-value')) { + text = el.getAttribute('data-value'); + } + + if (!text) return; + + navigator.clipboard.writeText(text) + .then(() => { + console.log('Testo copiato negli appunti!'); + }) + .catch(err => { + console.error('Errore nel copiare:', err); + }); + }); + } } #update() { @@ -88,14 +145,12 @@ export class MouseInfoPanel extends Panel { var selectedUnits = getApp().getUnitsManager().getSelectedUnits(); if (selectedUnits && selectedUnits.length == 1) { - this.getElement().querySelector(`#unit-coordinates`)?.classList.remove('hide'); - this.getElement().querySelector(`#unit-coordinates-title`)?.classList.remove('hide'); + this.getElement().querySelector(`#unit-coordinates-container`)?.classList.remove('hide'); selectedUnitPosition = new LatLng(selectedUnits[0].getPosition().lat, selectedUnits[0].getPosition().lng); } else { selectedUnitPosition = null; this.#unitElevation = null; - this.getElement().querySelector(`#unit-coordinates`)?.classList.add('hide'); - this.getElement().querySelector(`#unit-coordinates-title`)?.classList.add('hide'); + this.getElement().querySelector(`#unit-coordinates-container`)?.classList.add('hide'); } /* Draw measures from selected unit, from pin location, and from bullseyes */ From 064c24e02368e481fbbe767c4085b93c1ae1aafd Mon Sep 17 00:00:00 2001 From: MarcoJayUsai Date: Mon, 18 Nov 2024 21:56:01 +0100 Subject: [PATCH 04/11] fix(map): reconnecting players will not be displayed with wrong name or wrong coalition --- backend/core/src/unit.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/backend/core/src/unit.cpp b/backend/core/src/unit.cpp index 4bd03fba..5c5050f0 100644 --- a/backend/core/src/unit.cpp +++ b/backend/core/src/unit.cpp @@ -57,6 +57,21 @@ void Unit::initialize(json::value json) void Unit::update(json::value json, double dt) { + if (json.has_string_field(L"name")) + setName(to_string(json[L"name"])); + + if (json.has_string_field(L"unitName")) + setUnitName(to_string(json[L"unitName"])); + + if (json.has_string_field(L"groupName")) + setGroupName(to_string(json[L"groupName"])); + + if (json.has_string_field(L"callsign")) + setCallsign(to_string(json[L"callsign"])); + + if (json.has_number_field(L"coalitionID")) + setCoalition(json[L"coalitionID"].as_number().to_int32()); + if (json.has_object_field(L"position")) { setPosition({ From 89051c3e85b15371c67fffe65ecc9f3f4e206e45 Mon Sep 17 00:00:00 2001 From: MarcoJayUsai Date: Tue, 19 Nov 2024 13:58:16 +0100 Subject: [PATCH 05/11] refactor(unit): moved data update code from initialize to update; made initialize and update final --- backend/core/include/unit.h | 4 ++-- backend/core/src/unit.cpp | 28 ++++++---------------------- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/backend/core/include/unit.h b/backend/core/include/unit.h index a4ded619..83f39c4b 100644 --- a/backend/core/include/unit.h +++ b/backend/core/include/unit.h @@ -19,12 +19,12 @@ public: ~Unit(); /********** Methods **********/ - void initialize(json::value json); + virtual void initialize(json::value json) final; virtual void setDefaults(bool force = false); void runAILoop(); - void update(json::value json, double dt); + virtual void update(json::value json, double dt) final; void refreshLeaderData(unsigned long long time); unsigned int getID() { return ID; } diff --git a/backend/core/src/unit.cpp b/backend/core/src/unit.cpp index 5c5050f0..0ad51970 100644 --- a/backend/core/src/unit.cpp +++ b/backend/core/src/unit.cpp @@ -28,28 +28,6 @@ Unit::~Unit() void Unit::initialize(json::value json) { - if (json.has_string_field(L"name")) - setName(to_string(json[L"name"])); - - if (json.has_string_field(L"unitName")) - setUnitName(to_string(json[L"unitName"])); - - if (json.has_string_field(L"groupName")) - setGroupName(to_string(json[L"groupName"])); - - if (json.has_string_field(L"callsign")) - setCallsign(to_string(json[L"callsign"])); - - if (json.has_number_field(L"coalitionID")) - setCoalition(json[L"coalitionID"].as_number().to_int32()); - - //if (json.has_number_field(L"Country")) - // setCountry(json[L"Country"].as_number().to_int32()); - - /* All units which contain the name "Olympus" are automatically under AI control */ - if (getUnitName().find("Olympus") != string::npos) - setControlled(true); - update(json, 0); setDefaults(); } @@ -71,6 +49,12 @@ void Unit::update(json::value json, double dt) if (json.has_number_field(L"coalitionID")) setCoalition(json[L"coalitionID"].as_number().to_int32()); + //if (json.has_number_field(L"Country")) + // setCountry(json[L"Country"].as_number().to_int32()); + + /* All units which contain the name "Olympus" are automatically under AI control */ + if (getUnitName().find("Olympus") != string::npos) + setControlled(true); if (json.has_object_field(L"position")) { From b61289d99664c5ab44127bd335b14a77f8a5a438 Mon Sep 17 00:00:00 2001 From: MarcoJayUsai Date: Wed, 20 Nov 2024 11:27:40 +0100 Subject: [PATCH 06/11] fix(mouseinfopanel): switched to right mouse button to copy coordinates, added tip --- frontend/server/views/panels/mouseinfo.ejs | 8 +++----- .../website/plugins/controltips/src/controltipsplugin.ts | 5 +++++ frontend/website/src/panels/mouseinfopanel.ts | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/server/views/panels/mouseinfo.ejs b/frontend/server/views/panels/mouseinfo.ejs index 20981dec..fd4ca53c 100644 --- a/frontend/server/views/panels/mouseinfo.ejs +++ b/frontend/server/views/panels/mouseinfo.ejs @@ -88,11 +88,9 @@
-
-
-
-
-
+
+
+
diff --git a/frontend/website/plugins/controltips/src/controltipsplugin.ts b/frontend/website/plugins/controltips/src/controltipsplugin.ts index 4d2bfe4d..f68f7add 100644 --- a/frontend/website/plugins/controltips/src/controltipsplugin.ts +++ b/frontend/website/plugins/controltips/src/controltipsplugin.ts @@ -204,6 +204,11 @@ export class ControlTipsPlugin implements OlympusPlugin { "key": `Period`, "action": "Increase precision", "mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *` + }, + { + "key": `Mouse2`, + "action": "Copy to clipboard", + "mouseoverSelector": `#unit-coordinates-container > #unit-coordinates > .mouse-tool-item > .copyable` } ] }, diff --git a/frontend/website/src/panels/mouseinfopanel.ts b/frontend/website/src/panels/mouseinfopanel.ts index 1b3a0d05..4431d378 100644 --- a/frontend/website/src/panels/mouseinfopanel.ts +++ b/frontend/website/src/panels/mouseinfopanel.ts @@ -110,7 +110,7 @@ export class MouseInfoPanel extends Panel { const copyableElements = document.getElementsByClassName('copyable'); for (const element of copyableElements) { - element.addEventListener('click', (ev) => { + element.addEventListener('contextmenu', (ev) => { if (!ev.target) return; const el = ev.target as HTMLElement; From 2cadebcabdcb73b928b25156fc9f3cde80acffd4 Mon Sep 17 00:00:00 2001 From: MarcoJayUsai Date: Wed, 20 Nov 2024 11:43:10 +0100 Subject: [PATCH 07/11] feat(map): click selected unit coordinates panel will now change location system --- frontend/server/public/stylesheets/panels/mouseinfo.css | 1 + .../website/plugins/controltips/src/controltipsplugin.ts | 5 +++++ frontend/website/src/panels/mouseinfopanel.ts | 8 +++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/frontend/server/public/stylesheets/panels/mouseinfo.css b/frontend/server/public/stylesheets/panels/mouseinfo.css index 2917847e..d9cbd47d 100644 --- a/frontend/server/public/stylesheets/panels/mouseinfo.css +++ b/frontend/server/public/stylesheets/panels/mouseinfo.css @@ -115,6 +115,7 @@ } #unit-coordinates[data-location-system] [data-location-system] { + cursor:pointer; display:none; } diff --git a/frontend/website/plugins/controltips/src/controltipsplugin.ts b/frontend/website/plugins/controltips/src/controltipsplugin.ts index f68f7add..2c1850da 100644 --- a/frontend/website/plugins/controltips/src/controltipsplugin.ts +++ b/frontend/website/plugins/controltips/src/controltipsplugin.ts @@ -205,6 +205,11 @@ export class ControlTipsPlugin implements OlympusPlugin { "action": "Increase precision", "mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *` }, + { + "key": `Mouse1 or Z`, + "action": "Change location system", + "mouseoverSelector": "#unit-coordinates *" + }, { "key": `Mouse2`, "action": "Copy to clipboard", diff --git a/frontend/website/src/panels/mouseinfopanel.ts b/frontend/website/src/panels/mouseinfopanel.ts index 4431d378..b1db15bd 100644 --- a/frontend/website/src/panels/mouseinfopanel.ts +++ b/frontend/website/src/panels/mouseinfopanel.ts @@ -83,6 +83,12 @@ export class MouseInfoPanel extends Panel { /* Selected unit coordinates panel interaction */ this.#unitCoordinatesElement = this.getElement().querySelector( '#unit-coordinates' ); + this.#unitCoordinatesElement.addEventListener( "click", ( ev:MouseEvent ) => { + console.log('cliccato elemento unit coordinates'); + + this.#changeLocationSystem(); + }); + const unitCoordsToggleEl = this.getElement().querySelector('#unit-coordinates-toggle'); const unitCoordsContainer = this.getElement().querySelector('#unit-coordinates-container'); unitCoordsToggleEl.addEventListener("click", (ev: MouseEvent) => { @@ -129,7 +135,7 @@ export class MouseInfoPanel extends Panel { navigator.clipboard.writeText(text) .then(() => { - console.log('Testo copiato negli appunti!'); + //console.log('Testo copiato negli appunti!'); }) .catch(err => { console.error('Errore nel copiare:', err); From 6bb150a41ca23a81abbba08a16e42d18d30bcef9 Mon Sep 17 00:00:00 2001 From: MarcoJayUsai Date: Wed, 20 Nov 2024 12:50:56 +0100 Subject: [PATCH 08/11] feat(map): added selected air units FL in unit coordinates panel; added new coordinates system --- .../public/stylesheets/panels/mouseinfo.css | 2 + frontend/server/views/panels/mouseinfo.ejs | 20 ++++ frontend/website/src/panels/mouseinfopanel.ts | 107 +++++++++--------- 3 files changed, 74 insertions(+), 55 deletions(-) diff --git a/frontend/server/public/stylesheets/panels/mouseinfo.css b/frontend/server/public/stylesheets/panels/mouseinfo.css index d9cbd47d..657a86b9 100644 --- a/frontend/server/public/stylesheets/panels/mouseinfo.css +++ b/frontend/server/public/stylesheets/panels/mouseinfo.css @@ -104,6 +104,7 @@ } #coordinates-tool[data-location-system="LatLng"] [data-location-system="LatLng"], +#coordinates-tool[data-location-system="LatLngDec"] [data-location-system="LatLngDec"], #coordinates-tool[data-location-system="MGRS"] [data-location-system="MGRS"], #coordinates-tool[data-location-system="UTM"] [data-location-system="UTM"] { display:flex; @@ -120,6 +121,7 @@ } #unit-coordinates[data-location-system="LatLng"] [data-location-system="LatLng"], +#unit-coordinates[data-location-system="LatLngDec"] [data-location-system="LatLngDec"], #unit-coordinates[data-location-system="MGRS"] [data-location-system="MGRS"], #unit-coordinates[data-location-system="UTM"] [data-location-system="UTM"] { display:flex; diff --git a/frontend/server/views/panels/mouseinfo.ejs b/frontend/server/views/panels/mouseinfo.ejs index fd4ca53c..78b96cbd 100644 --- a/frontend/server/views/panels/mouseinfo.ejs +++ b/frontend/server/views/panels/mouseinfo.ejs @@ -42,6 +42,16 @@
+
+
+
+
+ +
+
+
+
+
@@ -77,6 +87,16 @@
+ +
+
+
+
+ +
+
+
+
diff --git a/frontend/website/src/panels/mouseinfopanel.ts b/frontend/website/src/panels/mouseinfopanel.ts index b1db15bd..8c72b18d 100644 --- a/frontend/website/src/panels/mouseinfopanel.ts +++ b/frontend/website/src/panels/mouseinfopanel.ts @@ -10,7 +10,7 @@ import { log } from "console"; export class MouseInfoPanel extends Panel { #coordinatesElement:HTMLElement; #unitCoordinatesElement:HTMLElement; - #locationSystems = [ "LatLng", "MGRS", "UTM" ]; + #locationSystems = [ "LatLng", "MGRS", "UTM", "LatLngDec" ]; #measureMarker: Marker; #measurePoint: LatLng | null = null; #measureIcon: Icon; @@ -20,8 +20,6 @@ export class MouseInfoPanel extends Panel { #selectedMGRSPrecisionIndex = 3; #selectedLocationSystemIndex = 0; #elevationRequest: XMLHttpRequest | null = null; - #unitElevationRequest: XMLHttpRequest | null = null; - #unitElevation: any = null; #updateInterval: any = null; @@ -40,8 +38,20 @@ export class MouseInfoPanel extends Panel { getApp().getMap()?.on('mousemove', (e: any) => this.#onMouseMove(e)); getApp().getMap()?.on('drag', (e: any) => this.#onMouseMove(e)); - document.addEventListener('unitsSelection', (e: CustomEvent) => this.#update()); - document.addEventListener('clearSelection', () => this.#update()); + document.addEventListener('unitsSelection', (e: CustomEvent) => { + /* Let's update selected unit coordinates every second, useful for moving units */ + this.#updateInterval = setInterval(() => { + var selectedUnits = getApp().getUnitsManager().getSelectedUnits(); + if (selectedUnits && selectedUnits.length == 1) { + this.#update() + } + }, 1000); + this.#update() + }); + document.addEventListener('clearSelection', () => { + clearInterval(this.#updateInterval) + this.#update() + }); this.#coordinatesElement = this.getElement().querySelector( '#coordinates-tool' ); @@ -84,8 +94,6 @@ export class MouseInfoPanel extends Panel { this.#unitCoordinatesElement = this.getElement().querySelector( '#unit-coordinates' ); this.#unitCoordinatesElement.addEventListener( "click", ( ev:MouseEvent ) => { - console.log('cliccato elemento unit coordinates'); - this.#changeLocationSystem(); }); @@ -99,14 +107,7 @@ export class MouseInfoPanel extends Panel { } }); - /* Let's update selected unit coordinates every second, useful for moving units */ - this.#updateInterval = setInterval(() => { - var selectedUnits = getApp().getUnitsManager().getSelectedUnits(); - if (selectedUnits && selectedUnits.length == 1) { - this.#update() - } else { - } - }, 1000); + /* Let's make coordinates copy-able */ this.#listenForCopyableElements(); @@ -147,15 +148,17 @@ export class MouseInfoPanel extends Panel { #update() { const mousePosition = getApp().getMap().getMouseCoordinates(); - var selectedUnitPosition = null; + let selectedUnitPosition = null; + let selectedUnitElevation = null; var selectedUnits = getApp().getUnitsManager().getSelectedUnits(); if (selectedUnits && selectedUnits.length == 1) { this.getElement().querySelector(`#unit-coordinates-container`)?.classList.remove('hide'); selectedUnitPosition = new LatLng(selectedUnits[0].getPosition().lat, selectedUnits[0].getPosition().lng); + selectedUnitElevation = selectedUnits[0].getPosition().alt; } else { selectedUnitPosition = null; - this.#unitElevation = null; + selectedUnitElevation = null; this.getElement().querySelector(`#unit-coordinates-container`)?.classList.add('hide'); } @@ -173,6 +176,7 @@ export class MouseInfoPanel extends Panel { /* Draw coordinates */ var coords = formatcoords(mousePosition.lat, mousePosition.lng); var coordString = coords.format('XDDMMss', {decimalPlaces: 4}); + let decCoordsString = coords.format('XDDm', {decimalPlaces: 3}); if ( this.#getLocationSystem() === "MGRS" ) { const mgrs = latLngToMGRS( mousePosition.lat, mousePosition.lng, this.#MGRSPrecisions[ this.#selectedMGRSPrecisionIndex ] ); @@ -181,7 +185,11 @@ export class MouseInfoPanel extends Panel { const utm = latLngToUTM( mousePosition.lat, mousePosition.lng ); this.#drawCoordinates("ref-mouse-position-utm-northing", "mouse-position-utm-northing", "N"+utm.northing); this.#drawCoordinates("ref-mouse-position-utm-easting", "mouse-position-utm-easting", "E"+utm.easting); - } else { + } else if (this.#getLocationSystem() === "LatLngDec") { + this.#drawCoordinates("ref-mouse-position-latitude-dec", "mouse-position-latitude-dec", decCoordsString.split(" ")[0]); + this.#drawCoordinates("ref-mouse-position-longitude-dec", "mouse-position-longitude-dec", decCoordsString.split(" ")[1]); + } + else { this.#drawCoordinates("ref-mouse-position-latitude", "mouse-position-latitude", coordString.split(" ")[0]); this.#drawCoordinates("ref-mouse-position-longitude", "mouse-position-longitude", coordString.split(" ")[1]); } @@ -189,19 +197,37 @@ export class MouseInfoPanel extends Panel { /* Draw selected unit coordinates */ if (selectedUnitPosition) { var unitCoords = formatcoords(selectedUnitPosition.lat, selectedUnitPosition.lng); - var unitCoordString = unitCoords.format('XDDMMss', {decimalPlaces: 4}); + var unitCoordString = unitCoords.format('XDDMMss', { decimalPlaces: 4 }); + let decCoordsString = unitCoords.format('XDDm', { decimalPlaces: 3 }); - if ( this.#getLocationSystem() === "MGRS" ) { - const mgrs = latLngToMGRS( selectedUnitPosition.lat, selectedUnitPosition.lng, this.#MGRSPrecisions[ this.#selectedMGRSPrecisionIndex ] ); - this.#drawCoordinates("ref-unit-position-mgrs", "unit-position-mgrs", "M"+mgrs.groups.join(" ") ); - } else if ( this.#getLocationSystem() === "UTM" ) { - const utm = latLngToUTM( selectedUnitPosition.lat, selectedUnitPosition.lng ); - this.#drawCoordinates("ref-unit-position-utm-northing", "unit-position-utm-northing", "N"+utm.northing); - this.#drawCoordinates("ref-unit-position-utm-easting", "unit-position-utm-easting", "E"+utm.easting); + if (this.#getLocationSystem() === "MGRS") { + const mgrs = latLngToMGRS(selectedUnitPosition.lat, selectedUnitPosition.lng, this.#MGRSPrecisions[this.#selectedMGRSPrecisionIndex]); + this.#drawCoordinates("ref-unit-position-mgrs", "unit-position-mgrs", "M" + mgrs.groups.join(" ")); + } else if (this.#getLocationSystem() === "UTM") { + const utm = latLngToUTM(selectedUnitPosition.lat, selectedUnitPosition.lng); + this.#drawCoordinates("ref-unit-position-utm-northing", "unit-position-utm-northing", "N" + utm.northing); + this.#drawCoordinates("ref-unit-position-utm-easting", "unit-position-utm-easting", "E" + utm.easting); + } else if (this.#getLocationSystem() === "LatLngDec") { + this.#drawCoordinates("ref-unit-position-latitude-dec", "unit-position-latitude-dec", decCoordsString.split(" ")[0]); + this.#drawCoordinates("ref-unit-position-longitude-dec", "unit-position-longitude-dec", decCoordsString.split(" ")[1]); } else { this.#drawCoordinates("ref-unit-position-latitude", "unit-position-latitude", unitCoordString.split(" ")[0]); this.#drawCoordinates("ref-unit-position-longitude", "unit-position-longitude", unitCoordString.split(" ")[1]); } + + const unitElevationElement = this.getElement().querySelector(`#unit-position-elevation`) as HTMLElement; + let displayedHeight = "0"; + + switch (selectedUnits[0].getCategory()) { + case 'Aircraft': + displayedHeight = "FL" + zeroAppend(Math.floor(mToFt(selectedUnitElevation as number) / 100), 3); + break; + default: + displayedHeight = Math.floor(mToFt(selectedUnitElevation as number)) + " ft" + break; + } + + unitElevationElement.dataset.value = displayedHeight; } /* Get the ground elevation from the server endpoint */ @@ -227,35 +253,6 @@ export class MouseInfoPanel extends Panel { this.#elevationRequest.onabort = () => {this.#elevationRequest = null;} this.#elevationRequest.send(); } - - /* Get the ground elevation from the server endpoint for the unit */ - if (this.#unitElevationRequest == null && this.#unitElevation == null && selectedUnitPosition !== null) { - - this.#unitElevationRequest = new XMLHttpRequest(); - this.#unitElevationRequest.open('GET', `api/elevation/${selectedUnitPosition.lat}/${selectedUnitPosition.lng}`, true); - this.#unitElevationRequest.timeout = 500; // ms - this.#unitElevationRequest.responseType = 'json'; - this.#unitElevationRequest.onload = () => { - var status = this.#unitElevationRequest?.status; - if (status === 200) { - this.#unitElevation = this.#unitElevationRequest?.response; - - const el = this.getElement().querySelector(`#unit-position-elevation`) as HTMLElement; - try { - el.dataset.value = `${Math.floor(mToFt(parseFloat(this.#unitElevation)))} ft`; - } catch { - el.dataset.value = `N/A`; - } - } else { - this.#unitElevation = null; - } - this.#unitElevationRequest = null; - }; - this.#unitElevationRequest.ontimeout = () => {this.#unitElevationRequest = null;} - this.#unitElevationRequest.onerror = () => {this.#unitElevationRequest = null;} - this.#unitElevationRequest.onabort = () => {this.#unitElevationRequest = null;} - this.#unitElevationRequest.send(); - } } #onMapClick(e: any) { From f00fce7fe72c075259e868a29cffd40023390952 Mon Sep 17 00:00:00 2001 From: MarcoJayUsai Date: Fri, 22 Nov 2024 15:10:44 +0100 Subject: [PATCH 09/11] fix(selected unit coords): added minutes indication in latlngdec coordinates format In the coordinates panel, a lat lng with decimal minutes would appear without the ending " ' " character. --- frontend/website/src/panels/mouseinfopanel.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/website/src/panels/mouseinfopanel.ts b/frontend/website/src/panels/mouseinfopanel.ts index 8c72b18d..c36ac803 100644 --- a/frontend/website/src/panels/mouseinfopanel.ts +++ b/frontend/website/src/panels/mouseinfopanel.ts @@ -186,8 +186,8 @@ export class MouseInfoPanel extends Panel { this.#drawCoordinates("ref-mouse-position-utm-northing", "mouse-position-utm-northing", "N"+utm.northing); this.#drawCoordinates("ref-mouse-position-utm-easting", "mouse-position-utm-easting", "E"+utm.easting); } else if (this.#getLocationSystem() === "LatLngDec") { - this.#drawCoordinates("ref-mouse-position-latitude-dec", "mouse-position-latitude-dec", decCoordsString.split(" ")[0]); - this.#drawCoordinates("ref-mouse-position-longitude-dec", "mouse-position-longitude-dec", decCoordsString.split(" ")[1]); + this.#drawCoordinates("ref-mouse-position-latitude-dec", "mouse-position-latitude-dec", decCoordsString.split(" ")[0] + "'"); + this.#drawCoordinates("ref-mouse-position-longitude-dec", "mouse-position-longitude-dec", decCoordsString.split(" ")[1] + "'"); } else { this.#drawCoordinates("ref-mouse-position-latitude", "mouse-position-latitude", coordString.split(" ")[0]); @@ -208,8 +208,8 @@ export class MouseInfoPanel extends Panel { this.#drawCoordinates("ref-unit-position-utm-northing", "unit-position-utm-northing", "N" + utm.northing); this.#drawCoordinates("ref-unit-position-utm-easting", "unit-position-utm-easting", "E" + utm.easting); } else if (this.#getLocationSystem() === "LatLngDec") { - this.#drawCoordinates("ref-unit-position-latitude-dec", "unit-position-latitude-dec", decCoordsString.split(" ")[0]); - this.#drawCoordinates("ref-unit-position-longitude-dec", "unit-position-longitude-dec", decCoordsString.split(" ")[1]); + this.#drawCoordinates("ref-unit-position-latitude-dec", "unit-position-latitude-dec", decCoordsString.split(" ")[0] + "'"); + this.#drawCoordinates("ref-unit-position-longitude-dec", "unit-position-longitude-dec", decCoordsString.split(" ")[1] + "'"); } else { this.#drawCoordinates("ref-unit-position-latitude", "unit-position-latitude", unitCoordString.split(" ")[0]); this.#drawCoordinates("ref-unit-position-longitude", "unit-position-longitude", unitCoordString.split(" ")[1]); From 8b5df691eca2354c696dc85deeba4eee327fe871 Mon Sep 17 00:00:00 2001 From: MarcoJayUsai Date: Fri, 22 Nov 2024 15:14:57 +0100 Subject: [PATCH 10/11] fix(selected unit coords): failsafe in case of absence of the navigator element --- frontend/website/src/panels/mouseinfopanel.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/website/src/panels/mouseinfopanel.ts b/frontend/website/src/panels/mouseinfopanel.ts index c36ac803..dc71a5a0 100644 --- a/frontend/website/src/panels/mouseinfopanel.ts +++ b/frontend/website/src/panels/mouseinfopanel.ts @@ -116,6 +116,8 @@ export class MouseInfoPanel extends Panel { #listenForCopyableElements() { const copyableElements = document.getElementsByClassName('copyable'); + // TODO: copy all the coordinates and elevation instead of copying only lat, lng or elevation. + for (const element of copyableElements) { element.addEventListener('contextmenu', (ev) => { if (!ev.target) return; @@ -134,12 +136,14 @@ export class MouseInfoPanel extends Panel { if (!text) return; + if(!navigator || !navigator.clipboard) return; + navigator.clipboard.writeText(text) .then(() => { - //console.log('Testo copiato negli appunti!'); + // Text copied to clipboard. TODO: add a toast or alert for this event. }) .catch(err => { - console.error('Errore nel copiare:', err); + console.error('An error occurred while copying text to clipboard: ', err); }); }); } From 7fe9b0d19f3ee96bd2a11db9691d99b279d9f386 Mon Sep 17 00:00:00 2001 From: Davide Passoni Date: Wed, 11 Dec 2024 18:06:59 +0100 Subject: [PATCH 11/11] fix: buttons and actions no longer getting stuck fix: context menu resizes if accordion is opened feat: added expanding descriptions for context actions --- databases/units/groundunitdatabase.json | 10 +-- frontend/react/src/constants/constants.ts | 2 +- frontend/react/src/map/boxselect.ts | 34 +++-------- frontend/react/src/map/map.ts | 9 +++ .../react/src/map/markers/custommarker.ts | 8 +++ .../src/map/markers/stylesheets/airbase.css | 4 ++ frontend/react/src/map/stylesheets/map.css | 4 ++ frontend/react/src/mission/airbase.ts | 8 ++- frontend/react/src/shortcut/shortcut.ts | 12 +++- .../react/src/ui/components/olstatebutton.tsx | 4 +- .../react/src/ui/components/oltooltip.tsx | 6 ++ .../src/ui/contextmenus/mapcontextmenu.tsx | 9 +++ .../src/ui/contextmenus/spawncontextmenu.tsx | 12 +++- frontend/react/src/ui/panels/maptoolbar.tsx | 61 ++++++++++++------- frontend/react/src/ui/ui.css | 18 ++++++ frontend/react/src/unit/unit.ts | 8 +++ 16 files changed, 145 insertions(+), 64 deletions(-) diff --git a/databases/units/groundunitdatabase.json b/databases/units/groundunitdatabase.json index 9aa77084..43537996 100644 --- a/databases/units/groundunitdatabase.json +++ b/databases/units/groundunitdatabase.json @@ -2267,7 +2267,7 @@ "coalition": "red", "era": "Mid Cold War", "category": "groundunit", - "label": "AK-74", + "label": "AK-74 (Type 1)", "shortLabel": "AK-74", "filename": "", "type": "Infantry", @@ -5558,7 +5558,7 @@ "coalition": "red", "era": "Early Cold War", "category": "groundunit", - "label": "AK-74", + "label": "AK-74 (Type 4)", "shortLabel": "AK-74", "filename": "", "type": "Infantry", @@ -7722,7 +7722,7 @@ "coalition": "red", "era": "Early Cold War", "category": "groundunit", - "label": "Insurgent AK-74", + "label": "AK-74 (Insurgent)", "shortLabel": "AK-74 (Ins)", "type": "Infantry", "enabled": true, @@ -7880,7 +7880,7 @@ "coalition": "red", "era": "Late Cold War", "category": "groundunit", - "label": "AK-74", + "label": "AK-74 (Type 2)", "shortLabel": "AK-74", "type": "Infantry", "enabled": true, @@ -7974,7 +7974,7 @@ "coalition": "red", "era": "Late Cold War", "category": "groundunit", - "label": "AK-74", + "label": "AK-74 (Type 3)", "shortLabel": "AK-74", "type": "Infantry", "enabled": true, diff --git a/frontend/react/src/constants/constants.ts b/frontend/react/src/constants/constants.ts index 93b11d36..978b7fed 100644 --- a/frontend/react/src/constants/constants.ts +++ b/frontend/react/src/constants/constants.ts @@ -513,7 +513,7 @@ export namespace ContextActions { .getUnitsManager() .addDestination(targetPosition, getApp().getMap().getKeepRelativePositions(), getApp().getMap().getDestinationRotation(), units); }, - { type: ContextActionType.MOVE, code: "ControlLeft", shiftKey: false } + { type: ContextActionType.MOVE, code: null} ); export const DELETE = new ContextAction( diff --git a/frontend/react/src/map/boxselect.ts b/frontend/react/src/map/boxselect.ts index d4db058c..edfa9635 100644 --- a/frontend/react/src/map/boxselect.ts +++ b/frontend/react/src/map/boxselect.ts @@ -12,7 +12,6 @@ export var BoxSelect = Handler.extend({ this._map = map; this._container = map.getContainer(); this._pane = map.getPanes().overlayPane; - this._resetStateTimeout = 0; map.on("unload", this._destroy, this); }, @@ -34,23 +33,12 @@ export var BoxSelect = Handler.extend({ }, _resetState: function () { - this._resetStateTimeout = 0; this._moved = false; }, - _clearDeferredResetState: function () { - if (this._resetStateTimeout !== 0) { - clearTimeout(this._resetStateTimeout); - this._resetStateTimeout = 0; - } - }, - _onMouseDown: function (e: any) { if (this._map.getSelectionEnabled() && e.button == 0) { - // Clear the deferred resetState if it hasn't executed yet, otherwise it - // will interrupt the interaction and orphan a box element in the container. - this._clearDeferredResetState(); - this._resetState(); + if (this._moved) this._finish(); DomUtil.disableImageDrag(); this._map.dragging.disable(); @@ -66,7 +54,7 @@ export var BoxSelect = Handler.extend({ touchmove: this._onMouseMove, touchend: this._onMouseUp, mousemove: this._onMouseMove, - mouseup: this._onMouseUp + mouseup: this._onMouseUp, }, this ); @@ -76,20 +64,10 @@ export var BoxSelect = Handler.extend({ }, _onMouseUp: function (e: any) { - if (e.button !== 0) { - return; - } - - this._finish(); - - if (!this._moved) { - return; - } - // Postpone to next JS tick so internal click event handling - // still see it as "moved". - window.setTimeout(Util.bind(this._resetState, this), 0); + if (e.button !== 0) return; + window.setTimeout(Util.bind(this._finish, this), 0); + if (!this._moved) return; var bounds = new LatLngBounds(this._map.containerPointToLatLng(this._startPoint), this._map.containerPointToLatLng(this._point)); - this._map.fire("selectionend", { selectionBounds: bounds }); }, @@ -141,5 +119,7 @@ export var BoxSelect = Handler.extend({ }, this ); + + this._resetState(); }, }); diff --git a/frontend/react/src/map/map.ts b/frontend/react/src/map/map.ts index 3c9411da..e63e6059 100644 --- a/frontend/react/src/map/map.ts +++ b/frontend/react/src/map/map.ts @@ -297,6 +297,11 @@ export class Map extends L.Map { ContextActionChangedEvent.on((contextAction) => this.#updateDestinationPreviewMarkers()); MapOptionsChangedEvent.on((mapOptions) => this.#moveDestinationPreviewMarkers()); + window.addEventListener("blur", () => { + this.setSelectionEnabled(false); + this.setPasteEnabled(false); + }) + /* Pan interval */ this.#panInterval = window.setInterval(() => { if (this.#panUp || this.#panDown || this.#panRight || this.#panLeft) @@ -806,6 +811,10 @@ export class Map extends L.Map { return this.#contextAction; } + getDefaultContextAction() { + return this.#contextActionSet?.getDefaultContextAction(); + } + executeDefaultContextAction(targetUnit: Unit | null, targetPosition: L.LatLng | null, originalEvent?: MouseEvent) { this.#contextActionSet?.getDefaultContextAction()?.executeCallback(targetUnit, targetPosition, originalEvent); } diff --git a/frontend/react/src/map/markers/custommarker.ts b/frontend/react/src/map/markers/custommarker.ts index 8c68779a..2e3a0f00 100644 --- a/frontend/react/src/map/markers/custommarker.ts +++ b/frontend/react/src/map/markers/custommarker.ts @@ -1,8 +1,16 @@ import { DivIcon, Map, Marker, MarkerOptions, LatLngExpression } from "leaflet"; +import { SelectionEnabledChangedEvent } from "../../events"; export class CustomMarker extends Marker { constructor(latlng: LatLngExpression, options?: MarkerOptions) { super(latlng, options); + + SelectionEnabledChangedEvent.on((enabled) => { + const el = this.getElement(); + if (el === undefined) return; + if (enabled) el.classList.add("disable-pointer-events"); + else el.classList.remove("disable-pointer-events"); + }); } onAdd(map: Map): this { diff --git a/frontend/react/src/map/markers/stylesheets/airbase.css b/frontend/react/src/map/markers/stylesheets/airbase.css index 6b1c30c6..1fa991a9 100644 --- a/frontend/react/src/map/markers/stylesheets/airbase.css +++ b/frontend/react/src/map/markers/stylesheets/airbase.css @@ -32,3 +32,7 @@ [data-awacs-mode] .airbase-icon svg * { fill: transparent !important; } + +#map-container .leaflet-airbase-marker.airbase-disable-pointer-events { + pointer-events: none; +} \ No newline at end of file diff --git a/frontend/react/src/map/stylesheets/map.css b/frontend/react/src/map/stylesheets/map.css index 12e7e2e4..c7b07fa6 100644 --- a/frontend/react/src/map/stylesheets/map.css +++ b/frontend/react/src/map/stylesheets/map.css @@ -234,3 +234,7 @@ path.leaflet-interactive:focus { .smoke-orange-cursor { cursor: url("/images/cursors/smoke-orange.svg"), auto !important; } + +#map-container .disable-pointer-events { + pointer-events: none; +} \ No newline at end of file diff --git a/frontend/react/src/mission/airbase.ts b/frontend/react/src/mission/airbase.ts index a526d042..0135fd05 100644 --- a/frontend/react/src/mission/airbase.ts +++ b/frontend/react/src/mission/airbase.ts @@ -28,12 +28,14 @@ export class Airbase extends CustomMarker { this.#img = document.createElement("img"); AppStateChangedEvent.on((state, subState) => { - const element = this.getElement(); - if (element) element.style.pointerEvents = state === OlympusState.IDLE || state === OlympusState.AIRBASE ? "all" : "none"; + const el = this.getElement(); + if (el === undefined) return; + if (state === OlympusState.IDLE || state === OlympusState.AIRBASE) el.classList.remove("airbase-disable-pointer-events"); + else el.classList.add("airbase-disable-pointer-events"); }); AirbaseSelectedEvent.on((airbase) => { - this.#selected = (airbase === this); + this.#selected = airbase === this; if (this.getElement()?.querySelector(".airbase-icon")) (this.getElement()?.querySelector(".airbase-icon") as HTMLElement).dataset.selected = `${this.#selected}`; }); diff --git a/frontend/react/src/shortcut/shortcut.ts b/frontend/react/src/shortcut/shortcut.ts index 8f915653..b947ef3e 100644 --- a/frontend/react/src/shortcut/shortcut.ts +++ b/frontend/react/src/shortcut/shortcut.ts @@ -20,7 +20,17 @@ export class Shortcut { document.addEventListener("keyup", (ev: any) => { if (this.#modal) return; if (this.#keydown && this.getOptions().code === ev.code) { - console.log(`Keydown up for shortcut ${this.#id}`) + console.log(`Keyup for shortcut ${this.#id}`) + ev.preventDefault(); + this.#keydown = false; + this.getOptions().keyUpCallback(ev); + } + }); + + /* Forced keyup, in case the window loses focus */ + document.addEventListener("blur", (ev: any) => { + if (this.#keydown) { + console.log(`Keyup (forced by blur) for shortcut ${this.#id}`) ev.preventDefault(); this.#keydown = false; this.getOptions().keyUpCallback(ev); diff --git a/frontend/react/src/ui/components/olstatebutton.tsx b/frontend/react/src/ui/components/olstatebutton.tsx index 42bd329a..2ed67987 100644 --- a/frontend/react/src/ui/components/olstatebutton.tsx +++ b/frontend/react/src/ui/components/olstatebutton.tsx @@ -9,7 +9,7 @@ export function OlStateButton(props: { buttonColor?: string | null; checked: boolean; icon?: IconProp; - tooltip?: string | JSX.Element | JSX.Element[]; + tooltip?: string | (() => JSX.Element | JSX.Element[]); tooltipPosition?: string; onClick: () => void; onMouseUp?: () => void; @@ -64,7 +64,7 @@ export function OlStateButton(props: { {props.children}
- {hover && props.tooltip && } + {hover && props.tooltip && } ); } diff --git a/frontend/react/src/ui/components/oltooltip.tsx b/frontend/react/src/ui/components/oltooltip.tsx index 1038065d..bbe26976 100644 --- a/frontend/react/src/ui/components/oltooltip.tsx +++ b/frontend/react/src/ui/components/oltooltip.tsx @@ -72,6 +72,12 @@ export function OlTooltip(props: { content: string | JSX.Element | JSX.Element[] const button = props.buttonRef.current as HTMLButtonElement; setPosition(content, button); + + const resizeObserver = new ResizeObserver(() => { + setPosition(content, button); + }); + resizeObserver.observe(content); + return () => resizeObserver.disconnect(); // clean up } }); diff --git a/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx b/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx index 1934063c..d729fedd 100644 --- a/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx +++ b/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx @@ -26,6 +26,7 @@ export function MapContextMenu(props: {}) { const [latLng, setLatLng] = useState(null as null | LatLng); const [unit, setUnit] = useState(null as null | Unit); const [selectedUnits, setSelectedUnits] = useState([] as Unit[]); + const [height, setHeight] = useState(0); var contentRef = useRef(null); @@ -68,6 +69,14 @@ export function MapContextMenu(props: {}) { content.style.left = `${newXPosition}px`; content.style.top = `${newYposition}px`; + + setHeight(content.clientHeight); + + const resizeObserver = new ResizeObserver(() => { + setHeight(content.clientHeight); + }); + resizeObserver.observe(content); + return () => resizeObserver.disconnect(); // clean up } }); diff --git a/frontend/react/src/ui/contextmenus/spawncontextmenu.tsx b/frontend/react/src/ui/contextmenus/spawncontextmenu.tsx index c08f62bf..fe00e69c 100644 --- a/frontend/react/src/ui/contextmenus/spawncontextmenu.tsx +++ b/frontend/react/src/ui/contextmenus/spawncontextmenu.tsx @@ -62,6 +62,7 @@ export function SpawnContextMenu(props: {}) { const [showCost, setShowCost] = useState(false); const [spawnCoalition, setSpawnCoalition] = useState("blue" as Coalition); const [showMore, setShowMore] = useState(false); + const [height, setHeight] = useState(0); useEffect(() => { if (selectedRole) setBlueprints(getApp()?.getUnitsManager().getDatabase().getByRole(selectedRole)); @@ -152,17 +153,24 @@ export function SpawnContextMenu(props: {}) { 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 ( <>
diff --git a/frontend/react/src/ui/panels/maptoolbar.tsx b/frontend/react/src/ui/panels/maptoolbar.tsx index 5061b0ed..40e288c4 100644 --- a/frontend/react/src/ui/panels/maptoolbar.tsx +++ b/frontend/react/src/ui/panels/maptoolbar.tsx @@ -152,26 +152,28 @@ export function MapToolBar(props: {}) { key={"select"} checked={selectionEnabled} icon={faObjectGroup} - tooltip={ -
- {shortcutCombination(shortcuts["toggleSelectionEnabled"]?.getOptions())} -
Box selection
+ tooltip={() => ( +
+
+ {shortcutCombination(shortcuts["toggleSelectionEnabled"]?.getOptions())} +
Box selection
+
- } + )} tooltipPosition="side" onClick={() => { getApp().getMap().setSelectionEnabled(!selectionEnabled); if (!selectionEnabled) { - getApp() - .getMap() - .getContainer() - .addEventListener( - "mouseup", - () => { - getApp().getMap().setSelectionEnabled(false); - }, - { once: true, signal: controller.signal } - ); + window.addEventListener( + "mouseup", + () => { + getApp().getMap().setSelectionEnabled(false); + }, + { once: true, signal: controller.signal } + ); } else { controller.abort(); } @@ -184,12 +186,12 @@ export function MapToolBar(props: {}) { key={"copy"} checked={false} icon={faCopy} - tooltip={ + tooltip={() => (
{shortcutCombination(shortcuts["copyUnits"]?.getOptions())}
Copy selected units
- } + )} tooltipPosition="side" onClick={() => { getApp().getUnitsManager().copy(selectedUnits); @@ -199,14 +201,21 @@ export function MapToolBar(props: {}) { )} {copiedUnitsData.length > 0 && (
- (
{shortcutCombination(shortcuts["pasteUnits"]?.getOptions())}
Paste copied units
- } tooltipPosition="side" onClick={() => { - getApp().getMap().setPasteEnabled(!pasteEnabled) - }} /> + )} + tooltipPosition="side" + onClick={() => { + getApp().getMap().setPasteEnabled(!pasteEnabled); + }} + />
)} @@ -218,12 +227,18 @@ export function MapToolBar(props: {}) { key={contextActionIt.getId()} checked={contextActionIt === contextAction} icon={contextActionIt.getIcon()} - tooltip={ + tooltip={() => ( +
{shortcutCombination(contextActionIt.getOptions())}
{contextActionIt.getLabel()}
- } +
{contextActionIt.getDescription()}
+
+ )} tooltipPosition="side" buttonColor={CONTEXT_ACTION_COLORS[contextActionIt.getOptions().type ?? 0]} onClick={() => { diff --git a/frontend/react/src/ui/ui.css b/frontend/react/src/ui/ui.css index 62f01669..95147ad0 100644 --- a/frontend/react/src/ui/ui.css +++ b/frontend/react/src/ui/ui.css @@ -103,4 +103,22 @@ input[type="range"]:focus::-moz-range-thumb { .no-scrollbar { -ms-overflow-style: none; /* IE and Edge */ scrollbar-width: none; /* Firefox */ +} + +@keyframes tooltipFadeInHeight { + 99% { + height: 25px; + } + 100% { + height: fit-content; + } +} + +@keyframes tooltipFadeInWidth { + 99% { + width: 0px; + } + 100% { + width: 200px; + } } \ No newline at end of file diff --git a/frontend/react/src/unit/unit.ts b/frontend/react/src/unit/unit.ts index 60fa5731..cc42c5e2 100644 --- a/frontend/react/src/unit/unit.ts +++ b/frontend/react/src/unit/unit.ts @@ -1372,6 +1372,14 @@ export abstract class Unit extends CustomMarker { #onRightShortClick(e: any) { console.log(`Right short click on ${this.getUnitName()}`); + + window.clearTimeout(this.#rightMouseDownTimeout); + if ( + getApp().getState() === OlympusState.UNIT_CONTROL && + getApp().getMap().getDefaultContextAction() && + getApp().getMap().getDefaultContextAction()?.getTarget() === ContextActionTarget.POINT + ) + getApp().getMap().executeDefaultContextAction(null, this.getPosition(), e.originalEvent); } #onRightLongClick(e: any) {