mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-04-10 19:15:13 +00:00
Added a GameSelectorComponent for displaying game media in SystemView.
This commit is contained in:
parent
31c5b200d1
commit
cc8123f5a6
|
@ -1443,6 +1443,10 @@ void CollectionSystemsManager::trimCollectionCount(FileData* rootFolder, int lim
|
||||||
(CollectionFileData*)rootFolder->getChildrenListToDisplay().back();
|
(CollectionFileData*)rootFolder->getChildrenListToDisplay().back();
|
||||||
ViewController::getInstance()->getGamelistView(curSys).get()->remove(gameToRemove, false);
|
ViewController::getInstance()->getGamelistView(curSys).get()->remove(gameToRemove, false);
|
||||||
}
|
}
|
||||||
|
// Also update the lists of last played and most played games as these could otherwise
|
||||||
|
// contain dangling pointers.
|
||||||
|
rootFolder->updateLastPlayedList();
|
||||||
|
rootFolder->updateMostPlayedList();
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool CollectionSystemsManager::themeFolderExists(const std::string& folder)
|
const bool CollectionSystemsManager::themeFolderExists(const std::string& folder)
|
||||||
|
|
|
@ -39,6 +39,8 @@ FileData::FileData(FileType type,
|
||||||
, mEnvData {envData}
|
, mEnvData {envData}
|
||||||
, mSystem {system}
|
, mSystem {system}
|
||||||
, mOnlyFolders {false}
|
, mOnlyFolders {false}
|
||||||
|
, mUpdateChildrenLastPlayed {false}
|
||||||
|
, mUpdateChildrenMostPlayed {false}
|
||||||
, mDeletionFlag {false}
|
, mDeletionFlag {false}
|
||||||
{
|
{
|
||||||
// Metadata needs at least a name field (since that's what getName() will return).
|
// Metadata needs at least a name field (since that's what getName() will return).
|
||||||
|
@ -736,6 +738,9 @@ void FileData::sort(const SortType& type, bool mFavoritesOnTop)
|
||||||
sortFavoritesOnTop(*type.comparisonFunction, mGameCount);
|
sortFavoritesOnTop(*type.comparisonFunction, mGameCount);
|
||||||
else
|
else
|
||||||
sort(*type.comparisonFunction, mGameCount);
|
sort(*type.comparisonFunction, mGameCount);
|
||||||
|
|
||||||
|
updateLastPlayedList();
|
||||||
|
updateMostPlayedList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileData::countGames(std::pair<unsigned int, unsigned int>& gameCount)
|
void FileData::countGames(std::pair<unsigned int, unsigned int>& gameCount)
|
||||||
|
@ -743,9 +748,6 @@ void FileData::countGames(std::pair<unsigned int, unsigned int>& gameCount)
|
||||||
bool isKidMode = (Settings::getInstance()->getString("UIMode") == "kid" ||
|
bool isKidMode = (Settings::getInstance()->getString("UIMode") == "kid" ||
|
||||||
Settings::getInstance()->getBool("ForceKid"));
|
Settings::getInstance()->getBool("ForceKid"));
|
||||||
|
|
||||||
(Settings::getInstance()->getString("UIMode") == "kid" ||
|
|
||||||
Settings::getInstance()->getBool("ForceKid"));
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < mChildren.size(); ++i) {
|
for (unsigned int i = 0; i < mChildren.size(); ++i) {
|
||||||
if (mChildren[i]->getType() == GAME && mChildren[i]->getCountAsGame()) {
|
if (mChildren[i]->getType() == GAME && mChildren[i]->getCountAsGame()) {
|
||||||
if (!isKidMode || (isKidMode && mChildren[i]->getKidgame())) {
|
if (!isKidMode || (isKidMode && mChildren[i]->getKidgame())) {
|
||||||
|
@ -761,6 +763,36 @@ void FileData::countGames(std::pair<unsigned int, unsigned int>& gameCount)
|
||||||
mGameCount = gameCount;
|
mGameCount = gameCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileData::updateLastPlayedList()
|
||||||
|
{
|
||||||
|
if (!mUpdateChildrenLastPlayed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mChildrenLastPlayed.clear();
|
||||||
|
mChildrenLastPlayed = getChildrenRecursive();
|
||||||
|
|
||||||
|
std::stable_sort(mChildrenLastPlayed.begin(), mChildrenLastPlayed.end());
|
||||||
|
std::sort(std::begin(mChildrenLastPlayed), std::end(mChildrenLastPlayed),
|
||||||
|
[](FileData* a, FileData* b) {
|
||||||
|
return a->metadata.get("lastplayed") > b->metadata.get("lastplayed");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileData::updateMostPlayedList()
|
||||||
|
{
|
||||||
|
if (!mUpdateChildrenMostPlayed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mChildrenMostPlayed.clear();
|
||||||
|
mChildrenMostPlayed = getChildrenRecursive();
|
||||||
|
|
||||||
|
std::stable_sort(mChildrenMostPlayed.begin(), mChildrenMostPlayed.end());
|
||||||
|
std::sort(std::begin(mChildrenMostPlayed), std::end(mChildrenMostPlayed),
|
||||||
|
[](FileData* a, FileData* b) {
|
||||||
|
return a->metadata.getInt("playcount") > b->metadata.getInt("playcount");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const FileData::SortType& FileData::getSortTypeFromString(const std::string& desc) const
|
const FileData::SortType& FileData::getSortTypeFromString(const std::string& desc) const
|
||||||
{
|
{
|
||||||
std::vector<FileData::SortType> SortTypes = FileSorts::SortTypes;
|
std::vector<FileData::SortType> SortTypes = FileSorts::SortTypes;
|
||||||
|
|
|
@ -56,6 +56,13 @@ public:
|
||||||
const std::vector<FileData*>& getChildren() const { return mChildren; }
|
const std::vector<FileData*>& getChildren() const { return mChildren; }
|
||||||
SystemData* getSystem() const { return mSystem; }
|
SystemData* getSystem() const { return mSystem; }
|
||||||
SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
||||||
|
|
||||||
|
// These functions are used by GameSelectorComponent.
|
||||||
|
const std::vector<FileData*>& getChildrenLastPlayed() const { return mChildrenLastPlayed; }
|
||||||
|
const std::vector<FileData*>& getChildrenMostPlayed() const { return mChildrenMostPlayed; }
|
||||||
|
void setUpdateChildrenLastPlayed(bool state) { mUpdateChildrenLastPlayed = state; }
|
||||||
|
void setUpdateChildrenMostPlayed(bool state) { mUpdateChildrenMostPlayed = state; }
|
||||||
|
|
||||||
const bool getOnlyFoldersFlag() const { return mOnlyFolders; }
|
const bool getOnlyFoldersFlag() const { return mOnlyFolders; }
|
||||||
const bool getHasFoldersFlag() const { return mHasFolders; }
|
const bool getHasFoldersFlag() const { return mHasFolders; }
|
||||||
static const std::string getROMDirectory();
|
static const std::string getROMDirectory();
|
||||||
|
@ -127,7 +134,8 @@ public:
|
||||||
MetaDataList metadata;
|
MetaDataList metadata;
|
||||||
// Only count the games, a cheaper alternative to a full sort when that is not required.
|
// Only count the games, a cheaper alternative to a full sort when that is not required.
|
||||||
void countGames(std::pair<unsigned int, unsigned int>& gameCount);
|
void countGames(std::pair<unsigned int, unsigned int>& gameCount);
|
||||||
|
void updateLastPlayedList();
|
||||||
|
void updateMostPlayedList();
|
||||||
void setSortTypeString(std::string typestring) { mSortTypeString = typestring; }
|
void setSortTypeString(std::string typestring) { mSortTypeString = typestring; }
|
||||||
const std::string& getSortTypeString() const { return mSortTypeString; }
|
const std::string& getSortTypeString() const { return mSortTypeString; }
|
||||||
const FileData::SortType& getSortTypeFromString(const std::string& desc) const;
|
const FileData::SortType& getSortTypeFromString(const std::string& desc) const;
|
||||||
|
@ -146,10 +154,14 @@ private:
|
||||||
std::unordered_map<std::string, FileData*> mChildrenByFilename;
|
std::unordered_map<std::string, FileData*> mChildrenByFilename;
|
||||||
std::vector<FileData*> mChildren;
|
std::vector<FileData*> mChildren;
|
||||||
std::vector<FileData*> mFilteredChildren;
|
std::vector<FileData*> mFilteredChildren;
|
||||||
|
std::vector<FileData*> mChildrenLastPlayed;
|
||||||
|
std::vector<FileData*> mChildrenMostPlayed;
|
||||||
// The pair includes all games, and favorite games.
|
// The pair includes all games, and favorite games.
|
||||||
std::pair<unsigned int, unsigned int> mGameCount;
|
std::pair<unsigned int, unsigned int> mGameCount;
|
||||||
bool mOnlyFolders;
|
bool mOnlyFolders;
|
||||||
bool mHasFolders;
|
bool mHasFolders;
|
||||||
|
bool mUpdateChildrenLastPlayed;
|
||||||
|
bool mUpdateChildrenMostPlayed;
|
||||||
// Used for flagging a game for deletion from its gamelist.xml file.
|
// Used for flagging a game for deletion from its gamelist.xml file.
|
||||||
bool mDeletionFlag;
|
bool mDeletionFlag;
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,6 +42,7 @@ set(CORE_HEADERS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeComponent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeEditComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeEditComponent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/FlexboxComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/FlexboxComponent.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GameSelectorComponent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GridTileComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GridTileComponent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/HelpComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/HelpComponent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/IList.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/IList.h
|
||||||
|
|
|
@ -279,6 +279,9 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
||||||
{"forceUppercase", BOOLEAN}, // For backward compatibility with legacy themes.
|
{"forceUppercase", BOOLEAN}, // For backward compatibility with legacy themes.
|
||||||
{"lineSpacing", FLOAT},
|
{"lineSpacing", FLOAT},
|
||||||
{"zIndex", FLOAT}}},
|
{"zIndex", FLOAT}}},
|
||||||
|
{"gameselector",
|
||||||
|
{{"selection", STRING},
|
||||||
|
{"count", UNSIGNED_INTEGER}}},
|
||||||
{"helpsystem",
|
{"helpsystem",
|
||||||
{{"pos", NORMALIZED_PAIR},
|
{{"pos", NORMALIZED_PAIR},
|
||||||
{"origin", NORMALIZED_PAIR},
|
{"origin", NORMALIZED_PAIR},
|
||||||
|
|
124
es-core/src/components/GameSelectorComponent.h
Normal file
124
es-core/src/components/GameSelectorComponent.h
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
|
// GameSelectorComponent.h
|
||||||
|
//
|
||||||
|
// Makes a selection of games based on theme-controlled criteria.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ES_CORE_COMPONENTS_GAME_SELECTOR_COMPONENT_H
|
||||||
|
#define ES_CORE_COMPONENTS_GAME_SELECTOR_COMPONENT_H
|
||||||
|
|
||||||
|
#include "GuiComponent.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "ThemeData.h"
|
||||||
|
|
||||||
|
class GameSelectorComponent : public GuiComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GameSelectorComponent(SystemData* system)
|
||||||
|
: mSystem {system}
|
||||||
|
, mGameSelection {GameSelection::RANDOM}
|
||||||
|
, mGameCount {1}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<FileData*>& getGames() const { return mGames; }
|
||||||
|
|
||||||
|
void refreshGames()
|
||||||
|
{
|
||||||
|
mGames.clear();
|
||||||
|
|
||||||
|
bool isKidMode {(Settings::getInstance()->getString("UIMode") == "kid" ||
|
||||||
|
Settings::getInstance()->getBool("ForceKid"))};
|
||||||
|
|
||||||
|
if (mGameSelection == GameSelection::RANDOM) {
|
||||||
|
for (int i = 0; i < mGameCount; ++i) {
|
||||||
|
FileData* randomGame {mSystem->getRandomGame()};
|
||||||
|
if (randomGame != nullptr)
|
||||||
|
mGames.emplace_back(randomGame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mGameSelection == GameSelection::LAST_PLAYED) {
|
||||||
|
for (auto& child : mSystem->getRootFolder()->getChildrenLastPlayed()) {
|
||||||
|
if (child->getType() != GAME)
|
||||||
|
continue;
|
||||||
|
if (!child->getCountAsGame())
|
||||||
|
continue;
|
||||||
|
if (isKidMode && !child->getKidgame())
|
||||||
|
continue;
|
||||||
|
if (child->metadata.get("lastplayed") == "0")
|
||||||
|
continue;
|
||||||
|
mGames.emplace_back(child);
|
||||||
|
if (static_cast<int>(mGames.size()) == mGameCount)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mGameSelection == GameSelection::MOST_PLAYED) {
|
||||||
|
for (auto& child : mSystem->getRootFolder()->getChildrenMostPlayed()) {
|
||||||
|
if (child->getType() != GAME)
|
||||||
|
continue;
|
||||||
|
if (!child->getCountAsGame())
|
||||||
|
continue;
|
||||||
|
if (isKidMode && !child->getKidgame())
|
||||||
|
continue;
|
||||||
|
if (child->metadata.get("playcount") == "0")
|
||||||
|
continue;
|
||||||
|
mGames.emplace_back(child);
|
||||||
|
if (static_cast<int>(mGames.size()) == mGameCount)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
|
const std::string& view,
|
||||||
|
const std::string& element,
|
||||||
|
unsigned int properties)
|
||||||
|
{
|
||||||
|
const ThemeData::ThemeElement* elem {theme->getElement(view, element, "gameselector")};
|
||||||
|
if (!elem)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (elem->has("selection")) {
|
||||||
|
const std::string selection {elem->get<std::string>("selection")};
|
||||||
|
if (selection == "random") {
|
||||||
|
mGameSelection = GameSelection::RANDOM;
|
||||||
|
}
|
||||||
|
else if (selection == "lastplayed") {
|
||||||
|
mGameSelection = GameSelection::LAST_PLAYED;
|
||||||
|
mSystem->getRootFolder()->setUpdateChildrenLastPlayed(true);
|
||||||
|
mSystem->getRootFolder()->updateLastPlayedList();
|
||||||
|
}
|
||||||
|
else if (selection == "mostplayed") {
|
||||||
|
mGameSelection = GameSelection::MOST_PLAYED;
|
||||||
|
mSystem->getRootFolder()->setUpdateChildrenMostPlayed(true);
|
||||||
|
mSystem->getRootFolder()->updateMostPlayedList();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mGameSelection = GameSelection::RANDOM;
|
||||||
|
LOG(LogWarning) << "GameSelectorComponent: Invalid theme configuration, property "
|
||||||
|
"<selection> set to \""
|
||||||
|
<< selection << "\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elem->has("count"))
|
||||||
|
mGameCount = glm::clamp(static_cast<int>(elem->get<unsigned int>("count")), 1, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class GameSelection {
|
||||||
|
RANDOM, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||||
|
LAST_PLAYED,
|
||||||
|
MOST_PLAYED
|
||||||
|
};
|
||||||
|
|
||||||
|
SystemData* mSystem;
|
||||||
|
std::vector<FileData*> mGames;
|
||||||
|
|
||||||
|
GameSelection mGameSelection;
|
||||||
|
int mGameCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ES_CORE_COMPONENTS_GAME_SELECTOR_COMPONENT_H
|
Loading…
Reference in a new issue