Unify loadgame and savegame dialog following e0ea53a8ee, refs #2030.

This way the save dialog gains the sortable list and details section
feature from 10b49f9c18 / D246 by removing a folder of code, refs #4413.
Fixes a style warning about the old dialog using a style for an 'olist'
type for a 'list' type, refs be963ec9b7 / D2232.

Subsequently move the gui/common/ helper file to the page code, meaning
it's not loaded for every GUI page needlessly anymore.
Fix map preview aspect ratio.
Use object-oriented code for the moved savegame code, refs #5387, but
conserve the rest of the code to limit the changes for auditability.

Differential Revision: https://code.wildfiregames.com/D2290
Tested on: Jenkins

This was SVN commit r22923.
This commit is contained in:
elexis 2019-09-18 02:33:43 +00:00
parent 003d588d13
commit bdc6a7d3fd
9 changed files with 93 additions and 177 deletions

View File

@ -0,0 +1,52 @@
/**
* This class obtains the current simulation state to be saved along the savegame,
* asks the user whether to overwrite a savegame and performs the saving.
*/
class SavegameWriter
{
constructor(data)
{
this.savedGameData = data && data.savedGameData || {};
let simulationState = Engine.GuiInterfaceCall("GetSimulationState");
this.savedGameData.timeElapsed = simulationState.timeElapsed;
this.savedGameData.states = simulationState.players.map(pState => pState.state);
}
getSavedGameData()
{
return this.savedGameData;
}
saveGame()
{
let gameSelection = Engine.GetGUIObjectByName("gameSelection");
let gameLabel = gameSelection.list[gameSelection.selected];
let gameID = gameSelection.list_data[gameSelection.selected];
let desc = Engine.GetGUIObjectByName("saveGameDesc").caption;
let name = gameID || "savegame";
if (!gameID)
{
this.reallySaveGame(name, desc, true);
return;
}
messageBox(
500, 200,
sprintf(translate("\"%(label)s\""), { "label": gameLabel }) + "\n" +
translate("Saved game will be permanently overwritten, are you sure?"),
translate("OVERWRITE SAVE"),
[translate("No"), translate("Yes")],
[null, () => { this.reallySaveGame(name, desc, false); }]);
}
reallySaveGame(name, desc, nameIsPrefix)
{
if (nameIsPrefix)
Engine.SaveGamePrefix(name, desc, this.savedGameData);
else
Engine.SaveGame(name, desc, this.savedGameData);
Engine.PopGuiPage();
}
}

View File

@ -64,8 +64,7 @@ function reallyDeleteGame(gameID)
if (!Engine.DeleteSavedGame(gameID))
error("Could not delete saved game: " + gameID);
// Run init again to refresh saved game list
init();
updateSavegameList();
}
function deleteTooltip()

View File

@ -1,3 +1,5 @@
var g_SavegameWriter;
var g_SavedGamesMetadata = [];
/**
@ -5,7 +7,29 @@ var g_SavedGamesMetadata = [];
*/
const g_CivData = loadCivData(false, false);
function init()
function init(data)
{
let save = Engine.IsGameStarted();
if (save)
g_SavegameWriter = new SavegameWriter(data);
let confirmButton = Engine.GetGUIObjectByName("confirmButton");
confirmButton.caption = save ? translate("Save") : translate("Load");
confirmButton.onPress = save ? () => { g_SavegameWriter.saveGame(); } : loadGame;
Engine.GetGUIObjectByName("title").caption = save ? translate("Save Game") : translate("Load Game")
Engine.GetGUIObjectByName("saveGameDesc").hidden = !save;
updateSavegameList();
// Select the most recent savegame to be loaded, or no savegame to be overwritten
let gameSelection = Engine.GetGUIObjectByName("gameSelection");
if (!save && gameSelection.list.length)
gameSelection.selected = 0;
else
selectionChanged();
}
function updateSavegameList()
{
let savedGames = Engine.GetSavedGames();
@ -17,6 +41,10 @@ function init()
let gameSelection = Engine.GetGUIObjectByName("gameSelection");
gameSelection.enabled = !!savedGames.length;
gameSelection.onSelectionChange = selectionChanged;
gameSelection.onSelectionColumnChange = updateSavegameList;
gameSelection.onMouseLeftDoubleClickItem = loadGame;
Engine.GetGUIObjectByName("gameSelectionFeedback").hidden = !!savedGames.length;
let selectedGameId = gameSelection.list_data[gameSelection.selected];
@ -87,9 +115,6 @@ function init()
gameSelection.selected = selectedGameIndex;
else if (gameSelection.selected >= g_SavedGamesMetadata.length) // happens when deleting the last saved game
gameSelection.selected = g_SavedGamesMetadata.length - 1;
else if (gameSelection.selected == -1 && g_SavedGamesMetadata.length)
gameSelection.selected = 0;
selectionChanged();
Engine.GetGUIObjectByName("deleteGameButton").tooltip = deleteTooltip();
}
@ -99,7 +124,7 @@ function selectionChanged()
let metadata = g_SavedGamesMetadata[Engine.GetGUIObjectByName("gameSelection").selected];
Engine.GetGUIObjectByName("invalidGame").hidden = !!metadata;
Engine.GetGUIObjectByName("validGame").hidden = !metadata;
Engine.GetGUIObjectByName("loadGameButton").enabled = !!metadata;
Engine.GetGUIObjectByName("confirmButton").enabled = !!metadata || Engine.IsGameStarted();
Engine.GetGUIObjectByName("deleteGameButton").enabled = !!metadata;
if (!metadata)
@ -170,8 +195,7 @@ function loadGame()
message,
translate("Warning"),
[translate("No"), translate("Yes")],
[init, function(){ reallyLoadGame(gameId); }]
);
[undefined, () => { reallyLoadGame(gameId); }]);
}
function reallyLoadGame(gameId)
@ -179,10 +203,7 @@ function reallyLoadGame(gameId)
let metadata = Engine.StartSavedGame(gameId);
if (!metadata)
{
// Probably the file wasn't found
// Show error and refresh saved game list
error("Could not load saved game: " + gameId);
init();
return;
}

View File

@ -10,9 +10,7 @@
<object type="image" style="ModernDialog" size="50%-460 50%-325 50%+460 50%+325">
<object type="text" style="TitleText" size="50%-128 -18 50%+128 14">
<translatableAttribute id="caption">Load Game</translatableAttribute>
</object>
<object name="title" type="text" style="TitleText" size="50%-128 -18 50%+128 14"/>
<object type="image" size="0 20 630 100%">
<object name="gameSelection"
@ -24,10 +22,6 @@
type="olist"
auto_scroll="true"
>
<action on="SelectionChange">selectionChanged();</action>
<action on="SelectionColumnChange">init();</action>
<action on="MouseLeftDoubleClickItem">loadGame();</action>
<column id="date" color="255 255 255" width="25%">
<translatableAttribute id="heading" context="replay">Date / Time</translatableAttribute>
</column>
@ -49,6 +43,10 @@
<translatableAttribute id="caption">No saved games found.</translatableAttribute>
</object>
<object name="saveGameDesc" size="24 100%-96 100%-24 100%-72" type="input" style="ModernInput">
<action on="Press">saveGame();</action>
</object>
<object type="button" size="0%+25 100%-60 33%+10 100%-32" style="StoneButton" hotkey="cancel">
<translatableAttribute id="caption">Cancel</translatableAttribute>
<action on="Press">Engine.PopGuiPage();</action>
@ -59,16 +57,12 @@
<action on="Press">deleteGame();</action>
</object>
<object name="loadGameButton" type="button" style="StoneButton" size="66%-5 100%-60 100%-25 100%-32">
<translatableAttribute id="caption">Load</translatableAttribute>
<action on="Press">loadGame();</action>
</object>
<object name="confirmButton" type="button" style="StoneButton" size="66%-5 100%-60 100%-25 100%-32"/>
</object>
<object name="filterPanel" size="630 25 100%-20 60">
<object name="compatibilityFilter" type="checkbox" checked="true" style="ModernTickBox" size="0 0 20 20">
<action on="Press">init();</action>
<action on="Press">updateSavegameList();</action>
</object>
<object type="text" size="25 0 100% 100%" text_align="left" textcolor="white">
@ -79,7 +73,7 @@
<object name="validGame" type="image" size="630 60 100%-20 100%">
<object size="0 0 100%-15 1" type="image" sprite="ModernWhiteLine" z="25" />
<object name="savedMapName" size="0 0 100% 20" type="text" style="ModernLabelText" />
<object name="savedInfoPreview" size="20 20 240 240" type="image" sprite="" />
<object name="savedInfoPreview" size="0 30 260 218" type="image" />
<object size="0 250 50% 270" type="text" style="ModernLeftLabelText">
<translatableAttribute id="caption">Players:</translatableAttribute>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<page>
<include>common/modern/setup.xml</include>
<include>common/modern/styles.xml</include>
<include>common/modern/sprites.xml</include>
<include>common/setup.xml</include>
<include>common/sprites.xml</include>
<include>common/styles.xml</include>
<include>savegame/save.xml</include>
</page>

View File

@ -1,84 +0,0 @@
var g_Descriptions;
var g_SavedGameData;
function selectDescription()
{
let gameSelection = Engine.GetGUIObjectByName("gameSelection");
let gameID = gameSelection.list_data[gameSelection.selected];
Engine.GetGUIObjectByName("deleteGameButton").enabled = !!gameID;
if (!gameID)
return;
Engine.GetGUIObjectByName("saveGameDesc").caption = g_Descriptions[gameID];
}
function init(data)
{
g_SavedGameData = data && data.savedGameData || {};
let simulationState = Engine.GuiInterfaceCall("GetSimulationState");
g_SavedGameData.timeElapsed = simulationState.timeElapsed;
g_SavedGameData.states = simulationState.players.map(pState => pState.state);
let savedGames = Engine.GetSavedGames().sort(sortDecreasingDate);
let gameSelection = Engine.GetGUIObjectByName("gameSelection");
gameSelection.enabled = savedGames.length != 0;
if (!savedGames.length)
{
gameSelection.list = [translate("No saved games found")];
gameSelection.selected = -1;
return;
}
g_Descriptions = {};
for (let game of savedGames)
g_Descriptions[game.id] = game.metadata.description || "";
let engineInfo = Engine.GetEngineInfo();
gameSelection.list = savedGames.map(game => generateSavegameLabel(game.metadata, engineInfo));
gameSelection.list_data = savedGames.map(game => game.id);
gameSelection.selected = Math.min(gameSelection.selected, gameSelection.list.length - 1);
Engine.GetGUIObjectByName("deleteGameButton").tooltip = deleteTooltip();
}
function saveGame()
{
let gameSelection = Engine.GetGUIObjectByName("gameSelection");
let gameLabel = gameSelection.list[gameSelection.selected];
let gameID = gameSelection.list_data[gameSelection.selected];
let desc = Engine.GetGUIObjectByName("saveGameDesc").caption;
let name = gameID || "savegame";
if (!gameID)
{
reallySaveGame(name, desc, true);
return;
}
messageBox(
500, 200,
sprintf(translate("\"%(label)s\""), { "label": gameLabel }) + "\n" +
translate("Saved game will be permanently overwritten, are you sure?"),
translate("OVERWRITE SAVE"),
[translate("No"), translate("Yes")],
[null, function(){ reallySaveGame(name, desc, false); }]
);
}
function reallySaveGame(name, desc, nameIsPrefix)
{
if (nameIsPrefix)
Engine.SaveGamePrefix(name, desc, g_SavedGameData);
else
Engine.SaveGame(name, desc, g_SavedGameData);
closeSave();
}
function closeSave()
{
Engine.PopGuiPage();
}

View File

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<objects>
<script directory="gui/common/"/>
<script directory="gui/savegame/"/>
<!-- Add a translucent black background to fade out the page -->
<object type="image" z="0" sprite="ModernFade"/>
<object type="image" style="ModernDialog" size="50%-300 50%-200 50%+300 50%+200">
<object type="image" z="0" sprite="ModernFade"/>
<object type="text" style="TitleText" size="50%-128 -18 50%+128 14">
<translatableAttribute id="caption">Save Game</translatableAttribute>
</object>
<object name="gameSelection"
style="ModernList"
type="list"
size="24 24 100%-24 100%-124">
<action on="selectionchange">
selectDescription();
</action>
</object>
<object size="24 100%-124 100%-24 100%-100" name="descLabel" type="text" style="ModernLeftLabelText">
<translatableAttribute id="caption">Description:</translatableAttribute>
</object>
<object name="saveGameDesc" size="24 100%-96 100%-24 100%-72" type="input" style="ModernInput">
<action on="Press">saveGame();</action>
</object>
<object name="saveButton" type="button" size="0%+25 100%-60 33%+10 100%-32" style="StoneButton" hotkey="cancel">
<translatableAttribute id="caption">Cancel</translatableAttribute>
<action on="Press">closeSave(true);</action>
</object>
<object name="deleteGameButton" type="button" size="33%+20 100%-60 66%-15 100%-32" style="StoneButton" hotkey="session.savedgames.delete">
<translatableAttribute id="caption">Delete</translatableAttribute>
<action on="Press">deleteGame();</action>
</object>
<object type="button" style="StoneButton" size="66%-5 100%-60 100%-25 100%-32">
<translatableAttribute id="caption">Save</translatableAttribute>
<action on="Press">saveGame();</action>
</object>
</object>
</objects>

View File

@ -226,7 +226,7 @@ function openSave()
pauseGame();
Engine.PushGuiPage(
"page_savegame.xml",
"page_loadgame.xml",
{ "savedGameData": getSavedGameData() },
resumeGame);
}

View File

@ -263,7 +263,6 @@
"gui/reference/structree/**.js",
"gui/reference/viewer/**.js",
"gui/replaymenu/**.js",
"gui/savegame/**.js",
"gui/splashscreen/**.js",
"gui/summary/**.js"
],
@ -298,7 +297,6 @@
"gui/reference/structree/**.xml",
"gui/reference/viewer/**.xml",
"gui/replaymenu/**.xml",
"gui/savegame/**.xml",
"gui/splashscreen/**.xml",
"gui/summary/**.xml"
],