From a60fe463d4b6f02fbcb7ef8d4614541788ad32ac Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Fri, 28 Jun 2013 19:44:28 +0200 Subject: [PATCH] Support sorting of game list via input You can now map the functions "sortordernext" and "sortorderprevious" to inputs (in es_input.cfg) and toggle the game list sort order with them. The order is: "file name, ascending" (default), "file name, descending", "rating ascending", "rating descending", "user rating ascending", "user rating descending", "time played ascending", "times played descending", "last played time ascending", "last played time descending". --- src/FolderData.cpp | 47 +++++++++++++++++------ src/FolderData.h | 23 ++++++++++-- src/InputManager.cpp | 3 ++ src/components/GuiGameList.cpp | 69 +++++++++++++++++++++++++++++++++- src/components/GuiGameList.h | 8 ++++ 5 files changed, 134 insertions(+), 16 deletions(-) diff --git a/src/FolderData.cpp b/src/FolderData.cpp index 2d229b675..ac9e08477 100644 --- a/src/FolderData.cpp +++ b/src/FolderData.cpp @@ -4,6 +4,9 @@ #include #include + +std::map FolderData::sortStateNameMap; + bool FolderData::isFolder() const { return true; } const std::string & FolderData::getName() const { return mName; } const std::string & FolderData::getPath() const { return mPath; } @@ -11,10 +14,16 @@ unsigned int FolderData::getFileCount() { return mFileVector.size(); } FolderData::FolderData(SystemData* system, std::string path, std::string name) + : mSystem(system), mPath(path), mName(name) { - mSystem = system; - mPath = path; - mName = name; + //first created folder data initializes the list + if (sortStateNameMap.empty()) { + sortStateNameMap[compareFileName] = "file name"; + sortStateNameMap[compareRating] = "rating"; + sortStateNameMap[compareUserRating] = "user rating"; + sortStateNameMap[compareTimesPlayed] = "times played"; + sortStateNameMap[compareLastPlayed] = "last time played"; + } } FolderData::~FolderData() @@ -32,6 +41,22 @@ void FolderData::pushFileData(FileData* file) mFileVector.push_back(file); } +//sort this folder and any subfolders +void FolderData::sort(ComparisonFunction & comparisonFunction, bool ascending) +{ + std::sort(mFileVector.begin(), mFileVector.end(), comparisonFunction); + + for(unsigned int i = 0; i < mFileVector.size(); i++) + { + if(mFileVector.at(i)->isFolder()) + ((FolderData*)mFileVector.at(i))->sort(comparisonFunction, ascending); + } + + if (!ascending) { + std::reverse(mFileVector.begin(), mFileVector.end()); + } +} + //returns if file1 should come before file2 bool FolderData::compareFileName(const FileData* file1, const FileData* file2) { @@ -95,16 +120,16 @@ bool FolderData::compareLastPlayed(const FileData* file1, const FileData* file2) return false; } -//sort this folder and any subfolders -void FolderData::sort() +std::string FolderData::getSortStateName(ComparisonFunction & comparisonFunction, bool ascending) { - std::sort(mFileVector.begin(), mFileVector.end(), compareFileName); - - for(unsigned int i = 0; i < mFileVector.size(); i++) - { - if(mFileVector.at(i)->isFolder()) - ((FolderData*)mFileVector.at(i))->sort(); + std::string temp = sortStateNameMap[comparisonFunction]; + if (ascending) { + temp.append(" (ascending)"); } + else { + temp.append(" (descending)"); + } + return temp; } FileData* FolderData::getFile(unsigned int i) const diff --git a/src/FolderData.h b/src/FolderData.h index 7391f824e..6f47329c7 100644 --- a/src/FolderData.h +++ b/src/FolderData.h @@ -1,14 +1,30 @@ #ifndef _FOLDER_H_ #define _FOLDER_H_ -#include "FileData.h" +#include #include +#include "FileData.h" + + class SystemData; //This class lets us hold a vector of FileDatas within under a common name. class FolderData : public FileData { +public: + typedef bool ComparisonFunction(const FileData* a, const FileData* b); + struct SortState + { + ComparisonFunction & comparisonFunction; + bool ascending; + + SortState(ComparisonFunction & sortFunction, bool sortAscending) : comparisonFunction(sortFunction), ascending(sortAscending) {} + }; + +private: + static std::map sortStateNameMap; + public: FolderData(SystemData* system, std::string path, std::string name); ~FolderData(); @@ -24,13 +40,14 @@ public: void pushFileData(FileData* file); - void sort(); - + void sort(ComparisonFunction & comparisonFunction = compareFileName, bool ascending = true); static bool compareFileName(const FileData* file1, const FileData* file2); static bool compareRating(const FileData* file1, const FileData* file2); static bool compareUserRating(const FileData* file1, const FileData* file2); static bool compareTimesPlayed(const FileData* file1, const FileData* file2); static bool compareLastPlayed(const FileData* file1, const FileData* file2); + static std::string getSortStateName(ComparisonFunction & comparisonFunction = compareFileName, bool ascending = true); + private: SystemData* mSystem; std::string mPath; diff --git a/src/InputManager.cpp b/src/InputManager.cpp index e3490e207..8a4b916be 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -404,6 +404,9 @@ void InputManager::loadDefaultConfig() cfg->mapInput("mastervolup", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_PLUS, 1, true)); cfg->mapInput("mastervoldown", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_MINUS, 1, true)); + + cfg->mapInput("sortordernext", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_F7, 1, true)); + cfg->mapInput("sortorderprevious", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_F8, 1, true)); } void InputManager::writeConfig() diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index a65c94668..044aa0325 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -7,15 +7,31 @@ #include "../Log.h" #include "../Settings.h" + +std::vector GuiGameList::sortStates; + + Vector2i GuiGameList::getImagePos() { return Vector2i((int)(Renderer::getScreenWidth() * mTheme->getFloat("gameImageOffsetX")), (int)(Renderer::getScreenHeight() * mTheme->getFloat("gameImageOffsetY"))); } GuiGameList::GuiGameList(Window* window, bool useDetail) : GuiComponent(window), - mDescription(window), mTransitionImage(window, 0, 0, "", Renderer::getScreenWidth(), Renderer::getScreenHeight(), true) + mDescription(window), mTransitionImage(window, 0, 0, "", Renderer::getScreenWidth(), Renderer::getScreenHeight(), true), mDetailed(useDetail), sortStateIndex(0) { - mDetailed = useDetail; + //first object initializes the vector + if (sortStates.empty()) { + sortStates.push_back(FolderData::SortState(FolderData::compareFileName, true)); + sortStates.push_back(FolderData::SortState(FolderData::compareFileName, false)); + sortStates.push_back(FolderData::SortState(FolderData::compareRating, true)); + sortStates.push_back(FolderData::SortState(FolderData::compareRating, false)); + sortStates.push_back(FolderData::SortState(FolderData::compareUserRating, true)); + sortStates.push_back(FolderData::SortState(FolderData::compareUserRating, false)); + sortStates.push_back(FolderData::SortState(FolderData::compareTimesPlayed, true)); + sortStates.push_back(FolderData::SortState(FolderData::compareTimesPlayed, false)); + sortStates.push_back(FolderData::SortState(FolderData::compareLastPlayed, true)); + sortStates.push_back(FolderData::SortState(FolderData::compareLastPlayed, false)); + } mTheme = new ThemeComponent(mWindow, mDetailed); @@ -190,6 +206,16 @@ bool GuiGameList::input(InputConfig* config, Input input) } } + //change sort order + if(config->isMappedTo("sortordernext", input) && input.value != 0) { + setNextSortIndex(); + //std::cout << "Sort order is " << FolderData::getSortStateName(sortStates.at(sortStateIndex).comparisonFunction, sortStates.at(sortStateIndex).ascending) << std::endl; + } + else if(config->isMappedTo("sortorderprevious", input) && input.value != 0) { + setPreviousSortIndex(); + //std::cout << "Sort order is " << FolderData::getSortStateName(sortStates.at(sortStateIndex).comparisonFunction, sortStates.at(sortStateIndex).ascending) << std::endl; + } + //open the "start menu" if(config->isMappedTo("menu", input) && input.value != 0) { @@ -219,6 +245,45 @@ bool GuiGameList::input(InputConfig* config, Input input) return false; } +void GuiGameList::setSortIndex(size_t index) +{ + //make the index valid + if (index >= sortStates.size()) { + index = 0; + } + if (index != sortStateIndex) { + //get sort state from vector and sort list + sortStateIndex = index; + sort(sortStates.at(sortStateIndex).comparisonFunction, sortStates.at(sortStateIndex).ascending); + } +} + +void GuiGameList::setNextSortIndex() +{ + //make the index wrap around + if ((sortStateIndex - 1) >= sortStates.size()) { + setSortIndex(0); + } + setSortIndex(sortStateIndex + 1); +} + +void GuiGameList::setPreviousSortIndex() +{ + //make the index wrap around + if (((int)sortStateIndex - 1) < 0) { + setSortIndex(sortStates.size() - 1); + } + setSortIndex(sortStateIndex - 1); +} + +void GuiGameList::sort(FolderData::ComparisonFunction & comparisonFunction, bool ascending) +{ + //resort list and update it + mFolder->sort(comparisonFunction, ascending); + updateList(); + updateDetailData(); +} + void GuiGameList::updateList() { if(mDetailed) diff --git a/src/components/GuiGameList.h b/src/components/GuiGameList.h index 7f51a0f15..2dae2f2ba 100644 --- a/src/components/GuiGameList.h +++ b/src/components/GuiGameList.h @@ -17,6 +17,9 @@ //It has a TextListComponent child that handles the game list, a ThemeComponent that handles the theming system, and an ImageComponent for game images. class GuiGameList : public GuiComponent { + static std::vector sortStates; + size_t sortStateIndex; + public: GuiGameList(Window* window, bool useDetail = false); virtual ~GuiGameList(); @@ -32,6 +35,11 @@ public: void updateDetailData(); + void setSortIndex(size_t index); + void setNextSortIndex(); + void setPreviousSortIndex(); + void sort(FolderData::ComparisonFunction & comparisonFunction = FolderData::compareFileName, bool ascending = true); + static GuiGameList* create(Window* window); static const float sInfoWidth;