Index: binaries/data/mods/public/gui/session/hotkeys/camera.xml
===================================================================
--- binaries/data/mods/public/gui/session/hotkeys/camera.xml
+++ binaries/data/mods/public/gui/session/hotkeys/camera.xml
@@ -1,92 +0,0 @@
-
-
Index: binaries/data/mods/public/gui/session/hotkeys/misc.xml
===================================================================
--- binaries/data/mods/public/gui/session/hotkeys/misc.xml
+++ binaries/data/mods/public/gui/session/hotkeys/misc.xml
@@ -1,126 +0,0 @@
-
-
-
- closeOpenDialogs();
-
-
-
- openChat();
-
-
-
- openChat(g_IsObserver ? "/observers" : "/allies");
-
-
-
- openChat(g_LastChatAddressee);
-
-
-
- g_ShowGUI = !g_ShowGUI;
-
-
-
- toggleMenu();
-
-
-
- toggleTrade();
-
-
-
- toggleTutorial();
-
-
-
- openGameSummary();
-
-
-
- toggleConfigBool("silhouettes");
-
-
-
-
- var newSetting = !Engine.Renderer_GetShowSkyEnabled();
- Engine.Renderer_SetShowSkyEnabled(newSetting);
-
-
-
-
- togglePause();
-
-
-
- Engine.QuickSave();
-
-
-
- Engine.QuickLoad();
-
-
-
- performCommand(g_Selection.toList().map(ent => GetEntityState(ent)), "delete");
-
-
-
- unloadAll();
-
-
-
- stopUnits(g_Selection.toList());
-
-
-
- backToWork();
-
-
-
- updateSelectionDetails();
- updateSelectionDetails();
-
-
-
-
- updateSelectionDetails();
- updateBarterButtons();
-
-
-
- updateSelectionDetails();
- updateBarterButtons();
-
-
-
-
-
- findIdleUnit(g_MilitaryTypes);
-
-
-
- findIdleUnit(["!Domestic"]);
-
-
-
- clearSelection();
-
-
-
- toggleRangeOverlay("Attack");
-
-
-
- toggleRangeOverlay("Auras");
-
-
-
- toggleRangeOverlay("Heal");
-
-
-
-
- g_ShowAllStatusBars = !g_ShowAllStatusBars;
- recalculateStatusBarDisplay();
-
-
-
Index: binaries/data/mods/public/gui/session/hotkeys/training.xml
===================================================================
--- binaries/data/mods/public/gui/session/hotkeys/training.xml
+++ binaries/data/mods/public/gui/session/hotkeys/training.xml
@@ -1,37 +0,0 @@
-
-
-
-
- addTrainingByPosition(0);
-
-
-
-
- addTrainingByPosition(1);
-
-
-
-
- addTrainingByPosition(2);
-
-
-
-
- addTrainingByPosition(3);
-
-
-
-
- addTrainingByPosition(4);
-
-
-
-
- addTrainingByPosition(5);
-
-
-
-
- addTrainingByPosition(6);
-
-
Index: binaries/data/mods/public/gui/session/input.js
===================================================================
--- binaries/data/mods/public/gui/session/input.js
+++ binaries/data/mods/public/gui/session/input.js
@@ -61,6 +61,174 @@
var doublePressTimer = 0;
var prevHotkey = 0;
+var g_Hotkeys = {
+ "session.backtowork":
+ { "hotkeydown": () => backToWork() },
+ "session.gui.tutorial.toggle":
+ { "hotkeydown": () => toggleTutorial() },
+ "silhouettes":
+ { "hotkeydown": () => toggleConfigBool("silhouettes") },
+ "session.stop":
+ { "hotkeydown": () => stopUnits(g_Selection.toList()) },
+ "quicksave":
+ { "hotkeydown": () => Engine.QuickSave() },
+ "quickload":
+ { "hotkeydown": () => Engine.QuickLoad() },
+ "session.kill":
+ { "hotkeydown": () => performCommand(g_Selection.toList().map(ent => GetEntityState(ent)), "delete") },
+ "session.unload":
+ { "hotkeydown": () => unloadAll() },
+ "session.batchtrain":
+ { "hotkeydown": () => updateSelectionDetails(), "hotkeyup": () => updateSelectionDetails() },
+ "session.massbarter":
+ { "hotkeydown": () => {
+ updateSelectionDetails();
+ updateBarterButtons();
+ },
+ "hotkeyup": () => {
+ updateSelectionDetails();
+ updateBarterButtons();
+ } },
+ "cancel":
+ { "hotkeydown": () => closeOpenDialogs() },
+ "teamchat":
+ { "hotkeydown": () => openChat(g_IsObserver ? "/observers" : "/allies") },
+ "privatechat":
+ { "hotkeydown": () => openChat(g_LastChatAddressee) },
+ "session.gui.toggle":
+ { "hotkeydown": () => g_ShowGUI = !g_ShowGUI },
+ "showsky":
+ { "hotkeydown": () => {
+ var newSetting = !Engine.Renderer_GetShowSkyEnabled();
+ Engine.Renderer_SetShowSkyEnabled(newSetting);
+ } },
+ // Find idle warrior - TODO: Potentially move this to own UI button?
+ "selection.idlewarrior":
+ { "hotkeydown": () => findIdleUnit(g_MilitaryTypes) },
+ "selection.idleunit":
+ { "hotkeydown": () => findIdleUnit(["!Domestic"]) },
+ "selection.cancel":
+ { "hotkeydown": () => clearSelection() },
+ "session.toggleattackrange":
+ { "hotkeydown": () => toggleRangeOverlay("Attack") },
+ "session.toggleaurasrange":
+ { "hotkeydown": () => toggleRangeOverlay("Auras") },
+ "session.togglehealrange":
+ { "hotkeydown": () => toggleRangeOverlay("Heal") },
+ "session.showstatusbars":
+ { "hotkeydown": () => {
+ g_ShowAllStatusBars = !g_ShowAllStatusBars;
+ recalculateStatusBarDisplay();
+ } },
+
+ // Queue first unit in the training queue.
+ "session.queueunit.1":
+ { "hotkeydown": () => addTrainingByPosition(0) },
+ // Queue 2nd unit in the training queue.
+ "session.queueunit.2":
+ { "hotkeydown": () => addTrainingByPosition(1) },
+ "session.queueunit.3":
+ { "hotkeydown": () => addTrainingByPosition(2) },
+ "session.queueunit.4":
+ { "hotkeydown": () => addTrainingByPosition(3) },
+ "session.queueunit.5":
+ { "hotkeydown": () => addTrainingByPosition(4) },
+ "session.queueunit.6":
+ { "hotkeydown": () => addTrainingByPosition(5) },
+ "session.queueunit.7":
+ { "hotkeydown": () => addTrainingByPosition(6) },
+
+ // camera.follow mode - follow the first unit in the selection.
+ "camera.follow":
+ { "hotkeydown": () => setCameraFollow(g_Selection.getFirstSelected()) },
+ "camera.rallypointfocus":
+ { "hotkeydown": () => performCommand(g_Selection.toList().map(ent => GetEntityState(ent)), "focus-rally") },
+ // Camera jumping - press a hotkey to mark a position and another hotkey to jump back there.
+ "camera.jump.1":
+ { "hotkeydown": () => jumpCamera(1) },
+ "camera.jump.2":
+ { "hotkeydown": () => jumpCamera(2) },
+ "camera.jump.3":
+ { "hotkeydown": () => jumpCamera(3) },
+ "camera.jump.4":
+ { "hotkeydown": () => jumpCamera(4) },
+ "camera.jump.5":
+ { "hotkeydown": () => jumpCamera(5) },
+ "camera.jump.6":
+ { "hotkeydown": () => jumpCamera(6) },
+ "camera.jump.7":
+ { "hotkeydown": () => jumpCamera(7) },
+ "camera.jump.8":
+ { "hotkeydown": () => jumpCamera(8) },
+ "camera.jump.9":
+ { "hotkeydown": () => jumpCamera(9) },
+ "camera.jump.10":
+ { "hotkeydown": () => jumpCamera(10) },
+ "camera.jump.set.1":
+ { "hotkeydown": () => setJumpCamera(1) },
+ "camera.jump.set.2":
+ { "hotkeydown": () => setJumpCamera(2) },
+ "camera.jump.set.3":
+ { "hotkeydown": () => setJumpCamera(3) },
+ "camera.jump.set.4":
+ { "hotkeydown": () => setJumpCamera(4) },
+ "camera.jump.set.5":
+ { "hotkeydown": () => setJumpCamera(5) },
+ "camera.jump.set.6":
+ { "hotkeydown": () => setJumpCamera(6) },
+ "camera.jump.set.7":
+ { "hotkeydown": () => setJumpCamera(7) },
+ "camera.jump.set.8":
+ { "hotkeydown": () => setJumpCamera(8) },
+ "camera.jump.set.9":
+ { "hotkeydown": () => setJumpCamera(9) },
+ "camera.jump.set.10":
+ { "hotkeydown": () => setJumpCamera(10) }
+};
+
+/**
+ * Group hotkeys that are mapped on the same key to one array, that is later processed if hotkey is hitted.
+ * If explicity want only one function happening on condition
+ * When hitted, the processing can be stopped by returning a true in a function. So only furthe
+ */
+function groupHotkeysMappedSameKey()
+{
+ let getUnifiedHotkeyName = name => Engine.ConfigDB_GetValue("user", name).toLowerCase().replace("escape", "esc");
+
+ for (let hotkeyA in g_Hotkeys)
+ {
+ let keyA = getUnifiedHotkeyName("hotkey." + hotkeyA);
+
+ for (let typeA in g_Hotkeys[hotkeyA])
+ {
+ // Has hotkey already been checked.
+ if (!g_Hotkeys[hotkeyA][typeA] || Array.isArray(g_Hotkeys[hotkeyA][typeA]))
+ continue;
+
+ for (let hotkeyB in g_Hotkeys)
+ {
+ // Same hotkey.
+ if (hotkeyB == hotkeyA)
+ continue;
+
+ let keyB = getUnifiedHotkeyName("hotkey." + hotkeyB);
+ for (let typeB in g_Hotkeys[hotkeyB])
+ {
+ // Same key and type.
+ if (keyB == keyA && typeA == typeB)
+ {
+ if (!Array.isArray(g_Hotkeys[hotkeyA][typeA]))
+ g_Hotkeys[hotkeyA][typeA] = [g_Hotkeys[hotkeyA][typeA]];
+
+ g_Hotkeys[hotkeyA][typeA].push(g_Hotkeys[hotkeyB][typeB])
+ g_Hotkeys[hotkeyB][typeB] = "";
+ }
+ }
+ }
+ }
+ }
+}
+
function updateCursorAndTooltip()
{
var cursorSet = false;
@@ -797,6 +965,13 @@
g_ShowGuarded = (ev.type == "hotkeydown");
updateAdditionalHighlight();
}
+ else if (!!g_Hotkeys[ev.hotkey] && !!g_Hotkeys[ev.hotkey][ev.type])
+ {
+ if (Array.isArray(g_Hotkeys[ev.hotkey][ev.type]))
+ g_Hotkeys[ev.hotkey][ev.type].some(exec => exec());
+ else
+ g_Hotkeys[ev.hotkey][ev.type]();
+ }
if (inputState != INPUT_NORMAL && inputState != INPUT_SELECTING)
clickedEntity = INVALID_ENTITY;
Index: binaries/data/mods/public/gui/session/menu.js
===================================================================
--- binaries/data/mods/public/gui/session/menu.js
+++ binaries/data/mods/public/gui/session/menu.js
@@ -130,12 +130,6 @@
Engine.PushGuiPage("page_lobby.xml", { "dialog": true });
}
-function chatMenuButton()
-{
- closeOpenDialogs();
- openChat();
-}
-
function diplomacyMenuButton()
{
closeOpenDialogs();
@@ -1238,11 +1232,20 @@
function closeOpenDialogs()
{
+ if (Engine.GetGUIObjectByName("chatDialogPanel").hidden &&
+ !g_IsMenuOpen &&
+ !g_IsDiplomacyOpen &&
+ !g_IsTradeOpen &&
+ !g_IsObjectivesOpen)
+ return false;
+
closeMenu();
closeChat();
closeDiplomacy();
closeTrade();
closeObjectives();
+
+ return true;
}
function formatTributeTooltip(playerID, resourceCode, amount)
Index: binaries/data/mods/public/gui/session/menu.xml
===================================================================
--- binaries/data/mods/public/gui/session/menu.xml
+++ binaries/data/mods/public/gui/session/menu.xml
@@ -24,9 +24,10 @@
style="StoneButtonFancy"
size="0 32 100% 60"
tooltip_style="sessionToolTip"
+ hotkey="chat"
>
Chat
- chatMenuButton();
+ openChat();
@@ -48,6 +49,7 @@
style="StoneButtonFancy"
size="0 96 100% 124"
tooltip_style="sessionToolTip"
+ hotkey="summary"
>
Summary
openGameSummary();
@@ -62,7 +64,6 @@
hotkey="lobby"
>
Lobby
- Show the multiplayer lobby in a dialog window.
lobbyDialogButton();
@@ -83,6 +84,7 @@
style="StoneButtonFancy"
size="0 192 100% 220"
tooltip_style="sessionToolTip"
+ hotkey="pause"
>
Pause
togglePause();
Index: binaries/data/mods/public/gui/session/session.js
===================================================================
--- binaries/data/mods/public/gui/session/session.js
+++ binaries/data/mods/public/gui/session/session.js
@@ -200,6 +200,53 @@
*/
var g_MilitaryTypes = ["Melee", "Ranged"];
+/**
+ * Setting tooltips, hotkey descriptions in tooltips and enable/disable states of the GUI buttons.
+ */
+var g_GuiButtons = () => { return {
+ "menuButton": { "description": "Toggle the in-game menu." },
+ "manualButton": { "description": "Show the game manual." },
+ "saveGameButton": { "description": "Save the current game." },
+ "summaryButton": { "description": "Show the summary dialog." },
+ "lobbyButton": { "description": "Show the multiplayer lobby in a dialog.", "enabled": Engine.HasXmppClient() },
+ "chatButton": { "hotkey": [
+ { "hotkey": "chat", "description": translate("Chat"), "showOnlyWhenUsed": true },
+ { "hotkey": "teamchat", "description": translate("Team chat"), "showOnlyWhenUsed": true },
+ { "hotkey": "privatechat", "description": translate("Private chat"), "showOnlyWhenUsed": true }
+ ] },
+ "optionsButton": { "description": "Show the options dialog." },
+ "pauseButton": { "description": "Toggle pause the game.", "enabled": !g_IsObserver || !g_IsNetworked || g_IsController },
+ "menuResignButton": { "description": "Resign from the current game.", "enabled": !g_IsObserver },
+ "menuExitButton": { "description": "Exit from the current game." },
+ "tradeButton1": { "description": "Barter & Trade" },
+ "idleWorkerButton": { "description": "Find idle worker." },
+ "diplomacyColorsButton": { "description": "Toggle Diplomacy Colors." },
+ "tradeHelp": {
+ "description": colorizeHotkey(
+ translate("Select one type of goods you want to modify by clicking on it, and then use the arrows of the other types to modify their shares. You can also press %(hotkey)s while selecting one type of goods to bring its share to 100%%."),
+ "session.fulltradeswap")
+ },
+ "barterHelp": {
+ "description": sprintf(
+ translate("Start by selecting the resource you wish to sell from the upper row. For each time the lower buttons are pressed, %(quantity)s of the upper resource will be sold for the displayed quantity of the lower. Press and hold %(hotkey)s to temporarily multiply the traded amount by %(multiplier)s."), {
+ "quantity": g_BarterResourceSellQuantity,
+ "hotkey": colorizeHotkey("%(hotkey)s", "session.massbarter"),
+ "multiplier": g_BarterMultiplier
+ })
+ },
+ "chatInput": {
+ "description": translateWithContext("chat input", "Type the message to send.") + "\n" +
+ colorizeAutocompleteHotkey() +
+ colorizeHotkey("\n" + translate("Press %(hotkey)s to open the public chat."), "chat") +
+ colorizeHotkey(
+ "\n" + (g_IsObserver ?
+ translate("Press %(hotkey)s to open the observer chat.") :
+ translate("Press %(hotkey)s to open the ally chat.")),
+ "teamchat") +
+ colorizeHotkey("\n" + translate("Press %(hotkey)s to open the previously selected private chat."), "privatechat")
+ }
+} };
+
function GetSimState()
{
if (!g_SimState)
@@ -290,6 +337,7 @@
initializeMusic(); // before changing the perspective
initSessionMenuButtons();
+ groupHotkeysMappedSameKey();
for (let slot in Engine.GetGUIObjectByName("panelEntityPanel").children)
initPanelEntities(slot);
@@ -430,39 +478,40 @@
}
/**
- * Depends on the current player (g_IsObserver).
+ * Setting enable/disable state and tooltip with hotkey information to GUI Buttons.
*/
-function updateHotkeyTooltips()
+function updateGuiButtons()
{
- Engine.GetGUIObjectByName("chatInput").tooltip =
- translateWithContext("chat input", "Type the message to send.") + "\n" +
- colorizeAutocompleteHotkey() +
- colorizeHotkey("\n" + translate("Press %(hotkey)s to open the public chat."), "chat") +
- colorizeHotkey(
- "\n" + (g_IsObserver ?
- translate("Press %(hotkey)s to open the observer chat.") :
- translate("Press %(hotkey)s to open the ally chat.")),
- "teamchat") +
- colorizeHotkey("\n" + translate("Press %(hotkey)s to open the previously selected private chat."), "privatechat");
-
- Engine.GetGUIObjectByName("idleWorkerButton").tooltip =
- colorizeHotkey("%(hotkey)s" + " ", "selection.idleworker") +
- translate("Find idle worker");
-
- Engine.GetGUIObjectByName("diplomacyColorsButton").tooltip =
- colorizeHotkey("%(hotkey)s" + " ", "diplomacycolors") +
- translate("Toggle Diplomacy Colors");
-
- Engine.GetGUIObjectByName("tradeHelp").tooltip = colorizeHotkey(
- translate("Select one type of goods you want to modify by clicking on it, and then use the arrows of the other types to modify their shares. You can also press %(hotkey)s while selecting one type of goods to bring its share to 100%%."),
- "session.fulltradeswap");
-
- Engine.GetGUIObjectByName("barterHelp").tooltip = sprintf(
- translate("Start by selecting the resource you wish to sell from the upper row. For each time the lower buttons are pressed, %(quantity)s of the upper resource will be sold for the displayed quantity of the lower. Press and hold %(hotkey)s to temporarily multiply the traded amount by %(multiplier)s."), {
- "quantity": g_BarterResourceSellQuantity,
- "hotkey": colorizeHotkey("%(hotkey)s", "session.massbarter"),
- "multiplier": g_BarterMultiplier
- });
+ let colorizedHotkey = name => {
+ let hotkey = Engine.ConfigDB_GetValue("user", "hotkey." + name);
+ return !hotkey || hotkey == "unused" ? "" : setStringTags("\\[" + hotkey + "]", g_HotkeyTags);
+ }
+
+ let getTooltip = (hotkey, description) =>
+ colorizedHotkey(hotkey) == "" ? description : translate(description) != "" ? sprintf(translate("%(hotkey)s: " + description), {
+ "hotkey": colorizedHotkey(hotkey)
+ }) : colorizedHotkey(hotkey);
+
+ let buttons = g_GuiButtons();
+ for (let name in buttons)
+ {
+ let button = buttons[name];
+ let enabled = button.enabled == undefined || button.enabled;
+ let guiObj = Engine.GetGUIObjectByName(name);
+ guiObj.enabled = enabled;
+ let hotkey = button.hotkey || guiObj.hotkey || "";
+
+ if ((!hotkey && !button.description) || !enabled)
+ continue;
+
+ if (hotkey && Array.isArray(hotkey))
+ guiObj.tooltip = hotkey.map(tooltip =>
+ !!tooltip.showOnlyWhenUsed && colorizedHotkey(tooltip.hotkey) == "" ? "" :
+ getTooltip(tooltip.hotkey, tooltip.description)).join("\n");
+ else
+ if (!hotkey || typeof(hotkey) == 'string')
+ guiObj.tooltip = getTooltip(hotkey, button.description || "");
+ }
}
function initPanelEntities(slot)
@@ -555,7 +604,8 @@
updateDisplayedPlayerColors();
updateTopPanel();
updateChatAddressees();
- updateHotkeyTooltips();
+ updateGuiButtons();
+ // updateHotkeyTooltips();
// Update GUI and clear player-dependent cache
g_TemplateData = {};
@@ -690,10 +740,6 @@
let alphaLabel = Engine.GetGUIObjectByName("alphaLabel");
alphaLabel.hidden = isPlayer && !viewPlayer.hidden;
alphaLabel.size = isPlayer ? "50%+44 0 100%-283 100%" : "155 0 85%-279 100%";
-
- Engine.GetGUIObjectByName("pauseButton").enabled = !g_IsObserver || !g_IsNetworked || g_IsController;
- Engine.GetGUIObjectByName("menuResignButton").enabled = !g_IsObserver;
- Engine.GetGUIObjectByName("lobbyButton").enabled = Engine.HasXmppClient();
}
function reportPerformance(time)
Index: binaries/data/mods/public/gui/session/top_panel/button_menu.xml
===================================================================
--- binaries/data/mods/public/gui/session/top_panel/button_menu.xml
+++ binaries/data/mods/public/gui/session/top_panel/button_menu.xml
@@ -5,6 +5,7 @@
style="StoneButtonFancy"
tooltip_style="sessionToolTip"
z="70"
+ hotkey="session.gui.menu.toggle"
>