Index: binaries/data/config/default.cfg
===================================================================
--- binaries/data/config/default.cfg
+++ binaries/data/config/default.cfg
@@ -324,6 +324,10 @@
fastforward = Space ; If timewarp mode enabled, speed up the game
rewind = Backspace ; If timewarp mode enabled, go back to earlier point in the game
+[hotkey.gamesetup]
+nexttab = "Alt+S" ; Show next option tab
+prevtab = "Alt+W" ; Show previous option tab
+
[hotkey.text] ; > GUI TEXTBOX HOTKEYS
delete.left = "Ctrl+Backspace" ; Delete word to the left of cursor
delete.right = "Ctrl+Del" ; Delete word to the right of cursor
Index: binaries/data/mods/mod/gui/common/modern/sprites.xml
===================================================================
--- binaries/data/mods/mod/gui/common/modern/sprites.xml
+++ binaries/data/mods/mod/gui/common/modern/sprites.xml
@@ -483,6 +483,26 @@
- Misc. -
==========================================
-->
+
+
+
+
+
+
+
+
+
+
+
!g_IsNetworked,
+ "hidden": () => {
+ if (!g_IsNetworked)
+ return true;
+
+ let size = Engine.GetGUIObjectByName("chatPanel").getComputedSize();
+ return size.right - size.left < g_MinChatWidth;
+ },
},
"chatInput": {
"tooltip": () => colorizeAutocompleteHotkey(translate("Press %(hotkey)s to autocomplete playernames or settings.")),
@@ -912,14 +986,7 @@
},
"teamResetButton": {
"hidden": () => g_GameAttributes.mapType == "scenario" || !g_IsController,
- },
- // Display these after having hidden every GUI object in the "More Options" dialog
- "moreOptionsLabel": {
- "hidden": () => false,
- },
- "hideMoreOptions": {
- "hidden": () => false,
- },
+ }
};
/**
@@ -1064,7 +1131,8 @@
for (let dropdown in g_PlayerDropdowns)
initPlayerDropdowns(dropdown);
- resizeMoreOptionsWindow();
+ placeOptionTabButtons();
+ displayOptions();
initSPTips();
@@ -1083,6 +1151,119 @@
hideLoadingWindow();
}
+function placeOptionTabButtons()
+{
+ let frame = Engine.GetGUIObjectByName("optionTabButtons");
+ let frameSize = frame.size;
+ let frameBottom = frameSize.top + g_OptionOrderGUI.length * (g_TabButtonHeight + g_TabButtonDist);
+ frameSize.bottom = frameBottom;
+ frame.size = frameSize;
+
+ let gameDescription = Engine.GetGUIObjectByName("mapInfoDescriptionFrame");
+ let gameDescriptionSize = gameDescription.size;
+ gameDescriptionSize.top = frameBottom + 3;
+ gameDescription.size = gameDescriptionSize;
+ for (let category in g_OptionOrderGUI)
+ {
+ let button = Engine.GetGUIObjectByName("optionTabButton[" + category + "]");
+ if (!button)
+ {
+ warn("Too few tab-buttons!");
+ break;
+ }
+
+ button.hidden = false;
+
+ let size = button.size;
+ size.top = category * (g_TabButtonHeight + g_TabButtonDist) + g_TabButtonDist / 2;
+ size.bottom = size.top + g_TabButtonHeight;
+ button.size = size;
+ button.tooltip = g_OptionOrderGUI[category].tooltip || "";
+
+ button.onPress = (category => function() {
+ if (category == g_SelectedCategory)
+ g_SelectedCategory = undefined;
+ else
+ g_SelectedCategory = category;
+ displayOptions();
+ })(category);
+
+ Engine.GetGUIObjectByName("tabButtonText[" + category + "]").caption = g_OptionOrderGUI[category].label;
+ }
+}
+
+function displayOptions()
+{
+ // Highlight the selected tab
+ Engine.GetGUIObjectByName("optionTabButtons").children.forEach((button, i) => {
+ button.sprite = i == g_SelectedCategory ? "ModernTabVerticalForeground" : "ModernTabVerticalBackground";
+ });
+
+ updateGUIObjects();
+ Engine.GetGUIObjectByName("options").hidden = false;
+}
+
+/**
+ * Perform hotkey action.
+ */
+function nextOptionTab(backward)
+{
+ let panels = g_OptionOrderGUI.length;
+ if (g_SelectedCategory != undefined)
+ {
+ g_SelectedCategory += backward ? -1 : 1;
+ g_SelectedCategory = g_SelectedCategory < 0 ? panels - 1 : g_SelectedCategory >= panels ? 0 : g_SelectedCategory;
+ }
+ else
+ g_SelectedCategory = backward ? panels - 1 : 0;
+
+ displayOptions();
+}
+
+/**
+ * Slide options panel.
+ */
+function updateOptionsPanelPosition(dt)
+{
+ let panel = Engine.GetGUIObjectByName("options");
+
+ let border = Engine.GetGUIObjectByName("optionTabButtons").size.left;
+ let offset = 0;
+ if (g_SelectedCategory == undefined)
+ {
+ let maxOffset = border - panel.size.left;
+ if (maxOffset > 0)
+ offset = Math.min(g_SlideSpeed * dt, maxOffset);
+ }
+ else if (border > panel.size.right)
+ offset = Math.min(g_SlideSpeed * dt, border - panel.size.right);
+ else
+ {
+ let maxOffset = panel.size.right - border;
+ if (maxOffset > 0)
+ offset = -Math.min(g_SlideSpeed * dt, maxOffset);
+ }
+
+ let size = panel.size;
+ size.left += offset;
+ size.right += offset;
+ panel.size = size;
+
+ let optionBackground = Engine.GetGUIObjectByName("optionBackground");
+ let backgroundSize = optionBackground.size;
+ backgroundSize.left = size.left;
+ optionBackground.size = backgroundSize;
+ if (g_IsNetworked)
+ {
+ let chatPanel = Engine.GetGUIObjectByName("chatPanel");
+ let chatSize = chatPanel.size;
+
+ chatSize.right += offset;
+ chatPanel.size = chatSize;
+ chatPanel.hidden = g_MiscControls.chatPanel.hidden();
+ }
+}
+
function hideLoadingWindow()
{
let loadingWindow = Engine.GetGUIObjectByName("loadingWindow");
@@ -1095,20 +1276,22 @@
}
/**
- * Options in the "More Options" or "Map" panel use a generic name.
+ * Options under the option tabs use a generic name.
* Player settings use custom names.
*/
function getGUIObjectNameFromSetting(name)
{
- for (let panel in g_OptionOrderGUI)
+ let idxOffset = 0;
+ for (let category of g_OptionOrderGUI)
{
- let idx = g_OptionOrderGUI[panel].indexOf(name);
+ let idx = category.options.indexOf(name);
if (idx != -1)
return [
- panel + "Option",
+ "option",
g_Dropdowns[name] ? "Dropdown" : "Checkbox",
- "[" + idx + "]"
+ "[" + (idx + idxOffset) + "]"
];
+ idxOffset += category.options.length;
}
// Assume there is a GUI object with exactly that setting name
@@ -1194,45 +1377,117 @@
Engine.ConfigDB_WriteValueToFile("user", "gui.gamesetup.enabletips", enabled, "config/user.cfg");
}
-function verticallyDistributeGUIObjects(parent, objectHeight, ignore)
+/**
+ * Distribute the currently visible options over the option panel.
+ * First calculate the number of columns required, then place the objects.
+ */
+function distributeOptions()
{
- let yPos;
-
- let parentObject = Engine.GetGUIObjectByName(parent);
+ let parentObject = Engine.GetGUIObjectByName("options");
+ let actualParentSize = parentObject.getComputedSize();
+ let oldColumns = Math.round((actualParentSize.right - actualParentSize.left) / g_ColumnWidth) - 1;
+
+ let maxPerColumn = Math.floor((actualParentSize.bottom - actualParentSize.top) / g_OptionHeight);
+ let childs = 0;
+ let checkboxLeft = true;
for (let child of parentObject.children)
{
- if (ignore.indexOf(child.name) != -1)
+ if (child.hidden)
continue;
- let childSize = child.size;
- yPos = yPos || childSize.top;
+ for (let grandChild of child.children)
+ {
+ if (grandChild.hidden && grandChild.enabled)
+ continue;
+ // Two consecutive checkboxes can be alligned horizontally
+ if (grandChild.name.substr(0, 14) == "optionCheckbox" && !checkboxLeft)
+ checkboxLeft = true;
+ else if (grandChild.name.substr(0, 14) == "optionCheckbox" && checkboxLeft)
+ {
+ checkboxLeft = false;
+ ++childs;
+ }
+ else if (grandChild.name.substr(0, 14) == "optionDropdown")
+ {
+ checkboxLeft = true;
+ ++childs;
+ }
+ }
+ }
+
+ let perColumn = childs / Math.ceil(childs / maxPerColumn);
+
+ let yPos = g_OptionDist;
+ checkboxLeft = true;
+ let column = 0;
+ let thisColumn = 0;
+ let parentSize = parentObject.size;
+
+ for (let child of parentObject.children)
+ {
if (child.hidden)
continue;
- childSize.top = yPos;
- childSize.bottom = yPos + objectHeight - 2;
- child.size = childSize;
-
- yPos += objectHeight;
- }
- return yPos;
-}
+ let childSize = child.size;
+ for (let grandChild of child.children)
+ {
+ if (grandChild.hidden && grandChild.enabled)
+ continue;
-/**
- * Remove empty space in case of hidden options (like cheats, rating or victory duration)
- */
-function resizeMoreOptionsWindow()
-{
- verticallyDistributeGUIObjects("mapOptions", 32, []);
+ // Place two consecutive checkboxes horizontally alligned
+ if (grandChild.name.substr(0, 14) == "optionCheckbox" && !checkboxLeft)
+ {
+ childSize = new GUISize(
+ column * g_ColumnWidth + g_ColumnWidth / 2,
+ yPos - g_OptionHeight,
+ column * g_ColumnWidth + 3/2 * g_ColumnWidth - 15,
+ yPos - g_OptionDist);
+ checkboxLeft = true;
+ }
+ else if (grandChild.name.substr(0, 14) == "optionCheckbox" && checkboxLeft)
+ {
+ if (thisColumn >= perColumn)
+ {
+ yPos = g_OptionDist;
+ ++column;
+ thisColumn = 0;
+ }
+
+ childSize = new GUISize(
+ column * g_ColumnWidth,
+ yPos,
+ column * g_ColumnWidth + g_ColumnWidth - 10,
+ yPos + g_OptionHeight - g_OptionDist);
+ yPos += g_OptionHeight;
+ checkboxLeft = false;
+ ++thisColumn;
+ }
+ else if (grandChild.name.substr(0, 14) == "optionDropdown")
+ {
+ if (thisColumn >= perColumn)
+ {
+ yPos = g_OptionDist;
+ ++column;
+ thisColumn = 0;
+ }
+
+ childSize = new GUISize(
+ column * g_ColumnWidth,
+ yPos,
+ column * g_ColumnWidth + g_ColumnWidth - 5,
+ yPos + g_OptionHeight - g_OptionDist);
+ yPos += g_OptionHeight;
+ checkboxLeft = true;
+ ++thisColumn;
+ }
- let yPos = verticallyDistributeGUIObjects("moreOptions", 32, ["moreOptionsLabel"]);
+ child.size = childSize;
+ }
+ }
- // Resize the vertically centered window containing the options
- let moreOptions = Engine.GetGUIObjectByName("moreOptions");
- let mSize = moreOptions.size;
- mSize.bottom = mSize.top + yPos + 20;
- moreOptions.size = mSize;
+ parentSize.right += (column - oldColumns) * g_ColumnWidth;
+ parentObject.size = parentSize;
}
/**
@@ -1519,6 +1774,8 @@
}))));
initDropdown("biome");
+ updateGUIDropdown("biome");
+ distributeOptions();
}
function loadMapData(name)
@@ -1674,6 +1931,20 @@
handleNetMessages();
updateTimers();
+
+ let now = Date.now();
+ let tickLength = now - g_LastTickTime;
+ g_LastTickTime = now;
+
+ updateOptionsPanelPosition(tickLength);
+}
+
+/**
+ * Keep everything nicely fitted in there box when resizing.
+ */
+function onWindowResized()
+{
+ distributeOptions();
}
/**
@@ -1782,10 +2053,11 @@
let indexHidden = isControlArrayElementHidden(playerIdx);
let obj = (playerIdx === undefined ? g_Dropdowns : g_PlayerDropdowns)[name];
- let selected = indexHidden ? -1 : dropdown.list_data.indexOf(String(obj.get(playerIdx)));
- let enabled = !indexHidden && (!obj.enabled || obj.enabled(playerIdx));
let hidden = indexHidden || obj.hidden && obj.hidden(playerIdx);
+ let selected = hidden ? -1 : dropdown.list_data.indexOf(String(obj.get(playerIdx)));
+ let enabled = !indexHidden && (!obj.enabled || obj.enabled(playerIdx));
+ dropdown.enabled = g_IsController && enabled;
dropdown.hidden = !g_IsController || !enabled || hidden;
dropdown.selected = selected;
dropdown.tooltip = !indexHidden && obj.tooltip ? obj.tooltip(-1, playerIdx) : "";
@@ -1825,7 +2097,7 @@
Engine.GetGUIObjectByName(guiName + "Dropdown" + guiIdx).hidden = true;
checkbox.checked = checked;
- checkbox.enabled = enabled;
+ checkbox.enabled = g_IsController && enabled;
checkbox.hidden = hidden || !g_IsController;
checkbox.tooltip = obj.tooltip ? obj.tooltip() : "";
@@ -1990,16 +2262,20 @@
updatePlayerAssignmentChoices();
// Hide exceeding dropdowns and checkboxes
- for (let panel in g_OptionOrderGUI)
- for (let child of Engine.GetGUIObjectByName(panel + "Options").children)
- child.hidden = true;
+ for (let child of Engine.GetGUIObjectByName("options").children)
+ child.hidden = true;
// Show the relevant ones
- for (let name in g_Dropdowns)
- updateGUIDropdown(name);
-
- for (let name in g_Checkboxes)
- updateGUICheckbox(name);
+ if (g_SelectedCategory != undefined)
+ {
+ for (let name in g_Dropdowns)
+ if (g_OptionOrderGUI[g_SelectedCategory].options.indexOf(name) != -1)
+ updateGUIDropdown(name);
+
+ for (let name in g_Checkboxes)
+ if (g_OptionOrderGUI[g_SelectedCategory].options.indexOf(name) != -1)
+ updateGUICheckbox(name);
+ }
for (let i = 0; i < g_MaxPlayers; ++i)
{
@@ -2014,7 +2290,7 @@
updateGUIMiscControl(name);
updateGameDescription();
- resizeMoreOptionsWindow();
+ distributeOptions();
rightAlignCancelButton();
updateAutocompleteEntries();
@@ -2264,12 +2540,6 @@
Engine.GetGUIObjectByName("chatText").caption = g_ChatMessages.join("\n");
}
-function showMoreOptions(show)
-{
- Engine.GetGUIObjectByName("moreOptionsFade").hidden = !show;
- Engine.GetGUIObjectByName("moreOptions").hidden = !show;
-}
-
function resetCivilizations()
{
for (let i in g_GameAttributes.settings.PlayerData)
Index: binaries/data/mods/public/gui/gamesetup/gamesetup.xml
===================================================================
--- binaries/data/mods/public/gui/gamesetup/gamesetup.xml
+++ binaries/data/mods/public/gui/gamesetup/gamesetup.xml
@@ -14,6 +14,13 @@
+
+
+
-
-
+
+
+
+
+
-
-
+
+
+
+
+
-
+
+
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
+
+
-
+
@@ -233,6 +255,7 @@
style="StoneButton"
size="100%-164 100%-52 100%-24 100%-24"
tooltip_style="onscreenToolTip"
+ z="21"
>
if (g_IsController)
@@ -249,83 +272,11 @@
style="StoneButton"
size="100%-308 100%-52 100%-168 100%-24"
tooltip_style="onscreenToolTip"
+ z="21"
>
Back
cancelSetup();
-
-
-
-
-
- More Options
- See more game options
- showMoreOptions(true);
-
-
-
-
-
-
-
-
-
- More Options
-
-
-
-
-
-
-
-
-
-
-
-
-
- OK
- Close more game options window
- showMoreOptions(false);
-
-
-
-
Index: binaries/data/mods/public/gui/manual/intro.txt
===================================================================
--- binaries/data/mods/public/gui/manual/intro.txt
+++ binaries/data/mods/public/gui/manual/intro.txt
@@ -140,3 +140,7 @@
[font="sans-bold-14"]When loading a saved game
[font="sans-14"]Delete: delete the selected saved game asking confirmation
Shift: do not ask confirmation when deleting a saved game
+
+[font="sans-bold-14"]In Gamesetup
+[font="sans-14"]Alt + W: Move to next option tab
+Alt + S: Move to previous option tab