Rewrote and moved the quick selector letter index generation.

This commit is contained in:
Leon Styhre 2020-10-30 18:34:05 +01:00
parent 7f0aede274
commit 005952addf
10 changed files with 88 additions and 94 deletions

View file

@ -439,10 +439,8 @@ void FileData::removeChild(FileData* file)
void FileData::sort(ComparisonFunction& comparator, bool ascending,
std::pair<unsigned int, unsigned int>& gameCount)
{
mFirstLetterIndex.clear();
mOnlyFolders = true;
bool foldersOnTop = Settings::getInstance()->getBool("FoldersOnTop");
bool hasFolders = false;
std::vector<FileData*> mChildrenFolders;
std::vector<FileData*> mChildrenOthers;
@ -454,9 +452,6 @@ void FileData::sort(ComparisonFunction& comparator, bool ascending,
if (mSystem->isCollection() && mSystem->getFullName() == "collections") {
std::pair<unsigned int, unsigned int> 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<unsigned int, unsigned int>& gameCount)
{
mFirstLetterIndex.clear();
mOnlyFolders = true;
std::vector<FileData*> mChildrenFolders;
std::vector<FileData*> mChildrenFavoritesFolders;
std::vector<FileData*> mChildrenFavorites;
std::vector<FileData*> 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<unsigned int, unsigned int> 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());

View file

@ -55,8 +55,6 @@ public:
inline const std::vector<FileData*>& getChildren() const { return mChildren; }
inline SystemData* getSystem() const { return mSystem; }
inline SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
const std::vector<std::string>& getFirstLetterIndex() const
{ return mFirstLetterIndex; };
const bool getOnlyFoldersFlag() { return mOnlyFolders; }
bool viewHasOnlyFolders();
static const std::string getROMDirectory();
@ -148,7 +146,6 @@ private:
std::unordered_map<std::string,FileData*> mChildrenByFilename;
std::vector<FileData*> mChildren;
std::vector<FileData*> mFilteredChildren;
std::vector<std::string> mFirstLetterIndex;
// The pair includes non-favorite games, and favorite games.
std::pair<unsigned int, unsigned int> mGameCount;
bool mOnlyFolders;

View file

@ -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.

View file

@ -58,6 +58,7 @@ void BasicGameListView::populateList(const std::vector<FileData*>& files)
std::string inCollectionPrefix;
generateGamelistInfo(files);
generateFirstLetterIndex(files);
if (CollectionSystemManager::get()->isEditing()) {
editingCollection = CollectionSystemManager::get()->getEditingCollection();

View file

@ -38,6 +38,9 @@ public:
virtual bool isListScrolling() override { return mList.isScrolling(); };
virtual void stopListScrolling() override { mList.stopScrolling(); };
virtual const std::vector<std::string>& getFirstLetterIndex() override
{ return mFirstLetterIndex; };
protected:
virtual std::string getQuickSystemSelectRightButton() override;
virtual std::string getQuickSystemSelectLeftButton() override;

View file

@ -249,6 +249,7 @@ void GridGameListView::populateList(const std::vector<FileData*>& files)
firstGameEntry = nullptr;
generateGamelistInfo(files);
generateFirstLetterIndex(files);
mGrid.clear();
mHeaderText.setText(mRoot->getSystem()->getFullName());

View file

@ -41,6 +41,9 @@ public:
virtual std::vector<HelpPrompt> getHelpPrompts() override;
virtual void launch(FileData* game) override;
virtual const std::vector<std::string>& getFirstLetterIndex() override
{ return mFirstLetterIndex; };
protected:
virtual void update(int deltaTime) override;
virtual std::string getQuickSystemSelectRightButton() override;

View file

@ -46,6 +46,7 @@ public:
virtual FileData* getFirstEntry() = 0;
virtual FileData* getLastEntry() = 0;
virtual FileData* getFirstGameEntry() = 0;
virtual const std::vector<std::string>& getFirstLetterIndex() = 0;
virtual bool input(InputConfig* config, Input input) override;
virtual void remove(FileData* game, bool deleteFile) = 0;

View file

@ -373,3 +373,65 @@ void ISimpleGameListView::generateGamelistInfo(const std::vector<FileData*>& fil
if (files.size() > 0 && files.front()->getParent() != mRoot)
mIsFolder = true;
}
void ISimpleGameListView::generateFirstLetterIndex(const std::vector<FileData*>& 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);
}

View file

@ -33,12 +33,15 @@ public:
virtual bool input(InputConfig* config, Input input) override;
virtual void launch(FileData* game) override = 0;
virtual const std::vector<std::string>& getFirstLetterIndex() override = 0;
protected:
virtual std::string getQuickSystemSelectRightButton() = 0;
virtual std::string getQuickSystemSelectLeftButton() = 0;
virtual void populateList(const std::vector<FileData*>& files) = 0;
void generateGamelistInfo(const std::vector<FileData*>& files);
void generateFirstLetterIndex(const std::vector<FileData*>& files);
TextComponent mHeaderText;
ImageComponent mHeaderImage;
@ -47,6 +50,8 @@ protected:
std::vector<GuiComponent*> mThemeExtras;
std::stack<FileData*> mCursorStack;
std::vector<std::string> mFirstLetterIndex;
unsigned int mGameCount;
unsigned int mFavoritesGameCount;
unsigned int mFilteredGameCount;