diff --git a/binaries/data/mods/mod/gui/common/functions_msgbox.js b/binaries/data/mods/mod/gui/common/functions_msgbox.js
index f289749a72..acf524bff3 100644
--- a/binaries/data/mods/mod/gui/common/functions_msgbox.js
+++ b/binaries/data/mods/mod/gui/common/functions_msgbox.js
@@ -1,50 +1,18 @@
-// We want to pass callback functions for the different buttons in a convenient way.
-// Because passing functions accross compartment boundaries is a pain, we just store them here together with some optional arguments.
-// The messageBox page will return the code of the pressed button and the according function will be called.
-var g_MessageBoxBtnFunctions = [];
-var g_MessageBoxCallbackArgs = [];
-
-function messageBoxCallbackFunction(btnCode)
-{
- if (btnCode !== undefined && g_MessageBoxBtnFunctions[btnCode])
- {
- // Cache the variables to make it possible to call a messageBox from a callback function.
- let callbackFunction = g_MessageBoxBtnFunctions[btnCode];
- let callbackArgs = g_MessageBoxCallbackArgs[btnCode];
-
- g_MessageBoxBtnFunctions = [];
- g_MessageBoxCallbackArgs = [];
-
- if (callbackArgs !== undefined)
- callbackFunction(callbackArgs);
- else
- callbackFunction();
- return;
- }
-
- g_MessageBoxBtnFunctions = [];
- g_MessageBoxCallbackArgs = [];
-}
-
function messageBox(mbWidth, mbHeight, mbMessage, mbTitle, mbButtonCaptions, mbBtnCode, mbCallbackArgs)
{
- if (g_MessageBoxBtnFunctions && g_MessageBoxBtnFunctions.length)
- {
- warn("A messagebox was called when a previous callback function is still set, aborting!");
- return;
- }
-
- g_MessageBoxBtnFunctions = mbBtnCode;
- g_MessageBoxCallbackArgs = mbCallbackArgs || g_MessageBoxCallbackArgs;
-
- Engine.PushGuiPage("page_msgbox.xml", {
- "width": mbWidth,
- "height": mbHeight,
- "message": mbMessage,
- "title": mbTitle,
- "buttonCaptions": mbButtonCaptions,
- "callback": mbBtnCode && "messageBoxCallbackFunction"
- });
+ Engine.PushGuiPage(
+ "page_msgbox.xml",
+ {
+ "width": mbWidth,
+ "height": mbHeight,
+ "message": mbMessage,
+ "title": mbTitle,
+ "buttonCaptions": mbButtonCaptions
+ },
+ btnCode => {
+ if (mbBtnCode !== undefined && mbBtnCode[btnCode])
+ mbBtnCode[btnCode](mbCallbackArgs ? mbCallbackArgs[btnCode] : undefined);
+ });
}
function openURL(url)
diff --git a/binaries/data/mods/mod/gui/common/terms.js b/binaries/data/mods/mod/gui/common/terms.js
index 6992d7056c..6d6a4b7a6b 100644
--- a/binaries/data/mods/mod/gui/common/terms.js
+++ b/binaries/data/mods/mod/gui/common/terms.js
@@ -7,24 +7,29 @@ function initTerms(terms)
function openTerms(page)
{
- Engine.PushGuiPage("page_termsdialog.xml", {
- "file": g_Terms[page].file,
- "title": g_Terms[page].title,
- "sprintf": g_Terms[page].sprintf,
- "urlButtons": g_Terms[page].urlButtons || [],
- "termsURL": g_Terms[page].termsURL || undefined,
- "page": page,
- "callback": "acceptTerms"
- });
-}
+ Engine.PushGuiPage(
+ "page_termsdialog.xml",
+ {
+ "file": g_Terms[page].file,
+ "title": g_Terms[page].title,
+ "sprintf": g_Terms[page].sprintf,
+ "urlButtons": g_Terms[page].urlButtons || [],
+ "termsURL": g_Terms[page].termsURL || undefined,
+ "page": page
+ },
+ data => {
+ g_Terms[data.page].accepted = data.accepted;
-function acceptTerms(data)
-{
- g_Terms[data.page].accepted = data.accepted;
- Engine.ConfigDB_CreateAndWriteValueToFile("user", g_Terms[data.page].config, data.accepted ? getTermsHash(data.page) : "0", "config/user.cfg");
+ Engine.ConfigDB_CreateAndWriteValueToFile(
+ "user",
+ g_Terms[data.page].config,
+ data.accepted ? getTermsHash(data.page) : "0",
+ "config/user.cfg");
- if (g_Terms[data.page].callback)
- g_Terms[data.page].callback(data);
+ if (g_Terms[data.page].callback)
+ g_Terms[data.page].callback(data);
+ }
+ );
}
function checkTerms()
diff --git a/binaries/data/mods/mod/gui/modio/modio.js b/binaries/data/mods/mod/gui/modio/modio.js
index c31c5912eb..f5cc5b9837 100644
--- a/binaries/data/mods/mod/gui/modio/modio.js
+++ b/binaries/data/mods/mod/gui/modio/modio.js
@@ -268,9 +268,9 @@ function cancelRequest()
hideDialog();
}
-function closePage(data)
+function closePage()
{
- Engine.PopGuiPageCB(undefined);
+ Engine.PopGuiPage();
}
function showErrorMessageBox(caption, title, buttonCaptions, buttonActions)
diff --git a/binaries/data/mods/mod/gui/modmod/modmodio.js b/binaries/data/mods/mod/gui/modmod/modmodio.js
index 3125b41029..b3e69f1044 100644
--- a/binaries/data/mods/mod/gui/modmod/modmodio.js
+++ b/binaries/data/mods/mod/gui/modmod/modmodio.js
@@ -26,7 +26,5 @@ function downloadModsButton()
function openModIo(data)
{
if (data.accepted)
- Engine.PushGuiPage("page_modio.xml", {
- "callback": "initMods"
- });
+ Engine.PushGuiPage("page_modio.xml", {}, initMods);
}
diff --git a/binaries/data/mods/mod/gui/msgbox/msgbox.js b/binaries/data/mods/mod/gui/msgbox/msgbox.js
index 58f2b09356..9276a482c6 100644
--- a/binaries/data/mods/mod/gui/msgbox/msgbox.js
+++ b/binaries/data/mods/mod/gui/msgbox/msgbox.js
@@ -28,22 +28,15 @@ function init(data)
let mbButton = [];
captions.forEach((caption, i) => {
mbButton[i] = Engine.GetGUIObjectByName("mbButton" + (i + 1));
-
- let action = function()
- {
- if (data.callback)
- Engine.PopGuiPageCB(i);
- else
- Engine.PopGuiPage();
- };
-
mbButton[i].caption = caption;
- mbButton[i].onPress = action;
mbButton[i].hidden = false;
+ mbButton[i].onPress = () => {
+ Engine.PopGuiPage(i);
+ };
// Convention: Cancel is the first button
if (i == 0)
- mbCancelHotkey.onPress = action;
+ mbCancelHotkey.onPress = mbButton[i].onPress;
});
// Distribute buttons horizontally
diff --git a/binaries/data/mods/mod/gui/termsdialog/termsdialog.js b/binaries/data/mods/mod/gui/termsdialog/termsdialog.js
index 818b19039f..4420e990bb 100644
--- a/binaries/data/mods/mod/gui/termsdialog/termsdialog.js
+++ b/binaries/data/mods/mod/gui/termsdialog/termsdialog.js
@@ -82,7 +82,7 @@ function initLanguageSelection()
function closeTerms(accepted)
{
- Engine.PopGuiPageCB({
+ Engine.PopGuiPage({
"page": g_TermsPage,
"accepted": accepted
});
diff --git a/binaries/data/mods/public/gui/aiconfig/aiconfig.js b/binaries/data/mods/public/gui/aiconfig/aiconfig.js
index 9d44575564..5a3bb81d4f 100644
--- a/binaries/data/mods/public/gui/aiconfig/aiconfig.js
+++ b/binaries/data/mods/public/gui/aiconfig/aiconfig.js
@@ -69,10 +69,7 @@ function checkBehavior()
function returnAI(save = true)
{
let idx = Engine.GetGUIObjectByName("aiSelection").selected;
-
- // Pop the page before calling the callback, so the callback runs
- // in the parent GUI page's context
- Engine.PopGuiPageCB({
+ Engine.PopGuiPage({
"save": save,
"id": g_AIDescriptions[idx].id,
"name": g_AIDescriptions[idx].data.name,
diff --git a/binaries/data/mods/public/gui/civinfo/civinfo.js b/binaries/data/mods/public/gui/civinfo/civinfo.js
index f20d78012a..2dbc5d81ee 100644
--- a/binaries/data/mods/public/gui/civinfo/civinfo.js
+++ b/binaries/data/mods/public/gui/civinfo/civinfo.js
@@ -3,11 +3,6 @@
*/
const g_CivData = loadCivData(true, false);
-/**
- * Callback function name on closing gui via Engine.PopGuiPage().
- */
-var g_Callback = "";
-
var g_SelectedCiv = "";
/**
@@ -15,9 +10,6 @@ var g_SelectedCiv = "";
*/
function init(data = {})
{
- if (data.callback)
- g_Callback = data.callback;
-
var civList = Object.keys(g_CivData).map(civ => ({ "name": g_CivData[civ].Name, "code": civ })).sort(sortNameIgnoreCase);
var civSelection = Engine.GetGUIObjectByName("civSelection");
@@ -94,16 +86,12 @@ function subHeading(obj)
function switchToStrucTreePage()
{
- Engine.PopGuiPage();
- Engine.PushGuiPage("page_structree.xml", { "civ": g_SelectedCiv, "callback": g_Callback });
+ Engine.PopGuiPage({ "civ": g_SelectedCiv, "nextPage": "page_structree.xml" });
}
function closePage()
{
- if (g_Callback)
- Engine.PopGuiPageCB({ "civ": g_SelectedCiv, "page": "page_civinfo.xml" });
- else
- Engine.PopGuiPage();
+ Engine.PopGuiPage({ "civ": g_SelectedCiv, "page": "page_civinfo.xml" });
}
/**
diff --git a/binaries/data/mods/public/gui/gamesetup/gamesetup.js b/binaries/data/mods/public/gui/gamesetup/gamesetup.js
index 1567bf68c3..a3953cd6ec 100644
--- a/binaries/data/mods/public/gui/gamesetup/gamesetup.js
+++ b/binaries/data/mods/public/gui/gamesetup/gamesetup.js
@@ -22,7 +22,7 @@ const g_CivData = loadCivData(false, false);
* Store civilization code and page (structree or history) opened in civilization info.
*/
var g_CivInfo = {
- "code": "",
+ "civ": "",
"page": "page_civinfo.xml"
};
@@ -1047,10 +1047,10 @@ var g_MiscControls = {
"hotkey_structree": colorizeHotkey("%(hotkey)s", "structree")
}),
"onPress": () => function() {
- Engine.PushGuiPage(g_CivInfo.page, {
- "civ": g_CivInfo.code,
- "callback": "storeCivInfoPage"
- });
+ Engine.PushGuiPage(
+ g_CivInfo.page,
+ { "civ": g_CivInfo.civ },
+ storeCivInfoPage);
}
},
"civResetButton": {
@@ -2423,30 +2423,26 @@ function openAIConfig(playerSlot)
{
g_LastViewedAIPlayer = playerSlot;
- Engine.PushGuiPage("page_aiconfig.xml", {
- "callback": "AIConfigCallback",
- "playerSlot": playerSlot,
- "id": g_GameAttributes.settings.PlayerData[playerSlot].AI,
- "difficulty": g_GameAttributes.settings.PlayerData[playerSlot].AIDiff,
- "behavior": g_GameAttributes.settings.PlayerData[playerSlot].AIBehavior
- });
-}
+ Engine.PushGuiPage(
+ "page_aiconfig.xml",
+ {
+ "playerSlot": playerSlot,
+ "id": g_GameAttributes.settings.PlayerData[playerSlot].AI,
+ "difficulty": g_GameAttributes.settings.PlayerData[playerSlot].AIDiff,
+ "behavior": g_GameAttributes.settings.PlayerData[playerSlot].AIBehavior
+ },
+ ai => {
+ g_LastViewedAIPlayer = -1;
-/**
- * Called after closing the dialog.
- */
-function AIConfigCallback(ai)
-{
- g_LastViewedAIPlayer = -1;
+ if (!ai.save || !g_IsController)
+ return;
- if (!ai.save || !g_IsController)
- return;
+ g_GameAttributes.settings.PlayerData[ai.playerSlot].AI = ai.id;
+ g_GameAttributes.settings.PlayerData[ai.playerSlot].AIDiff = ai.difficulty;
+ g_GameAttributes.settings.PlayerData[ai.playerSlot].AIBehavior = ai.behavior;
- g_GameAttributes.settings.PlayerData[ai.playerSlot].AI = ai.id;
- g_GameAttributes.settings.PlayerData[ai.playerSlot].AIDiff = ai.difficulty;
- g_GameAttributes.settings.PlayerData[ai.playerSlot].AIBehavior = ai.behavior;
-
- updateGameAttributes();
+ updateGameAttributes();
+ });
}
function reloadPlayerAssignmentChoices()
@@ -2775,6 +2771,11 @@ function updateAutocompleteEntries()
function storeCivInfoPage(data)
{
- g_CivInfo.code = data.civ;
- g_CivInfo.page = data.page;
+ if (data.nextPage)
+ Engine.PushGuiPage(
+ data.nextPage,
+ { "civ": data.civ },
+ storeCivInfoPage);
+ else
+ g_CivInfo = data;
}
diff --git a/binaries/data/mods/public/gui/gamesetup/gamesetup.xml b/binaries/data/mods/public/gui/gamesetup/gamesetup.xml
index 5b3aeee277..5c3538b3b3 100644
--- a/binaries/data/mods/public/gui/gamesetup/gamesetup.xml
+++ b/binaries/data/mods/public/gui/gamesetup/gamesetup.xml
@@ -6,15 +6,11 @@
Close
- closeManual();
+ Engine.PopGuiPage();
+
View Online
openURL("https://trac.wildfiregames.com/wiki/0adManual");
diff --git a/binaries/data/mods/public/gui/options/options.js b/binaries/data/mods/public/gui/options/options.js
index 0f541b8eda..bd30f3e635 100644
--- a/binaries/data/mods/public/gui/options/options.js
+++ b/binaries/data/mods/public/gui/options/options.js
@@ -4,12 +4,7 @@
var g_Options;
/**
- * Remember whether to unpause running singleplayer games.
- */
-var g_HasCallback;
-
-/**
- * Functions to call after closing the page.
+ * Names of session functions to be called after closing the page.
*/
var g_CloseCallbacks;
@@ -170,8 +165,7 @@ var g_OptionType = {
function init(data, hotloadData)
{
- g_CloseCallbacks = new Set();
- g_HasCallback = hotloadData && hotloadData.callback || data && data.callback;
+ g_CloseCallbacks = hotloadData ? hotloadData.closeCallbacks : new Set();
g_TabCategorySelected = hotloadData ? hotloadData.tabCategorySelected : 0;
g_Options = Engine.ReadJSONFile("gui/options/options.json");
@@ -190,7 +184,7 @@ function getHotloadData()
{
return {
"tabCategorySelected": g_TabCategorySelected,
- "callback": g_HasCallback
+ "closeCallbacks": g_CloseCallbacks
};
}
@@ -382,8 +376,5 @@ function closePage()
function closePageWithoutConfirmation()
{
- if (g_HasCallback)
- Engine.PopGuiPageCB(g_CloseCallbacks);
- else
- Engine.PopGuiPage();
+ Engine.PopGuiPage(g_CloseCallbacks);
}
diff --git a/binaries/data/mods/public/gui/pregame/mainmenu.js b/binaries/data/mods/public/gui/pregame/mainmenu.js
index dda81b84d7..3120fcc715 100644
--- a/binaries/data/mods/public/gui/pregame/mainmenu.js
+++ b/binaries/data/mods/public/gui/pregame/mainmenu.js
@@ -105,9 +105,7 @@ function onTick()
function ShowSplashScreen()
{
- Engine.PushGuiPage("page_splashscreen.xml", {
- "callback": "ShowRenderPathMessage"
- });
+ Engine.PushGuiPage("page_splashscreen.xml", {}, ShowRenderPathMessage);
}
function ShowRenderPathMessage()
@@ -232,3 +230,15 @@ function getLobbyDisabledByBuild()
{
return translate("Launch the multiplayer lobby to join and host publicly visible games and chat with other players. \\[DISABLED BY BUILD]");
}
+
+function openStrucTree(page)
+{
+ closeMenu();
+ Engine.PushGuiPage(page, {}, storeCivInfoPage);
+}
+
+function storeCivInfoPage(data)
+{
+ if (data.nextPage)
+ Engine.PushGuiPage(data.nextPage, { "civ": data.civ }, storeCivInfoPage);
+}
diff --git a/binaries/data/mods/public/gui/pregame/mainmenu.xml b/binaries/data/mods/public/gui/pregame/mainmenu.xml
index 57be3592ea..3c7e10c58b 100644
--- a/binaries/data/mods/public/gui/pregame/mainmenu.xml
+++ b/binaries/data/mods/public/gui/pregame/mainmenu.xml
@@ -118,10 +118,7 @@
hotkey="structree"
>
Structure Tree
-
- closeMenu();
- Engine.PushGuiPage("page_structree.xml", {});
-
+ openStrucTree("page_structree.xml");
@@ -134,10 +131,7 @@
hotkey="civinfo"
>
History
-
- closeMenu();
- Engine.PushGuiPage("page_civinfo.xml");
-
+ openStrucTree("page_civinfo.xml");
diff --git a/binaries/data/mods/public/gui/reference/common/core.js b/binaries/data/mods/public/gui/reference/common/core.js
index 51f92d2ada..8e50996a84 100644
--- a/binaries/data/mods/public/gui/reference/common/core.js
+++ b/binaries/data/mods/public/gui/reference/common/core.js
@@ -1,13 +1,4 @@
var g_SelectedCiv = "gaia";
-var g_CallbackSet = false;
-
-function closePage()
-{
- if (g_CallbackSet)
- Engine.PopGuiPageCB(0);
- else
- Engine.PopGuiPage();
-}
/**
* Compile lists of templates buildable/trainable/researchable of a given civ.
diff --git a/binaries/data/mods/public/gui/reference/structree/structree.js b/binaries/data/mods/public/gui/reference/structree/structree.js
index a8e1368db6..2267dc32a9 100644
--- a/binaries/data/mods/public/gui/reference/structree/structree.js
+++ b/binaries/data/mods/public/gui/reference/structree/structree.js
@@ -8,11 +8,6 @@ var g_BuildList = {};
*/
var g_TrainList = {};
-/**
- * Callback function name on closing gui via Engine.PopGuiPage().
- */
-var g_Callback = "";
-
/**
* Initialize the page
*
@@ -20,9 +15,6 @@ var g_Callback = "";
*/
function init(data = {})
{
- if (data.callback)
- g_Callback = data.callback;
-
let civList = Object.keys(g_CivData).map(civ => ({
"name": g_CivData[civ].Name,
"code": civ,
@@ -52,16 +44,12 @@ function init(data = {})
function switchToCivInfoPage()
{
- Engine.PopGuiPage();
- Engine.PushGuiPage("page_civinfo.xml", { "civ": g_SelectedCiv, "callback": g_Callback });
+ Engine.PopGuiPage({ "civ": g_SelectedCiv, "nextPage": "page_civinfo.xml" });
}
function closePage()
{
- if (g_Callback)
- Engine.PopGuiPageCB({ "civ": g_SelectedCiv, "page": "page_structree.xml" });
- else
- Engine.PopGuiPage();
+ Engine.PopGuiPage({ "civ": g_SelectedCiv, "page": "page_structree.xml" });
}
/**
diff --git a/binaries/data/mods/public/gui/reference/viewer/viewer.js b/binaries/data/mods/public/gui/reference/viewer/viewer.js
index 68f5085953..e269463046 100644
--- a/binaries/data/mods/public/gui/reference/viewer/viewer.js
+++ b/binaries/data/mods/public/gui/reference/viewer/viewer.js
@@ -47,9 +47,6 @@ var g_RankIconPath = "session/icons/ranks/";
* @param {object} data - Contains the civCode and the name of the template to display.
* @param {string} data.templateName
* @param {string} [data.civ]
- * @param {*} [data.callback] - If set and loosely equivalent to true, a callback is
- * assumed to be setup ready be called by the Engine upon
- * closure of this page.
*/
function init(data)
{
@@ -60,9 +57,6 @@ function init(data)
return;
}
- if (data.callback)
- g_CallbackSet = true;
-
let templateName = removeFiltersFromTemplateName(data.templateName);
let isTech = techDataExists(templateName);
diff --git a/binaries/data/mods/public/gui/reference/viewer/viewer.xml b/binaries/data/mods/public/gui/reference/viewer/viewer.xml
index 40b8cfbb79..db918ef23c 100644
--- a/binaries/data/mods/public/gui/reference/viewer/viewer.xml
+++ b/binaries/data/mods/public/gui/reference/viewer/viewer.xml
@@ -35,7 +35,7 @@
hotkey="cancel"
>
Close
- closePage();
+ Engine.PopGuiPage();
diff --git a/binaries/data/mods/public/gui/savegame/save.js b/binaries/data/mods/public/gui/savegame/save.js
index fea4675a8d..1325e7750e 100644
--- a/binaries/data/mods/public/gui/savegame/save.js
+++ b/binaries/data/mods/public/gui/savegame/save.js
@@ -80,7 +80,7 @@ function reallySaveGame(name, desc, nameIsPrefix)
function closeSave()
{
- Engine.PopGuiPageCB(0);
+ Engine.PopGuiPage();
}
// HACK: Engine.SaveGame* expects this function to be defined on the current page.
diff --git a/binaries/data/mods/public/gui/session/hotkeys/misc.xml b/binaries/data/mods/public/gui/session/hotkeys/misc.xml
index 07049c0b6e..28c3b17288 100644
--- a/binaries/data/mods/public/gui/session/hotkeys/misc.xml
+++ b/binaries/data/mods/public/gui/session/hotkeys/misc.xml
@@ -33,15 +33,11 @@
-
- Engine.PushGuiPage("page_civinfo.xml", { "civ": g_CivInfo.code, "callback": "storeCivInfoPage" });
-
+ openStrucTree("page_civinfo.xml");
-
- Engine.PushGuiPage("page_structree.xml", { "civ": g_CivInfo.code, "callback": "storeCivInfoPage" });
-
+ openStrucTree("page_structree.xml");
diff --git a/binaries/data/mods/public/gui/session/menu.js b/binaries/data/mods/public/gui/session/menu.js
index 0cc871a88a..a1bf783b22 100644
--- a/binaries/data/mods/public/gui/session/menu.js
+++ b/binaries/data/mods/public/gui/session/menu.js
@@ -29,7 +29,7 @@ var g_IdleTraderTextColor = "orange";
* Store civilization code and page (structree or history) opened in civilization info.
*/
var g_CivInfo = {
- "code": "",
+ "civ": "",
"page": "page_structree.xml"
};
@@ -225,10 +225,10 @@ function openSave()
closeOpenDialogs();
pauseGame();
- Engine.PushGuiPage("page_savegame.xml", {
- "savedGameData": getSavedGameData(),
- "callback": "resumeGame"
- });
+ Engine.PushGuiPage(
+ "page_savegame.xml",
+ { "savedGameData": getSavedGameData() },
+ resumeGame);
}
function openOptions()
@@ -236,18 +236,16 @@ function openOptions()
closeOpenDialogs();
pauseGame();
- Engine.PushGuiPage("page_options.xml", {
- "callback": "optionsPageClosed"
- });
-}
+ Engine.PushGuiPage(
+ "page_options.xml",
+ {},
+ callbackFunctionNames => {
+ for (let functionName of callbackFunctionNames)
+ if (global[functionName])
+ global[functionName]();
-function optionsPageClosed(data)
-{
- for (let callback of data)
- if (global[callback])
- global[callback]();
-
- resumeGame();
+ resumeGame();
+ });
}
function openChat(command = "")
@@ -1090,41 +1088,51 @@ function openGameSummary()
pauseGame();
let extendedSimState = Engine.GuiInterfaceCall("GetExtendedSimulationState");
- Engine.PushGuiPage("page_summary.xml", {
- "sim": {
- "mapSettings": g_GameAttributes.settings,
- "playerStates": extendedSimState.players.filter((state, player) =>
- g_IsObserver || player == 0 || player == g_ViewedPlayer ||
- extendedSimState.players[g_ViewedPlayer].hasSharedLos && g_Players[player].isMutualAlly[g_ViewedPlayer]),
- "timeElapsed": extendedSimState.timeElapsed
+ Engine.PushGuiPage(
+ "page_summary.xml",
+ {
+ "sim": {
+ "mapSettings": g_GameAttributes.settings,
+ "playerStates": extendedSimState.players.filter((state, player) =>
+ g_IsObserver || player == 0 || player == g_ViewedPlayer ||
+ extendedSimState.players[g_ViewedPlayer].hasSharedLos && g_Players[player].isMutualAlly[g_ViewedPlayer]),
+ "timeElapsed": extendedSimState.timeElapsed
+ },
+ "gui": {
+ "dialog": true,
+ "isInGame": true
+ },
+ "selectedData": g_SummarySelectedData
},
- "gui": {
- "dialog": true,
- "isInGame": true
- },
- "selectedData": g_SummarySelectedData,
- "callback": "resumeGameAndSaveSummarySelectedData"
- });
+ resumeGameAndSaveSummarySelectedData);
}
-function openStrucTree()
+function openStrucTree(page)
{
closeOpenDialogs();
pauseGame();
- // TODO add info about researched techs and unlocked entities
-
- Engine.PushGuiPage(g_CivInfo.page, {
- "civ": g_CivInfo.code || g_Players[g_ViewedPlayer].civ,
- "callback": "storeCivInfoPage"
- });
+ Engine.PushGuiPage(
+ page,
+ {
+ "civ": g_CivInfo.civ || g_Players[g_ViewedPlayer].civ
+ // TODO add info about researched techs and unlocked entities
+ },
+ storeCivInfoPage);
}
function storeCivInfoPage(data)
{
- g_CivInfo.code = data.civ;
- g_CivInfo.page = data.page;
- resumeGame();
+ if (data.nextPage)
+ Engine.PushGuiPage(
+ data.nextPage,
+ { "civ": data.civ },
+ storeCivInfoPage);
+ else
+ {
+ g_CivInfo = data;
+ resumeGame();
+ }
}
/**
diff --git a/binaries/data/mods/public/gui/session/selection_panels.js b/binaries/data/mods/public/gui/session/selection_panels.js
index aa7626b227..df1deffa05 100644
--- a/binaries/data/mods/public/gui/session/selection_panels.js
+++ b/binaries/data/mods/public/gui/session/selection_panels.js
@@ -1143,11 +1143,13 @@ function showTemplateDetails(templateName, civCode)
{
pauseGame();
- Engine.PushGuiPage("page_viewer.xml", {
- "templateName": templateName,
- "callback": "resumeGame",
- "civ": civCode
- });
+ Engine.PushGuiPage(
+ "page_viewer.xml",
+ {
+ "templateName": templateName,
+ "civ": civCode
+ },
+ resumeGame);
}
/**
diff --git a/binaries/data/mods/public/gui/session/top_panel/civ_icon.xml b/binaries/data/mods/public/gui/session/top_panel/civ_icon.xml
index 7883610371..784f1b32fa 100644
--- a/binaries/data/mods/public/gui/session/top_panel/civ_icon.xml
+++ b/binaries/data/mods/public/gui/session/top_panel/civ_icon.xml
@@ -6,6 +6,6 @@
tooltip_style="sessionToolTipBold"
>
- openStrucTree()
+ openStrucTree(g_CivInfo.page)
diff --git a/binaries/data/mods/public/gui/splashscreen/splashscreen.js b/binaries/data/mods/public/gui/splashscreen/splashscreen.js
index 662dd47823..b26f81b62c 100644
--- a/binaries/data/mods/public/gui/splashscreen/splashscreen.js
+++ b/binaries/data/mods/public/gui/splashscreen/splashscreen.js
@@ -10,5 +10,5 @@ function closePage()
{
Engine.ConfigDB_CreateAndWriteValueToFile("user", "gui.splashscreen.enable", String(Engine.GetGUIObjectByName("displaySplashScreen").checked), "config/user.cfg");
Engine.ConfigDB_CreateAndWriteValueToFile("user", "gui.splashscreen.version", Engine.GetFileMTime(g_SplashScreenFile), "config/user.cfg");
- Engine.PopGuiPageCB();
+ Engine.PopGuiPage();
}
diff --git a/binaries/data/mods/public/gui/summary/summary.js b/binaries/data/mods/public/gui/summary/summary.js
index 077ce8c078..4a643e6c4d 100644
--- a/binaries/data/mods/public/gui/summary/summary.js
+++ b/binaries/data/mods/public/gui/summary/summary.js
@@ -443,7 +443,7 @@ function continueButton()
"charts": g_SelectedChart
};
if (g_GameData.gui.isInGame)
- Engine.PopGuiPageCB({
+ Engine.PopGuiPage({
"explicitResume": 0,
"summarySelectedData": summarySelectedData
});
diff --git a/source/gui/GUIManager.cpp b/source/gui/GUIManager.cpp
index 1478d16747..c4ceb6d44a 100644
--- a/source/gui/GUIManager.cpp
+++ b/source/gui/GUIManager.cpp
@@ -89,19 +89,24 @@ void CGUIManager::SwitchPage(const CStrW& pageName, ScriptInterface* srcScriptIn
m_PageStack.clear();
- PushPage(pageName, initDataClone);
+ PushPage(pageName, initDataClone, JS::UndefinedHandleValue);
}
-void CGUIManager::PushPage(const CStrW& pageName, shared_ptr initData)
+void CGUIManager::PushPage(const CStrW& pageName, shared_ptr initData, JS::HandleValue callbackFunction)
{
+ // Store the callback handler in the current GUI page before opening the new one
+ if (!m_PageStack.empty() && !callbackFunction.isUndefined())
+ m_PageStack.back().SetCallbackFunction(*m_ScriptInterface, callbackFunction);
+
// Push the page prior to loading its contents, because that may push
// another GUI page on init which should be pushed on top of this new page.
m_PageStack.emplace_back(pageName, initData);
m_PageStack.back().LoadPage(m_ScriptRuntime);
+
ResetCursor();
}
-void CGUIManager::PopPage()
+void CGUIManager::PopPage(shared_ptr args)
{
if (m_PageStack.size() < 2)
{
@@ -110,58 +115,11 @@ void CGUIManager::PopPage()
}
m_PageStack.pop_back();
-}
-
-void CGUIManager::PopPageCB(shared_ptr args)
-{
- shared_ptr initDataClone = m_PageStack.back().initData;
- PopPage();
-
- shared_ptr scriptInterface = m_PageStack.back().gui->GetScriptInterface();
- JSContext* cx = scriptInterface->GetContext();
- JSAutoRequest rq(cx);
-
- JS::RootedValue initDataVal(cx);
- if (!initDataClone)
- {
- LOGERROR("Called PopPageCB when initData (which should contain the callback function name) isn't set!");
- return;
- }
-
- scriptInterface->ReadStructuredClone(initDataClone, &initDataVal);
-
- if (!scriptInterface->HasProperty(initDataVal, "callback"))
- {
- LOGERROR("Called PopPageCB when the callback function name isn't set!");
- return;
- }
-
- std::string callback;
- if (!scriptInterface->GetProperty(initDataVal, "callback", callback))
- {
- LOGERROR("Failed to get the callback property as a string from initData in PopPageCB!");
- return;
- }
-
- JS::RootedValue global(cx, scriptInterface->GetGlobalObject());
- if (!scriptInterface->HasProperty(global, callback.c_str()))
- {
- LOGERROR("The specified callback function %s does not exist in the page %s", callback, utf8_from_wstring(m_PageStack.back().name));
- return;
- }
-
- JS::RootedValue argVal(cx);
- if (args)
- scriptInterface->ReadStructuredClone(args, &argVal);
- if (!scriptInterface->CallFunctionVoid(global, callback.c_str(), argVal))
- {
- LOGERROR("Failed to call the callback function %s in the page %s", callback, utf8_from_wstring(m_PageStack.back().name));
- return;
- }
+ m_PageStack.back().PerformCallbackFunction(args);
}
CGUIManager::SGUIPage::SGUIPage(const CStrW& pageName, const shared_ptr initData)
- : name(pageName), initData(initData), inputs(), gui()
+ : name(pageName), initData(initData), inputs(), gui(), callbackFunction()
{
}
@@ -256,6 +214,52 @@ void CGUIManager::SGUIPage::LoadPage(shared_ptr scriptRuntime)
LOGERROR("GUI page '%s': Failed to call init() function", utf8_from_wstring(name));
}
+void CGUIManager::SGUIPage::SetCallbackFunction(ScriptInterface& scriptInterface, JS::HandleValue callbackFunc)
+{
+ if (!callbackFunc.isObject())
+ {
+ LOGERROR("Given callback handler is not an object!");
+ return;
+ }
+
+ // Does not require JSAutoRequest
+ if (!JS_ObjectIsFunction(scriptInterface.GetContext(), &callbackFunc.toObject()))
+ {
+ LOGERROR("Given callback handler is not a function!");
+ return;
+ }
+
+ callbackFunction = std::make_shared(scriptInterface.GetJSRuntime(), callbackFunc);
+}
+
+void CGUIManager::SGUIPage::PerformCallbackFunction(shared_ptr args)
+{
+ if (!callbackFunction)
+ return;
+
+ shared_ptr scriptInterface = gui->GetScriptInterface();
+ JSContext* cx = scriptInterface->GetContext();
+ JSAutoRequest rq(cx);
+
+ JS::RootedObject globalObj(cx, &scriptInterface->GetGlobalObject().toObject());
+
+ JS::RootedValue funcVal(cx, *callbackFunction);
+
+ // Delete the callback function, so that it is not called again
+ callbackFunction.reset();
+
+ JS::RootedValue argVal(cx);
+ if (args)
+ scriptInterface->ReadStructuredClone(args, &argVal);
+
+ JS::AutoValueVector paramData(cx);
+ paramData.append(argVal);
+
+ JS::RootedValue result(cx);
+
+ JS_CallFunctionValue(cx, globalObj, funcVal, paramData, &result);
+}
+
Status CGUIManager::ReloadChangedFile(const VfsPath& path)
{
for (SGUIPage& p : m_PageStack)
diff --git a/source/gui/GUIManager.h b/source/gui/GUIManager.h
index ba76727dc4..615c4e1081 100644
--- a/source/gui/GUIManager.h
+++ b/source/gui/GUIManager.h
@@ -72,15 +72,15 @@ public:
* Load a new GUI page and make it active. All current pages will be retained,
* and will still be drawn and receive tick events, but will not receive
* user inputs.
+ * If given, the callbackHandler function will be executed once this page is closed.
*/
- void PushPage(const CStrW& pageName, shared_ptr initData);
+ void PushPage(const CStrW& pageName, shared_ptr initData, JS::HandleValue callbackFunc);
/**
* Unload the currently active GUI page, and make the previous page active.
* (There must be at least two pages when you call this.)
*/
- void PopPage();
- void PopPageCB(shared_ptr args);
+ void PopPage(shared_ptr args);
/**
* Called when a file has been modified, to hotload changes.
@@ -145,13 +145,37 @@ private:
{
// COPYABLE, because event handlers may invalidate page stack iterators by open or close pages,
// and event handlers need to be called for the entire stack.
+
+ /**
+ * Initializes the data that will be used to create the CGUI page one or multiple times (hotloading).
+ */
SGUIPage(const CStrW& pageName, const shared_ptr initData);
+
+ /**
+ * Create the CGUI with it's own ScriptInterface. Deletes the previous CGUI if it existed.
+ */
void LoadPage(shared_ptr scriptRuntime);
+ /**
+ * Sets the callback handler when a new page is opened that will be performed when the page is closed.
+ */
+ void SetCallbackFunction(ScriptInterface& scriptInterface, JS::HandleValue callbackFunc);
+
+ /**
+ * Execute the stored callback function with the given arguments.
+ */
+ void PerformCallbackFunction(shared_ptr args);
+
CStrW name;
boost::unordered_set inputs; // for hotloading
shared_ptr initData; // data to be passed to the init() function
shared_ptr gui; // the actual GUI page
+
+ /**
+ * Function executed by this parent GUI page when the child GUI page it pushed is popped.
+ * Notice that storing it in the SGUIPage instead of CGUI means that it will survive the hotloading CGUI reset.
+ */
+ shared_ptr callbackFunction;
};
shared_ptr top() const;
diff --git a/source/gui/scripting/JSInterface_GUIManager.cpp b/source/gui/scripting/JSInterface_GUIManager.cpp
index 33d868559b..89a22e9974 100644
--- a/source/gui/scripting/JSInterface_GUIManager.cpp
+++ b/source/gui/scripting/JSInterface_GUIManager.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018 Wildfire Games.
+/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -27,9 +27,9 @@
// Note that the initData argument may only contain clonable data.
// Functions aren't supported for example!
-void JSI_GUIManager::PushGuiPage(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name, JS::HandleValue initData)
+void JSI_GUIManager::PushGuiPage(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name, JS::HandleValue initData, JS::HandleValue callbackFunction)
{
- g_GUI->PushPage(name, pCxPrivate->pScriptInterface->WriteStructuredClone(initData));
+ g_GUI->PushPage(name, pCxPrivate->pScriptInterface->WriteStructuredClone(initData), callbackFunction);
}
void JSI_GUIManager::SwitchGuiPage(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name, JS::HandleValue initData)
@@ -37,14 +37,9 @@ void JSI_GUIManager::SwitchGuiPage(ScriptInterface::CxPrivate* pCxPrivate, const
g_GUI->SwitchPage(name, pCxPrivate->pScriptInterface, initData);
}
-void JSI_GUIManager::PopGuiPage(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
+void JSI_GUIManager::PopGuiPage(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue args)
{
- g_GUI->PopPage();
-}
-
-void JSI_GUIManager::PopGuiPageCB(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue args)
-{
- g_GUI->PopPageCB(pCxPrivate->pScriptInterface->WriteStructuredClone(args));
+ g_GUI->PopPage(pCxPrivate->pScriptInterface->WriteStructuredClone(args));
}
JS::Value JSI_GUIManager::GetGUIObjectByName(ScriptInterface::CxPrivate* pCxPrivate, const std::string& name)
@@ -82,10 +77,9 @@ CParamNode JSI_GUIManager::GetTemplate(ScriptInterface::CxPrivate* UNUSED(pCxPri
void JSI_GUIManager::RegisterScriptFunctions(const ScriptInterface& scriptInterface)
{
- scriptInterface.RegisterFunction("PushGuiPage");
+ scriptInterface.RegisterFunction("PushGuiPage");
scriptInterface.RegisterFunction("SwitchGuiPage");
- scriptInterface.RegisterFunction("PopGuiPage");
- scriptInterface.RegisterFunction("PopGuiPageCB");
+ scriptInterface.RegisterFunction("PopGuiPage");
scriptInterface.RegisterFunction("GetGUIObjectByName");
scriptInterface.RegisterFunction("SetCursor");
scriptInterface.RegisterFunction("ResetCursor");
diff --git a/source/gui/scripting/JSInterface_GUIManager.h b/source/gui/scripting/JSInterface_GUIManager.h
index 0d1119ae8d..b69aae1669 100644
--- a/source/gui/scripting/JSInterface_GUIManager.h
+++ b/source/gui/scripting/JSInterface_GUIManager.h
@@ -23,10 +23,9 @@
namespace JSI_GUIManager
{
- void PushGuiPage(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name, JS::HandleValue initData);
+ void PushGuiPage(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name, JS::HandleValue initData, JS::HandleValue callbackFunction);
void SwitchGuiPage(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name, JS::HandleValue initData);
- void PopGuiPage(ScriptInterface::CxPrivate* pCxPrivate);
- void PopGuiPageCB(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue args);
+ void PopGuiPage(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue args);
JS::Value GetGUIObjectByName(ScriptInterface::CxPrivate* pCxPrivate, const std::string& name);
std::wstring SetCursor(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& name);
void ResetCursor(ScriptInterface::CxPrivate* pCxPrivate);