Added gamelist info field which displays some useful information.

This commit is contained in:
Leon Styhre 2020-10-30 14:19:21 +01:00
parent d9c885baf3
commit 7f0aede274
17 changed files with 197 additions and 25 deletions

View file

@ -46,6 +46,7 @@ Many bugs have been fixed, and numerous features that were only partially implem
* Improved input device configuration, and default keyboard mappings are now applied if the keyboard has not been configured by the user
* GUI-configurable option to sort favorite games above non-favorite games (favorites marked with stars)
* GUI-configurable option to sort folders on top of the gamelists
* Added a gamelist info text field displaying the game count, any applied filters as well as an icon if a folder has been entered
* Expanded the metadata for folders and made it possible to mark them as favorites
* Added new component GuiComplexTextEditPopup to handle changes to configuration file entries and similar
* Speed improvements and optimizations, the application now starts faster and feels more responsive

View file

@ -366,6 +366,8 @@ Example `navigationsounds.xml`, to be included from the main theme file:
* System Logo/Text - 50
* `text name="logoText"`
* `image name="logo"`
* Gamelist information - 50
* `text name="gamelistInfo"`
### Theme variables
@ -431,6 +433,8 @@ Reference
- A header image. If a non-empty `path` is specified, `text name="logoText"` will be hidden and this image will be, by default, displayed roughly in its place.
* `textlist name="gamelist"` - ALL
- The gamelist. `primaryColor` is for games, `secondaryColor` is for folders. Left aligned by default.
* `text name="gamelistInfo"` - ALL
- Displays the game count (all games as well as favorites), any applied filters, and an folder icon if a folder has been entered.
* Metadata
* Labels
@ -480,6 +484,8 @@ Reference
- A header image. If a non-empty `path` is specified, `text name="logoText"` will be hidden and this image will be, by default, displayed roughly in its place.
* `textlist name="gamelist"` - ALL
- The gamelist. `primaryColor` is for games, `secondaryColor` is for folders. Left aligned by default.
* `text name="gamelistInfo"` - ALL
- Displays the game count (all games as well as favorites), any applied filters, and an folder icon if a folder has been entered.
* Metadata
* Labels
@ -539,6 +545,8 @@ Reference
- Note that many of the default gridtile parameters change the selected gridtile parameters if they are not explicitly set by the theme. For example, changing the background image of the default gridtile also change the background image of the selected gridtile. Refer to the gridtile documentation for more informations.
* `gridtile name="selected"` - ALL
- See default gridtile description right above.
* `text name="gamelistInfo"` - ALL
- Displays the game count (all games as well as favorites), any applied filters, and an folder icon if a folder has been entered.
* Metadata
* Labels

View file

@ -70,6 +70,7 @@ It's possible to manually set a specific gamelist view style in the UI settings
In additions to the styles just described, there is a **Grid** view style as well, but as of version 1.0.0 this is very limited and not recommended. Future versions of EmulationStation may update this style to a more useful state.
If the theme supports it, there's a gamelist information field displayed in the gamelist view, showing the number of games for the system (total and favorites) as well as a folder icon if a folder has been entered. When applying any filters to the gamelist, the game counter is replaced with the amount of games filtered (as in 'filtered / total games'). This functionality is specific to EmulationStation Desktop Edition so older themes will not support this.
## Help system

View file

@ -944,6 +944,15 @@ void CollectionSystemManager::populateAutoCollection(CollectionSystemData* sysDa
if (sysDecl.type == AUTO_LAST_PLAYED)
trimCollectionCount(rootFolder, LAST_PLAYED_MAX);
// For the 'recent' collection we need to populate the gamelist once more as the
// collection was trimmed down to 50 items. If we don't do this, the game count will
// not be correct as it would include all the games prior to trimming.
if (rootFolder->getName() == "recent") {
ViewController::get()->getGameListView(rootFolder->getSystem()).get()->
onFileChanged(rootFolder->getChildren().front(), false);
}
sysData->isPopulated = true;
}

View file

@ -51,12 +51,14 @@ void BasicGameListView::onFileChanged(FileData* file, bool reloadGameList)
void BasicGameListView::populateList(const std::vector<FileData*>& files)
{
firstGameEntry = nullptr;
mFirstGameEntry = nullptr;
bool favoriteStar = true;
bool isEditing = false;
std::string editingCollection;
std::string inCollectionPrefix;
generateGamelistInfo(files);
if (CollectionSystemManager::get()->isEditing()) {
editingCollection = CollectionSystemManager::get()->getEditingCollection();
isEditing = true;
@ -75,8 +77,8 @@ void BasicGameListView::populateList(const std::vector<FileData*>& files)
mHeaderText.setText(mRoot->getSystem()->getFullName());
if (files.size() > 0) {
for (auto it = files.cbegin(); it != files.cend(); it++) {
if (!firstGameEntry && (*it)->getType() == GAME)
firstGameEntry = (*it);
if (!mFirstGameEntry && (*it)->getType() == GAME)
mFirstGameEntry = (*it);
// Add a leading tick mark icon to the game name if it's part of the custom collection
// currently being edited.
if (isEditing && (*it)->getType() == GAME) {
@ -157,7 +159,7 @@ FileData* BasicGameListView::getLastEntry()
FileData* BasicGameListView::getFirstGameEntry()
{
return firstGameEntry;
return mFirstGameEntry;
}
void BasicGameListView::addPlaceholder()

View file

@ -48,7 +48,7 @@ protected:
TextListComponent<FileData*> mList;
// Points to the first game in the list, i.e. the first entry which is of the type 'GAME'.
FileData* firstGameEntry;
FileData* mFirstGameEntry;
std::string FAVORITE_CHAR;
std::string FOLDER_CHAR;

View file

@ -22,6 +22,7 @@ DetailedGameListView::DetailedGameListView(
: BasicGameListView(window, root),
mDescContainer(window),
mDescription(window),
mGamelistInfo(window),
mThumbnail(window),
mMarquee(window),
@ -123,6 +124,12 @@ DetailedGameListView::DetailedGameListView(
mDescription.setSize(mDescContainer.getSize().x(), 0);
mDescContainer.addChild(&mDescription);
mGamelistInfo.setOrigin(0.5f, 0.5f);
mGamelistInfo.setFont(Font::get(FONT_SIZE_SMALL));
mGamelistInfo.setDefaultZIndex(50);
mGamelistInfo.setVisible(true);
addChild(&mGamelistInfo);
initMDLabels();
initMDValues();
}
@ -168,6 +175,8 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
mDescription.applyTheme(theme, getName(), "md_description",
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
mGamelistInfo.applyTheme(theme, getName(), "gamelistInfo", ALL ^ ThemeFlags::TEXT);
sortChildren();
}
@ -268,7 +277,7 @@ void DetailedGameListView::updateInfoPanel()
// If we're scrolling, hide the metadata fields if the last game had this options set,
// or if we're in the grouped custom collection view.
if (mList.isScrolling())
if (mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true" ||
if ((mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true") ||
(mLastUpdated->getSystem()->isCustomCollection() &&
mLastUpdated->getPath() == mLastUpdated->getSystem()->getName()))
hideMetaDataFields = true;
@ -339,6 +348,28 @@ void DetailedGameListView::updateInfoPanel()
mImage.setImage(file->getImagePath());
}
// Populate the gamelistInfo field which shows an icon if a folder has been entered
// as well as the game count for the entire system (total and favorites separately).
// If a filter has been applied, then the number of filtered and total games replaces
// the game counter.
std::string gamelistInfoString;
if (mIsFolder)
gamelistInfoString = "\uF07C ";
if (mIsFiltered) {
gamelistInfoString += "\uF0b0 " + std::to_string(mFilteredGameCount) + " / " +
std::to_string(mGameCount);
}
else {
gamelistInfoString += "\uF11b " + std::to_string(mGameCount);
if (!(file->getSystem()->isCollection() &&
file->getSystem()->getFullName() == "favorites"))
gamelistInfoString += " \uF005 " + std::to_string(mFavoritesGameCount);
}
mGamelistInfo.setValue(gamelistInfoString);
// Fade in the game image.
auto func = [this](float t) {
mImage.setOpacity(static_cast<unsigned char>(Math::lerp(

View file

@ -58,6 +58,7 @@ private:
ScrollableContainer mDescContainer;
TextComponent mDescription;
TextComponent mGamelistInfo;
FileData* mLastUpdated;
};

View file

@ -33,6 +33,7 @@ GridGameListView::GridGameListView(
mDescContainer(window),
mDescription(window),
mGamelistInfo(window),
mLblRating(window),
mLblReleaseDate(window),
@ -55,7 +56,7 @@ GridGameListView::GridGameListView(
{
const float padding = 0.01f;
// Create the correct type of video window.
// Create the correct type of video window.
#if defined(_RPI_)
if (Settings::getInstance()->getBool("VideoOmxPlayer"))
mVideo = new VideoPlayerComponent(window);
@ -138,6 +139,12 @@ GridGameListView::GridGameListView(
mVideo->setVisible(false);
addChild(mVideo);
mGamelistInfo.setOrigin(0.5f, 0.5f);
mGamelistInfo.setFont(Font::get(FONT_SIZE_SMALL));
mGamelistInfo.setDefaultZIndex(50);
mGamelistInfo.setVisible(true);
addChild(&mGamelistInfo);
initMDLabels();
initMDValues();
updateInfoPanel();
@ -241,6 +248,8 @@ void GridGameListView::populateList(const std::vector<FileData*>& files)
{
firstGameEntry = nullptr;
generateGamelistInfo(files);
mGrid.clear();
mHeaderText.setText(mRoot->getSystem()->getFullName());
if (files.size() > 0) {
@ -303,6 +312,8 @@ void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
populateList(mRoot->getChildrenListToDisplay());
mGrid.setCursor(file);
mGamelistInfo.applyTheme(theme, getName(), "gamelistInfo", ALL ^ ThemeFlags::TEXT);
sortChildren();
}
@ -425,15 +436,29 @@ void GridGameListView::updateInfoPanel()
fadingOut = true;
}
else {
// Temporary fix to disable only audio from playing.
// if (!mVideo->setVideo(file->getVideoPath()))
// mVideo->setDefaultVideo();
// mVideoPlaying = true;
// mVideo->setImage(file->getThumbnailPath());
mMarquee.setImage(file->getMarqueePath());
// mImage.setImage(file->getImagePath());
// Populate the gamelistInfo field which shows an icon if a folder has been entered
// as well as the game count for the entire system (total and favorites separately).
// If a filter has been applied, then the number of filtered and total games replaces
// the game counter.
std::string gamelistInfoString;
if (mIsFiltered) {
gamelistInfoString += "\uF0b0 " + std::to_string(mFilteredGameCount) + " / " +
std::to_string(mGameCount);
}
else {
gamelistInfoString += "\uF11b " + std::to_string(mGameCount);
if (!(file->getSystem()->isCollection() &&
file->getSystem()->getFullName() == "favorites"))
gamelistInfoString += " \uF005 " + std::to_string(mFavoritesGameCount);
}
if (mIsFolder)
gamelistInfoString += " \uF07C";
mGamelistInfo.setValue(gamelistInfoString);
mDescription.setText(file->metadata.get("desc"));
mDescContainer.reset();

View file

@ -89,6 +89,7 @@ private:
ScrollableContainer mDescContainer;
TextComponent mDescription;
TextComponent mGamelistInfo;
};
#endif // ES_APP_VIEWS_GAME_LIST_GRID_GAME_LIST_VIEW_H

View file

@ -13,6 +13,7 @@
#include "views/UIModeController.h"
#include "views/ViewController.h"
#include "CollectionSystemManager.h"
#include "FileFilterIndex.h"
#include "Settings.h"
#include "Sound.h"
#include "SystemData.h"
@ -337,3 +338,38 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
return IGameListView::input(config, input);
}
void ISimpleGameListView::generateGamelistInfo(const std::vector<FileData*>& files)
{
// Generate data needed for the gamelistInfo field, which is displayed from the
// gamelist interfaces (Detailed/Video/Grid).
mIsFiltered = false;
mIsFolder = false;
std::pair<unsigned int, unsigned int> gameCount;
FileFilterIndex* idx = mRoot->getSystem()->getIndex();
// For the 'recent' collection we need to recount the games as the collection was
// trimmed down to 50 items. If we don't do this, the game count will not be correct
// as it would include all the games prior to trimming.
if (mRoot->getPath() == "recent")
mRoot->countGames(gameCount);
if (files.size() > 0 && files.front()->getParent() != mRoot &&
files.front()->getSystem()->isGroupedCustomCollection())
gameCount = files.front()->getSystem()->getRootFolder()->getGameCount();
else
gameCount = mRoot->getGameCount();
mGameCount = gameCount.first + gameCount.second;
mFavoritesGameCount = gameCount.second;
mFilteredGameCount = 0;
if (idx->isFiltered()) {
mIsFiltered = true;
mFilteredGameCount = mRoot->getFilesRecursive(GAME, true, false).size();
}
if (files.size() > 0 && files.front()->getParent() != mRoot)
mIsFolder = true;
}

View file

@ -38,12 +38,20 @@ protected:
virtual std::string getQuickSystemSelectLeftButton() = 0;
virtual void populateList(const std::vector<FileData*>& files) = 0;
void generateGamelistInfo(const std::vector<FileData*>& files);
TextComponent mHeaderText;
ImageComponent mHeaderImage;
ImageComponent mBackground;
std::vector<GuiComponent*> mThemeExtras;
std::stack<FileData*> mCursorStack;
unsigned int mGameCount;
unsigned int mFavoritesGameCount;
unsigned int mFilteredGameCount;
bool mIsFiltered;
bool mIsFolder;
};
#endif // ES_APP_VIEWS_GAME_LIST_ISIMPLE_GAME_LIST_VIEW_H

View file

@ -30,6 +30,7 @@ VideoGameListView::VideoGameListView(
: BasicGameListView(window, root),
mDescContainer(window),
mDescription(window),
mGamelistInfo(window),
mThumbnail(window),
mMarquee(window),
@ -141,6 +142,12 @@ VideoGameListView::VideoGameListView(
mDescription.setSize(mDescContainer.getSize().x(), 0);
mDescContainer.addChild(&mDescription);
mGamelistInfo.setOrigin(0.5f, 0.5f);
mGamelistInfo.setFont(Font::get(FONT_SIZE_SMALL));
mGamelistInfo.setDefaultZIndex(50);
mGamelistInfo.setVisible(true);
addChild(&mGamelistInfo);
initMDLabels();
initMDValues();
}
@ -193,6 +200,8 @@ void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
mDescription.applyTheme(theme, getName(), "md_description",
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
mGamelistInfo.applyTheme(theme, getName(), "gamelistInfo", ALL ^ ThemeFlags::TEXT);
sortChildren();
}
@ -293,7 +302,7 @@ void VideoGameListView::updateInfoPanel()
// If we're scrolling, hide the metadata fields if the last game had this options set,
// or if we're in the grouped custom collection view.
if (mList.isScrolling())
if (mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true" ||
if ((mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true") ||
(mLastUpdated->getSystem()->isCustomCollection() &&
mLastUpdated->getPath() == mLastUpdated->getSystem()->getName()))
hideMetaDataFields = true;
@ -382,6 +391,28 @@ void VideoGameListView::updateInfoPanel()
mVideoPlaying = true;
// Populate the gamelistInfo field which shows an icon if a folder has been entered
// as well as the game count for the entire system (total and favorites separately).
// If a filter has been applied, then the number of filtered and total games replaces
// the game counter.
std::string gamelistInfoString;
if (mIsFolder)
gamelistInfoString = "\uF07C ";
if (mIsFiltered) {
gamelistInfoString += "\uF0b0 " + std::to_string(mFilteredGameCount) + " / " +
std::to_string(mGameCount);
}
else {
gamelistInfoString += "\uF11b " + std::to_string(mGameCount);
if (!(file->getSystem()->isCollection() &&
file->getSystem()->getFullName() == "favorites"))
gamelistInfoString += " \uF005 " + std::to_string(mFavoritesGameCount);
}
mGamelistInfo.setValue(gamelistInfoString);
// Fade in the game image.
auto func = [this](float t) {
mVideo->setOpacity((unsigned char)(Math::lerp(

View file

@ -65,6 +65,7 @@ private:
ScrollableContainer mDescContainer;
TextComponent mDescription;
TextComponent mGamelistInfo;
bool mVideoPlaying;
FileData* mLastUpdated;

View file

@ -109,14 +109,14 @@ std::map<std::string, std::map<std::string,
{ "container", {
{ "pos", NORMALIZED_PAIR },
{ "size", NORMALIZED_PAIR },
{ "origin", NORMALIZED_PAIR },
{ "visible", BOOLEAN },
{ "zIndex", FLOAT } } },
{ "origin", NORMALIZED_PAIR },
{ "visible", BOOLEAN },
{ "zIndex", FLOAT } } },
{ "ninepatch", {
{ "pos", NORMALIZED_PAIR },
{ "size", NORMALIZED_PAIR },
{ "path", PATH },
{ "visible", BOOLEAN },
{ "visible", BOOLEAN },
{ "zIndex", FLOAT } } },
{ "datetime", {
{ "pos", NORMALIZED_PAIR },
@ -134,8 +134,8 @@ std::map<std::string, std::map<std::string,
{ "value", STRING },
{ "format", STRING },
{ "displayRelative", BOOLEAN },
{ "visible", BOOLEAN },
{ "zIndex", FLOAT } } },
{ "visible", BOOLEAN },
{ "zIndex", FLOAT } } },
{ "rating", {
{ "pos", NORMALIZED_PAIR },
{ "size", NORMALIZED_PAIR },
@ -173,8 +173,8 @@ std::map<std::string, std::map<std::string,
{ "rotationOrigin", NORMALIZED_PAIR },
{ "default", PATH },
{ "delay", FLOAT },
{ "visible", BOOLEAN },
{ "zIndex", FLOAT },
{ "visible", BOOLEAN },
{ "zIndex", FLOAT },
{ "showSnapshotNoVideo", BOOLEAN },
{ "showSnapshotDelay", BOOLEAN } } },
{ "carousel", {

View file

@ -37,6 +37,9 @@
<primaryColor>262626</primaryColor>
<secondaryColor>4d4d4d</secondaryColor>
</textlist>
<text name="gamelistInfo">
<color>505050</color>
</text>
</view>
<view name="detailed, video">

View file

@ -233,6 +233,13 @@ based on: 'recalbox-multi' by the Recalbox community
<alignment>left</alignment>
<horizontalMargin>0.01</horizontalMargin>
</textlist>
<text name="gamelistInfo">
<fontPath>./core/fonts/Exo2-BoldCondensed.otf</fontPath>
<fontSize>0.025</fontSize>
<size>0.2 0.1</size>
<pos>0.873 0.212</pos>
<alignment>right</alignment>
</text>
<image name="md_marquee">
<origin>1 1</origin>
<pos>0.9135 0.165</pos>
@ -299,9 +306,16 @@ based on: 'recalbox-multi' by the Recalbox community
<alignment>left</alignment>
</text>
<imagegrid name="gamegrid">
<pos>0.05 0.13</pos>
<pos>0.05 0.14</pos>
<margin>0.05 0.05</margin>
</imagegrid>
<text name="gamelistInfo">
<fontPath>./core/fonts/Exo2-BoldCondensed.otf</fontPath>
<fontSize>0.025</fontSize>
<size>0.2 0.1</size>
<pos>0.165 0.105</pos>
<alignment>left</alignment>
</text>
<image name="logo">
<pos>0.792 0.085</pos>
<maxSize>0.22 0.07</maxSize>