Added the ability to control the system name suffix from the theme configuration.

Also removed the corresponding 'Show system names in collections' menu option.
This commit is contained in:
Leon Styhre 2023-01-14 14:05:24 +01:00
parent 635fdaca06
commit 3bbc761c8f
20 changed files with 333 additions and 136 deletions

View file

@ -756,6 +756,9 @@ SystemData* CollectionSystemsManager::getSystemToView(SystemData* sys)
FileData* CollectionSystemsManager::updateCollectionFolderMetadata(SystemData* sys) FileData* CollectionSystemsManager::updateCollectionFolderMetadata(SystemData* sys)
{ {
if (sys->getRootFolder()->getParent() == nullptr)
return nullptr;
FileData* rootFolder {sys->getRootFolder()}; FileData* rootFolder {sys->getRootFolder()};
FileFilterIndex* idx {rootFolder->getSystem()->getIndex()}; FileFilterIndex* idx {rootFolder->getSystem()->getIndex()};
std::string desc {"This collection is empty"}; std::string desc {"This collection is empty"};
@ -763,7 +766,7 @@ FileData* CollectionSystemsManager::updateCollectionFolderMetadata(SystemData* s
std::vector<FileData*> gamesListRandom; std::vector<FileData*> gamesListRandom;
if (UIModeController::getInstance()->isUIModeKid()) { if (UIModeController::getInstance()->isUIModeKid()) {
for (FileData* game : rootFolder->getChildrenListToDisplay()) { for (auto game : rootFolder->getChildrenListToDisplay()) {
if (game->getKidgame()) if (game->getKidgame())
gamesList.push_back(game); gamesList.push_back(game);
} }
@ -781,11 +784,11 @@ FileData* CollectionSystemsManager::updateCollectionFolderMetadata(SystemData* s
std::mt19937 engine {randDev()}; std::mt19937 engine {randDev()};
int target; int target;
for (int i = 0; i < 3; ++i) { for (int i {0}; i < 3; ++i) {
std::uniform_int_distribution<int> uniform_dist {0, gameCount - 1 - i}; std::uniform_int_distribution<int> uniform_dist {0, gameCount - 1 - i};
target = uniform_dist(engine); target = uniform_dist(engine);
gamesListRandom.push_back(gamesList[target]); gamesListRandom.push_back(gamesList[target]);
std::vector<FileData*>::iterator it {(gamesList.begin() + target)}; std::vector<FileData*>::iterator it {gamesList.begin() + target};
gamesList.erase(it); gamesList.erase(it);
if (gamesList.size() == 0) if (gamesList.size() == 0)
break; break;
@ -796,31 +799,62 @@ FileData* CollectionSystemsManager::updateCollectionFolderMetadata(SystemData* s
} }
if (gameCount > 0) { if (gameCount > 0) {
if (Settings::getInstance()->getBool("CollectionShowSystemInfo")) { auto nameSuffix = ViewController::getInstance()
->getGamelistView(sys->getRootFolder()->getParent()->getSystem())
->getDescriptionSystemNameSuffix();
if (nameSuffix.first) {
auto caseConversion = [nameSuffix](std::string name) -> std::string {
if (nameSuffix.second == LetterCase::UPPERCASE)
return Utils::String::toUpper(name);
else if (nameSuffix.second == LetterCase::CAPITALIZE)
return Utils::String::toCapitalized(name);
else
return Utils::String::toLower(name);
};
switch (gameCount) { switch (gameCount) {
case 1: { case 1: {
desc = "This collection contains 1 game: '" + desc = "This collection contains 1 game: '";
gamesList[0]->metadata.get("name") + " [" + desc.append(gamesList[0]->metadata.get("name"))
gamesList[0]->getSourceFileData()->getSystem()->getName() + "]'"; .append(" [")
.append(caseConversion(
gamesList[0]->getSourceFileData()->getSystem()->getName()))
.append("]'");
break; break;
} }
case 2: { case 2: {
desc = "This collection contains 2 games: '" + desc = "This collection contains 2 games: '";
gamesList[0]->metadata.get("name") + " [" + desc.append(gamesList[0]->metadata.get("name"))
gamesList[0]->getSourceFileData()->getSystem()->getName() + "]' and '" + .append(" [")
gamesList[1]->metadata.get("name") + " [" + .append(caseConversion(
gamesList[1]->getSourceFileData()->getSystem()->getName() + "]'"; gamesList[0]->getSourceFileData()->getSystem()->getName()))
.append("]' and '")
.append(gamesList[1]->metadata.get("name"))
.append(" [")
.append(caseConversion(
gamesList[1]->getSourceFileData()->getSystem()->getName()))
.append("]'");
break; break;
} }
default: { default: {
desc = "This collection contains " + std::to_string(gameCount) + " games: '" + desc = "This collection contains ";
gamesList[0]->metadata.get("name") + " [" + desc.append(std::to_string(gameCount))
gamesList[0]->getSourceFileData()->getSystem()->getName() + "]', '" + .append(" games: '")
gamesList[1]->metadata.get("name") + " [" + .append(gamesList[0]->metadata.get("name"))
gamesList[1]->getSourceFileData()->getSystem()->getName() + "]' and '" + .append(" [")
gamesList[2]->metadata.get("name") + " [" + .append(caseConversion(
gamesList[2]->getSourceFileData()->getSystem()->getName() + "]'"; gamesList[0]->getSourceFileData()->getSystem()->getName()))
desc += (gameCount == 3 ? "" : ", among others"); .append("]', '")
.append(gamesList[1]->metadata.get("name"))
.append(" [")
.append(caseConversion(
gamesList[1]->getSourceFileData()->getSystem()->getName()))
.append("]' and '")
.append(gamesList[2]->metadata.get("name"))
.append(" [")
.append(caseConversion(
gamesList[2]->getSourceFileData()->getSystem()->getName()))
.append("]'");
desc.append(gameCount == 3 ? "" : ", among others");
break; break;
} }
} }
@ -828,31 +862,40 @@ FileData* CollectionSystemsManager::updateCollectionFolderMetadata(SystemData* s
else { else {
switch (gameCount) { switch (gameCount) {
case 1: { case 1: {
desc = "This collection contains 1 game: '" + desc = "This collection contains 1 game: '";
gamesList[0]->metadata.get("name") + " '"; desc.append(gamesList[0]->metadata.get("name")).append("'");
break; break;
} }
case 2: { case 2: {
desc = "This collection contains 2 games: '" + desc = "This collection contains 2 games: '";
gamesList[0]->metadata.get("name") + "' and '" + desc.append(gamesList[0]->metadata.get("name"))
gamesList[1]->metadata.get("name") + "'"; .append("' and '")
.append(gamesList[1]->metadata.get("name"))
.append("'");
break; break;
} }
default: { default: {
desc = "This collection contains " + std::to_string(gameCount) + " games: '" + desc = "This collection contains ";
gamesList[0]->metadata.get("name") + "', '" + desc.append(std::to_string(gameCount))
gamesList[1]->metadata.get("name") + "' and '" + .append(" games: '")
gamesList[2]->metadata.get("name") + "'"; .append(gamesList[0]->metadata.get("name"))
desc += (gameCount == 3 ? "" : ", among others"); .append("', '")
.append(gamesList[1]->metadata.get("name"))
.append("' and '")
.append(gamesList[2]->metadata.get("name"))
.append("'");
desc.append(gameCount == 3 ? "" : ", among others");
break; break;
} }
} }
} }
} }
if (idx->isFiltered()) if (idx->isFiltered()) {
desc += "\n\n'" + rootFolder->getSystem()->getFullName() + desc.append("\n\n'")
"' is filtered so there may be more games available"; .append(rootFolder->getSystem()->getFullName())
.append("' is filtered so there may be more games available");
}
rootFolder->metadata.set("desc", desc); rootFolder->metadata.set("desc", desc);
@ -1139,7 +1182,7 @@ void CollectionSystemsManager::populateAutoCollection(CollectionSystemData* sysD
if (!(*gameIt)->getCountAsGame()) if (!(*gameIt)->getCountAsGame())
continue; continue;
CollectionFileData* newGame = new CollectionFileData(*gameIt, newSys); CollectionFileData* newGame {new CollectionFileData(*gameIt, newSys)};
rootFolder->addChild(newGame); rootFolder->addChild(newGame);
index->addToIndex(newGame); index->addToIndex(newGame);
} }

View file

@ -21,7 +21,6 @@
#include "Window.h" #include "Window.h"
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
#include "utils/PlatformUtil.h" #include "utils/PlatformUtil.h"
#include "utils/StringUtil.h"
#include "utils/TimeUtil.h" #include "utils/TimeUtil.h"
#include "views/GamelistView.h" #include "views/GamelistView.h"
#include "views/ViewController.h" #include "views/ViewController.h"
@ -73,23 +72,6 @@ FileData::~FileData()
mParent->removeChild(this); mParent->removeChild(this);
} }
std::string FileData::getDisplayName() const
{
const std::string& stem {Utils::FileSystem::getStem(mPath)};
return stem;
}
std::string FileData::getCleanName() const
{
return Utils::String::removeParenthesis(this->getDisplayName());
}
const std::string& FileData::getName()
{
// Return metadata name.
return metadata.get("name");
}
const std::string& FileData::getSortName() const std::string& FileData::getSortName()
{ {
if (mSystem->isCustomCollection() && mType == GAME) { if (mSystem->isCustomCollection() && mType == GAME) {
@ -1965,7 +1947,6 @@ CollectionFileData::CollectionFileData(FileData* file, SystemData* system)
{ {
// We use this constructor to create a clone of the filedata, and change its system. // We use this constructor to create a clone of the filedata, and change its system.
mSourceFileData = file->getSourceFileData(); mSourceFileData = file->getSourceFileData();
refreshMetadata();
mParent = nullptr; mParent = nullptr;
metadata = mSourceFileData->metadata; metadata = mSourceFileData->metadata;
mSystemName = mSourceFileData->getSystem()->getName(); mSystemName = mSourceFileData->getSystem()->getName();
@ -1978,25 +1959,3 @@ CollectionFileData::~CollectionFileData()
mParent->removeChild(this); mParent->removeChild(this);
mParent = nullptr; mParent = nullptr;
} }
void CollectionFileData::refreshMetadata()
{
metadata = mSourceFileData->metadata;
mDirty = true;
}
const std::string& CollectionFileData::getName()
{
if (mDirty) {
mCollectionFileName = mSourceFileData->metadata.get("name");
mCollectionFileName.append(" [")
.append(Utils::String::toUpper(mSourceFileData->getSystem()->getName()))
.append("]");
mDirty = false;
}
if (Settings::getInstance()->getBool("CollectionShowSystemInfo"))
return mCollectionFileName;
return mSourceFileData->metadata.get("name");
}

View file

@ -13,6 +13,7 @@
#include "MetaData.h" #include "MetaData.h"
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
#include "utils/StringUtil.h"
#include <functional> #include <functional>
#include <unordered_map> #include <unordered_map>
@ -38,8 +39,19 @@ public:
virtual ~FileData(); virtual ~FileData();
virtual const std::string& getName(); const std::string& getName() { return metadata.get("name"); }
const std::string& getSortName(); const std::string& getSortName();
// Returns our best guess at the "real" name for this file.
std::string getDisplayName() const
{
const std::string& stem {Utils::FileSystem::getStem(mPath)};
return stem;
}
std::string getCleanName() const
{
return Utils::String::removeParenthesis(this->getDisplayName());
}
const bool getFavorite(); const bool getFavorite();
const bool getKidgame(); const bool getKidgame();
const bool getHidden(); const bool getHidden();
@ -108,12 +120,6 @@ public:
virtual FileData* getSourceFileData() { return this; } virtual FileData* getSourceFileData() { return this; }
const std::string& getSystemName() const { return mSystemName; } const std::string& getSystemName() const { return mSystemName; }
// Returns our best guess at the "real" name for this file.
std::string getDisplayName() const;
// As above, but also remove parenthesis.
std::string getCleanName() const;
void launchGame(); void launchGame();
const std::string findEmulatorPath(std::string& command); const std::string findEmulatorPath(std::string& command);
@ -173,15 +179,8 @@ class CollectionFileData : public FileData
public: public:
CollectionFileData(FileData* file, SystemData* system); CollectionFileData(FileData* file, SystemData* system);
~CollectionFileData(); ~CollectionFileData();
const std::string& getName();
void refreshMetadata();
FileData* getSourceFileData() { return mSourceFileData; } FileData* getSourceFileData() { return mSourceFileData; }
std::string getKey() { return getFullPath(); } std::string getKey() { return getFullPath(); }
private:
// Needs to be updated when metadata changes.
std::string mCollectionFileName;
bool mDirty;
}; };
#endif // ES_APP_FILE_DATA_H #endif // ES_APP_FILE_DATA_H

View file

@ -22,7 +22,6 @@
FileFilterIndex::FileFilterIndex() FileFilterIndex::FileFilterIndex()
: mFilterByText {false} : mFilterByText {false}
, mTextRemoveSystem {false}
, mFilterByRatings {false} , mFilterByRatings {false}
, mFilterByDeveloper {false} , mFilterByDeveloper {false}
, mFilterByPublisher {false} , mFilterByPublisher {false}
@ -404,15 +403,8 @@ bool FileFilterIndex::showFile(FileData* game)
bool keepGoing = false; bool keepGoing = false;
// Name filters take precedence over all other filters, so if there is no match for // Name filters take precedence over all other filters, so if there is no match for
// the game name, then always return false. If we're in a collection system and the option // the game name, then always return false.
// to show the system name has been enabled, then exclude the system name that is encapsulated if (mTextFilter != "" &&
// in [] from the search string.
if (mTextFilter != "" && mTextRemoveSystem &&
!(Utils::String::toUpper(game->getName().substr(0, game->getName().find_last_of("[")))
.find(Utils::String::toUpper(mTextFilter)) != std::string::npos)) {
return false;
}
else if (mTextFilter != "" &&
!(Utils::String::toUpper(game->getName()).find(Utils::String::toUpper(mTextFilter)) != !(Utils::String::toUpper(game->getName()).find(Utils::String::toUpper(mTextFilter)) !=
std::string::npos)) { std::string::npos)) {
return false; return false;

View file

@ -62,7 +62,6 @@ public:
bool isFiltered(); bool isFiltered();
bool isKeyBeingFilteredBy(std::string key, FilterIndexType type); bool isKeyBeingFilteredBy(std::string key, FilterIndexType type);
std::vector<FilterDataDecl>& getFilterDataDecls() { return filterDataDecl; } std::vector<FilterDataDecl>& getFilterDataDecls() { return filterDataDecl; }
void setTextRemoveSystem(bool status) { mTextRemoveSystem = status; }
void importIndex(FileFilterIndex* indexToImport); void importIndex(FileFilterIndex* indexToImport);
void resetIndex(); void resetIndex();
@ -92,7 +91,6 @@ private:
std::string mTextFilter; std::string mTextFilter;
bool mFilterByText; bool mFilterByText;
bool mTextRemoveSystem;
bool mFilterByRatings; bool mFilterByRatings;
bool mFilterByDeveloper; bool mFilterByDeveloper;

View file

@ -368,22 +368,6 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(std::string title)
setInvalidateCachedBackground(); setInvalidateCachedBackground();
} }
}); });
// Show system names in collections.
auto collection_show_system_info = std::make_shared<SwitchComponent>();
collection_show_system_info->setState(
Settings::getInstance()->getBool("CollectionShowSystemInfo"));
addWithLabel("SHOW SYSTEM NAMES IN COLLECTIONS", collection_show_system_info);
addSaveFunc([this, collection_show_system_info] {
if (collection_show_system_info->getState() !=
Settings::getInstance()->getBool("CollectionShowSystemInfo")) {
Settings::getInstance()->setBool("CollectionShowSystemInfo",
collection_show_system_info->getState());
setNeedsSaving();
setNeedsReloading();
setInvalidateCachedBackground();
}
});
} }
void GuiCollectionSystemsOptions::createCustomCollection(std::string inName) void GuiCollectionSystemsOptions::createCustomCollection(std::string inName)

View file

@ -35,15 +35,6 @@ void GuiGamelistFilter::initializeMenu()
// Get filters from system. // Get filters from system.
mFilterIndex = mSystem->getIndex(); mFilterIndex = mSystem->getIndex();
// If this is a collection and system names are shown per game, then let FileFilterIndex
// know about this so the system names will not be included in game name text searches.
if (ViewController::getInstance()->getState().getSystem()->isCollection()) {
if (Settings::getInstance()->getBool("CollectionShowSystemInfo"))
mFilterIndex->setTextRemoveSystem(true);
else
mFilterIndex->setTextRemoveSystem(false);
}
ComponentListRow row; ComponentListRow row;
// Show filtered menu. // Show filtered menu.

View file

@ -32,6 +32,7 @@ GamelistBase::GamelistBase(FileData* root)
, mIsFolder {false} , mIsFolder {false}
, mVideoPlaying {false} , mVideoPlaying {false}
, mLeftRightAvailable {true} , mLeftRightAvailable {true}
, mSystemNameSuffix {false}
{ {
setSize(Renderer::getScreenWidth(), Renderer::getScreenHeight()); setSize(Renderer::getScreenWidth(), Renderer::getScreenHeight());
} }
@ -552,7 +553,8 @@ void GamelistBase::populateList(const std::vector<FileData*>& files, FileData* f
mFirstGameEntry = nullptr; mFirstGameEntry = nullptr;
bool favoriteStar {true}; bool favoriteStar {true};
bool isEditing {false}; bool isEditing {false};
bool customCollection {false}; bool isCollection {false};
bool isCustomCollection {false};
std::string editingCollection; std::string editingCollection;
std::string inCollectionPrefix; std::string inCollectionPrefix;
LetterCase letterCase {LetterCase::NONE}; LetterCase letterCase {LetterCase::NONE};
@ -563,10 +565,11 @@ void GamelistBase::populateList(const std::vector<FileData*>& files, FileData* f
} }
if (files.size() > 0) { if (files.size() > 0) {
customCollection = files.front()->getSystem()->isCustomCollection(); isCollection = files.front()->getSystem()->isCollection();
isCustomCollection = files.front()->getSystem()->isCustomCollection();
// Read the settings that control whether a unicode star character should be added // Read the settings that control whether a unicode star character should be added
// as a prefix to the game name. // as a prefix to the game name.
if (customCollection) if (isCustomCollection)
favoriteStar = Settings::getInstance()->getBool("FavStarCustom"); favoriteStar = Settings::getInstance()->getBool("FavStarCustom");
else else
favoriteStar = Settings::getInstance()->getBool("FavoritesStar"); favoriteStar = Settings::getInstance()->getBool("FavoritesStar");
@ -575,6 +578,25 @@ void GamelistBase::populateList(const std::vector<FileData*>& files, FileData* f
if (mPrimary != nullptr) if (mPrimary != nullptr)
mPrimary->clear(); mPrimary->clear();
auto nameSuffixFunc = [this](std::vector<FileData*>::const_iterator it, std::string& name) {
if ((*it)->getType() == GAME) {
const LetterCase letterCase {mPrimary->getLetterCaseSystemNameSuffix()};
name.append(" [");
if (letterCase == LetterCase::UPPERCASE) {
name.append(
Utils::String::toUpper((*it)->getSourceFileData()->getSystem()->getName()));
}
else if (letterCase == LetterCase::CAPITALIZE) {
name.append(Utils::String::toCapitalized(
(*it)->getSourceFileData()->getSystem()->getName()));
}
else {
name.append((*it)->getSourceFileData()->getSystem()->getName());
}
name.append("]");
}
};
auto theme = mRoot->getSystem()->getTheme(); auto theme = mRoot->getSystem()->getTheme();
std::string name; std::string name;
std::string defaultImage; std::string defaultImage;
@ -596,7 +618,7 @@ void GamelistBase::populateList(const std::vector<FileData*>& files, FileData* f
if (!mFirstGameEntry && (*it)->getType() == GAME) if (!mFirstGameEntry && (*it)->getType() == GAME)
mFirstGameEntry = (*it); mFirstGameEntry = (*it);
if (customCollection && (*it)->getType() == FOLDER) { if (isCustomCollection && (*it)->getType() == FOLDER) {
letterCase = mPrimary->getLetterCaseCustomCollections(); letterCase = mPrimary->getLetterCaseCustomCollections();
if (letterCase == LetterCase::UNDEFINED) if (letterCase == LetterCase::UNDEFINED)
letterCase = mPrimary->getLetterCase(); letterCase = mPrimary->getLetterCase();
@ -617,6 +639,9 @@ void GamelistBase::populateList(const std::vector<FileData*>& files, FileData* f
else if (letterCase == LetterCase::CAPITALIZE) else if (letterCase == LetterCase::CAPITALIZE)
carouselEntry.name = Utils::String::toCapitalized(carouselEntry.name); carouselEntry.name = Utils::String::toCapitalized(carouselEntry.name);
if (isCollection && mSystemNameSuffix)
nameSuffixFunc(it, carouselEntry.name);
if (defaultImage != "") if (defaultImage != "")
carouselEntry.data.defaultImagePath = defaultImage; carouselEntry.data.defaultImagePath = defaultImage;
@ -634,6 +659,9 @@ void GamelistBase::populateList(const std::vector<FileData*>& files, FileData* f
else if (letterCase == LetterCase::CAPITALIZE) else if (letterCase == LetterCase::CAPITALIZE)
gridEntry.name = Utils::String::toCapitalized(gridEntry.name); gridEntry.name = Utils::String::toCapitalized(gridEntry.name);
if (isCollection && mSystemNameSuffix)
nameSuffixFunc(it, gridEntry.name);
if (defaultImage != "") if (defaultImage != "")
gridEntry.data.defaultImagePath = defaultImage; gridEntry.data.defaultImagePath = defaultImage;
@ -698,6 +726,9 @@ void GamelistBase::populateList(const std::vector<FileData*>& files, FileData* f
else if (letterCase == LetterCase::CAPITALIZE) else if (letterCase == LetterCase::CAPITALIZE)
name = Utils::String::toCapitalized(name); name = Utils::String::toCapitalized(name);
if (isCollection && mSystemNameSuffix)
nameSuffixFunc(it, name);
textListEntry.name = name; textListEntry.name = name;
textListEntry.object = *it; textListEntry.object = *it;
if ((*it)->getType() == FOLDER) if ((*it)->getType() == FOLDER)

View file

@ -115,6 +115,7 @@ protected:
bool mIsFolder; bool mIsFolder;
bool mVideoPlaying; bool mVideoPlaying;
bool mLeftRightAvailable; bool mLeftRightAvailable;
bool mSystemNameSuffix;
private: private:
}; };

View file

@ -36,6 +36,25 @@ GamelistView::~GamelistView()
mThemeExtras.clear(); mThemeExtras.clear();
} }
const std::pair<bool, LetterCase> GamelistView::getDescriptionSystemNameSuffix() const
{
if (mLegacyMode)
return std::make_pair(true, LetterCase::UPPERCASE);
bool suffix {false};
LetterCase letterCase {LetterCase::UPPERCASE};
for (auto& text : mContainerTextComponents) {
if (text->getThemeMetadata() == "description" && text->getSystemNameSuffix()) {
suffix = true;
letterCase = text->getLetterCaseSystemNameSuffix();
break;
}
}
return std::make_pair(suffix, letterCase);
}
void GamelistView::onFileChanged(FileData* file, bool reloadGamelist) void GamelistView::onFileChanged(FileData* file, bool reloadGamelist)
{ {
if (reloadGamelist) { if (reloadGamelist) {
@ -379,6 +398,8 @@ void GamelistView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
addChild(mPrimary); addChild(mPrimary);
} }
mSystemNameSuffix = mPrimary->getSystemNameSuffix();
populateList(mRoot->getChildrenListToDisplay(), mRoot); populateList(mRoot->getChildrenListToDisplay(), mRoot);
// Check whether the primary component uses the left and right buttons for its navigation. // Check whether the primary component uses the left and right buttons for its navigation.
@ -893,8 +914,26 @@ void GamelistView::updateView(const CursorState& state)
continue; continue;
} }
if (metadata == "name" && file->getSystem()->isCollection() &&
text->getSystemNameSuffix()) {
const LetterCase letterCase {text->getLetterCaseSystemNameSuffix()};
std::string suffix {" ["};
if (letterCase == LetterCase::UPPERCASE)
suffix.append(
Utils::String::toUpper(file->getSourceFileData()->getSystem()->getName()));
else if (letterCase == LetterCase::CAPITALIZE)
suffix.append(Utils::String::toCapitalized(
file->getSourceFileData()->getSystem()->getName()));
else
suffix.append(file->getSourceFileData()->getSystem()->getName());
suffix.append("]");
text->setValue(getMetadataValue() + suffix);
}
else {
text->setValue(getMetadataValue()); text->setValue(getMetadataValue());
} }
}
for (auto& date : mDateTimeComponents) { for (auto& date : mDateTimeComponents) {
std::string metadata {date->getThemeMetadata()}; std::string metadata {date->getThemeMetadata()};

View file

@ -18,6 +18,8 @@ public:
GamelistView(FileData* root); GamelistView(FileData* root);
~GamelistView(); ~GamelistView();
const std::pair<bool, LetterCase> getDescriptionSystemNameSuffix() const;
// Called when a FileData* is added, has its metadata changed, or is removed. // Called when a FileData* is added, has its metadata changed, or is removed.
void onFileChanged(FileData* file, bool reloadGamelist) override; void onFileChanged(FileData* file, bool reloadGamelist) override;
void onShow() override; void onShow() override;

View file

@ -1240,8 +1240,35 @@ void SystemView::updateGameSelectors()
std::vector<FileData*> games {gameSelector->getGames()}; std::vector<FileData*> games {gameSelector->getGames()};
if (games.size() > gameSelectorEntry) { if (games.size() > gameSelectorEntry) {
const std::string metadata {text->getThemeMetadata()}; const std::string metadata {text->getThemeMetadata()};
if (metadata == "name") if (metadata == "name") {
if (mPrimary->getSelected()->isCollection() && text->getSystemNameSuffix()) {
const LetterCase letterCase {text->getLetterCaseSystemNameSuffix()};
std::string suffix {" ["};
if (letterCase == LetterCase::UPPERCASE) {
suffix.append(Utils::String::toUpper(games.at(gameSelectorEntry)
->getSourceFileData()
->getSystem()
->getName()));
}
else if (letterCase == LetterCase::CAPITALIZE) {
suffix.append(Utils::String::toCapitalized(games.at(gameSelectorEntry)
->getSourceFileData()
->getSystem()
->getName()));
}
else {
suffix.append(games.at(gameSelectorEntry)
->getSourceFileData()
->getSystem()
->getName());
}
suffix.append("]");
text->setValue(games.at(gameSelectorEntry)->metadata.get("name") + suffix);
}
else {
text->setValue(games.at(gameSelectorEntry)->metadata.get("name")); text->setValue(games.at(gameSelectorEntry)->metadata.get("name"));
}
}
if (metadata == "description") if (metadata == "description")
text->setValue(games.at(gameSelectorEntry)->metadata.get("desc")); text->setValue(games.at(gameSelectorEntry)->metadata.get("desc"));
if (metadata == "rating") if (metadata == "rating")

View file

@ -235,7 +235,6 @@ void Settings::setDefaults()
mStringMap["CollectionCustomGrouping"] = {"unthemed", "unthemed"}; mStringMap["CollectionCustomGrouping"] = {"unthemed", "unthemed"};
mBoolMap["FavFirstCustom"] = {false, false}; mBoolMap["FavFirstCustom"] = {false, false};
mBoolMap["FavStarCustom"] = {false, false}; mBoolMap["FavStarCustom"] = {false, false};
mBoolMap["CollectionShowSystemInfo"] = {true, true};
// Other settings. // Other settings.
mStringMap["MediaDirectory"] = {"", ""}; mStringMap["MediaDirectory"] = {"", ""};

View file

@ -182,6 +182,8 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"letterCaseAutoCollections", STRING}, {"letterCaseAutoCollections", STRING},
{"letterCaseCustomCollections", STRING}, {"letterCaseCustomCollections", STRING},
{"lineSpacing", FLOAT}, {"lineSpacing", FLOAT},
{"systemNameSuffix", BOOLEAN},
{"letterCaseSystemNameSuffix", STRING},
{"fadeAbovePrimary", BOOLEAN}, {"fadeAbovePrimary", BOOLEAN},
{"zIndex", FLOAT}, {"zIndex", FLOAT},
{"legacyZIndexMode", STRING}}}, // For backward compatibility with legacy themes. {"legacyZIndexMode", STRING}}}, // For backward compatibility with legacy themes.
@ -227,6 +229,8 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"letterCaseAutoCollections", STRING}, {"letterCaseAutoCollections", STRING},
{"letterCaseCustomCollections", STRING}, {"letterCaseCustomCollections", STRING},
{"lineSpacing", FLOAT}, {"lineSpacing", FLOAT},
{"systemNameSuffix", BOOLEAN},
{"letterCaseSystemNameSuffix", STRING},
{"fadeAbovePrimary", BOOLEAN}, {"fadeAbovePrimary", BOOLEAN},
{"zIndex", FLOAT}}}, {"zIndex", FLOAT}}},
{"textlist", {"textlist",
@ -259,6 +263,8 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"lineSpacing", FLOAT}, {"lineSpacing", FLOAT},
{"indicators", STRING}, {"indicators", STRING},
{"collectionIndicators", STRING}, {"collectionIndicators", STRING},
{"systemNameSuffix", BOOLEAN},
{"letterCaseSystemNameSuffix", STRING},
{"fadeAbovePrimary", BOOLEAN}, {"fadeAbovePrimary", BOOLEAN},
{"zIndex", FLOAT}}}, {"zIndex", FLOAT}}},
{"image", {"image",
@ -368,6 +374,8 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"systemdata", STRING}, {"systemdata", STRING},
{"metadata", STRING}, {"metadata", STRING},
{"defaultValue", STRING}, {"defaultValue", STRING},
{"systemNameSuffix", BOOLEAN},
{"letterCaseSystemNameSuffix", STRING},
{"metadataElement", BOOLEAN}, {"metadataElement", BOOLEAN},
{"gameselector", STRING}, {"gameselector", STRING},
{"gameselectorEntry", UNSIGNED_INTEGER}, {"gameselectorEntry", UNSIGNED_INTEGER},

View file

@ -20,6 +20,8 @@ TextComponent::TextComponent()
, mColorOpacity {1.0f} , mColorOpacity {1.0f}
, mBgColorOpacity {0.0f} , mBgColorOpacity {0.0f}
, mRenderBackground {false} , mRenderBackground {false}
, mSystemNameSuffix {false}
, mLetterCaseSystemNameSuffix {LetterCase::UPPERCASE}
, mUppercase {false} , mUppercase {false}
, mLowercase {false} , mLowercase {false}
, mCapitalize {false} , mCapitalize {false}
@ -49,6 +51,8 @@ TextComponent::TextComponent(const std::string& text,
, mColorOpacity {1.0f} , mColorOpacity {1.0f}
, mBgColorOpacity {0.0f} , mBgColorOpacity {0.0f}
, mRenderBackground {false} , mRenderBackground {false}
, mSystemNameSuffix {false}
, mLetterCaseSystemNameSuffix {LetterCase::UPPERCASE}
, mUppercase {false} , mUppercase {false}
, mLowercase {false} , mLowercase {false}
, mCapitalize {false} , mCapitalize {false}
@ -465,6 +469,12 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
mDefaultValue = defaultValue; mDefaultValue = defaultValue;
} }
} }
if (mThemeMetadata == "name" || mThemeMetadata == "description") {
if (elem->has("systemNameSuffix"))
mSystemNameSuffix = elem->get<bool>("systemNameSuffix");
else
mSystemNameSuffix = true;
}
break; break;
} }
} }
@ -475,6 +485,24 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
} }
} }
if (properties & LETTER_CASE && elem->has("letterCaseSystemNameSuffix")) {
const std::string& letterCase {elem->get<std::string>("letterCaseSystemNameSuffix")};
if (letterCase == "uppercase") {
mLetterCaseSystemNameSuffix = LetterCase::UPPERCASE;
}
else if (letterCase == "lowercase") {
mLetterCaseSystemNameSuffix = LetterCase::LOWERCASE;
}
else if (letterCase == "capitalize") {
mLetterCaseSystemNameSuffix = LetterCase::CAPITALIZE;
}
else {
LOG(LogWarning) << "TextComponent: Invalid theme configuration, property "
"\"letterCaseSystemNameSuffix\" for element \""
<< element.substr(5) << "\" defined as \"" << letterCase << "\"";
}
}
if (properties & LETTER_CASE && elem->has("letterCase")) { if (properties & LETTER_CASE && elem->has("letterCase")) {
const std::string& letterCase {elem->get<std::string>("letterCase")}; const std::string& letterCase {elem->get<std::string>("letterCase")};
if (letterCase == "uppercase") { if (letterCase == "uppercase") {

View file

@ -77,6 +77,8 @@ public:
std::shared_ptr<Font> getFont() const override { return mFont; } std::shared_ptr<Font> getFont() const override { return mFont; }
Alignment getHorizontalAlignment() { return mHorizontalAlignment; } Alignment getHorizontalAlignment() { return mHorizontalAlignment; }
Alignment getVerticalAlignment() { return mVerticalAlignment; } Alignment getVerticalAlignment() { return mVerticalAlignment; }
const bool getSystemNameSuffix() const { return mSystemNameSuffix; }
const LetterCase getLetterCaseSystemNameSuffix() const { return mLetterCaseSystemNameSuffix; }
int getTextCacheGlyphHeight() override int getTextCacheGlyphHeight() override
{ {
@ -108,6 +110,8 @@ private:
float mColorOpacity; float mColorOpacity;
float mBgColorOpacity; float mBgColorOpacity;
bool mRenderBackground; bool mRenderBackground;
bool mSystemNameSuffix;
LetterCase mLetterCaseSystemNameSuffix;
bool mUppercase; bool mUppercase;
bool mLowercase; bool mLowercase;

View file

@ -73,6 +73,11 @@ public:
{ {
return mLetterCaseCustomCollections; return mLetterCaseCustomCollections;
} }
const bool getSystemNameSuffix() const override { return mSystemNameSuffix; }
const LetterCase getLetterCaseSystemNameSuffix() const override
{
return mLetterCaseSystemNameSuffix;
}
void setCancelTransitionsCallback(const std::function<void()>& func) override void setCancelTransitionsCallback(const std::function<void()>& func) override
{ {
@ -176,6 +181,8 @@ private:
LetterCase mLetterCaseAutoCollections; LetterCase mLetterCaseAutoCollections;
LetterCase mLetterCaseCustomCollections; LetterCase mLetterCaseCustomCollections;
float mLineSpacing; float mLineSpacing;
bool mSystemNameSuffix;
LetterCase mLetterCaseSystemNameSuffix;
bool mFadeAbovePrimary; bool mFadeAbovePrimary;
}; };
@ -233,6 +240,8 @@ CarouselComponent<T>::CarouselComponent()
, mLetterCaseAutoCollections {LetterCase::UNDEFINED} , mLetterCaseAutoCollections {LetterCase::UNDEFINED}
, mLetterCaseCustomCollections {LetterCase::UNDEFINED} , mLetterCaseCustomCollections {LetterCase::UNDEFINED}
, mLineSpacing {1.5f} , mLineSpacing {1.5f}
, mSystemNameSuffix {true}
, mLetterCaseSystemNameSuffix {LetterCase::UPPERCASE}
, mFadeAbovePrimary {false} , mFadeAbovePrimary {false}
{ {
} }
@ -1611,6 +1620,27 @@ void CarouselComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
} }
} }
if (mGamelistView && elem->has("systemNameSuffix"))
mSystemNameSuffix = elem->get<bool>("systemNameSuffix");
if (mGamelistView && properties & LETTER_CASE && elem->has("letterCaseSystemNameSuffix")) {
const std::string& letterCase {elem->get<std::string>("letterCaseSystemNameSuffix")};
if (letterCase == "uppercase") {
mLetterCaseSystemNameSuffix = LetterCase::UPPERCASE;
}
else if (letterCase == "lowercase") {
mLetterCaseSystemNameSuffix = LetterCase::LOWERCASE;
}
else if (letterCase == "capitalize") {
mLetterCaseSystemNameSuffix = LetterCase::CAPITALIZE;
}
else {
LOG(LogWarning) << "CarouselComponent: Invalid theme configuration, property "
"\"letterCaseSystemNameSuffix\" for element \""
<< element.substr(9) << "\" defined as \"" << letterCase << "\"";
}
}
if (elem->has("fadeAbovePrimary")) if (elem->has("fadeAbovePrimary"))
mFadeAbovePrimary = elem->get<bool>("fadeAbovePrimary"); mFadeAbovePrimary = elem->get<bool>("fadeAbovePrimary");

View file

@ -66,6 +66,11 @@ public:
{ {
return mLetterCaseCustomCollections; return mLetterCaseCustomCollections;
} }
const bool getSystemNameSuffix() const override { return mSystemNameSuffix; }
const LetterCase getLetterCaseSystemNameSuffix() const override
{
return mLetterCaseSystemNameSuffix;
}
const std::string& getDefaultGridImage() const { return mDefaultImage; } const std::string& getDefaultGridImage() const { return mDefaultImage; }
void setDefaultImage(std::string defaultImage) { mDefaultImage = defaultImage; } void setDefaultImage(std::string defaultImage) { mDefaultImage = defaultImage; }
bool input(InputConfig* config, Input input) override; bool input(InputConfig* config, Input input) override;
@ -176,6 +181,8 @@ private:
LetterCase mLetterCaseAutoCollections; LetterCase mLetterCaseAutoCollections;
LetterCase mLetterCaseCustomCollections; LetterCase mLetterCaseCustomCollections;
float mLineSpacing; float mLineSpacing;
bool mSystemNameSuffix;
LetterCase mLetterCaseSystemNameSuffix;
bool mFadeAbovePrimary; bool mFadeAbovePrimary;
}; };
@ -229,6 +236,8 @@ GridComponent<T>::GridComponent()
, mLetterCaseAutoCollections {LetterCase::UNDEFINED} , mLetterCaseAutoCollections {LetterCase::UNDEFINED}
, mLetterCaseCustomCollections {LetterCase::UNDEFINED} , mLetterCaseCustomCollections {LetterCase::UNDEFINED}
, mLineSpacing {1.5f} , mLineSpacing {1.5f}
, mSystemNameSuffix {true}
, mLetterCaseSystemNameSuffix {LetterCase::UPPERCASE}
, mFadeAbovePrimary {false} , mFadeAbovePrimary {false}
{ {
} }
@ -1180,6 +1189,27 @@ void GridComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
} }
} }
if (mGamelistView && elem->has("systemNameSuffix"))
mSystemNameSuffix = elem->get<bool>("systemNameSuffix");
if (mGamelistView && properties & LETTER_CASE && elem->has("letterCaseSystemNameSuffix")) {
const std::string& letterCase {elem->get<std::string>("letterCaseSystemNameSuffix")};
if (letterCase == "uppercase") {
mLetterCaseSystemNameSuffix = LetterCase::UPPERCASE;
}
else if (letterCase == "lowercase") {
mLetterCaseSystemNameSuffix = LetterCase::LOWERCASE;
}
else if (letterCase == "capitalize") {
mLetterCaseSystemNameSuffix = LetterCase::CAPITALIZE;
}
else {
LOG(LogWarning) << "GridComponent: Invalid theme configuration, property "
"\"letterCaseSystemNameSuffix\" for element \""
<< element.substr(5) << "\" defined as \"" << letterCase << "\"";
}
}
if (elem->has("fadeAbovePrimary")) if (elem->has("fadeAbovePrimary"))
mFadeAbovePrimary = elem->get<bool>("fadeAbovePrimary"); mFadeAbovePrimary = elem->get<bool>("fadeAbovePrimary");

View file

@ -47,6 +47,8 @@ public:
virtual const LetterCase getLetterCase() const = 0; virtual const LetterCase getLetterCase() const = 0;
virtual const LetterCase getLetterCaseAutoCollections() const = 0; virtual const LetterCase getLetterCaseAutoCollections() const = 0;
virtual const LetterCase getLetterCaseCustomCollections() const = 0; virtual const LetterCase getLetterCaseCustomCollections() const = 0;
virtual const bool getSystemNameSuffix() const = 0;
virtual const LetterCase getLetterCaseSystemNameSuffix() const = 0;
// Functions used by some primary components. // Functions used by some primary components.
virtual void onDemandTextureLoad() {} virtual void onDemandTextureLoad() {}

View file

@ -84,6 +84,11 @@ public:
{ {
return mLetterCaseCustomCollections; return mLetterCaseCustomCollections;
} }
const bool getSystemNameSuffix() const override { return mSystemNameSuffix; }
const LetterCase getLetterCaseSystemNameSuffix() const override
{
return mLetterCaseSystemNameSuffix;
}
private: private:
void onShow() override { mLoopTime = 0; } void onShow() override { mLoopTime = 0; }
@ -145,6 +150,8 @@ private:
float mLineSpacing; float mLineSpacing;
std::string mIndicators; std::string mIndicators;
std::string mCollectionIndicators; std::string mCollectionIndicators;
bool mSystemNameSuffix;
LetterCase mLetterCaseSystemNameSuffix;
bool mFadeAbovePrimary; bool mFadeAbovePrimary;
}; };
@ -181,6 +188,8 @@ TextListComponent<T>::TextListComponent()
, mLineSpacing {1.5f} , mLineSpacing {1.5f}
, mIndicators {"symbols"} , mIndicators {"symbols"}
, mCollectionIndicators {"symbols"} , mCollectionIndicators {"symbols"}
, mSystemNameSuffix {true}
, mLetterCaseSystemNameSuffix {LetterCase::UPPERCASE}
, mFadeAbovePrimary {false} , mFadeAbovePrimary {false}
{ {
} }
@ -711,6 +720,27 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
} }
} }
if (mGamelistView && elem->has("systemNameSuffix"))
mSystemNameSuffix = elem->get<bool>("systemNameSuffix");
if (mGamelistView && properties & LETTER_CASE && elem->has("letterCaseSystemNameSuffix")) {
const std::string& letterCase {elem->get<std::string>("letterCaseSystemNameSuffix")};
if (letterCase == "uppercase") {
mLetterCaseSystemNameSuffix = LetterCase::UPPERCASE;
}
else if (letterCase == "lowercase") {
mLetterCaseSystemNameSuffix = LetterCase::LOWERCASE;
}
else if (letterCase == "capitalize") {
mLetterCaseSystemNameSuffix = LetterCase::CAPITALIZE;
}
else {
LOG(LogWarning) << "TextListComponent: Invalid theme configuration, property "
"\"letterCaseSystemNameSuffix\" for element \""
<< element.substr(9) << "\" defined as \"" << letterCase << "\"";
}
}
if (elem->has("selectorImagePath")) { if (elem->has("selectorImagePath")) {
const std::string& path {elem->get<std::string>("selectorImagePath")}; const std::string& path {elem->get<std::string>("selectorImagePath")};
bool tile {elem->has("selectorImageTile") && elem->get<bool>("selectorImageTile")}; bool tile {elem->has("selectorImageTile") && elem->get<bool>("selectorImageTile")};