mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-01-30 03:55:40 +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();
|
||||
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)
|
||||
|
|
|
@ -39,6 +39,8 @@ FileData::FileData(FileType type,
|
|||
, mEnvData {envData}
|
||||
, mSystem {system}
|
||||
, mOnlyFolders {false}
|
||||
, mUpdateChildrenLastPlayed {false}
|
||||
, mUpdateChildrenMostPlayed {false}
|
||||
, mDeletionFlag {false}
|
||||
{
|
||||
// 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);
|
||||
else
|
||||
sort(*type.comparisonFunction, mGameCount);
|
||||
|
||||
updateLastPlayedList();
|
||||
updateMostPlayedList();
|
||||
}
|
||||
|
||||
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" ||
|
||||
Settings::getInstance()->getBool("ForceKid"));
|
||||
|
||||
(Settings::getInstance()->getString("UIMode") == "kid" ||
|
||||
Settings::getInstance()->getBool("ForceKid"));
|
||||
|
||||
for (unsigned int i = 0; i < mChildren.size(); ++i) {
|
||||
if (mChildren[i]->getType() == GAME && mChildren[i]->getCountAsGame()) {
|
||||
if (!isKidMode || (isKidMode && mChildren[i]->getKidgame())) {
|
||||
|
@ -761,6 +763,36 @@ void FileData::countGames(std::pair<unsigned int, unsigned int>& 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
|
||||
{
|
||||
std::vector<FileData::SortType> SortTypes = FileSorts::SortTypes;
|
||||
|
|
|
@ -56,6 +56,13 @@ public:
|
|||
const std::vector<FileData*>& getChildren() const { return mChildren; }
|
||||
SystemData* getSystem() const { return mSystem; }
|
||||
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 getHasFoldersFlag() const { return mHasFolders; }
|
||||
static const std::string getROMDirectory();
|
||||
|
@ -127,7 +134,8 @@ public:
|
|||
MetaDataList metadata;
|
||||
// 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 updateLastPlayedList();
|
||||
void updateMostPlayedList();
|
||||
void setSortTypeString(std::string typestring) { mSortTypeString = typestring; }
|
||||
const std::string& getSortTypeString() const { return mSortTypeString; }
|
||||
const FileData::SortType& getSortTypeFromString(const std::string& desc) const;
|
||||
|
@ -146,10 +154,14 @@ private:
|
|||
std::unordered_map<std::string, FileData*> mChildrenByFilename;
|
||||
std::vector<FileData*> mChildren;
|
||||
std::vector<FileData*> mFilteredChildren;
|
||||
std::vector<FileData*> mChildrenLastPlayed;
|
||||
std::vector<FileData*> mChildrenMostPlayed;
|
||||
// The pair includes all games, and favorite games.
|
||||
std::pair<unsigned int, unsigned int> mGameCount;
|
||||
bool mOnlyFolders;
|
||||
bool mHasFolders;
|
||||
bool mUpdateChildrenLastPlayed;
|
||||
bool mUpdateChildrenMostPlayed;
|
||||
// Used for flagging a game for deletion from its gamelist.xml file.
|
||||
bool mDeletionFlag;
|
||||
};
|
||||
|
|
|
@ -42,6 +42,7 @@ set(CORE_HEADERS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeEditComponent.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/HelpComponent.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.
|
||||
{"lineSpacing", FLOAT},
|
||||
{"zIndex", FLOAT}}},
|
||||
{"gameselector",
|
||||
{{"selection", STRING},
|
||||
{"count", UNSIGNED_INTEGER}}},
|
||||
{"helpsystem",
|
||||
{{"pos", 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