From 556b9fa3fee8ddaa91d70e7fd292be4c1fdfa498 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Fri, 28 Jun 2013 14:54:14 +0200 Subject: [PATCH 1/7] Add functions for writing data to gamelist.xml Also add a "rating" and "timePlayed" variable to GameData. Some cleanup in GameData and FolderData. Added sorting functions for rating and timesPlayed to FolderData. Testing and UI support still tbd. --- src/FileData.h | 6 +- src/FolderData.cpp | 100 ++++++++++++++++++++++++----- src/FolderData.h | 14 +++-- src/GameData.cpp | 101 +++++++++++++++++++++++------- src/GameData.h | 40 +++++++++--- src/SystemData.cpp | 7 +++ src/XMLReader.cpp | 152 ++++++++++++++++++++++++++++++++++++++++----- src/XMLReader.h | 3 + 8 files changed, 352 insertions(+), 71 deletions(-) diff --git a/src/FileData.h b/src/FileData.h index a0c7abde8..ebb44b9b9 100644 --- a/src/FileData.h +++ b/src/FileData.h @@ -9,9 +9,9 @@ class FileData { public: virtual ~FileData() { }; - virtual bool isFolder() = 0; - virtual std::string getName() = 0; - virtual std::string getPath() = 0; + virtual bool isFolder() const = 0; + virtual const std::string & getName() const = 0; + virtual const std::string & getPath() const = 0; }; #endif diff --git a/src/FolderData.cpp b/src/FolderData.cpp index 2bc937cca..5ea2cd8e5 100644 --- a/src/FolderData.cpp +++ b/src/FolderData.cpp @@ -1,13 +1,14 @@ #include "FolderData.h" #include "SystemData.h" +#include "GameData.h" #include #include -bool FolderData::isFolder() { return true; } -std::string FolderData::getName() { return mName; } -std::string FolderData::getPath() { return mPath; } +bool FolderData::isFolder() const { return true; } +const std::string & FolderData::getName() const { return mName; } +const std::string & FolderData::getPath() const { return mPath; } unsigned int FolderData::getFileCount() { return mFileVector.size(); } -FileData* FolderData::getFile(unsigned int i) { return mFileVector.at(i); } + FolderData::FolderData(SystemData* system, std::string path, std::string name) { @@ -32,7 +33,7 @@ void FolderData::pushFileData(FileData* file) } //returns if file1 should come before file2 -bool filesort(FileData* file1, FileData* file2) +bool FolderData::compareFileName(const FileData* file1, const FileData* file2) { std::string name1 = file1->getName(); std::string name2 = file2->getName(); @@ -43,25 +44,39 @@ bool filesort(FileData* file1, FileData* file2) { if(toupper(name1[i]) != toupper(name2[i])) { - if(toupper(name1[i]) < toupper(name2[i])) - { - return true; - }else{ - return false; - } + return toupper(name1[i]) < toupper(name2[i]); } } - if(name1.length() < name2.length()) - return true; - else - return false; + return name1.length() < name2.length(); +} + +bool FolderData::compareRating(const FileData* file1, const FileData* file2) +{ + //we need game data. try to cast + const GameData * game1 = dynamic_cast(file1); + const GameData * game2 = dynamic_cast(file2); + if (game1 != nullptr && game2 != nullptr) { + return game1->getRating() < game2->getRating(); + } + return false; +} + +bool FolderData::compareTimesPlayed(const FileData* file1, const FileData* file2) +{ + //we need game data. try to cast + const GameData * game1 = dynamic_cast(file1); + const GameData * game2 = dynamic_cast(file2); + if (game1 != nullptr && game2 != nullptr) { + return game1->getTimesPlayed() < game2->getTimesPlayed(); + } + return false; } //sort this folder and any subfolders void FolderData::sort() { - std::sort(mFileVector.begin(), mFileVector.end(), filesort); + std::sort(mFileVector.begin(), mFileVector.end(), compareFileName); for(unsigned int i = 0; i < mFileVector.size(); i++) { @@ -69,3 +84,56 @@ void FolderData::sort() ((FolderData*)mFileVector.at(i))->sort(); } } + +FileData* FolderData::getFile(unsigned int i) const +{ + return mFileVector.at(i); +} + +std::vector FolderData::getFiles(bool onlyFiles) const +{ + std::vector temp; + //now check if a child is a folder and get those children in turn + std::vector::const_iterator fdit = mFileVector.cbegin(); + while(fdit != mFileVector.cend()) { + //dynamically try to cast to FolderData type + FolderData * folder = dynamic_cast(*fdit); + if (folder != nullptr) { + //add this only when user wanted it + if (!onlyFiles) { + temp.push_back(*fdit); + } + } + else { + temp.push_back(*fdit); + } + ++fdit; + } + return temp; +} + +std::vector FolderData::getFilesRecursive(bool onlyFiles) const +{ + std::vector temp; + //now check if a child is a folder and get those children in turn + std::vector::const_iterator fdit = mFileVector.cbegin(); + while(fdit != mFileVector.cend()) { + //dynamically try to cast to FolderData type + FolderData * folder = dynamic_cast(*fdit); + if (folder != nullptr) { + //add this onyl when user wanted it + if (!onlyFiles) { + temp.push_back(*fdit); + } + //worked. Is actual folder data. recurse + std::vector children = folder->getFilesRecursive(onlyFiles); + //insert children into return vector + temp.insert(temp.end(), children.cbegin(), children.cend()); + } + else { + temp.push_back(*fdit); + } + ++fdit; + } + return temp; +} \ No newline at end of file diff --git a/src/FolderData.h b/src/FolderData.h index e453ac5e7..d91d69c64 100644 --- a/src/FolderData.h +++ b/src/FolderData.h @@ -13,16 +13,22 @@ public: FolderData(SystemData* system, std::string path, std::string name); ~FolderData(); - bool isFolder(); - std::string getName(); - std::string getPath(); + bool isFolder() const; + const std::string & getName() const; + const std::string & getPath() const; unsigned int getFileCount(); - FileData* getFile(unsigned int i); + FileData* getFile(unsigned int i) const; + std::vector getFiles(bool onlyFiles = false) const; + std::vector getFilesRecursive(bool onlyFiles = false) const; void pushFileData(FileData* file); void sort(); + + static bool compareFileName(const FileData* file1, const FileData* file2); + static bool compareRating(const FileData* file1, const FileData* file2); + static bool compareTimesPlayed(const FileData* file1, const FileData* file2); private: SystemData* mSystem; std::string mPath; diff --git a/src/GameData.cpp b/src/GameData.cpp index bb656be01..f72d9f9a4 100644 --- a/src/GameData.cpp +++ b/src/GameData.cpp @@ -2,23 +2,88 @@ #include #include -bool GameData::isFolder() { return false; } -std::string GameData::getName() { return mName; } -std::string GameData::getPath() { return mPath; } -std::string GameData::getDescription() { return mDescription; } -std::string GameData::getImagePath() { return mImagePath; } + +const std::string GameData::xmlTagGameList = "gameList"; +const std::string GameData::xmlTagGame = "game"; +const std::string GameData::xmlTagName = "name"; +const std::string GameData::xmlTagPath = "path"; +const std::string GameData::xmlTagDescription = "desc"; +const std::string GameData::xmlTagImagePath = "image"; +const std::string GameData::xmlTagRating = "rating"; +const std::string GameData::xmlTagTimesPlayed = "timesplayed"; + GameData::GameData(SystemData* system, std::string path, std::string name) + : mSystem(system), mPath(path), mName(name), mRating(0), mTimesPlayed(0) { - mSystem = system; - mPath = path; - mName = name; - - mDescription = ""; - mImagePath = ""; } -std::string GameData::getBashPath() +bool GameData::isFolder() const +{ + return false; +} + +const std::string & GameData::getName() const +{ + return mName; +} + +void GameData::setName(const std::string & name) +{ + mName = name; +} + +const std::string & GameData::getPath() const +{ + return mPath; +} + +void GameData::setPath(const std::string & path) +{ + mPath = path; +} + +const std::string & GameData::getDescription() const +{ + return mDescription; +} + +void GameData::setDescription(const std::string & description) +{ + mDescription = description; +} + +const std::string & GameData::getImagePath() const +{ + return mImagePath; +} + +void GameData::setImagePath(const std::string & imagePath) +{ + mImagePath = imagePath; +} + +size_t GameData::getRating() const +{ + return mRating; +} + +void GameData::setRating(size_t rating) +{ + mRating = rating; +} + +size_t GameData::getTimesPlayed() const +{ + return mTimesPlayed; +} + +void GameData::setTimesPlayed(size_t timesPlayed) +{ + mTimesPlayed = timesPlayed; +} + +std::string GameData::getBashPath() const { //a quick and dirty way to insert a backslash before most characters that would mess up a bash path std::string path = mPath; @@ -44,18 +109,8 @@ std::string GameData::getBashPath() } //returns the boost::filesystem stem of our path - e.g. for "/foo/bar.rom" returns "bar" -std::string GameData::getBaseName() +std::string GameData::getBaseName() const { boost::filesystem::path path(mPath); return path.stem().string(); } - -void GameData::set(std::string name, std::string description, std::string imagePath) -{ - if(!name.empty()) - mName = name; - if(!description.empty()) - mDescription = description; - if(!imagePath.empty() && boost::filesystem::exists(imagePath)) - mImagePath = imagePath; -} diff --git a/src/GameData.h b/src/GameData.h index ad0db2038..bd34be4ea 100644 --- a/src/GameData.h +++ b/src/GameData.h @@ -9,19 +9,41 @@ class GameData : public FileData { public: + //static tag names for reading/writing XML documents. This might fail in PUGIXML_WCHAR_MODE + //TODO: The class should have member to read fromXML() and write toXML() probably... + static const std::string xmlTagGameList; + static const std::string xmlTagGame; + static const std::string xmlTagName; + static const std::string xmlTagPath; + static const std::string xmlTagDescription; + static const std::string xmlTagImagePath; + static const std::string xmlTagRating; + static const std::string xmlTagTimesPlayed; + GameData(SystemData* system, std::string path, std::string name); - void set(std::string name = "", std::string description = "", std::string imagePath = ""); + const std::string & getName() const; + void setName(const std::string & name); - std::string getName(); - std::string getPath(); - std::string getBashPath(); - std::string getBaseName(); + const std::string & getPath() const; + void setPath(const std::string & path); - std::string getDescription(); - std::string getImagePath(); + const std::string & getDescription() const; + void setDescription(const std::string & description); - bool isFolder(); + const std::string & getImagePath() const; + void setImagePath(const std::string & imagePath); + + size_t getRating() const; + void setRating(size_t rating); + + size_t getTimesPlayed() const; + void setTimesPlayed(size_t timesPlayed); + + std::string getBashPath() const; + std::string getBaseName() const; + + bool isFolder() const; private: SystemData* mSystem; std::string mPath; @@ -30,6 +52,8 @@ private: //extra data std::string mDescription; std::string mImagePath; + size_t mRating; + size_t mTimesPlayed; }; #endif diff --git a/src/SystemData.cpp b/src/SystemData.cpp index 2e983e5e4..d77bfb024 100644 --- a/src/SystemData.cpp +++ b/src/SystemData.cpp @@ -50,6 +50,10 @@ SystemData::SystemData(std::string name, std::string descName, std::string start SystemData::~SystemData() { + //save changed game data back to xml + if(!Settings::getInstance()->getBool("IGNOREGAMELIST")) { + updateGamelist(this); + } delete mRootFolder; } @@ -90,6 +94,9 @@ void SystemData::launchGame(Window* window, GameData* game) window->init(); VolumeControl::getInstance()->init(); AudioManager::getInstance()->init(); + + //update number of times the game has been launched + game->setTimesPlayed(game->getTimesPlayed() + 1); } void SystemData::populateFolder(FolderData* folder) diff --git a/src/XMLReader.cpp b/src/XMLReader.cpp index d1e19b8ae..928fbd8ff 100644 --- a/src/XMLReader.cpp +++ b/src/XMLReader.cpp @@ -117,19 +117,19 @@ void parseGamelist(SystemData* system) return; } - pugi::xml_node root = doc.child("gameList"); + pugi::xml_node root = doc.child(GameData::xmlTagGameList.c_str()); if(!root) { - LOG(LogError) << "Could not find node in gamelist \"" << xmlpath << "\"!"; + LOG(LogError) << "Could not find <" << GameData::xmlTagGameList << "> node in gamelist \"" << xmlpath << "\"!"; return; } - for(pugi::xml_node gameNode = root.child("game"); gameNode; gameNode = gameNode.next_sibling("game")) + for(pugi::xml_node gameNode = root.child(GameData::xmlTagGame.c_str()); gameNode; gameNode = gameNode.next_sibling(GameData::xmlTagGame.c_str())) { - pugi::xml_node pathNode = gameNode.child("path"); + pugi::xml_node pathNode = gameNode.child(GameData::xmlTagPath.c_str()); if(!pathNode) { - LOG(LogError) << " node contains no child!"; + LOG(LogError) << "<" << GameData::xmlTagGame << "> node contains no <" << GameData::xmlTagPath << "> child!"; continue; } @@ -152,13 +152,17 @@ void parseGamelist(SystemData* system) //actually gather the information in the XML doc, then pass it to the game's set method std::string newName, newDesc, newImage; - if(gameNode.child("name")) - newName = gameNode.child("name").text().get(); - if(gameNode.child("desc")) - newDesc = gameNode.child("desc").text().get(); - if(gameNode.child("image")) + if(gameNode.child(GameData::xmlTagName.c_str())) { - newImage = gameNode.child("image").text().get(); + game->setName(gameNode.child(GameData::xmlTagName.c_str()).text().get()); + } + if(gameNode.child(GameData::xmlTagDescription.c_str())) + { + game->setDescription(gameNode.child(GameData::xmlTagDescription.c_str()).text().get()); + } + if(gameNode.child(GameData::xmlTagImagePath.c_str())) + { + newImage = gameNode.child(GameData::xmlTagImagePath.c_str()).text().get(); //expand "." if(newImage[0] == '.') @@ -168,15 +172,129 @@ void parseGamelist(SystemData* system) newImage.insert(0, pathname.parent_path().string() ); } - //if the image doesn't exist, forget it - if(!boost::filesystem::exists(newImage)) - newImage = ""; + //if the image exist, set it + if(boost::filesystem::exists(newImage)) + { + game->setImagePath(newImage); + } } - game->set(newName, newDesc, newImage); - - }else{ + //get rating and the times played from the XML doc + if(gameNode.child(GameData::xmlTagRating.c_str())) + { + size_t rating; + std::istringstream(gameNode.child(GameData::xmlTagRating.c_str()).text().get()) >> rating; + game->setRating(rating); + } + if(gameNode.child(GameData::xmlTagTimesPlayed.c_str())) + { + size_t timesPlayed; + std::istringstream(gameNode.child(GameData::xmlTagTimesPlayed.c_str()).text().get()) >> timesPlayed; + game->setRating(timesPlayed); + } + } + else{ LOG(LogWarning) << "Game at \"" << path << "\" does not exist!"; } } } + +void addGameDataNode(pugi::xml_node & parent, const GameData * game) +{ + //create game and add to parent node + pugi::xml_node newGame = parent.append_child(GameData::xmlTagGame.c_str()); + //add values + if (!game->getPath().empty()) { + pugi::xml_node pathNode = newGame.append_child(GameData::xmlTagPath.c_str()); + pathNode.text().set(game->getPath().c_str()); + } + if (!game->getName().empty()) { + pugi::xml_node nameNode = newGame.append_child(GameData::xmlTagName.c_str()); + nameNode.text().set(game->getName().c_str()); + } + if (!game->getDescription().empty()) { + pugi::xml_node descriptionNode = newGame.append_child(GameData::xmlTagDescription.c_str()); + descriptionNode.text().set(game->getDescription().c_str()); + } + if (!game->getImagePath().empty()) { + pugi::xml_node imagePathNode = newGame.append_child(GameData::xmlTagImagePath.c_str()); + imagePathNode.text().set(game->getImagePath().c_str()); + } + //all other values are added regardless of their value + pugi::xml_node ratingNode = newGame.append_child(GameData::xmlTagRating.c_str()); + ratingNode.text().set(std::to_string((unsigned long long)game->getRating()).c_str()); + pugi::xml_node timesPlayedNode = newGame.append_child(GameData::xmlTagTimesPlayed.c_str()); + timesPlayedNode.text().set(std::to_string((unsigned long long)game->getTimesPlayed()).c_str()); +} + +void updateGamelist(SystemData* system) +{ + //We do this by reading the XML again, adding changes and then writing it back, + //because there might be information missing in our systemdata which would then miss in the new XML. + //We have the complete information for every game though, so we can simply remove a game + //we already have in the system from the XML, and then add it back from its GameData information... + + std::string xmlpath = system->getGamelistPath(); + if(xmlpath.empty()) { + return; + } + + LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\" before writing..."; + + pugi::xml_document doc; + pugi::xml_parse_result result = doc.load_file(xmlpath.c_str()); + + if(!result) { + LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n " << result.description(); + return; + } + + pugi::xml_node root = doc.child(GameData::xmlTagGameList.c_str()); + if(!root) { + LOG(LogError) << "Could not find <" << GameData::xmlTagGameList << "> node in gamelist \"" << xmlpath << "\"!"; + return; + } + + //now we have all the information from the XML. now iterate through all our games and add information from there + FolderData * rootFolder = system->getRootFolder(); + if (rootFolder != nullptr) { + //get only files, no folders + std::vector files = rootFolder->getFilesRecursive(true); + //iterate through all files, checking if they're already in the XML + std::vector::const_iterator fit = files.cbegin(); + while(fit != files.cend()) { + //try to cast to gamedata + const GameData * game = dynamic_cast(*fit); + if (game != nullptr) { + //worked. check if this games' path can be found somewhere in the XML + for(pugi::xml_node gameNode = root.child(GameData::xmlTagGame.c_str()); gameNode; gameNode = gameNode.next_sibling(GameData::xmlTagGame.c_str())) { + //get path from game node + pugi::xml_node pathNode = gameNode.child(GameData::xmlTagPath.c_str()); + if(!pathNode) + { + LOG(LogError) << "<" << GameData::xmlTagGame << "> node contains no <" << GameData::xmlTagPath << "> child!"; + continue; + } + //check path + if (pathNode.text().get() == game->getPath()) { + //found the game. remove it. it will be added again later with updated values + root.remove_child(gameNode); + //break node search loop + break; + } + } + //either the game content was removed, because it needs to be updated, + //or didn't exist in the first place, so just add it + addGameDataNode(root, game); + } + ++fit; + } + //now write the file + if (!doc.save_file(xmlpath.c_str())) { + LOG(LogError) << "Error saving XML file \"" << xmlpath << "\"!"; + } + } + else { + LOG(LogError) << "Found no root folder for system \"" << system->getName() << "\"!"; + } +} diff --git a/src/XMLReader.h b/src/XMLReader.h index 403c96fcf..ea3b4399b 100644 --- a/src/XMLReader.h +++ b/src/XMLReader.h @@ -7,4 +7,7 @@ class SystemData; //Loads gamelist.xml data into a SystemData. void parseGamelist(SystemData* system); +//Writes changes to SystemData back to a previously loaded gamelist.xml. +void updateGamelist(SystemData* system); + #endif From d99134763fedec2d04b9ae41a053405423424007 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Fri, 28 Jun 2013 16:13:57 +0200 Subject: [PATCH 2/7] Convert rating to float. Fix reading of timesPlayed. http://thegamesdb.net API seems to use a float. Fix a but where the times played was read into the rating member. --- src/GameData.cpp | 6 +++--- src/GameData.h | 6 +++--- src/XMLReader.cpp | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/GameData.cpp b/src/GameData.cpp index f72d9f9a4..908e5603a 100644 --- a/src/GameData.cpp +++ b/src/GameData.cpp @@ -14,7 +14,7 @@ const std::string GameData::xmlTagTimesPlayed = "timesplayed"; GameData::GameData(SystemData* system, std::string path, std::string name) - : mSystem(system), mPath(path), mName(name), mRating(0), mTimesPlayed(0) + : mSystem(system), mPath(path), mName(name), mRating(0.0f), mTimesPlayed(0) { } @@ -63,12 +63,12 @@ void GameData::setImagePath(const std::string & imagePath) mImagePath = imagePath; } -size_t GameData::getRating() const +float GameData::getRating() const { return mRating; } -void GameData::setRating(size_t rating) +void GameData::setRating(float rating) { mRating = rating; } diff --git a/src/GameData.h b/src/GameData.h index bd34be4ea..edcede2c2 100644 --- a/src/GameData.h +++ b/src/GameData.h @@ -34,8 +34,8 @@ public: const std::string & getImagePath() const; void setImagePath(const std::string & imagePath); - size_t getRating() const; - void setRating(size_t rating); + float getRating() const; + void setRating(float rating); size_t getTimesPlayed() const; void setTimesPlayed(size_t timesPlayed); @@ -52,7 +52,7 @@ private: //extra data std::string mDescription; std::string mImagePath; - size_t mRating; + float mRating; size_t mTimesPlayed; }; diff --git a/src/XMLReader.cpp b/src/XMLReader.cpp index 928fbd8ff..47e6527aa 100644 --- a/src/XMLReader.cpp +++ b/src/XMLReader.cpp @@ -182,7 +182,7 @@ void parseGamelist(SystemData* system) //get rating and the times played from the XML doc if(gameNode.child(GameData::xmlTagRating.c_str())) { - size_t rating; + float rating; std::istringstream(gameNode.child(GameData::xmlTagRating.c_str()).text().get()) >> rating; game->setRating(rating); } @@ -190,7 +190,7 @@ void parseGamelist(SystemData* system) { size_t timesPlayed; std::istringstream(gameNode.child(GameData::xmlTagTimesPlayed.c_str()).text().get()) >> timesPlayed; - game->setRating(timesPlayed); + game->setTimesPlayed(timesPlayed); } } else{ @@ -222,7 +222,7 @@ void addGameDataNode(pugi::xml_node & parent, const GameData * game) } //all other values are added regardless of their value pugi::xml_node ratingNode = newGame.append_child(GameData::xmlTagRating.c_str()); - ratingNode.text().set(std::to_string((unsigned long long)game->getRating()).c_str()); + ratingNode.text().set(std::to_string((long double)game->getRating()).c_str()); pugi::xml_node timesPlayedNode = newGame.append_child(GameData::xmlTagTimesPlayed.c_str()); timesPlayedNode.text().set(std::to_string((unsigned long long)game->getTimesPlayed()).c_str()); } From c61a470694b7491c0c2d748e6209eb5c3f343696 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Fri, 28 Jun 2013 17:25:18 +0200 Subject: [PATCH 3/7] Add user rating and last time played to game data That should be about it... --- src/FolderData.cpp | 22 ++++++++++++++++++++++ src/FolderData.h | 2 ++ src/GameData.cpp | 24 +++++++++++++++++++++++- src/GameData.h | 12 ++++++++++++ src/SystemData.cpp | 3 ++- src/XMLReader.cpp | 19 +++++++++++++++++++ 6 files changed, 80 insertions(+), 2 deletions(-) diff --git a/src/FolderData.cpp b/src/FolderData.cpp index 5ea2cd8e5..2d229b675 100644 --- a/src/FolderData.cpp +++ b/src/FolderData.cpp @@ -62,6 +62,17 @@ bool FolderData::compareRating(const FileData* file1, const FileData* file2) return false; } +bool FolderData::compareUserRating(const FileData* file1, const FileData* file2) +{ + //we need game data. try to cast + const GameData * game1 = dynamic_cast(file1); + const GameData * game2 = dynamic_cast(file2); + if (game1 != nullptr && game2 != nullptr) { + return game1->getUserRating() < game2->getUserRating(); + } + return false; +} + bool FolderData::compareTimesPlayed(const FileData* file1, const FileData* file2) { //we need game data. try to cast @@ -73,6 +84,17 @@ bool FolderData::compareTimesPlayed(const FileData* file1, const FileData* file2 return false; } +bool FolderData::compareLastPlayed(const FileData* file1, const FileData* file2) +{ + //we need game data. try to cast + const GameData * game1 = dynamic_cast(file1); + const GameData * game2 = dynamic_cast(file2); + if (game1 != nullptr && game2 != nullptr) { + return game1->getLastPlayed() < game2->getLastPlayed(); + } + return false; +} + //sort this folder and any subfolders void FolderData::sort() { diff --git a/src/FolderData.h b/src/FolderData.h index d91d69c64..7391f824e 100644 --- a/src/FolderData.h +++ b/src/FolderData.h @@ -28,7 +28,9 @@ public: 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); private: SystemData* mSystem; std::string mPath; diff --git a/src/GameData.cpp b/src/GameData.cpp index 908e5603a..ef8384dfd 100644 --- a/src/GameData.cpp +++ b/src/GameData.cpp @@ -10,11 +10,13 @@ const std::string GameData::xmlTagPath = "path"; const std::string GameData::xmlTagDescription = "desc"; const std::string GameData::xmlTagImagePath = "image"; const std::string GameData::xmlTagRating = "rating"; +const std::string GameData::xmlTagUserRating = "userrating"; const std::string GameData::xmlTagTimesPlayed = "timesplayed"; +const std::string GameData::xmlTagLastPlayed = "lastplayed"; GameData::GameData(SystemData* system, std::string path, std::string name) - : mSystem(system), mPath(path), mName(name), mRating(0.0f), mTimesPlayed(0) + : mSystem(system), mPath(path), mName(name), mRating(0.0f), mUserRating(0.0f), mTimesPlayed(0), mLastPlayed(0) { } @@ -73,6 +75,16 @@ void GameData::setRating(float rating) mRating = rating; } +float GameData::getUserRating() const +{ + return mUserRating; +} + +void GameData::setUserRating(float rating) +{ + mUserRating = rating; +} + size_t GameData::getTimesPlayed() const { return mTimesPlayed; @@ -83,6 +95,16 @@ void GameData::setTimesPlayed(size_t timesPlayed) mTimesPlayed = timesPlayed; } +std::time_t GameData::getLastPlayed() const +{ + return mLastPlayed; +} + +void GameData::setLastPlayed(std::time_t lastPlayed) +{ + mLastPlayed = lastPlayed; +} + std::string GameData::getBashPath() const { //a quick and dirty way to insert a backslash before most characters that would mess up a bash path diff --git a/src/GameData.h b/src/GameData.h index edcede2c2..ebfca5e69 100644 --- a/src/GameData.h +++ b/src/GameData.h @@ -2,6 +2,8 @@ #define _GAMEDATA_H_ #include +#include + #include "FileData.h" #include "SystemData.h" @@ -18,7 +20,9 @@ public: static const std::string xmlTagDescription; static const std::string xmlTagImagePath; static const std::string xmlTagRating; + static const std::string xmlTagUserRating; static const std::string xmlTagTimesPlayed; + static const std::string xmlTagLastPlayed; GameData(SystemData* system, std::string path, std::string name); @@ -37,9 +41,15 @@ public: float getRating() const; void setRating(float rating); + float getUserRating() const; + void setUserRating(float rating); + size_t getTimesPlayed() const; void setTimesPlayed(size_t timesPlayed); + std::time_t getLastPlayed() const; + void setLastPlayed(std::time_t lastPlayed); + std::string getBashPath() const; std::string getBaseName() const; @@ -53,7 +63,9 @@ private: std::string mDescription; std::string mImagePath; float mRating; + float mUserRating; size_t mTimesPlayed; + std::time_t mLastPlayed; }; #endif diff --git a/src/SystemData.cpp b/src/SystemData.cpp index d77bfb024..041b47716 100644 --- a/src/SystemData.cpp +++ b/src/SystemData.cpp @@ -95,8 +95,9 @@ void SystemData::launchGame(Window* window, GameData* game) VolumeControl::getInstance()->init(); AudioManager::getInstance()->init(); - //update number of times the game has been launched + //update number of times the game has been launched and the time game->setTimesPlayed(game->getTimesPlayed() + 1); + game->setLastPlayed(std::time(nullptr)); } void SystemData::populateFolder(FolderData* folder) diff --git a/src/XMLReader.cpp b/src/XMLReader.cpp index 47e6527aa..d8a8f0eea 100644 --- a/src/XMLReader.cpp +++ b/src/XMLReader.cpp @@ -186,12 +186,24 @@ void parseGamelist(SystemData* system) std::istringstream(gameNode.child(GameData::xmlTagRating.c_str()).text().get()) >> rating; game->setRating(rating); } + if(gameNode.child(GameData::xmlTagUserRating.c_str())) + { + float userRating; + std::istringstream(gameNode.child(GameData::xmlTagUserRating.c_str()).text().get()) >> userRating; + game->setUserRating(userRating); + } if(gameNode.child(GameData::xmlTagTimesPlayed.c_str())) { size_t timesPlayed; std::istringstream(gameNode.child(GameData::xmlTagTimesPlayed.c_str()).text().get()) >> timesPlayed; game->setTimesPlayed(timesPlayed); } + if(gameNode.child(GameData::xmlTagLastPlayed.c_str())) + { + std::time_t lastPlayed; + std::istringstream(gameNode.child(GameData::xmlTagLastPlayed.c_str()).text().get()) >> lastPlayed; + game->setLastPlayed(lastPlayed); + } } else{ LOG(LogWarning) << "Game at \"" << path << "\" does not exist!"; @@ -223,8 +235,15 @@ void addGameDataNode(pugi::xml_node & parent, const GameData * game) //all other values are added regardless of their value pugi::xml_node ratingNode = newGame.append_child(GameData::xmlTagRating.c_str()); ratingNode.text().set(std::to_string((long double)game->getRating()).c_str()); + + pugi::xml_node userRatingNode = newGame.append_child(GameData::xmlTagUserRating.c_str()); + userRatingNode.text().set(std::to_string((long double)game->getUserRating()).c_str()); + pugi::xml_node timesPlayedNode = newGame.append_child(GameData::xmlTagTimesPlayed.c_str()); timesPlayedNode.text().set(std::to_string((unsigned long long)game->getTimesPlayed()).c_str()); + + pugi::xml_node lastPlayedNode = newGame.append_child(GameData::xmlTagLastPlayed.c_str()); + lastPlayedNode.text().set(std::to_string((unsigned long long)game->getLastPlayed()).c_str()); } void updateGamelist(SystemData* system) From a60fe463d4b6f02fbcb7ef8d4614541788ad32ac Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Fri, 28 Jun 2013 19:44:28 +0200 Subject: [PATCH 4/7] 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; From 94e32f198bfb902ea9ef4c2b24a500902884d410 Mon Sep 17 00:00:00 2001 From: Bim Date: Sun, 30 Jun 2013 19:24:09 +0200 Subject: [PATCH 5/7] Make sort order changeable via fast-select menu Use the left/right keys to switch it. --- src/FolderData.h | 3 ++- src/components/GuiFastSelect.cpp | 34 +++++++++++++++++++++----------- src/components/GuiFastSelect.h | 6 +++--- src/components/GuiGameList.cpp | 27 ++++++++++++++----------- src/components/GuiGameList.h | 1 + 5 files changed, 45 insertions(+), 26 deletions(-) diff --git a/src/FolderData.h b/src/FolderData.h index 6f47329c7..ecbd844fb 100644 --- a/src/FolderData.h +++ b/src/FolderData.h @@ -18,8 +18,9 @@ public: { ComparisonFunction & comparisonFunction; bool ascending; + std::string description; - SortState(ComparisonFunction & sortFunction, bool sortAscending) : comparisonFunction(sortFunction), ascending(sortAscending) {} + SortState(ComparisonFunction & sortFunction, bool sortAscending, const std::string & sortDescription) : comparisonFunction(sortFunction), ascending(sortAscending), description(sortDescription) {} }; private: diff --git a/src/components/GuiFastSelect.cpp b/src/components/GuiFastSelect.cpp index 008f4b972..fee1ba337 100644 --- a/src/components/GuiFastSelect.cpp +++ b/src/components/GuiFastSelect.cpp @@ -7,17 +7,15 @@ const std::string GuiFastSelect::LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const int GuiFastSelect::SCROLLSPEED = 100; const int GuiFastSelect::SCROLLDELAY = 507; -GuiFastSelect::GuiFastSelect(Window* window, GuiGameList* parent, TextListComponent* list, char startLetter, GuiBoxData data, - int textcolor, std::shared_ptr & scrollsound, Font* font) : GuiComponent(window) +GuiFastSelect::GuiFastSelect(Window* window, GuiGameList* parent, TextListComponent* list, char startLetter, ThemeComponent * theme) + : GuiComponent(window), mParent(parent), mList(list), mTheme(theme) { mLetterID = LETTERS.find(toupper(startLetter)); if(mLetterID == std::string::npos) mLetterID = 0; - mParent = parent; - mList = list; - mScrollSound = scrollsound; - mFont = font; + mScrollSound = mTheme->getSound("menuScroll"); + mTextColor = mTheme->getColor("fastSelect"); mScrolling = false; mScrollTimer = 0; @@ -25,9 +23,7 @@ GuiFastSelect::GuiFastSelect(Window* window, GuiGameList* parent, TextListCompon unsigned int sw = Renderer::getScreenWidth(), sh = Renderer::getScreenHeight(); mBox = new GuiBox(window, (int)(sw * 0.2f), (int)(sh * 0.2f), (int)(sw * 0.6f), (int)(sh * 0.6f)); - mBox->setData(data); - - mTextColor = textcolor; + mBox->setData(mTheme->getBoxData()); } GuiFastSelect::~GuiFastSelect() @@ -41,11 +37,14 @@ void GuiFastSelect::render() unsigned int sw = Renderer::getScreenWidth(), sh = Renderer::getScreenHeight(); if(!mBox->hasBackground()) - Renderer::drawRect((int)(sw * 0.2f), (int)(sh * 0.2f), (int)(sw * 0.6f), (int)(sh * 0.6f), 0x000FF0FF); + Renderer::drawRect((int)(sw * 0.3f), (int)(sh * 0.3f), (int)(sw * 0.4f), (int)(sh * 0.4f), 0x000FF0AA); mBox->render(); - Renderer::drawCenteredText(LETTERS.substr(mLetterID, 1), 0, (int)(sh * 0.5f - (mFont->getHeight() * 0.5f)), mTextColor, mFont); + Renderer::drawCenteredText(LETTERS.substr(mLetterID, 1), 0, (int)(sh * 0.5f - (mTheme->getFastSelectFont()->getHeight() * 0.5f)), mTextColor, mTheme->getFastSelectFont()); + Renderer::drawCenteredText("Sort order:", 0, (int)(sh * 0.6f - (mTheme->getDescriptionFont()->getHeight() * 0.5f)), mTextColor, mTheme->getDescriptionFont()); + std::string sortString = "<- " + mParent->getSortState().description + " ->"; + Renderer::drawCenteredText(sortString, 0, (int)(sh * 0.6f + (mTheme->getDescriptionFont()->getHeight() * 0.5f)), mTextColor, mTheme->getDescriptionFont()); } bool GuiFastSelect::input(InputConfig* config, Input input) @@ -64,6 +63,19 @@ bool GuiFastSelect::input(InputConfig* config, Input input) return true; } + if(config->isMappedTo("left", input) && input.value != 0) + { + mParent->setPreviousSortIndex(); + mScrollSound->play(); + return true; + } + else if(config->isMappedTo("right", input) && input.value != 0) + { + mParent->setNextSortIndex(); + mScrollSound->play(); + return true; + } + if((config->isMappedTo("up", input) || config->isMappedTo("down", input)) && input.value == 0) { mScrolling = false; diff --git a/src/components/GuiFastSelect.h b/src/components/GuiFastSelect.h index 67032e1f1..81ae2ec4d 100644 --- a/src/components/GuiFastSelect.h +++ b/src/components/GuiFastSelect.h @@ -5,6 +5,7 @@ #include "../SystemData.h" #include "../FolderData.h" #include "../Sound.h" +#include "ThemeComponent.h" #include "TextListComponent.h" #include "GuiBox.h" @@ -13,8 +14,7 @@ class GuiGameList; class GuiFastSelect : public GuiComponent { public: - GuiFastSelect(Window* window, GuiGameList* parent, TextListComponent* list, char startLetter, GuiBoxData data, - int textcolor, std::shared_ptr & scrollsound, Font* font); + GuiFastSelect(Window* window, GuiGameList* parent, TextListComponent* list, char startLetter, ThemeComponent * theme); ~GuiFastSelect(); bool input(InputConfig* config, Input input); @@ -41,7 +41,7 @@ private: bool mScrolling; std::shared_ptr mScrollSound; - Font* mFont; + ThemeComponent * mTheme; }; #endif diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index c77775f46..e222de28e 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -21,16 +21,16 @@ GuiGameList::GuiGameList(Window* window, bool useDetail) : GuiComponent(window), { //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)); + sortStates.push_back(FolderData::SortState(FolderData::compareFileName, true, "file name, ascending")); + sortStates.push_back(FolderData::SortState(FolderData::compareFileName, false, "file name, descending")); + sortStates.push_back(FolderData::SortState(FolderData::compareRating, true, "database rating, ascending")); + sortStates.push_back(FolderData::SortState(FolderData::compareRating, false, "database rating, descending")); + sortStates.push_back(FolderData::SortState(FolderData::compareUserRating, true, "your rating, ascending")); + sortStates.push_back(FolderData::SortState(FolderData::compareUserRating, false, "your rating, descending")); + sortStates.push_back(FolderData::SortState(FolderData::compareTimesPlayed, true, "played least often")); + sortStates.push_back(FolderData::SortState(FolderData::compareTimesPlayed, false, "played most often")); + sortStates.push_back(FolderData::SortState(FolderData::compareLastPlayed, true, "played least recently")); + sortStates.push_back(FolderData::SortState(FolderData::compareLastPlayed, false, "played most recently")); } mTheme = new ThemeComponent(mWindow, mDetailed); @@ -227,7 +227,7 @@ bool GuiGameList::input(InputConfig* config, Input input) //open the fast select menu if(config->isMappedTo("select", input) && input.value != 0) { - mWindow->pushGui(new GuiFastSelect(mWindow, this, mList, mList->getSelectedObject()->getName()[0], mTheme->getBoxData(), mTheme->getColor("fastSelect"), mTheme->getSound("menuScroll"), mTheme->getFastSelectFont())); + mWindow->pushGui(new GuiFastSelect(mWindow, this, mList, mList->getSelectedObject()->getName()[0], mTheme)); return true; } @@ -246,6 +246,11 @@ bool GuiGameList::input(InputConfig* config, Input input) return false; } +const FolderData::SortState & GuiGameList::getSortState() const +{ + return sortStates.at(sortStateIndex); +} + void GuiGameList::setSortIndex(size_t index) { //make the index valid diff --git a/src/components/GuiGameList.h b/src/components/GuiGameList.h index 2dae2f2ba..8d270510b 100644 --- a/src/components/GuiGameList.h +++ b/src/components/GuiGameList.h @@ -35,6 +35,7 @@ public: void updateDetailData(); + const FolderData::SortState & getSortState() const; void setSortIndex(size_t index); void setNextSortIndex(); void setPreviousSortIndex(); From ac516565279b3b862ac8af325983b97c0ade01c9 Mon Sep 17 00:00:00 2001 From: Bim Date: Tue, 2 Jul 2013 23:14:33 +0200 Subject: [PATCH 6/7] Read/Write sort order to settings Not written to disk atm. --- src/Settings.cpp | 2 ++ src/components/GuiGameList.cpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Settings.cpp b/src/Settings.cpp index 52111668d..8319a3b8c 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -33,6 +33,8 @@ void Settings::setDefaults() mBoolMap["WINDOWED"] = false; mIntMap["DIMTIME"] = 30*1000; + + mIntMap["GameListSortIndex"] = 0; } template diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index 5aeda1106..a19fb2688 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -30,7 +30,7 @@ GuiGameList::GuiGameList(Window* window) : GuiComponent(window), mScreenshot(window), mDescription(window), mTransitionImage(window, 0, 0, "", Renderer::getScreenWidth(), Renderer::getScreenHeight(), true), - sortStateIndex(0) + sortStateIndex(Settings::getInstance()->getInt("GameListSortIndex")) { //first object initializes the vector if (sortStates.empty()) { @@ -247,6 +247,8 @@ void GuiGameList::setSortIndex(size_t index) sortStateIndex = index; sort(sortStates.at(sortStateIndex).comparisonFunction, sortStates.at(sortStateIndex).ascending); } + //save new index to settings + Settings::getInstance()->setInt("GameListSortIndex", sortStateIndex); } void GuiGameList::setNextSortIndex() From 45ed6ae4da40c4d64265bbde286298221aa1c9fc Mon Sep 17 00:00:00 2001 From: Bim Date: Wed, 3 Jul 2013 01:48:39 +0200 Subject: [PATCH 7/7] Add size set function to GuiComponent Similar to #92... --- src/GuiComponent.cpp | 13 +++++++++++++ src/GuiComponent.h | 3 +++ 2 files changed, 16 insertions(+) diff --git a/src/GuiComponent.cpp b/src/GuiComponent.cpp index 4a5ee0195..94afcdec0 100644 --- a/src/GuiComponent.cpp +++ b/src/GuiComponent.cpp @@ -102,6 +102,19 @@ Vector2u GuiComponent::getSize() return mSize; } +void GuiComponent::setSize(Vector2u size) +{ + mSize = size; + onSizeChanged(); +} + +void GuiComponent::setSize(unsigned int w, unsigned int h) +{ + mSize.x = w; + mSize.y = h; + onSizeChanged(); +} + //Children stuff. void GuiComponent::addChild(GuiComponent* cmp) { diff --git a/src/GuiComponent.h b/src/GuiComponent.h index b7f36af64..2335b3a33 100644 --- a/src/GuiComponent.h +++ b/src/GuiComponent.h @@ -36,6 +36,9 @@ public: virtual void onOffsetChanged() {}; Vector2u getSize(); + void setSize(Vector2u size); + void setSize(unsigned int w, unsigned int h); + virtual void onSizeChanged() {}; void setParent(GuiComponent* parent); GuiComponent* getParent();