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(); | ||||
|         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
	
	 Leon Styhre
						Leon Styhre