1
0
forked from 0ad/0ad

Add sortable columns to the loading screen and a compatibility filter for saved games.

Replace the unexplained orange and red colorization and replace it with
the greyout equal to the replay menu,
as the difference between compatibility types is explained when trying
to load the game.
Rename the ambiguous generateLabel to generateSavegameLabel.

Patch By: Vladislav
Differential Revision: https://code.wildfiregames.com/D246
This was SVN commit r19351.
This commit is contained in:
elexis 2017-03-27 12:55:43 +00:00
parent cedf7a33aa
commit 10b49f9c18
6 changed files with 152 additions and 47 deletions

View File

@ -158,3 +158,11 @@ function colorizeAutocompleteHotkey()
"[/color]"
});
}
/**
* Adds grey font if savegame/replay is not compatible.
*/
function compatibilityColor(text, isCompatible)
{
return isCompatible ? text : '[color="96 96 96"]' + text + '[/color]';
}

View File

@ -3,25 +3,27 @@ function sortDecreasingDate(a, b)
return b.metadata.time - a.metadata.time;
}
function generateLabel(metadata, engineInfo)
function isCompatibleSavegame(metadata, engineInfo)
{
let dateTimeString = Engine.FormatMillisecondsIntoDateStringLocal(metadata.time*1000, translate("yyyy-MM-dd HH:mm:ss"));
let dateString = sprintf(translate("\\[%(date)s]"), { "date": dateTimeString });
return engineInfo && hasSameSavegameVersion(metadata, engineInfo) &&
hasSameEngineVersion(metadata, engineInfo) & hasSameMods(metadata, engineInfo);
}
if (engineInfo)
{
if (!hasSameSavegameVersion(metadata, engineInfo) || !hasSameEngineVersion(metadata, engineInfo))
dateString = "[color=\"red\"]" + dateString + "[/color]";
else if (!hasSameMods(metadata, engineInfo))
dateString = "[color=\"orange\"]" + dateString + "[/color]";
}
function generateSavegameDateString(metadata, engineInfo)
{
return compatibilityColor(
Engine.FormatMillisecondsIntoDateStringLocal(metadata.time * 1000, translate("yyyy-MM-dd HH:mm:ss")),
isCompatibleSavegame(metadata, engineInfo));
}
function generateSavegameLabel(metadata, engineInfo)
{
return sprintf(
metadata.description ?
translate("%(dateString)s %(map)s - %(description)s") :
translate("%(dateString)s %(map)s"),
{
"dateString": dateString,
"dateString": generateSavegameDateString(metadata, engineInfo),
"map": metadata.initAttributes.map,
"description": metadata.description || ""
}

View File

@ -212,12 +212,12 @@ function displayReplayList()
let works = replay.isCompatible;
return {
"directories": replay.directory,
"months": greyout(getReplayDateTime(replay), works),
"popCaps": greyout(translatePopulationCapacity(replay.attribs.settings.PopulationCap), works),
"mapNames": greyout(getReplayMapName(replay), works),
"mapSizes": greyout(translateMapSize(replay.attribs.settings.Size), works),
"durations": greyout(getReplayDuration(replay), works),
"playerNames": greyout(getReplayPlayernames(replay), works)
"months": compatibilityColor(getReplayDateTime(replay), works),
"popCaps": compatibilityColor(translatePopulationCapacity(replay.attribs.settings.PopulationCap), works),
"mapNames": compatibilityColor(getReplayMapName(replay), works),
"mapSizes": compatibilityColor(translateMapSize(replay.attribs.settings.Size), works),
"durations": compatibilityColor(getReplayDuration(replay), works),
"playerNames": compatibilityColor(getReplayPlayernames(replay), works)
};
});
@ -286,14 +286,6 @@ function displayReplayDetails()
setMapPreviewImage("sgMapPreview", mapData.preview);
}
/**
* Adds grey font if replay is not compatible.
*/
function greyout(text, isCompatible)
{
return isCompatible ? text : '[color="96 96 96"]' + text + '[/color]';
}
/**
* Returns a human-readable version of the replay date.
*/

View File

@ -7,30 +7,89 @@ const g_CivData = loadCivData();
function init()
{
let gameSelection = Engine.GetGUIObjectByName("gameSelection");
let savedGames = Engine.GetSavedGames().sort(sortDecreasingDate);
gameSelection.enabled = !!savedGames.length;
if (!savedGames.length)
{
gameSelection.list = [translate("No saved games found")];
gameSelection.selected = -1;
return;
}
let savedGames = Engine.GetSavedGames();
// Get current game version and loaded mods
let engineInfo = Engine.GetEngineInfo();
g_SavedGamesMetadata = savedGames.map(game => game.metadata);
if (Engine.GetGUIObjectByName("compatibilityFilter").checked)
savedGames = savedGames.filter(game => isCompatibleSavegame(game.metadata, engineInfo));
gameSelection.list = savedGames.map(game => generateLabel(game.metadata, engineInfo));
gameSelection.list_data = savedGames.map(game => game.id);
let gameSelection = Engine.GetGUIObjectByName("gameSelection");
gameSelection.enabled = !!savedGames.length;
Engine.GetGUIObjectByName("gameSelectionFeedback").hidden = !!savedGames.length;
if (gameSelection.selected == -1)
let selectedGameId = gameSelection.list_data[gameSelection.selected];
// Save metadata for the detailed view
g_SavedGamesMetadata = savedGames.map(game =>
{
game.metadata.id = game.id;
return game.metadata;
});
const sortKey = gameSelection.selected_column;
const sortOrder = gameSelection.selected_column_order;
g_SavedGamesMetadata = g_SavedGamesMetadata.sort((a, b) =>
{
let cmpA, cmpB;
switch (sortKey)
{
case 'date':
cmpA = +a.time;
cmpB = +b.time;
break;
case 'mapName':
cmpA = translate(a.initAttributes.settings.Name);
cmpB = translate(b.initAttributes.settings.Name);
break;
case 'mapType':
cmpA = translateMapType(a.initAttributes.mapType);
cmpB = translateMapType(b.initAttributes.mapType);
break;
case 'description':
cmpA = a.description;
cmpB = b.description;
break;
}
if (cmpA < cmpB)
return -sortOrder;
else if (cmpA > cmpB)
return +sortOrder;
return 0;
});
let list = g_SavedGamesMetadata.map(metadata => {
let isCompatible = isCompatibleSavegame(metadata, engineInfo);
return {
"date": generateSavegameDateString(metadata, engineInfo),
"mapName": compatibilityColor(translate(metadata.initAttributes.settings.Name), isCompatible),
"mapType": compatibilityColor(translateMapType(metadata.initAttributes.mapType), isCompatible),
"description": compatibilityColor(metadata.description, isCompatible)
};
});
if (list.length)
list = prepareForDropdown(list);
gameSelection.list_date = list.date || [];
gameSelection.list_mapName = list.mapName || [];
gameSelection.list_mapType = list.mapType || [];
gameSelection.list_description = list.description || [];
// Change these last, otherwise crash
// list strings used in the delete dialog
gameSelection.list = g_SavedGamesMetadata.map(metadata => generateSavegameLabel(metadata, engineInfo));
gameSelection.list_data = g_SavedGamesMetadata.map(metadata => metadata.id);
if (gameSelection.selected == -1 && savedGames.length)
gameSelection.selected = 0;
else if (gameSelection.selected >= savedGames.length) // happens when deleting the last saved game
gameSelection.selected = savedGames.length - 1;
else if (gameSelection.selected >= g_SavedGamesMetadata.length) // happens when deleting the last saved game
gameSelection.selected = g_SavedGamesMetadata.length - 1;
else
selectionChanged();
gameSelection.selected = g_SavedGamesMetadata.findIndex(metadata => metadata.id == selectedGameId);
Engine.GetGUIObjectByName("deleteGameButton").tooltip = deleteTooltip();
}

View File

@ -14,15 +14,47 @@
<!-- Add a translucent black background to fade out the menu page -->
<object type="image" z="0" sprite="BackgroundTranslucent"/>
<object type="image" style="ModernDialog" size="50%-420 50%-325 50%+420 50%+325">
<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 type="image" size="0 20 550 100%">
<object name="gameSelection" style="ModernList" type="list" size="24 12 100%-24 100%-90">
<object type="image" size="0 20 630 100%">
<object name="gameSelection"
selected_column="date"
selected_column_order="-1"
sortable="true"
size="24 4 100%-24 100%-70"
sprite_asc="ModernArrowDown"
sprite_desc="ModernArrowUp"
sprite_not_sorted="ModernNotSorted"
style="ModernList"
type="olist"
>
<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>
<column id="mapType" color="255 255 255" width="15%">
<translatableAttribute id="heading" context="replay">Map Type</translatableAttribute>
</column>
<column id="mapName" color="255 255 255" width="35%">
<translatableAttribute id="heading" context="replay">Map Name</translatableAttribute>
</column>
<column id="description" color="255 255 255" width="25%">
<translatableAttribute id="heading" context="replay">Description</translatableAttribute>
</column>
</object>
<object name="gameSelectionFeedback" size="24 12 100%-24 100" type="text" style="ModernLabelText" hidden="true">
<translatableAttribute id="caption">No saved games found.</translatableAttribute>
</object>
<object type="button" size="0%+25 100%-60 33%+10 100%-32" style="StoneButton" hotkey="cancel">
@ -42,7 +74,18 @@
</object>
<object name="validGame" type="image" size="550 20 100%-20 100%">
<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>
</object>
<object type="text" size="25 0 100% 100%" text_align="left" textcolor="white">
<translatableAttribute id="caption">Filter compatible saved games</translatableAttribute>
</object>
</object>
<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="" />
@ -76,7 +119,7 @@
<object size="0 100%-32 100%-15 100%-31" type="image" sprite="ModernWhiteLine" z="25" />
</object>
<object name="invalidGame" size="570 55 790 155" type="image" sprite="logo" />
<object name="invalidGame" size="650 105 870 205" type="image" sprite="logo" />
</object>
</objects>

View File

@ -36,7 +36,8 @@ function init(data)
for (let game of savedGames)
g_Descriptions[game.id] = game.metadata.description || "";
gameSelection.list = savedGames.map(game => generateLabel(game.metadata));
let engineInfo = Engine.GetEngineInfo();
gameSelection.list = savedGames.map(game => generateSavegameLabel(game.metadata, engineInfo));
gameSelection.list_data = savedGames.map(game => game.id);
gameSelection.selected = -1;