From cfad51fdb43dec34c274b7fcf9c5719872c7b18a Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 8 Nov 2020 16:34:33 +0100 Subject: [PATCH] Added the ability to filter on game names. --- CONTRIBUTING.md | 2 +- es-app/src/FileFilterIndex.cpp | 32 +++++++++++++++-- es-app/src/FileFilterIndex.h | 11 ++++-- es-app/src/guis/GuiGamelistFilter.cpp | 50 ++++++++++++++++++++++++--- es-app/src/guis/GuiGamelistFilter.h | 1 + 5 files changed, 86 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 057ee0bc3..d9f202388 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,7 +47,7 @@ https://google.github.io/styleguide/cppguide.html * Name member variables starting with a small 'm', e.g. mMyMemberVariable * Use the same naming convention for functions as for local variables, e.g. someFunction() * Inline functions makes perfect sense to use, but don't overdo it by using them for functions that won't be called very frequently -* Never put more than one statement on a single line (there are some exceptions though like lambda expressions and some switch statements) +* Never put more than one statement on a single line (there are some exceptions though like lambda expressions and possibly switch statements) * Avoid overoptimizations, especially if it sacrifices readability, makes the code hard to expand on or is error prone * For the rest, check the code and have fun! :) diff --git a/es-app/src/FileFilterIndex.cpp b/es-app/src/FileFilterIndex.cpp index d8b70ed0a..8dc0b7d63 100644 --- a/es-app/src/FileFilterIndex.cpp +++ b/es-app/src/FileFilterIndex.cpp @@ -19,7 +19,8 @@ #define INCLUDE_UNKNOWN false; FileFilterIndex::FileFilterIndex() - : filterByFavorites(false), + : mFilterByText(false), + filterByFavorites(false), filterByGenre(false), filterByPlayers(false), filterByPubDev(false), @@ -269,6 +270,16 @@ void FileFilterIndex::setFilter(FilterIndexType type, std::vector* return; } + void FileFilterIndex::setTextFilter(std::string textFilter) + { + mTextFilter = textFilter; + + if (textFilter == "") + mFilterByText = false; + else + mFilterByText = true; + }; + void FileFilterIndex::clearAllFilters() { for (std::vector::const_iterator it = filterDataDecl.cbegin(); @@ -353,8 +364,19 @@ bool FileFilterIndex::showFile(FileData* game) return false; } + bool nameMatch = false; bool keepGoing = false; + // Name filters take precedence over all other filters, so if there is no match for + // the game name, then always return false. + if (mTextFilter != "" && !(Utils::String::toUpper(game-> + getName()).find(mTextFilter) != std::string::npos)) { + return false; + } + else if (mTextFilter != "") { + nameMatch = true; + } + for (std::vector::const_iterator it = filterDataDecl.cbegin(); it != filterDataDecl.cend(); ++it ) { FilterDataDecl filterData = (*it); @@ -377,7 +399,13 @@ bool FileFilterIndex::showFile(FileData* game) return false; } } - return keepGoing; + + // If there is a match for the game name, but not for any other filters, then return + // true as it means that the name filter is the only applied filter. + if (!keepGoing && nameMatch) + return true; + else + return keepGoing; } bool FileFilterIndex::isKeyBeingFilteredBy(std::string key, FilterIndexType type) diff --git a/es-app/src/FileFilterIndex.h b/es-app/src/FileFilterIndex.h index a51a649d3..15f16630d 100644 --- a/es-app/src/FileFilterIndex.h +++ b/es-app/src/FileFilterIndex.h @@ -50,12 +50,14 @@ public: void addToIndex(FileData* game); void removeFromIndex(FileData* game); void setFilter(FilterIndexType type, std::vector* values); + void setTextFilter(std::string textFilter); + std::string getTextFilter() { return mTextFilter; }; void clearAllFilters(); void debugPrintIndexes(); bool showFile(FileData* game); - bool isFiltered() { return (filterByFavorites || filterByGenre || filterByPlayers || - filterByPubDev || filterByRatings || filterByKidGame || filterByCompleted || - filterByBroken || filterByHidden ); }; + bool isFiltered() { return (mFilterByText || filterByFavorites || filterByGenre || + filterByPlayers || filterByPubDev || filterByRatings || filterByKidGame || + filterByCompleted || filterByBroken || filterByHidden ); }; bool isKeyBeingFilteredBy(std::string key, FilterIndexType type); std::vector& getFilterDataDecls(); @@ -82,6 +84,9 @@ private: void clearIndex(std::map indexMap); + std::string mTextFilter; + bool mFilterByText; + bool filterByFavorites; bool filterByGenre; bool filterByPlayers; diff --git a/es-app/src/guis/GuiGamelistFilter.cpp b/es-app/src/guis/GuiGamelistFilter.cpp index 10bee7896..8889e7361 100644 --- a/es-app/src/guis/GuiGamelistFilter.cpp +++ b/es-app/src/guis/GuiGamelistFilter.cpp @@ -11,6 +11,7 @@ #include "guis/GuiGamelistFilter.h" #include "components/OptionListComponent.h" +#include "guis/GuiTextEditPopup.h" #include "views/UIModeController.h" #include "views/ViewController.h" #include "SystemData.h" @@ -73,11 +74,15 @@ void GuiGamelistFilter::resetAllFilters() } mFilterIndex->resetFilters(); - for (std::map - >>::const_iterator it = mFilterOptions.cbegin(); it != mFilterOptions.cend(); ++it ) { - std::shared_ptr< OptionListComponent > optionList = it->second; + for (std::map>>:: + const_iterator it = mFilterOptions.cbegin(); it != mFilterOptions.cend(); ++it ) { + std::shared_ptr> optionList = it->second; optionList->selectNone(); } + bool testbool = mFilterIndex->isFiltered(); + + mFilterIndex->setTextFilter(""); + mTextFilterField->setValue(""); } GuiGamelistFilter::~GuiGamelistFilter() @@ -87,6 +92,43 @@ GuiGamelistFilter::~GuiGamelistFilter() void GuiGamelistFilter::addFiltersToMenu() { + ComponentListRow row; + + auto lbl = std::make_shared(mWindow, + Utils::String::toUpper("TEXT FILTER (GAME NAME)"), + Font::get(FONT_SIZE_MEDIUM), 0x777777FF); + + mTextFilterField = std::make_shared(mWindow, "", + Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_RIGHT); + + row.addElement(lbl, true); + row.addElement(mTextFilterField, true); + + auto spacer = std::make_shared(mWindow); + spacer->setSize(Renderer::getScreenWidth() * 0.005f, 0); + row.addElement(spacer, false); + + auto bracket = std::make_shared(mWindow); + bracket->setImage(":/graphics/arrow.svg"); + bracket->setResize(Vector2f(0, lbl->getFont()->getLetterHeight())); + row.addElement(bracket, false); + + mTextFilterField->setValue(mFilterIndex->getTextFilter()); + + // Callback function. + auto updateVal = [this](const std::string& newVal) { + mTextFilterField->setValue(Utils::String::toUpper(newVal)); + mFilterIndex->setTextFilter(Utils::String::toUpper(newVal)); + }; + + row.makeAcceptInputHandler([this, updateVal] { + mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), + "TEXT FILTER (GAME NAME)", mTextFilterField->getValue(), + updateVal, false, "OK", "APPLY CHANGES?")); + }); + + mMenu.addRow(row); + std::vector decls = mFilterIndex->getFilterDataDecls(); int skip = 0; @@ -108,7 +150,7 @@ void GuiGamelistFilter::addFiltersToMenu() ComponentListRow row; // Add genres. - optionList = std::make_shared< OptionListComponent> + optionList = std::make_shared> (mWindow, getHelpStyle(), menuLabel, true); for (auto it: *allKeys) optionList->add(it.first, it.first, mFilterIndex->isKeyBeingFilteredBy(it.first, type)); diff --git a/es-app/src/guis/GuiGamelistFilter.h b/es-app/src/guis/GuiGamelistFilter.h index c2ade8037..6649ff069 100644 --- a/es-app/src/guis/GuiGamelistFilter.h +++ b/es-app/src/guis/GuiGamelistFilter.h @@ -41,6 +41,7 @@ private: MenuComponent mMenu; SystemData* mSystem; FileFilterIndex* mFilterIndex; + std::shared_ptr mTextFilterField; }; #endif // ES_APP_GUIS_GUI_GAME_LIST_FILTER_H