From 005952addfc504547602d128e43fd297c0cf879d Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Fri, 30 Oct 2020 18:34:05 +0100 Subject: [PATCH] Rewrote and moved the quick selector letter index generation. --- es-app/src/FileData.cpp | 101 ++---------------- es-app/src/FileData.h | 3 - es-app/src/guis/GuiGamelistOptions.cpp | 2 +- .../src/views/gamelist/BasicGameListView.cpp | 1 + es-app/src/views/gamelist/BasicGameListView.h | 3 + .../src/views/gamelist/GridGameListView.cpp | 1 + es-app/src/views/gamelist/GridGameListView.h | 3 + es-app/src/views/gamelist/IGameListView.h | 1 + .../views/gamelist/ISimpleGameListView.cpp | 62 +++++++++++ .../src/views/gamelist/ISimpleGameListView.h | 5 + 10 files changed, 88 insertions(+), 94 deletions(-) diff --git a/es-app/src/FileData.cpp b/es-app/src/FileData.cpp index cdcc99e0a..c02d54abc 100644 --- a/es-app/src/FileData.cpp +++ b/es-app/src/FileData.cpp @@ -439,10 +439,8 @@ void FileData::removeChild(FileData* file) void FileData::sort(ComparisonFunction& comparator, bool ascending, std::pair& gameCount) { - mFirstLetterIndex.clear(); mOnlyFolders = true; bool foldersOnTop = Settings::getInstance()->getBool("FoldersOnTop"); - bool hasFolders = false; std::vector mChildrenFolders; std::vector mChildrenOthers; @@ -454,9 +452,6 @@ void FileData::sort(ComparisonFunction& comparator, bool ascending, if (mSystem->isCollection() && mSystem->getFullName() == "collections") { std::pair tempGameCount = {}; for (auto it = mChildren.cbegin(); it != mChildren.cend(); it++) { - // Build mFirstLetterIndex. - const char firstChar = toupper((*it)->getSortName().front()); - mFirstLetterIndex.push_back(std::string(1, firstChar)); if ((*it)->getChildren().size() > 0) (*it)->sort(comparator, ascending, gameCount); tempGameCount.first += gameCount.first; @@ -464,10 +459,6 @@ void FileData::sort(ComparisonFunction& comparator, bool ascending, gameCount = {}; } gameCount = tempGameCount; - // Sort and make each entry unique in mFirstLetterIndex. - std::sort(mFirstLetterIndex.begin(), mFirstLetterIndex.end()); - auto last = std::unique(mFirstLetterIndex.begin(), mFirstLetterIndex.end()); - mFirstLetterIndex.erase(last, mFirstLetterIndex.end()); return; } @@ -475,7 +466,6 @@ void FileData::sort(ComparisonFunction& comparator, bool ascending, for (unsigned int i = 0; i < mChildren.size(); i++) { if (mChildren[i]->getType() == FOLDER) { mChildrenFolders.push_back(mChildren[i]); - hasFolders = true; } else { mChildrenOthers.push_back(mChildren[i]); @@ -492,6 +482,7 @@ void FileData::sort(ComparisonFunction& comparator, bool ascending, if (foldersOnTop && mOnlyFolders) std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(), comparator); + std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(), comparator); if (!ascending) { @@ -527,11 +518,6 @@ void FileData::sort(ComparisonFunction& comparator, bool ascending, if ((*it)->getType() != FOLDER) mOnlyFolders = false; - if (!(foldersOnTop && (*it)->getType() == FOLDER)) { - // Build mFirstLetterIndex. - const char firstChar = toupper((*it)->getSortName().front()); - mFirstLetterIndex.push_back(std::string(1, firstChar)); - } // Iterate through any child folders. if ((*it)->getChildren().size() > 0) (*it)->sort(comparator, ascending, gameCount); @@ -539,38 +525,17 @@ void FileData::sort(ComparisonFunction& comparator, bool ascending, if (mSystem->isGroupedCustomCollection()) mGameCount = gameCount; - - // If there are only folders in the gamelist, then it makes sense to still - // generate a letter index. - if (mOnlyFolders) { - for (unsigned int i = 0; i < mChildrenFolders.size(); i++) { - const char firstChar = toupper(mChildrenFolders[i]->getSortName().front()); - mFirstLetterIndex.push_back(std::string(1, firstChar)); - } - mOnlyFolders = true; - } - - // Sort and make each entry unique in mFirstLetterIndex. - std::sort(mFirstLetterIndex.begin(), mFirstLetterIndex.end()); - auto last = std::unique(mFirstLetterIndex.begin(), mFirstLetterIndex.end()); - mFirstLetterIndex.erase(last, mFirstLetterIndex.end()); - - // If it's a mixed list and folders are sorted on top, add a folder icon to the index. - if (foldersOnTop && hasFolders && !mOnlyFolders) - mFirstLetterIndex.insert(mFirstLetterIndex.begin(), FOLDER_CHAR); } void FileData::sortFavoritesOnTop(ComparisonFunction& comparator, bool ascending, std::pair& gameCount) { - mFirstLetterIndex.clear(); mOnlyFolders = true; std::vector mChildrenFolders; std::vector mChildrenFavoritesFolders; std::vector mChildrenFavorites; std::vector mChildrenOthers; bool foldersOnTop = Settings::getInstance()->getBool("FoldersOnTop"); - bool hasFolders = false; if (mSystem->isGroupedCustomCollection()) gameCount = {}; @@ -580,9 +545,6 @@ void FileData::sortFavoritesOnTop(ComparisonFunction& comparator, bool ascending if (mSystem->isCollection() && mSystem->getFullName() == "collections") { std::pair tempGameCount = {}; for (auto it = mChildren.cbegin(); it != mChildren.cend(); it++) { - // Build mFirstLetterIndex. - const char firstChar = toupper((*it)->getSortName().front()); - mFirstLetterIndex.push_back(std::string(1, firstChar)); if ((*it)->getChildren().size() > 0) (*it)->sortFavoritesOnTop(comparator, ascending, gameCount); tempGameCount.first += gameCount.first; @@ -590,10 +552,6 @@ void FileData::sortFavoritesOnTop(ComparisonFunction& comparator, bool ascending gameCount = {}; } gameCount = tempGameCount; - // Sort and make each entry unique in mFirstLetterIndex. - std::sort(mFirstLetterIndex.begin(), mFirstLetterIndex.end()); - auto last = std::unique(mFirstLetterIndex.begin(), mFirstLetterIndex.end()); - mFirstLetterIndex.erase(last, mFirstLetterIndex.end()); return; } @@ -611,17 +569,12 @@ void FileData::sortFavoritesOnTop(ComparisonFunction& comparator, bool ascending mChildrenFolders.push_back(mChildren[i]); else mChildrenFavoritesFolders.push_back(mChildren[i]); - - hasFolders = true; } else if (mChildren[i]->getFavorite()) { mChildrenFavorites.push_back(mChildren[i]); } else { mChildrenOthers.push_back(mChildren[i]); - // Build mFirstLetterIndex. - const char firstChar = toupper(mChildren[i]->getSortName().front()); - mFirstLetterIndex.push_back(std::string(1, firstChar)); } if (mChildren[i]->getType() != FOLDER) @@ -644,48 +597,6 @@ void FileData::sortFavoritesOnTop(ComparisonFunction& comparator, bool ascending getSortTypeFromString("filename, ascending").comparisonFunction); } - // If there are only favorites in the gamelist, it makes sense to still generate - // a letter index. For instance to be able to quick jump in the 'favorites' - // collection. Doing this additional work here only for the applicable gamelists is - // probably faster than building a redundant index for all gamelists during sorting. - if (mChildrenOthers.size() == 0 && mChildrenFavorites.size() > 0) { - for (unsigned int i = 0; i < mChildren.size(); i++) { - if (foldersOnTop && mChildren[i]->getType() == FOLDER) { - continue; - } - else { - const char firstChar = toupper(mChildren[i]->getSortName().front()); - mFirstLetterIndex.push_back(std::string(1, firstChar)); - } - } - } - // If there are only folders in the gamelist, then it also makes sense to generate - // a letter index. - else if (mOnlyFolders) { - for (unsigned int i = 0; i < mChildrenFolders.size(); i++) { - const char firstChar = toupper(mChildrenFolders[i]->getSortName().front()); - mFirstLetterIndex.push_back(std::string(1, firstChar)); - } - } - - // Sort and make each entry unique in mFirstLetterIndex. - std::sort(mFirstLetterIndex.begin(), mFirstLetterIndex.end()); - auto last = std::unique(mFirstLetterIndex.begin(), mFirstLetterIndex.end()); - mFirstLetterIndex.erase(last, mFirstLetterIndex.end()); - - // If there were at least one favorite folder in the gamelist, insert the favorite - // unicode character in the first position. - if (foldersOnTop && mOnlyFolders && mChildrenFavoritesFolders.size() > 0) - mFirstLetterIndex.insert(mFirstLetterIndex.begin(), FAVORITE_CHAR); - // If there were at least one favorite in the gamelist, insert the favorite - // unicode character in the first position. - else if (mChildrenOthers.size() > 0 && mChildrenFavorites.size() > 0) - mFirstLetterIndex.insert(mFirstLetterIndex.begin(), FAVORITE_CHAR); - - // If it's a mixed list and folders are sorted on top, add a folder icon to the index. - if (foldersOnTop && hasFolders && !mOnlyFolders) - mFirstLetterIndex.insert(mFirstLetterIndex.begin(), FOLDER_CHAR); - // If descending sorting is requested, always perform a ascending sort by filename first. // This adds a slight (probably negligible) overhead but it will avoid strange sorting // issues where the secondary sorting is reversed for some sort types. @@ -722,6 +633,16 @@ void FileData::sortFavoritesOnTop(ComparisonFunction& comparator, bool ascending (*it)->sortFavoritesOnTop(comparator, ascending, gameCount); } + // If folders are not sorted on top, mChildrenFavoritesFolders and mChildrenFolders + // could be empty. So due to this, step through all mChildren and see if there are + // any folders that we need to iterate. + if (mChildrenFavoritesFolders.size() == 0 && mChildrenFolders.size() == 0) { + for (auto it = mChildren.cbegin(); it != mChildren.cend(); it++) { + if ((*it)->getChildren().size() > 0) + (*it)->sortFavoritesOnTop(comparator, ascending, gameCount); + } + } + if (!ascending) { if (foldersOnTop && mOnlyFolders) { std::reverse(mChildrenFavoritesFolders.begin(), mChildrenFavoritesFolders.end()); diff --git a/es-app/src/FileData.h b/es-app/src/FileData.h index 30c091fc1..4d4f8b4c0 100644 --- a/es-app/src/FileData.h +++ b/es-app/src/FileData.h @@ -55,8 +55,6 @@ public: inline const std::vector& getChildren() const { return mChildren; } inline SystemData* getSystem() const { return mSystem; } inline SystemEnvironmentData* getSystemEnvData() const { return mEnvData; } - const std::vector& getFirstLetterIndex() const - { return mFirstLetterIndex; }; const bool getOnlyFoldersFlag() { return mOnlyFolders; } bool viewHasOnlyFolders(); static const std::string getROMDirectory(); @@ -148,7 +146,6 @@ private: std::unordered_map mChildrenByFilename; std::vector mChildren; std::vector mFilteredChildren; - std::vector mFirstLetterIndex; // The pair includes non-favorite games, and favorite games. std::pair mGameCount; bool mOnlyFolders; diff --git a/es-app/src/guis/GuiGamelistOptions.cpp b/es-app/src/guis/GuiGamelistOptions.cpp index 79dc27857..a19b9d253 100644 --- a/es-app/src/guis/GuiGamelistOptions.cpp +++ b/es-app/src/guis/GuiGamelistOptions.cpp @@ -71,7 +71,7 @@ GuiGamelistOptions::GuiGamelistOptions( row.elements.clear(); // The letter index is generated in FileData during gamelist sorting. - mFirstLetterIndex = file->getParent()->getFirstLetterIndex(); + mFirstLetterIndex = getGamelist()->getFirstLetterIndex(); // Don't include the folder name starting characters if folders are sorted on top // unless the list only contains folders. diff --git a/es-app/src/views/gamelist/BasicGameListView.cpp b/es-app/src/views/gamelist/BasicGameListView.cpp index 1eac5d8ad..a5e32003a 100644 --- a/es-app/src/views/gamelist/BasicGameListView.cpp +++ b/es-app/src/views/gamelist/BasicGameListView.cpp @@ -58,6 +58,7 @@ void BasicGameListView::populateList(const std::vector& files) std::string inCollectionPrefix; generateGamelistInfo(files); + generateFirstLetterIndex(files); if (CollectionSystemManager::get()->isEditing()) { editingCollection = CollectionSystemManager::get()->getEditingCollection(); diff --git a/es-app/src/views/gamelist/BasicGameListView.h b/es-app/src/views/gamelist/BasicGameListView.h index b1aa8f436..3d3cc668e 100644 --- a/es-app/src/views/gamelist/BasicGameListView.h +++ b/es-app/src/views/gamelist/BasicGameListView.h @@ -38,6 +38,9 @@ public: virtual bool isListScrolling() override { return mList.isScrolling(); }; virtual void stopListScrolling() override { mList.stopScrolling(); }; + virtual const std::vector& getFirstLetterIndex() override + { return mFirstLetterIndex; }; + protected: virtual std::string getQuickSystemSelectRightButton() override; virtual std::string getQuickSystemSelectLeftButton() override; diff --git a/es-app/src/views/gamelist/GridGameListView.cpp b/es-app/src/views/gamelist/GridGameListView.cpp index 61458446f..d3acf87f4 100644 --- a/es-app/src/views/gamelist/GridGameListView.cpp +++ b/es-app/src/views/gamelist/GridGameListView.cpp @@ -249,6 +249,7 @@ void GridGameListView::populateList(const std::vector& files) firstGameEntry = nullptr; generateGamelistInfo(files); + generateFirstLetterIndex(files); mGrid.clear(); mHeaderText.setText(mRoot->getSystem()->getFullName()); diff --git a/es-app/src/views/gamelist/GridGameListView.h b/es-app/src/views/gamelist/GridGameListView.h index 34836ff60..b48964d70 100644 --- a/es-app/src/views/gamelist/GridGameListView.h +++ b/es-app/src/views/gamelist/GridGameListView.h @@ -41,6 +41,9 @@ public: virtual std::vector getHelpPrompts() override; virtual void launch(FileData* game) override; + virtual const std::vector& getFirstLetterIndex() override + { return mFirstLetterIndex; }; + protected: virtual void update(int deltaTime) override; virtual std::string getQuickSystemSelectRightButton() override; diff --git a/es-app/src/views/gamelist/IGameListView.h b/es-app/src/views/gamelist/IGameListView.h index d1ab47bfd..29c09faf5 100644 --- a/es-app/src/views/gamelist/IGameListView.h +++ b/es-app/src/views/gamelist/IGameListView.h @@ -46,6 +46,7 @@ public: virtual FileData* getFirstEntry() = 0; virtual FileData* getLastEntry() = 0; virtual FileData* getFirstGameEntry() = 0; + virtual const std::vector& getFirstLetterIndex() = 0; virtual bool input(InputConfig* config, Input input) override; virtual void remove(FileData* game, bool deleteFile) = 0; diff --git a/es-app/src/views/gamelist/ISimpleGameListView.cpp b/es-app/src/views/gamelist/ISimpleGameListView.cpp index d520ab6c2..44876e73d 100644 --- a/es-app/src/views/gamelist/ISimpleGameListView.cpp +++ b/es-app/src/views/gamelist/ISimpleGameListView.cpp @@ -373,3 +373,65 @@ void ISimpleGameListView::generateGamelistInfo(const std::vector& fil if (files.size() > 0 && files.front()->getParent() != mRoot) mIsFolder = true; } + +void ISimpleGameListView::generateFirstLetterIndex(const std::vector& files) +{ + const std::string favoriteChar = mRoot->FAVORITE_CHAR; + const std::string folderChar = mRoot->FOLDER_CHAR; + std::string firstChar; + + bool onlyFavorites = true; + bool onlyFolders = true; + bool hasFavorites = false; + bool hasFolders = false; + bool favoritesSorting = false; + + mFirstLetterIndex.clear(); + + if (files.size() > 0 && files.front()->getSystem()->isGroupedCustomCollection()) + favoritesSorting = Settings::getInstance()->getBool("FavFirstCustom"); + else + favoritesSorting = Settings::getInstance()->getBool("FavoritesFirst"); + + bool foldersOnTop = Settings::getInstance()->getBool("FoldersOnTop"); + + // Find out if there are only favorites and/or only folders in the list. + for (auto it = files.begin(); it != files.end(); it++) { + if (!((*it)->getFavorite())) + onlyFavorites = false; + if (!((*it)->getType() == FOLDER)) + onlyFolders = false; + } + + // Build the index. + for (auto it = files.begin(); it != files.end(); it++) { + if ((*it)->getType() == FOLDER && (*it)->getFavorite() && + favoritesSorting && !onlyFavorites) { + hasFavorites = true; + } + else if ((*it)->getType() == FOLDER && foldersOnTop && !onlyFolders) { + hasFolders = true; + } + else if ((*it)->getType() == GAME && (*it)->getFavorite() && + favoritesSorting && !onlyFavorites) { + hasFavorites = true; + } + else { + firstChar = toupper((*it)->getSortName().front()); + mFirstLetterIndex.push_back(firstChar); + } + } + + // Sort and make each entry unique. + std::sort(mFirstLetterIndex.begin(), mFirstLetterIndex.end()); + auto last = std::unique(mFirstLetterIndex.begin(), mFirstLetterIndex.end()); + mFirstLetterIndex.erase(last, mFirstLetterIndex.end()); + + // If there are any favorites and/or folders in the list, insert their respective + // Unicode characters at the beginning of the vector. + if (hasFavorites) + mFirstLetterIndex.insert(mFirstLetterIndex.begin(), favoriteChar); + + if (hasFolders) + mFirstLetterIndex.insert(mFirstLetterIndex.begin(), folderChar); +} diff --git a/es-app/src/views/gamelist/ISimpleGameListView.h b/es-app/src/views/gamelist/ISimpleGameListView.h index b25bdb29a..1c72738fb 100644 --- a/es-app/src/views/gamelist/ISimpleGameListView.h +++ b/es-app/src/views/gamelist/ISimpleGameListView.h @@ -33,12 +33,15 @@ public: virtual bool input(InputConfig* config, Input input) override; virtual void launch(FileData* game) override = 0; + virtual const std::vector& getFirstLetterIndex() override = 0; + protected: virtual std::string getQuickSystemSelectRightButton() = 0; virtual std::string getQuickSystemSelectLeftButton() = 0; virtual void populateList(const std::vector& files) = 0; void generateGamelistInfo(const std::vector& files); + void generateFirstLetterIndex(const std::vector& files); TextComponent mHeaderText; ImageComponent mHeaderImage; @@ -47,6 +50,8 @@ protected: std::vector mThemeExtras; std::stack mCursorStack; + std::vector mFirstLetterIndex; + unsigned int mGameCount; unsigned int mFavoritesGameCount; unsigned int mFilteredGameCount;