PushGuiPage support for passing a function instead of a function name.
Allows coding the GUI without global functions which break prototype-oriented coding, refs #5322, fixing the concern in4b1297b328
. Supports stacked message boxes and removes the according workaround. Change structree / civinfo switch-dialog code from760a47335d
to perform the callback for page that actually registered the callback. Ensure the parent that the callbackhandler is always called if the page is closed. Merge PopGuiPage and PopGuiPageCB following that choice, incidentally leaving cleaner code. Differential Revision: https://code.wildfiregames.com/D1684 Comments by: Yves, Vladislav, wraitii, leper This was SVN commit r22676.
This commit is contained in:
parent
a06cfe309b
commit
86c151ebaa
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -268,9 +268,9 @@ function cancelRequest()
|
||||
hideDialog();
|
||||
}
|
||||
|
||||
function closePage(data)
|
||||
function closePage()
|
||||
{
|
||||
Engine.PopGuiPageCB(undefined);
|
||||
Engine.PopGuiPage();
|
||||
}
|
||||
|
||||
function showErrorMessageBox(caption, title, buttonCaptions, buttonActions)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -82,7 +82,7 @@ function initLanguageSelection()
|
||||
|
||||
function closeTerms(accepted)
|
||||
{
|
||||
Engine.PopGuiPageCB({
|
||||
Engine.PopGuiPage({
|
||||
"page": g_TermsPage,
|
||||
"accepted": accepted
|
||||
});
|
||||
|
@ -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,
|
||||
|
@ -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" });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -6,15 +6,11 @@
|
||||
<script directory="gui/gamesetup/"/>
|
||||
|
||||
<object hotkey="civinfo">
|
||||
<action on="Press">
|
||||
Engine.PushGuiPage("page_civinfo.xml", { "civ": g_CivInfo.code, "callback": "storeCivInfoPage" });
|
||||
</action>
|
||||
<action on="Press">Engine.PushGuiPage("page_civinfo.xml", { "civ": g_CivInfo.civ }, storeCivInfoPage);</action>
|
||||
</object>
|
||||
|
||||
<object hotkey="structree">
|
||||
<action on="Press">
|
||||
Engine.PushGuiPage("page_structree.xml", { "civ": g_CivInfo.code, "callback": "storeCivInfoPage" });
|
||||
</action>
|
||||
<action on="Press">Engine.PushGuiPage("page_structree.xml", { "civ": g_CivInfo.civ }, storeCivInfoPage);</action>
|
||||
</object>
|
||||
|
||||
<object hotkey="cancel">
|
||||
|
@ -55,7 +55,7 @@ function languageSelectionChanged()
|
||||
function openAdvancedMenu()
|
||||
{
|
||||
let localeText = Engine.GetGUIObjectByName("localeText");
|
||||
Engine.PushGuiPage("page_locale_advanced.xml", { "callback": "applyFromAdvancedMenu", "locale": localeText.caption });
|
||||
Engine.PushGuiPage("page_locale_advanced.xml", { "locale": localeText.caption }, applyFromAdvancedMenu);
|
||||
}
|
||||
|
||||
function applyFromAdvancedMenu(locale)
|
||||
|
@ -114,5 +114,5 @@ function autoDetectLocale()
|
||||
function applySelectedLocale()
|
||||
{
|
||||
var resultingLocaleText = Engine.GetGUIObjectByName("resultingLocale");
|
||||
Engine.PopGuiPageCB(resultingLocaleText.caption);
|
||||
Engine.PopGuiPage(resultingLocaleText.caption);
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
var hasCallback = false;
|
||||
|
||||
function init(data)
|
||||
{
|
||||
Engine.GetGUIObjectByName("mainText").caption = Engine.TranslateLines(Engine.ReadFile("gui/manual/intro.txt"));
|
||||
hasCallback = data && data.callback;
|
||||
}
|
||||
|
||||
function closeManual()
|
||||
{
|
||||
if (hasCallback)
|
||||
Engine.PopGuiPageCB();
|
||||
else
|
||||
Engine.PopGuiPage();
|
||||
}
|
@ -14,13 +14,16 @@
|
||||
</object>
|
||||
|
||||
<object type="image" sprite="ModernFade" size="20 20 100%-20 100%-58">
|
||||
<object name="mainText" type="text" style="ModernTextPanel"/>
|
||||
<object name="mainText" type="text" style="ModernTextPanel">
|
||||
<action on="Load">this.caption = Engine.TranslateLines(Engine.ReadFile("gui/manual/intro.txt"));</action>
|
||||
</object>
|
||||
</object>
|
||||
|
||||
<object type="button" style="ModernButtonRed" tooltip_style="snToolTip" size="100%-408 100%-52 100%-218 100%-24" hotkey="cancel">
|
||||
<translatableAttribute id="caption">Close</translatableAttribute>
|
||||
<action on="Press">closeManual();</action>
|
||||
<action on="Press">Engine.PopGuiPage();</action>
|
||||
</object>
|
||||
|
||||
<object name="url" type="button" style="ModernButtonRed" size="100%-214 100%-52 100%-24 100%-24">
|
||||
<translatableAttribute id="caption">View Online</translatableAttribute>
|
||||
<action on="Press">openURL("https://trac.wildfiregames.com/wiki/0adManual");</action>
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -118,10 +118,7 @@
|
||||
hotkey="structree"
|
||||
>
|
||||
<translatableAttribute id="caption">Structure Tree</translatableAttribute>
|
||||
<action on="Press">
|
||||
closeMenu();
|
||||
Engine.PushGuiPage("page_structree.xml", {});
|
||||
</action>
|
||||
<action on="Press">openStrucTree("page_structree.xml");</action>
|
||||
</object>
|
||||
|
||||
<!-- HISTORY BUTTON -->
|
||||
@ -134,10 +131,7 @@
|
||||
hotkey="civinfo"
|
||||
>
|
||||
<translatableAttribute id="caption">History</translatableAttribute>
|
||||
<action on="Press">
|
||||
closeMenu();
|
||||
Engine.PushGuiPage("page_civinfo.xml");
|
||||
</action>
|
||||
<action on="Press">openStrucTree("page_civinfo.xml");</action>
|
||||
</object>
|
||||
|
||||
</object>
|
||||
|
@ -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.
|
||||
|
@ -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" });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
||||
hotkey="cancel"
|
||||
>
|
||||
<translatableAttribute id="caption">Close</translatableAttribute>
|
||||
<action on="Press">closePage();</action>
|
||||
<action on="Press">Engine.PopGuiPage();</action>
|
||||
</object>
|
||||
</object>
|
||||
|
||||
|
@ -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.
|
||||
|
@ -33,15 +33,11 @@
|
||||
</object>
|
||||
|
||||
<object hotkey="civinfo">
|
||||
<action on="Press">
|
||||
Engine.PushGuiPage("page_civinfo.xml", { "civ": g_CivInfo.code, "callback": "storeCivInfoPage" });
|
||||
</action>
|
||||
<action on="Press">openStrucTree("page_civinfo.xml");</action>
|
||||
</object>
|
||||
|
||||
<object hotkey="structree">
|
||||
<action on="Press">
|
||||
Engine.PushGuiPage("page_structree.xml", { "civ": g_CivInfo.code, "callback": "storeCivInfoPage" });
|
||||
</action>
|
||||
<action on="Press">openStrucTree("page_structree.xml");</action>
|
||||
</object>
|
||||
|
||||
<object hotkey="silhouettes">
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6,6 +6,6 @@
|
||||
tooltip_style="sessionToolTipBold"
|
||||
>
|
||||
<object name="civIconOverlay" style="CivIconOverlay" size="0 0 100% 100%" type="button">
|
||||
<action on="Press">openStrucTree()</action>
|
||||
<action on="Press">openStrucTree(g_CivInfo.page)</action>
|
||||
</object>
|
||||
</object>
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -443,7 +443,7 @@ function continueButton()
|
||||
"charts": g_SelectedChart
|
||||
};
|
||||
if (g_GameData.gui.isInGame)
|
||||
Engine.PopGuiPageCB({
|
||||
Engine.PopGuiPage({
|
||||
"explicitResume": 0,
|
||||
"summarySelectedData": summarySelectedData
|
||||
});
|
||||
|
@ -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<ScriptInterface::StructuredClone> initData)
|
||||
void CGUIManager::PushPage(const CStrW& pageName, shared_ptr<ScriptInterface::StructuredClone> 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<ScriptInterface::StructuredClone> args)
|
||||
{
|
||||
if (m_PageStack.size() < 2)
|
||||
{
|
||||
@ -110,58 +115,11 @@ void CGUIManager::PopPage()
|
||||
}
|
||||
|
||||
m_PageStack.pop_back();
|
||||
}
|
||||
|
||||
void CGUIManager::PopPageCB(shared_ptr<ScriptInterface::StructuredClone> args)
|
||||
{
|
||||
shared_ptr<ScriptInterface::StructuredClone> initDataClone = m_PageStack.back().initData;
|
||||
PopPage();
|
||||
|
||||
shared_ptr<ScriptInterface> 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<ScriptInterface::StructuredClone> 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> 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<JS::PersistentRootedValue>(scriptInterface.GetJSRuntime(), callbackFunc);
|
||||
}
|
||||
|
||||
void CGUIManager::SGUIPage::PerformCallbackFunction(shared_ptr<ScriptInterface::StructuredClone> args)
|
||||
{
|
||||
if (!callbackFunction)
|
||||
return;
|
||||
|
||||
shared_ptr<ScriptInterface> 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)
|
||||
|
@ -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<ScriptInterface::StructuredClone> initData);
|
||||
void PushPage(const CStrW& pageName, shared_ptr<ScriptInterface::StructuredClone> 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<ScriptInterface::StructuredClone> args);
|
||||
void PopPage(shared_ptr<ScriptInterface::StructuredClone> 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<ScriptInterface::StructuredClone> initData);
|
||||
|
||||
/**
|
||||
* Create the CGUI with it's own ScriptInterface. Deletes the previous CGUI if it existed.
|
||||
*/
|
||||
void LoadPage(shared_ptr<ScriptRuntime> 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<ScriptInterface::StructuredClone> args);
|
||||
|
||||
CStrW name;
|
||||
boost::unordered_set<VfsPath> inputs; // for hotloading
|
||||
shared_ptr<ScriptInterface::StructuredClone> initData; // data to be passed to the init() function
|
||||
shared_ptr<CGUI> 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<JS::PersistentRootedValue> callbackFunction;
|
||||
};
|
||||
|
||||
shared_ptr<CGUI> top() const;
|
||||
|
@ -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<void, std::wstring, JS::HandleValue, &PushGuiPage>("PushGuiPage");
|
||||
scriptInterface.RegisterFunction<void, std::wstring, JS::HandleValue, JS::HandleValue, &PushGuiPage>("PushGuiPage");
|
||||
scriptInterface.RegisterFunction<void, std::wstring, JS::HandleValue, &SwitchGuiPage>("SwitchGuiPage");
|
||||
scriptInterface.RegisterFunction<void, &PopGuiPage>("PopGuiPage");
|
||||
scriptInterface.RegisterFunction<void, JS::HandleValue, &PopGuiPageCB>("PopGuiPageCB");
|
||||
scriptInterface.RegisterFunction<void, JS::HandleValue, &PopGuiPage>("PopGuiPage");
|
||||
scriptInterface.RegisterFunction<JS::Value, std::string, &GetGUIObjectByName>("GetGUIObjectByName");
|
||||
scriptInterface.RegisterFunction<std::wstring, std::wstring, &SetCursor>("SetCursor");
|
||||
scriptInterface.RegisterFunction<void, &ResetCursor>("ResetCursor");
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user