| 
									
										
										
										
											2020-09-13 07:05:05 +00:00
										 |  |  | import { makeDiv } from "../../../core/utils"; | 
					
						
							|  |  |  | import { T } from "../../../translations"; | 
					
						
							|  |  |  | import { | 
					
						
							|  |  |  |     getStringForKeyCode, | 
					
						
							|  |  |  |     KEYCODE_LMB, | 
					
						
							|  |  |  |     KEYCODE_MMB, | 
					
						
							|  |  |  |     KEYCODE_RMB, | 
					
						
							|  |  |  |     KEYMAPPINGS, | 
					
						
							|  |  |  | } from "../../key_action_mapper"; | 
					
						
							|  |  |  | import { BaseHUDPart } from "../base_hud_part"; | 
					
						
							|  |  |  | import { DynamicDomAttach } from "../dynamic_dom_attach"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const DIVIDER_TOKEN = "/"; | 
					
						
							|  |  |  | const ADDER_TOKEN = "+"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {{ keyCode: number }} KeyCode | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {{ | 
					
						
							|  |  |  |  *   condition: () => boolean, | 
					
						
							|  |  |  |  *   keys: Array<KeyCode|number|string>, | 
					
						
							|  |  |  |  *   label: string, | 
					
						
							|  |  |  |  *   cachedElement?: HTMLElement, | 
					
						
							|  |  |  |  *   cachedVisibility?: boolean | 
					
						
							|  |  |  |  * }} KeyBinding | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class HUDKeybindingOverlay extends BaseHUDPart { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * HELPER / Returns if there is a building selected for placement | 
					
						
							|  |  |  |      * @returns {boolean} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     get buildingPlacementActive() { | 
					
						
							|  |  |  |         const placer = this.root.hud.parts.buildingPlacer; | 
					
						
							|  |  |  |         return !this.mapOverviewActive && placer && !!placer.currentMetaBuilding.get(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * HELPER / Returns if there is a building selected for placement and | 
					
						
							|  |  |  |      * it supports the belt planner | 
					
						
							|  |  |  |      * @returns {boolean} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     get buildingPlacementSupportsBeltPlanner() { | 
					
						
							|  |  |  |         const placer = this.root.hud.parts.buildingPlacer; | 
					
						
							|  |  |  |         return ( | 
					
						
							|  |  |  |             !this.mapOverviewActive && | 
					
						
							|  |  |  |             placer && | 
					
						
							|  |  |  |             placer.currentMetaBuilding.get() && | 
					
						
							|  |  |  |             placer.currentMetaBuilding.get().getHasDirectionLockAvailable() | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * HELPER / Returns if there is a building selected for placement and | 
					
						
							|  |  |  |      * it has multiplace enabled by default | 
					
						
							|  |  |  |      * @returns {boolean} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     get buildingPlacementStaysInPlacement() { | 
					
						
							|  |  |  |         const placer = this.root.hud.parts.buildingPlacer; | 
					
						
							|  |  |  |         return ( | 
					
						
							|  |  |  |             !this.mapOverviewActive && | 
					
						
							|  |  |  |             placer && | 
					
						
							|  |  |  |             placer.currentMetaBuilding.get() && | 
					
						
							|  |  |  |             placer.currentMetaBuilding.get().getStayInPlacementMode() | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * HELPER / Returns if there is a blueprint selected for placement | 
					
						
							|  |  |  |      * @returns {boolean} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     get blueprintPlacementActive() { | 
					
						
							|  |  |  |         const placer = this.root.hud.parts.blueprintPlacer; | 
					
						
							|  |  |  |         return placer && !!placer.currentBlueprint.get(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * HELPER / Returns if the belt planner is currently active | 
					
						
							|  |  |  |      * @returns {boolean} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     get beltPlannerActive() { | 
					
						
							|  |  |  |         const placer = this.root.hud.parts.buildingPlacer; | 
					
						
							|  |  |  |         return !this.mapOverviewActive && placer && placer.isDirectionLockActive; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * HELPER / Returns if there is a last blueprint available | 
					
						
							|  |  |  |      * @returns {boolean} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     get lastBlueprintAvailable() { | 
					
						
							|  |  |  |         const placer = this.root.hud.parts.blueprintPlacer; | 
					
						
							|  |  |  |         return placer && !!placer.lastBlueprintUsed; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * HELPER / Returns if there is anything selected on the map | 
					
						
							|  |  |  |      * @returns {boolean} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     get anythingSelectedOnMap() { | 
					
						
							|  |  |  |         const selector = this.root.hud.parts.massSelector; | 
					
						
							|  |  |  |         return selector && selector.selectedUids.size > 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * HELPER / Returns if there is a building or blueprint selected for placement | 
					
						
							|  |  |  |      * @returns {boolean} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     get anyPlacementActive() { | 
					
						
							|  |  |  |         return this.buildingPlacementActive || this.blueprintPlacementActive; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * HELPER / Returns if the map overview is active | 
					
						
							|  |  |  |      * @returns {boolean} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     get mapOverviewActive() { | 
					
						
							|  |  |  |         return this.root.camera.getIsMapOverlayActive(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Initializes the element | 
					
						
							|  |  |  |      * @param {HTMLElement} parent | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     createElements(parent) { | 
					
						
							|  |  |  |         const mapper = this.root.keyMapper; | 
					
						
							|  |  |  |         const k = KEYMAPPINGS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @type {Array<KeyBinding>} */ | 
					
						
							|  |  |  |         this.keybindings = [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Move map - Including mouse
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.moveMap, | 
					
						
							|  |  |  |                 keys: [ | 
					
						
							|  |  |  |                     KEYCODE_LMB, | 
					
						
							|  |  |  |                     DIVIDER_TOKEN, | 
					
						
							|  |  |  |                     k.navigation.mapMoveUp, | 
					
						
							|  |  |  |                     k.navigation.mapMoveLeft, | 
					
						
							|  |  |  |                     k.navigation.mapMoveDown, | 
					
						
							|  |  |  |                     k.navigation.mapMoveRight, | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |                 condition: () => !this.anyPlacementActive, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Move map - No mouse
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.moveMap, | 
					
						
							|  |  |  |                 keys: [ | 
					
						
							|  |  |  |                     k.navigation.mapMoveUp, | 
					
						
							|  |  |  |                     k.navigation.mapMoveLeft, | 
					
						
							|  |  |  |                     k.navigation.mapMoveDown, | 
					
						
							|  |  |  |                     k.navigation.mapMoveRight, | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |                 condition: () => this.anyPlacementActive, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // [OVERVIEW] Create marker with right click
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.createMarker, | 
					
						
							|  |  |  |                 keys: [KEYCODE_RMB], | 
					
						
							|  |  |  |                 condition: () => this.mapOverviewActive && !this.blueprintPlacementActive, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Pipette
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.pipette, | 
					
						
							|  |  |  |                 keys: [k.placement.pipette], | 
					
						
							|  |  |  |                 condition: () => !this.mapOverviewActive && !this.blueprintPlacementActive, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Cancel placement
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.stopPlacement, | 
					
						
							|  |  |  |                 keys: [KEYCODE_RMB], | 
					
						
							|  |  |  |                 condition: () => this.anyPlacementActive, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Delete with right click
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.delete, | 
					
						
							|  |  |  |                 keys: [KEYCODE_RMB], | 
					
						
							|  |  |  |                 condition: () => | 
					
						
							|  |  |  |                     !this.anyPlacementActive && !this.mapOverviewActive && !this.anythingSelectedOnMap, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Area select
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.selectBuildings, | 
					
						
							|  |  |  |                 keys: [k.massSelect.massSelectStart, ADDER_TOKEN, KEYCODE_LMB], | 
					
						
							|  |  |  |                 condition: () => !this.anyPlacementActive && !this.anythingSelectedOnMap, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Place building
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.placeBuilding, | 
					
						
							|  |  |  |                 keys: [KEYCODE_LMB], | 
					
						
							|  |  |  |                 condition: () => this.anyPlacementActive, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Rotate
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.rotateBuilding, | 
					
						
							|  |  |  |                 keys: [k.placement.rotateWhilePlacing], | 
					
						
							|  |  |  |                 condition: () => this.anyPlacementActive && !this.beltPlannerActive, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // [BELT PLANNER] Flip Side
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.plannerSwitchSide, | 
					
						
							|  |  |  |                 keys: [k.placement.switchDirectionLockSide], | 
					
						
							|  |  |  |                 condition: () => this.beltPlannerActive, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Place last blueprint
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.pasteLastBlueprint, | 
					
						
							|  |  |  |                 keys: [k.massSelect.pasteLastBlueprint], | 
					
						
							|  |  |  |                 condition: () => !this.blueprintPlacementActive && this.lastBlueprintAvailable, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Belt planner
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.lockBeltDirection, | 
					
						
							|  |  |  |                 keys: [k.placementModifiers.lockBeltDirection], | 
					
						
							|  |  |  |                 condition: () => this.buildingPlacementSupportsBeltPlanner && !this.beltPlannerActive, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // [SELECTION] Destroy
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.delete, | 
					
						
							|  |  |  |                 keys: [k.massSelect.confirmMassDelete], | 
					
						
							|  |  |  |                 condition: () => this.anythingSelectedOnMap, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // [SELECTION] Cancel
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.clearSelection, | 
					
						
							|  |  |  |                 keys: [k.general.back], | 
					
						
							|  |  |  |                 condition: () => this.anythingSelectedOnMap, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // [SELECTION] Cut
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.cutSelection, | 
					
						
							|  |  |  |                 keys: [k.massSelect.massSelectCut], | 
					
						
							|  |  |  |                 condition: () => this.anythingSelectedOnMap, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // [SELECTION] Copy
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.copySelection, | 
					
						
							|  |  |  |                 keys: [k.massSelect.massSelectCopy], | 
					
						
							|  |  |  |                 condition: () => this.anythingSelectedOnMap, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Switch layers
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.switchLayers, | 
					
						
							|  |  |  |                 keys: [k.ingame.switchLayers], | 
					
						
							|  |  |  |                 condition: () => true, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!this.root.app.settings.getAllSettings().alwaysMultiplace) { | 
					
						
							|  |  |  |             this.keybindings.push({ | 
					
						
							|  |  |  |                 // Multiplace
 | 
					
						
							|  |  |  |                 label: T.ingame.keybindingsOverlay.placeMultiple, | 
					
						
							|  |  |  |                 keys: [k.placementModifiers.placeMultiple], | 
					
						
							|  |  |  |                 condition: () => this.anyPlacementActive && !this.buildingPlacementStaysInPlacement, | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.element = makeDiv(parent, "ingame_HUD_KeybindingOverlay", []); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (let i = 0; i < this.keybindings.length; ++i) { | 
					
						
							|  |  |  |             let html = ""; | 
					
						
							|  |  |  |             const handle = this.keybindings[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (let k = 0; k < handle.keys.length; ++k) { | 
					
						
							|  |  |  |                 const key = handle.keys[k]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 switch (key) { | 
					
						
							|  |  |  |                     case KEYCODE_LMB: | 
					
						
							|  |  |  |                         html += `<code class="keybinding leftMouse"></code>`; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case KEYCODE_RMB: | 
					
						
							|  |  |  |                         html += `<code class="keybinding rightMouse"></code>`; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case KEYCODE_MMB: | 
					
						
							|  |  |  |                         html += `<code class="keybinding middleMouse"></code>`; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case DIVIDER_TOKEN: | 
					
						
							|  |  |  |                         html += `<i></i>`; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case ADDER_TOKEN: | 
					
						
							|  |  |  |                         html += `+`; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     default: | 
					
						
							|  |  |  |                         html += `<code class="keybinding">${getStringForKeyCode( | 
					
						
							|  |  |  |                             mapper.getBinding(/** @type {KeyCode} */ (key)).keyCode | 
					
						
							|  |  |  |                         )}</code>`; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             html += `<label>${handle.label}</label>`; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             handle.cachedElement = makeDiv(this.element, null, ["binding"], html); | 
					
						
							|  |  |  |             handle.cachedVisibility = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     initialize() { | 
					
						
							|  |  |  |         this.domAttach = new DynamicDomAttach(this.root, this.element, { | 
					
						
							|  |  |  |             trackHover: true, | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     update() { | 
					
						
							|  |  |  |         for (let i = 0; i < this.keybindings.length; ++i) { | 
					
						
							|  |  |  |             const handle = this.keybindings[i]; | 
					
						
							|  |  |  |             const visibility = handle.condition(); | 
					
						
							|  |  |  |             if (visibility !== handle.cachedVisibility) { | 
					
						
							|  |  |  |                 handle.cachedVisibility = visibility; | 
					
						
							|  |  |  |                 handle.cachedElement.classList.toggle("visible", visibility); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Required for hover
 | 
					
						
							|  |  |  |         this.domAttach.update(true); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |