Changeset View
Standalone View
binaries/data/mods/public/gui/gamesetup/gamesetup.js
Show First 20 Lines • Show All 293 Lines • ▼ Show 20 Lines | |||||
var g_Autocomplete = []; | var g_Autocomplete = []; | ||||
/** | /** | ||||
* Array of strings formatted as displayed, including playername. | * Array of strings formatted as displayed, including playername. | ||||
*/ | */ | ||||
var g_ChatMessages = []; | var g_ChatMessages = []; | ||||
/** | /** | ||||
* Minimum amount of pixels required for the chat panel to be visible. | |||||
*/ | |||||
var g_MinChatWidth = 74; | |||||
/** | |||||
* Filename and translated title of all maps, given the currently selected | * Filename and translated title of all maps, given the currently selected | ||||
* maptype and filter. Sorted by title, shown in the dropdown. | * maptype and filter. Sorted by title, shown in the dropdown. | ||||
*/ | */ | ||||
var g_MapSelectionList = []; | var g_MapSelectionList = []; | ||||
/** | /** | ||||
* Cache containing the mapsettings. Just-in-time loading. | * Cache containing the mapsettings. Just-in-time loading. | ||||
*/ | */ | ||||
Show All 27 Lines | |||||
/** | /** | ||||
* Total number of units that the engine can run with smoothly. | * Total number of units that the engine can run with smoothly. | ||||
* It means a 4v4 with 150 population can still run nicely, but more than that might "lag". | * It means a 4v4 with 150 population can still run nicely, but more than that might "lag". | ||||
*/ | */ | ||||
var g_PopulationCapacityRecommendation = 1200; | var g_PopulationCapacityRecommendation = 1200; | ||||
/** | /** | ||||
* Vertical size of a tab button. | |||||
*/ | |||||
var g_TabButtonHeight = 30; | |||||
/** | |||||
* Vertical space between two tab buttons. | |||||
*/ | |||||
var g_TabButtonDist = 4; | |||||
/** | |||||
* Vertical size of an option object. | |||||
*/ | |||||
var g_OptionHeight = 32; | |||||
/** | |||||
* Virtical space between two option objects. | |||||
bb: typo | |||||
*/ | |||||
var g_OptionDist = 2; | |||||
/** | |||||
* Width of a column in the options panel. | |||||
*/ | |||||
var g_ColumnWidth = 320; | |||||
/** | |||||
* Pixels per millisecond the option panel slides when opening/closing. | |||||
*/ | |||||
var g_SlideSpeed = 1.2; | |||||
/** | |||||
* Numerical index of the chosen category. | |||||
*/ | |||||
var g_SelectedCategory = 0; | |||||
Not Done Inline Actionsnukable bb: nukable | |||||
/** | |||||
* Store last tick time. | |||||
*/ | |||||
var g_LastTickTime = Date.now(); | |||||
/** | |||||
* Tooltip extension for the option panel tooltip containing the hotkey information. | |||||
*/ | |||||
var g_OptionPanelHotkeyTooltip = " " + colorizeHotkey(translate("Use %(hotkey)s / " + colorizeHotkey("%(hotkey)s", "gamesetup.prevtab") + " to move an option tab down/up."), "gamesetup.nexttab"); | |||||
Done Inline ActionsDon't overestimate the abilities of the string extraction python script. I see why you posted it here, but by definition word separators like " " are posted between two words. If you append the hotkey tooltip programmatically, you have several advantages:
elexis: Don't overestimate the abilities of the string extraction python script.
I see why you posted… | |||||
/** | |||||
* Order in which the GUI elements will be shown. | * Order in which the GUI elements will be shown. | ||||
* All valid options are required to appear here. | * All valid options are required to appear here. | ||||
* The ones under "map" are shown in the map selection panel, | |||||
* the others in the "more options" dialog. | |||||
*/ | */ | ||||
var g_OptionOrderGUI = { | var g_OptionOrderGUI = [ | ||||
"map": [ | { | ||||
"label": translate("Map"), | |||||
"tooltip": translate("Toggle the map options tab.") + g_OptionPanelHotkeyTooltip, | |||||
Done Inline Actions"Toggle the %(name)s tab."? elexis: "Toggle the %(name)s tab."? | |||||
Not Done Inline Actions(getting some title case, but meh) bb: (getting some title case, but meh) | |||||
"options": [ | |||||
"mapType", | "mapType", | ||||
"mapFilter", | "mapFilter", | ||||
"mapSelection", | "mapSelection", | ||||
"numPlayers", | "numPlayers", | ||||
"mapSize" | "mapSize", | ||||
], | |||||
"more": [ | |||||
"biome", | "biome", | ||||
Done Inline Actionsadd "nomad", for current sync ffffffff: add "nomad", for current sync | |||||
"exploreMap", | |||||
"revealMap" | |||||
] | |||||
}, | |||||
{ | |||||
"label": translate("General"), | |||||
Done Inline ActionstranslateWithContext to prevent transifex questions elexis: translateWithContext to prevent transifex questions | |||||
"tooltip": translate("Toggle the general options tab.") + g_OptionPanelHotkeyTooltip, | |||||
"options": [ | |||||
"gameSpeed", | "gameSpeed", | ||||
"victoryCondition", | |||||
"relicCount", | |||||
"relicDuration", | |||||
"wonderDuration", | |||||
"populationCap", | "populationCap", | ||||
"startingResources", | "startingResources", | ||||
"ceasefire", | "ceasefire", | ||||
Done Inline ActionsGeneral == Miscellaneous. I guess it's hard to get it right with regards to the GUI space. elexis: General == Miscellaneous. I guess it's hard to get it right with regards to the GUI space. | |||||
Not Done Inline Actionsgeneral != misc bb: general != misc
Making a player tab absorbing the number of players above and popcap and… | |||||
"regicideGarrison", | |||||
"exploreMap", | |||||
"revealMap", | |||||
"disableTreasures", | "disableTreasures", | ||||
"disableSpies", | "disableSpies" | ||||
] | |||||
}, | |||||
{ | |||||
Done Inline Actionssingular elexis: singular | |||||
"label": translate("Victory Conditions"), | |||||
"tooltip": translate("Toggle the victory conditions options tab.") + g_OptionPanelHotkeyTooltip, | |||||
"options": [ | |||||
"victoryCondition", | |||||
"relicCount", | |||||
"relicDuration", | |||||
"wonderDuration", | |||||
"regicideGarrison" | |||||
] | |||||
}, | |||||
{ | |||||
"label": translate("Miscellaneous "), | |||||
"tooltip": translate("Toggle the miscellaneous options tab.") + g_OptionPanelHotkeyTooltip, | |||||
"options": [ | |||||
"lockTeams", | "lockTeams", | ||||
"lastManStanding", | "lastManStanding", | ||||
"enableCheats", | "enableCheats", | ||||
"enableRating" | "enableRating" | ||||
] | ] | ||||
}; | } | ||||
]; | |||||
Done Inline ActionsIf it doesn't contain only the order, it should be renamed. elexis: If it doesn't contain only the order, it should be renamed. | |||||
/** | /** | ||||
* Contains the logic of all multiple-choice gamesettings. | * Contains the logic of all multiple-choice gamesettings. | ||||
* | * | ||||
* Logic | * Logic | ||||
* ids - Array of identifier strings that indicate the selected value. | * ids - Array of identifier strings that indicate the selected value. | ||||
* default - Returns the index of the default value (not the value itself). | * default - Returns the index of the default value (not the value itself). | ||||
* defined - Whether a value for the setting is actually specified. | * defined - Whether a value for the setting is actually specified. | ||||
▲ Show 20 Lines • Show All 483 Lines • ▼ Show 20 Lines | var g_Checkboxes = { | ||||
}, | }, | ||||
}; | }; | ||||
/** | /** | ||||
* For setting up arbitrary GUI objects. | * For setting up arbitrary GUI objects. | ||||
*/ | */ | ||||
var g_MiscControls = { | var g_MiscControls = { | ||||
"chatPanel": { | "chatPanel": { | ||||
"hidden": () => !g_IsNetworked, | "hidden": () => { | ||||
if (!g_IsNetworked) | |||||
return true; | |||||
let size = Engine.GetGUIObjectByName("chatPanel").getComputedSize(); | |||||
return size.right - size.left < g_MinChatWidth; | |||||
}, | |||||
Not Done Inline ActionsWe can't avoid the situation in which the panel becomes too small? elexis: We can't avoid the situation in which the panel becomes too small?
We can assume >= 1024 | |||||
Not Done Inline Actionsno look at 2 columns on 1024, no chat then iirc bb: no look at 2 columns on 1024, no chat then iirc
With scrolling added, it can be removed I guess. | |||||
}, | }, | ||||
"chatInput": { | "chatInput": { | ||||
"tooltip": () => colorizeAutocompleteHotkey(translate("Press %(hotkey)s to autocomplete playernames or settings.")), | "tooltip": () => colorizeAutocompleteHotkey(translate("Press %(hotkey)s to autocomplete playernames or settings.")), | ||||
}, | }, | ||||
"cheatWarningText": { | "cheatWarningText": { | ||||
"hidden": () => !g_IsNetworked || !g_GameAttributes.settings.CheatsEnabled, | "hidden": () => !g_IsNetworked || !g_GameAttributes.settings.CheatsEnabled, | ||||
}, | }, | ||||
"cancelGame": { | "cancelGame": { | ||||
Show All 20 Lines | "hidden": () => | ||||
!g_PlayerAssignments[Engine.GetPlayerGUID()] || | !g_PlayerAssignments[Engine.GetPlayerGUID()] || | ||||
g_PlayerAssignments[Engine.GetPlayerGUID()].player == -1 && !g_IsController, | g_PlayerAssignments[Engine.GetPlayerGUID()].player == -1 && !g_IsController, | ||||
}, | }, | ||||
"civResetButton": { | "civResetButton": { | ||||
"hidden": () => g_GameAttributes.mapType == "scenario" || !g_IsController, | "hidden": () => g_GameAttributes.mapType == "scenario" || !g_IsController, | ||||
}, | }, | ||||
"teamResetButton": { | "teamResetButton": { | ||||
"hidden": () => g_GameAttributes.mapType == "scenario" || !g_IsController, | "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, | |||||
}, | |||||
}; | }; | ||||
/** | /** | ||||
* Contains gui elements that are repeated for every player. | * Contains gui elements that are repeated for every player. | ||||
*/ | */ | ||||
var g_PlayerMiscElements = { | var g_PlayerMiscElements = { | ||||
"playerBox": { | "playerBox": { | ||||
"size": (playerIdx) => ["0", 32 * playerIdx, "100%", 32 * (playerIdx + 1)].join(" "), | "size": (playerIdx) => ["0", 32 * playerIdx, "100%", 32 * (playerIdx + 1)].join(" "), | ||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Called after the first tick. | * Called after the first tick. | ||||
*/ | */ | ||||
function initGUIObjects() | function initGUIObjects() | ||||
{ | { | ||||
// Copy all initOrder values into one object | // Copy all initOrder values into one object | ||||
let initOrder = {}; | let initOrder = {}; | ||||
for (let dropdown in g_Dropdowns) | for (let dropdown in g_Dropdowns) | ||||
initOrder[dropdown] = g_Dropdowns[dropdown].initOrder; | initOrder[dropdown] = g_Dropdowns[dropdown].initOrder; | ||||
Not Done Inline Actionsspelling error bb: spelling error | |||||
for (let checkbox in g_Checkboxes) | for (let checkbox in g_Checkboxes) | ||||
Done Inline Actions" " -> "\n" elexis: " " -> "\n"
Also mimo says D1180 is a must-have, so should likely get that in. | |||||
Not Done Inline ActionsCan always be changed when/if doing D1180 bb: Can always be changed when/if doing D1180 | |||||
initOrder[checkbox] = g_Checkboxes[checkbox].initOrder; | initOrder[checkbox] = g_Checkboxes[checkbox].initOrder; | ||||
// Sort the object on initOrder so we can init the options in an arbitrary order | // Sort the object on initOrder so we can init the options in an arbitrary order | ||||
for (let option of Object.keys(initOrder).sort((a, b) => initOrder[a] - initOrder[b])) | for (let option of Object.keys(initOrder).sort((a, b) => initOrder[a] - initOrder[b])) | ||||
if (g_Dropdowns[option]) | if (g_Dropdowns[option]) | ||||
initDropdown(option); | initDropdown(option); | ||||
else if (g_Checkboxes[option]) | else if (g_Checkboxes[option]) | ||||
initCheckbox(option); | initCheckbox(option); | ||||
else | else | ||||
warn('The option "' + option + '" is not defined.'); | warn('The option "' + option + '" is not defined.'); | ||||
for (let dropdown in g_PlayerDropdowns) | for (let dropdown in g_PlayerDropdowns) | ||||
initPlayerDropdowns(dropdown); | initPlayerDropdowns(dropdown); | ||||
resizeMoreOptionsWindow(); | placeOptionTabButtons(); | ||||
displayOptions(); | |||||
initSPTips(); | initSPTips(); | ||||
loadPersistMatchSettings(); | loadPersistMatchSettings(); | ||||
updateGameAttributes(); | updateGameAttributes(); | ||||
sendRegisterGameStanzaImmediate(); | sendRegisterGameStanzaImmediate(); | ||||
if (g_IsTutorial) | if (g_IsTutorial) | ||||
{ | { | ||||
launchTutorial(); | launchTutorial(); | ||||
return; | return; | ||||
} | } | ||||
// Don't lift the curtain until the controls are updated the first time | // Don't lift the curtain until the controls are updated the first time | ||||
if (!g_IsNetworked) | if (!g_IsNetworked) | ||||
hideLoadingWindow(); | hideLoadingWindow(); | ||||
} | } | ||||
Not Done Inline ActionsDecoupled this from initGUIObjects in D2483. elexis: Decoupled this from initGUIObjects in D2483. | |||||
function placeOptionTabButtons() | |||||
{ | |||||
let frame = Engine.GetGUIObjectByName("optionTabButtons"); | |||||
Done Inline Actionslet optionTabButtons = Engine.GetGUIObjectByName("optionTabButtons"); This way we know which GUI object is modified without looking up this line. elexis: `let optionTabButtons = Engine.GetGUIObjectByName("optionTabButtons");`
This way we know which… | |||||
Not Done Inline Actionsmissing {number} and cap bb: missing `{number}` and cap | |||||
let frameSize = frame.size; | |||||
let frameBottom = frameSize.top + g_OptionOrderGUI.length * (g_TabButtonHeight + g_TabButtonDist); | |||||
Done Inline ActionsI don't like this function. It's name is extremely vague, sounds like it could do anything and nothing. From the naming it could be used everywhere. Just inline it (with a fat arrow or not) elexis: I don't like this function. It's name is extremely vague, sounds like it could do anything and… | |||||
Not Done Inline Actionsyup inline bb: yup inline | |||||
frameSize.bottom = frameBottom; | |||||
frame.size = frameSize; | |||||
let gameDescription = Engine.GetGUIObjectByName("mapInfoDescriptionFrame"); | |||||
let gameDescriptionSize = gameDescription.size; | |||||
Done Inline Actionsno explanation to dt? (maybe difftime)? ffffffff: no explanation to dt? (maybe difftime)? | |||||
Not Done Inline Actionsmaybe to much of a physicist to not understand dt, so just added the comment bb: maybe to much of a physicist to not understand dt, so just added the comment | |||||
Not Done Inline Actions(configDB entry would be nice I suppose, to save some time) elexis: (configDB entry would be nice I suppose, to save some time) | |||||
Not Done Inline ActionsAs in a config item for the speed (a slider), or for on/off (checkbox)? bb: As in a config item for the speed (a slider), or for on/off (checkbox)? | |||||
gameDescriptionSize.top = frameBottom + 3; | |||||
gameDescription.size = gameDescriptionSize; | |||||
Not Done Inline ActionsEasier to keep track of object if they have the same name in JS and XML, i.e let foo = Engine.GetGUIObjectByName("foo"); elexis: Easier to keep track of object if they have the same name in JS and XML, i.e `let foo = Engine. | |||||
for (let category in g_OptionOrderGUI) | |||||
{ | |||||
let button = Engine.GetGUIObjectByName("optionTabButton[" + category + "]"); | |||||
if (!button) | |||||
Done Inline ActionsIs there some mnemonic for the abstract for the abstract equality comparison test https://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3 or should we always use a strict comparison === when testing against falsy values? (same below) elexis: Is there some mnemonic for the abstract for the abstract equality comparison test https://www. | |||||
{ | |||||
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; | |||||
} | |||||
} | |||||
Done Inline ActionsCan that be replaced with a chatPanel hidden test? I.e. testing what we want to test for by definition, rather than the coincidentally equal value. elexis: Can that be replaced with a chatPanel hidden test? I.e. testing what we want to test for by… | |||||
Not Done Inline ActionsThe whole check should be removed, checking for hidden won't work as the panel can be hidden due to the small size bb: The whole check should be removed, checking for hidden won't work as the panel can be hidden… | |||||
Not Done Inline ActionsDecoupled chatPanel from settingTabs code in D2483. elexis: Decoupled chatPanel from settingTabs code in D2483. | |||||
function displayOptions() | |||||
{ | |||||
// Highlight the selected tab | |||||
Engine.GetGUIObjectByName("optionTabButtons").children.forEach((button, i) => { | |||||
button.sprite = i == g_SelectedCategory ? "ModernTabVerticalForeground" : "ModernTabVerticalBackground"; | |||||
}); | |||||
Done Inline Actions; ffffffff: ; | |||||
updateGUIObjects(); | |||||
Engine.GetGUIObjectByName("options").hidden = false; | |||||
} | |||||
Done Inline ActionsDon't add a second place that define state-dependent logic to determine the visibility of the SP tips. It should be set in g_MiscControls and you can call the function in that object if needed. elexis: Don't add a second place that define state-dependent logic to determine the visibility of the… | |||||
/** | |||||
* Perform hotkey action. | |||||
Done Inline ActionsIt's the third GUI page with this code? elexis: It's the third GUI page with this code?
gui/common/tab_buttons.js? | |||||
Not Done Inline Actionsnot the 4th? (summary, credits, options, this) bb: not the 4th? (summary, credits, options, this) | |||||
*/ | |||||
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() | function hideLoadingWindow() | ||||
{ | { | ||||
let loadingWindow = Engine.GetGUIObjectByName("loadingWindow"); | let loadingWindow = Engine.GetGUIObjectByName("loadingWindow"); | ||||
if (loadingWindow.hidden) | if (loadingWindow.hidden) | ||||
return; | return; | ||||
loadingWindow.hidden = true; | loadingWindow.hidden = true; | ||||
Engine.GetGUIObjectByName("setupWindow").hidden = false; | Engine.GetGUIObjectByName("setupWindow").hidden = false; | ||||
Engine.GetGUIObjectByName("chatInput").focus(); | Engine.GetGUIObjectByName("chatInput").focus(); | ||||
} | } | ||||
/** | /** | ||||
* 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. | * Player settings use custom names. | ||||
*/ | */ | ||||
function getGUIObjectNameFromSetting(name) | 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) | if (idx != -1) | ||||
return [ | return [ | ||||
panel + "Option", | "option", | ||||
g_Dropdowns[name] ? "Dropdown" : "Checkbox", | g_Dropdowns[name] ? "Dropdown" : "Checkbox", | ||||
"[" + idx + "]" | "[" + (idx + idxOffset) + "]" | ||||
]; | ]; | ||||
idxOffset += category.options.length; | |||||
} | } | ||||
Not Done Inline Actionssounds right. GUI order != init order. elexis: sounds right. GUI order != init order. | |||||
// Assume there is a GUI object with exactly that setting name | // Assume there is a GUI object with exactly that setting name | ||||
return [name, "", ""]; | return [name, "", ""]; | ||||
} | } | ||||
function initDropdown(name, playerIdx) | function initDropdown(name, playerIdx) | ||||
{ | { | ||||
let [guiName, guiType, guiIdx] = getGUIObjectNameFromSetting(name); | let [guiName, guiType, guiIdx] = getGUIObjectNameFromSetting(name); | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | |||||
function saveSPTipsSetting() | function saveSPTipsSetting() | ||||
{ | { | ||||
let enabled = String(Engine.GetGUIObjectByName("displaySPTips").checked); | let enabled = String(Engine.GetGUIObjectByName("displaySPTips").checked); | ||||
Engine.ConfigDB_CreateValue("user", "gui.gamesetup.enabletips", enabled); | Engine.ConfigDB_CreateValue("user", "gui.gamesetup.enabletips", enabled); | ||||
Engine.ConfigDB_WriteValueToFile("user", "gui.gamesetup.enabletips", enabled, "config/user.cfg"); | 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("options"); | ||||
let actualParentSize = parentObject.getComputedSize(); | |||||
let parentObject = Engine.GetGUIObjectByName(parent); | 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) | for (let child of parentObject.children) | ||||
{ | { | ||||
if (ignore.indexOf(child.name) != -1) | |||||
continue; | |||||
let childSize = child.size; | |||||
yPos = yPos || childSize.top; | |||||
if (child.hidden) | if (child.hidden) | ||||
continue; | continue; | ||||
childSize.top = yPos; | for (let grandChild of child.children) | ||||
childSize.bottom = yPos + objectHeight - 2; | { | ||||
child.size = childSize; | if (grandChild.hidden && grandChild.enabled) | ||||
Done Inline Actionslet childCount = settingsPanel.children.filter(child => child.hidden).length? Maybe even a reduce call to merge more stuff? elexis: `let childCount = settingsPanel.children.filter(child => child.hidden).length`?
Maybe even a… | |||||
Not Done Inline Actionsmissing negation bb: missing negation | |||||
continue; | |||||
yPos += objectHeight; | // Two consecutive checkboxes can be alligned horizontally | ||||
Not Done Inline ActionsDubious about this feature. elexis: Dubious about this feature.
IMO it's more clear to have two columns.
| |||||
Not Done Inline ActionsCoded it before using multiple columns, but left it in to avoid unused gui space and avoid multiple columns as much as possible (notice that two columns on 1024 will hide the chat). bb: Coded it before using multiple columns, but left it in to avoid unused gui space and avoid… | |||||
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") | |||||
Done Inline ActionsIf ES6 wouldn't provide startsWith, I'd still have recommended "optionDropdown."length to replace the magic 14. Is it even the right string? (See that's why we dont use magic numbers) elexis: If ES6 wouldn't provide `startsWith`, I'd still have recommended `"optionDropdown."length` to… | |||||
{ | |||||
checkboxLeft = true; | |||||
++childs; | |||||
} | |||||
} | } | ||||
return yPos; | |||||
} | } | ||||
/** | let perColumn = childs / Math.ceil(childs / maxPerColumn); | ||||
* Remove empty space in case of hidden options (like cheats, rating or victory duration) | |||||
*/ | let yPos = g_OptionDist; | ||||
function resizeMoreOptionsWindow() | checkboxLeft = true; | ||||
let column = 0; | |||||
let thisColumn = 0; | |||||
let parentSize = parentObject.size; | |||||
for (let child of parentObject.children) | |||||
{ | { | ||||
verticallyDistributeGUIObjects("mapOptions", 32, []); | if (child.hidden) | ||||
continue; | |||||
let yPos = verticallyDistributeGUIObjects("moreOptions", 32, ["moreOptionsLabel"]); | let childSize = child.size; | ||||
for (let grandChild of child.children) | |||||
{ | |||||
if (grandChild.hidden && grandChild.enabled) | |||||
continue; | |||||
// Resize the vertically centered window containing the options | // Place two consecutive checkboxes horizontally alligned | ||||
let moreOptions = Engine.GetGUIObjectByName("moreOptions"); | if (grandChild.name.substr(0, 14) == "optionCheckbox" && !checkboxLeft) | ||||
let mSize = moreOptions.size; | { | ||||
mSize.bottom = mSize.top + yPos + 20; | childSize = new GUISize( | ||||
moreOptions.size = mSize; | 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; | |||||
} | |||||
child.size = childSize; | |||||
} | |||||
} | |||||
parentSize.right += (column - oldColumns) * g_ColumnWidth; | |||||
parentObject.size = parentSize; | |||||
} | } | ||||
/** | /** | ||||
* Called when the client disconnects. | * Called when the client disconnects. | ||||
* The other cases from NetClient should never occur in the gamesetup. | * The other cases from NetClient should never occur in the gamesetup. | ||||
*/ | */ | ||||
function handleNetStatusMessage(message) | function handleNetStatusMessage(message) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 270 Lines • ▼ Show 20 Lines | g_BiomeList = biomeList && prepareForDropdown( | ||||
}].concat(biomeList.map(biome => ({ | }].concat(biomeList.map(biome => ({ | ||||
"Id": biome.Id, | "Id": biome.Id, | ||||
"Title": biome.Title, | "Title": biome.Title, | ||||
"Description": biome.Description, | "Description": biome.Description, | ||||
"Color": g_ColorRegular | "Color": g_ColorRegular | ||||
})))); | })))); | ||||
initDropdown("biome"); | initDropdown("biome"); | ||||
updateGUIDropdown("biome"); | |||||
distributeOptions(); | |||||
Not Done Inline Actions(how I love these hardcodings) elexis: (how I love these hardcodings) | |||||
Not Done Inline Actionswell the first line is actually a current bug, only unnoticed since when changing the map the more options window is closed, second line is a bit unfortunate bb: well the first line is actually a current bug, only unnoticed since when changing the map the… | |||||
Not Done Inline ActionsDecoupled biome, TriggerDifficulties and SettingTabsPanel in D2483. elexis: Decoupled biome, TriggerDifficulties and SettingTabsPanel in D2483. | |||||
} | } | ||||
function loadMapData(name) | function loadMapData(name) | ||||
{ | { | ||||
if (!name || !g_MapPath[g_GameAttributes.mapType]) | if (!name || !g_MapPath[g_GameAttributes.mapType]) | ||||
return undefined; | return undefined; | ||||
if (name == "random") | if (name == "random") | ||||
▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | function onTick() | ||||
{ | { | ||||
initGUIObjects(); | initGUIObjects(); | ||||
++g_LoadingState; | ++g_LoadingState; | ||||
} | } | ||||
else if (g_LoadingState == 2) | else if (g_LoadingState == 2) | ||||
handleNetMessages(); | handleNetMessages(); | ||||
updateTimers(); | updateTimers(); | ||||
let now = Date.now(); | |||||
let tickLength = now - g_LastTickTime; | |||||
g_LastTickTime = now; | |||||
updateOptionsPanelPosition(tickLength); | |||||
elexisUnsubmitted Not Done Inline Actions(Could avoid tickLength helper variable if we neglect the duration spent in updateOptionsPanelPosition, likely messy to do so though) elexis: (Could avoid `tickLength` helper variable if we neglect the duration spent in… | |||||
bbAuthorUnsubmitted Not Done Inline ActionsHad the same thought when coding, but this is equivalent to the code for the main menu sliding bb: Had the same thought when coding, but this is equivalent to the code for the main menu sliding | |||||
elexisUnsubmitted Not Done Inline ActionsEquivalent code you said? :-) elexis: Equivalent code you said? :-) | |||||
bbAuthorUnsubmitted Not Done Inline Actions(Yes I had plans to merge them together, but that will take a nice main-menu rewrite and so meh-ed it for now) bb: (Yes I had plans to merge them together, but that will take a nice main-menu rewrite and so meh… | |||||
} | |||||
/** | |||||
* Keep everything nicely fitted in there box when resizing. | |||||
*/ | |||||
function onWindowResized() | |||||
{ | |||||
distributeOptions(); | |||||
} | } | ||||
elexisUnsubmitted Done Inline ActionsGuess this can be inlined elexis: Guess this can be inlined | |||||
/** | /** | ||||
* Handles all pending messages sent by the net client. | * Handles all pending messages sent by the net client. | ||||
*/ | */ | ||||
function handleNetMessages() | function handleNetMessages() | ||||
{ | { | ||||
while (g_IsNetworked) | while (g_IsNetworked) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | function updateGUIDropdown(name, playerIdx = undefined) | ||||
let title = Engine.GetGUIObjectByName(guiName + "Title" + guiIdx + idxName); | let title = Engine.GetGUIObjectByName(guiName + "Title" + guiIdx + idxName); | ||||
if (guiType == "Dropdown") | if (guiType == "Dropdown") | ||||
Engine.GetGUIObjectByName(guiName + "Checkbox" + guiIdx).hidden = true; | Engine.GetGUIObjectByName(guiName + "Checkbox" + guiIdx).hidden = true; | ||||
let indexHidden = isControlArrayElementHidden(playerIdx); | let indexHidden = isControlArrayElementHidden(playerIdx); | ||||
let obj = (playerIdx === undefined ? g_Dropdowns : g_PlayerDropdowns)[name]; | 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 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; | |||||
bbAuthorUnsubmitted Not Done Inline Actionsmaybe do the same for checkboxes? only what should the value of checked be? bb: maybe do the same for checkboxes? only what should the value of `checked` be? | |||||
elexisUnsubmitted Not Done Inline ActionsYou mean showing disabled checkboxes to non-controllers? Maybe there hadn't been an accoridng sprite at the time. Anyway out of scope. elexis: You mean showing disabled checkboxes to non-controllers? Maybe there hadn't been an accoridng… | |||||
dropdown.hidden = !g_IsController || !enabled || hidden; | dropdown.hidden = !g_IsController || !enabled || hidden; | ||||
dropdown.selected = selected; | dropdown.selected = selected; | ||||
dropdown.tooltip = !indexHidden && obj.tooltip ? obj.tooltip(-1, playerIdx) : ""; | dropdown.tooltip = !indexHidden && obj.tooltip ? obj.tooltip(-1, playerIdx) : ""; | ||||
if (frame) | if (frame) | ||||
frame.hidden = hidden; | frame.hidden = hidden; | ||||
if (title && obj.title && !indexHidden) | if (title && obj.title && !indexHidden) | ||||
Show All 23 Lines | function updateGUICheckbox(name) | ||||
let label = Engine.GetGUIObjectByName(guiName + "Text" + guiIdx); | let label = Engine.GetGUIObjectByName(guiName + "Text" + guiIdx); | ||||
let frame = Engine.GetGUIObjectByName(guiName + "Frame" + guiIdx); | let frame = Engine.GetGUIObjectByName(guiName + "Frame" + guiIdx); | ||||
let title = Engine.GetGUIObjectByName(guiName + "Title" + guiIdx); | let title = Engine.GetGUIObjectByName(guiName + "Title" + guiIdx); | ||||
if (guiType == "Checkbox") | if (guiType == "Checkbox") | ||||
Engine.GetGUIObjectByName(guiName + "Dropdown" + guiIdx).hidden = true; | Engine.GetGUIObjectByName(guiName + "Dropdown" + guiIdx).hidden = true; | ||||
checkbox.checked = checked; | checkbox.checked = checked; | ||||
checkbox.enabled = enabled; | checkbox.enabled = g_IsController && enabled; | ||||
checkbox.hidden = hidden || !g_IsController; | checkbox.hidden = hidden || !g_IsController; | ||||
checkbox.tooltip = obj.tooltip ? obj.tooltip() : ""; | checkbox.tooltip = obj.tooltip ? obj.tooltip() : ""; | ||||
label.caption = checked ? translate("Yes") : translate("No"); | label.caption = checked ? translate("Yes") : translate("No"); | ||||
label.hidden = hidden || g_IsController; | label.hidden = hidden || g_IsController; | ||||
if (frame) | if (frame) | ||||
frame.hidden = hidden; | frame.hidden = hidden; | ||||
if (title && obj.title) | if (title && obj.title) | ||||
title.caption = sprintf(translate("%(option)s:"), { "option": obj.title() }); | title.caption = sprintf(translate("%(option)s:"), { "option": obj.title() }); | ||||
Done Inline Actionsstring context or comment elexis: string context or comment | |||||
} | } | ||||
function updateGUIMiscControl(name, playerIdx) | function updateGUIMiscControl(name, playerIdx) | ||||
{ | { | ||||
let idxName = playerIdx === undefined ? "" : "[" + playerIdx + "]"; | let idxName = playerIdx === undefined ? "" : "[" + playerIdx + "]"; | ||||
let obj = (playerIdx === undefined ? g_MiscControls : g_PlayerMiscElements)[name]; | let obj = (playerIdx === undefined ? g_MiscControls : g_PlayerMiscElements)[name]; | ||||
let control = Engine.GetGUIObjectByName(name + idxName); | let control = Engine.GetGUIObjectByName(name + idxName); | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
g_IsInGuiUpdate = true; | g_IsInGuiUpdate = true; | ||||
reloadMapFilterList(); | reloadMapFilterList(); | ||||
reloadBiomeList(); | reloadBiomeList(); | ||||
updatePlayerAssignmentChoices(); | updatePlayerAssignmentChoices(); | ||||
// Hide exceeding dropdowns and checkboxes | // Hide exceeding dropdowns and checkboxes | ||||
for (let panel in g_OptionOrderGUI) | for (let child of Engine.GetGUIObjectByName("options").children) | ||||
for (let child of Engine.GetGUIObjectByName(panel + "Options").children) | |||||
child.hidden = true; | child.hidden = true; | ||||
// Show the relevant ones | // Show the relevant ones | ||||
if (g_SelectedCategory != undefined) | |||||
elexisUnsubmitted Not Done Inline Actionsexplicit checks for undefined or casual negation ! as != undefined is equal to the latter, jshint confirmed iirc. See also falsy on MDN elexis: explicit checks for undefined or casual negation `!` as `!= undefined` is equal to the latter… | |||||
bbAuthorUnsubmitted Not Done Inline Actionsbut g_SelectedCategory can be 0 so if (g_SelectedCategory) would return false in that case... bb: but g_SelectedCategory can be 0 so if (g_SelectedCategory) would return false in that case... | |||||
{ | |||||
for (let name in g_Dropdowns) | for (let name in g_Dropdowns) | ||||
if (g_OptionOrderGUI[g_SelectedCategory].options.indexOf(name) != -1) | |||||
updateGUIDropdown(name); | updateGUIDropdown(name); | ||||
for (let name in g_Checkboxes) | for (let name in g_Checkboxes) | ||||
if (g_OptionOrderGUI[g_SelectedCategory].options.indexOf(name) != -1) | |||||
updateGUICheckbox(name); | updateGUICheckbox(name); | ||||
} | |||||
for (let i = 0; i < g_MaxPlayers; ++i) | for (let i = 0; i < g_MaxPlayers; ++i) | ||||
{ | { | ||||
for (let name in g_PlayerDropdowns) | for (let name in g_PlayerDropdowns) | ||||
updateGUIDropdown(name, i); | updateGUIDropdown(name, i); | ||||
for (let name in g_PlayerMiscElements) | for (let name in g_PlayerMiscElements) | ||||
updateGUIMiscControl(name, i); | updateGUIMiscControl(name, i); | ||||
} | } | ||||
for (let name in g_MiscControls) | for (let name in g_MiscControls) | ||||
updateGUIMiscControl(name); | updateGUIMiscControl(name); | ||||
updateGameDescription(); | updateGameDescription(); | ||||
resizeMoreOptionsWindow(); | distributeOptions(); | ||||
rightAlignCancelButton(); | rightAlignCancelButton(); | ||||
updateAutocompleteEntries(); | updateAutocompleteEntries(); | ||||
g_IsInGuiUpdate = false; | g_IsInGuiUpdate = false; | ||||
// Refresh AI config page | // Refresh AI config page | ||||
if (g_LastViewedAIPlayer != -1) | if (g_LastViewedAIPlayer != -1) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 233 Lines • ▼ Show 20 Lines | text = sprintf(translate("%(time)s %(message)s"), { | ||||
"message": text | "message": text | ||||
}); | }); | ||||
g_ChatMessages.push(text); | g_ChatMessages.push(text); | ||||
Engine.GetGUIObjectByName("chatText").caption = g_ChatMessages.join("\n"); | Engine.GetGUIObjectByName("chatText").caption = g_ChatMessages.join("\n"); | ||||
} | } | ||||
function showMoreOptions(show) | |||||
{ | |||||
Engine.GetGUIObjectByName("moreOptionsFade").hidden = !show; | |||||
Engine.GetGUIObjectByName("moreOptions").hidden = !show; | |||||
} | |||||
function resetCivilizations() | function resetCivilizations() | ||||
{ | { | ||||
for (let i in g_GameAttributes.settings.PlayerData) | for (let i in g_GameAttributes.settings.PlayerData) | ||||
g_GameAttributes.settings.PlayerData[i].Civ = "random"; | g_GameAttributes.settings.PlayerData[i].Civ = "random"; | ||||
updateGameAttributes(); | updateGameAttributes(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 153 Lines • Show Last 20 Lines |
typo