Merge pull request #210 from pjft/Custom-Collections

Added support for custom Game Collection creation
This commit is contained in:
John Rassa 2017-08-17 21:17:45 -04:00 committed by GitHub
commit 73280d2533
21 changed files with 1246 additions and 366 deletions

File diff suppressed because it is too large Load diff

View file

@ -34,6 +34,8 @@ struct CollectionSystemData
SystemData* system; SystemData* system;
CollectionSystemDecl decl; CollectionSystemDecl decl;
bool isEnabled; bool isEnabled;
bool isPopulated;
bool needsSave;
}; };
class CollectionSystemManager class CollectionSystemManager
@ -41,34 +43,73 @@ class CollectionSystemManager
public: public:
CollectionSystemManager(Window* window); CollectionSystemManager(Window* window);
~CollectionSystemManager(); ~CollectionSystemManager();
static void init(Window* window);
static CollectionSystemManager* get(); static CollectionSystemManager* get();
void loadEnabledListFromSettings(); static void init(Window* window);
static void deinit();
void saveCustomCollection(SystemData* sys);
void loadCollectionSystems(); void loadCollectionSystems();
void updateCollectionSystems(FileData* file); void loadEnabledListFromSettings();
void deleteCollectionFiles(FileData* file);
inline std::map<std::string, CollectionSystemData> getCollectionSystems() { return mAllCollectionSystems; };
void updateSystemsList(); void updateSystemsList();
bool isThemeAutoCompatible();
bool toggleGameInCollection(FileData* file, std::string collection); void refreshCollectionSystems(FileData* file);
void updateCollectionSystem(FileData* file, CollectionSystemData sysData);
void deleteCollectionFiles(FileData* file);
inline std::map<std::string, CollectionSystemData> getAutoCollectionSystems() { return mAutoCollectionSystemsData; };
inline std::map<std::string, CollectionSystemData> getCustomCollectionSystems() { return mCustomCollectionSystemsData; };
inline SystemData* getCustomCollectionsBundle() { return mCustomCollectionsBundle; };
std::vector<std::string> getUnusedSystemsFromTheme();
SystemData* addNewCustomCollection(std::string name);
bool isThemeGenericCollectionCompatible(bool genericCustomCollections);
bool isThemeCustomCollectionCompatible(std::vector<std::string> stringVector);
std::string getValidNewCollectionName(std::string name, int index = 0);
void setEditMode(std::string collectionName);
void exitEditMode();
inline bool isEditing() { return mIsEditingCustom; };
inline std::string getEditingCollection() { std::string res = mEditingCollection; return res; };
bool toggleGameInCollection(FileData* file);
SystemData* getSystemToView(SystemData* sys);
void updateCollectionFolderMetadata(SystemData* sys);
private: private:
static CollectionSystemManager* sInstance; static CollectionSystemManager* sInstance;
std::map<std::string, CollectionSystemDecl> mCollectionSystemDecls;
SystemEnvironmentData* mCollectionEnvData; SystemEnvironmentData* mCollectionEnvData;
static FileData::SortType getSortType(std::string desc); std::map<std::string, CollectionSystemDecl> mCollectionSystemDeclsIndex;
void initAvailableSystemsList(); std::map<std::string, CollectionSystemData> mAutoCollectionSystemsData;
std::map<std::string, CollectionSystemData> mCustomCollectionSystemsData;
Window* mWindow;
bool mIsEditingCustom;
std::string mEditingCollection;
CollectionSystemData* mEditingCollectionSystemData;
void initAutoCollectionSystems();
void initCustomCollectionSystems();
SystemData* getAllGamesCollection();
SystemData* createNewCollectionEntry(std::string name, CollectionSystemDecl sysDecl, bool index = true);
void populateAutoCollection(CollectionSystemData* sysData);
void populateCustomCollection(CollectionSystemData* sysData);
void removeCollectionsFromDisplayedSystems();
void addEnabledCollectionsToDisplayedSystems(std::map<std::string, CollectionSystemData>* colSystemData);
std::vector<std::string> getSystemsFromConfig(); std::vector<std::string> getSystemsFromConfig();
std::vector<std::string> getSystemsFromTheme(); std::vector<std::string> getSystemsFromTheme();
std::vector<std::string> getUnusedSystemsFromTheme(); std::vector<std::string> getCollectionsFromConfigFolder();
std::vector<std::string> getAutoThemeFolders(); std::vector<std::string> getCollectionThemeFolders(bool custom);
std::vector<std::string> getUserCollectionThemeFolders();
bool themeFolderExists(std::string folder); bool themeFolderExists(std::string folder);
void loadAutoCollectionSystems();
void loadCustomCollectionSystems(); // TO DO NEXT
SystemData* findCollectionSystem(std::string name);
bool includeFileInAutoCollections(FileData* file); bool includeFileInAutoCollections(FileData* file);
std::map<std::string, CollectionSystemData> mAllCollectionSystems;
std::vector<SystemData*> mAutoCollectionSystems; SystemData* mCustomCollectionsBundle;
std::vector<SystemData*> mCustomCollectionSystems;
Window* mWindow;
}; };
std::string getCustomCollectionConfigPath(std::string collectionName);
std::string getCollectionsFolder();
bool systemSort(SystemData* sys1, SystemData* sys2);

View file

@ -23,6 +23,7 @@ FileData::~FileData()
if(mParent) if(mParent)
mParent->removeChild(this); mParent->removeChild(this);
if(mType == GAME)
mSystem->getIndex()->removeFromIndex(this); mSystem->getIndex()->removeFromIndex(this);
mChildren.clear(); mChildren.clear();
@ -57,7 +58,7 @@ const std::string& FileData::getName()
const std::vector<FileData*>& FileData::getChildrenListToDisplay() { const std::vector<FileData*>& FileData::getChildrenListToDisplay() {
FileFilterIndex* idx = mSystem->getIndex(); FileFilterIndex* idx = CollectionSystemManager::get()->getSystemToView(mSystem)->getIndex();
if (idx->isFiltered()) { if (idx->isFiltered()) {
mFilteredChildren.clear(); mFilteredChildren.clear();
for(auto it = mChildren.begin(); it != mChildren.end(); it++) for(auto it = mChildren.begin(); it != mChildren.end(); it++)
@ -140,6 +141,7 @@ void FileData::removeChild(FileData* file)
{ {
if(*it == file) if(*it == file)
{ {
file->mParent = NULL;
mChildren.erase(it); mChildren.erase(it);
return; return;
} }
@ -210,14 +212,11 @@ void FileData::launchGame(Window* window)
//update last played time //update last played time
boost::posix_time::ptime time = boost::posix_time::second_clock::universal_time(); boost::posix_time::ptime time = boost::posix_time::second_clock::universal_time();
gameToUpdate->metadata.setTime("lastplayed", time); gameToUpdate->metadata.setTime("lastplayed", time);
CollectionSystemManager::get()->updateCollectionSystems(gameToUpdate); CollectionSystemManager::get()->refreshCollectionSystems(gameToUpdate);
} }
CollectionFileData::CollectionFileData(FileData* file, SystemData* system) CollectionFileData::CollectionFileData(FileData* file, SystemData* system)
: FileData(file->getType(), file->getPath(), file->getSystemEnvData(), system)/*, : FileData(file->getSourceFileData()->getType(), file->getSourceFileData()->getPath(), file->getSourceFileData()->getSystemEnvData(), system)
mSourceFileData(file->getSourceFileData()),
mParent(NULL),
metadata(file->getSourceFileData()->metadata)*/
{ {
// we use this constructor to create a clone of the filedata, and change its system // we use this constructor to create a clone of the filedata, and change its system
mSourceFileData = file->getSourceFileData(); mSourceFileData = file->getSourceFileData();
@ -260,3 +259,19 @@ const std::string& CollectionFileData::getName()
} }
return mCollectionFileName; return mCollectionFileName;
} }
// returns Sort Type based on a string description
FileData::SortType getSortTypeFromString(std::string desc) {
std::vector<FileData::SortType> SortTypes = FileSorts::SortTypes;
// find it
for(unsigned int i = 0; i < FileSorts::SortTypes.size(); i++)
{
const FileData::SortType& sort = FileSorts::SortTypes.at(i);
if(sort.description == desc)
{
return sort;
}
}
// if not found default to name, ascending
return FileSorts::SortTypes.at(0);
}

View file

@ -115,3 +115,5 @@ private:
std::string mCollectionFileName; std::string mCollectionFileName;
bool mDirty; bool mDirty;
}; };
FileData::SortType getSortTypeFromString(std::string desc);

View file

@ -20,11 +20,7 @@ FileFilterIndex::FileFilterIndex()
FileFilterIndex::~FileFilterIndex() FileFilterIndex::~FileFilterIndex()
{ {
clearIndex(genreIndexAllKeys); resetIndex();
clearIndex(playersIndexAllKeys);
clearIndex(pubDevIndexAllKeys);
clearIndex(ratingsIndexAllKeys);
clearIndex(favoritesIndexAllKeys);
} }
std::vector<FilterDataDecl>& FileFilterIndex::getFilterDataDecls() std::vector<FilterDataDecl>& FileFilterIndex::getFilterDataDecls()
@ -32,6 +28,50 @@ std::vector<FilterDataDecl>& FileFilterIndex::getFilterDataDecls()
return filterDataDecl; return filterDataDecl;
} }
void FileFilterIndex::importIndex(FileFilterIndex* indexToImport)
{
struct IndexImportStructure
{
std::map<std::string, int>* destinationIndex;
std::map<std::string, int>* sourceIndex;
};
IndexImportStructure indexStructDecls[] = {
{ &genreIndexAllKeys, &(indexToImport->genreIndexAllKeys) },
{ &playersIndexAllKeys, &(indexToImport->playersIndexAllKeys) },
{ &pubDevIndexAllKeys, &(indexToImport->pubDevIndexAllKeys) },
{ &ratingsIndexAllKeys, &(indexToImport->ratingsIndexAllKeys) },
{ &favoritesIndexAllKeys, &(indexToImport->favoritesIndexAllKeys) }
};
std::vector<IndexImportStructure> indexImportDecl = std::vector<IndexImportStructure>(indexStructDecls, indexStructDecls + sizeof(indexStructDecls) / sizeof(indexStructDecls[0]));
for (std::vector<IndexImportStructure>::iterator indexesIt = indexImportDecl.begin(); indexesIt != indexImportDecl.end(); ++indexesIt )
{
for (std::map<std::string, int>::iterator sourceIt = (*indexesIt).sourceIndex->begin(); sourceIt != (*indexesIt).sourceIndex->end(); ++sourceIt )
{
if ((*indexesIt).destinationIndex->find((*sourceIt).first) == (*indexesIt).destinationIndex->end())
{
// entry doesn't exist
(*((*indexesIt).destinationIndex))[(*sourceIt).first] = (*sourceIt).second;
}
else
{
(*((*indexesIt).destinationIndex))[(*sourceIt).first] += (*sourceIt).second;
}
}
}
}
void FileFilterIndex::resetIndex()
{
clearAllFilters();
clearIndex(genreIndexAllKeys);
clearIndex(playersIndexAllKeys);
clearIndex(pubDevIndexAllKeys);
clearIndex(ratingsIndexAllKeys);
clearIndex(favoritesIndexAllKeys);
}
std::string FileFilterIndex::getIndexableKey(FileData* game, FilterIndexType type, bool getSecondary) std::string FileFilterIndex::getIndexableKey(FileData* game, FilterIndexType type, bool getSecondary)
{ {
std::string key = ""; std::string key = "";
@ -170,21 +210,21 @@ void FileFilterIndex::clearAllFilters()
void FileFilterIndex::debugPrintIndexes() void FileFilterIndex::debugPrintIndexes()
{ {
LOG(LogError) << "Printing Indexes..."; LOG(LogInfo) << "Printing Indexes...";
for (auto x: playersIndexAllKeys) { for (auto x: playersIndexAllKeys) {
LOG(LogError) << "Multiplayer Index: " << x.first << ": " << x.second; LOG(LogInfo) << "Multiplayer Index: " << x.first << ": " << x.second;
} }
for (auto x: genreIndexAllKeys) { for (auto x: genreIndexAllKeys) {
LOG(LogError) << "Genre Index: " << x.first << ": " << x.second; LOG(LogInfo) << "Genre Index: " << x.first << ": " << x.second;
} }
for (auto x: ratingsIndexAllKeys) { for (auto x: ratingsIndexAllKeys) {
LOG(LogError) << "Ratings Index: " << x.first << ": " << x.second; LOG(LogInfo) << "Ratings Index: " << x.first << ": " << x.second;
} }
for (auto x: pubDevIndexAllKeys) { for (auto x: pubDevIndexAllKeys) {
LOG(LogError) << "PubDev Index: " << x.first << ": " << x.second; LOG(LogInfo) << "PubDev Index: " << x.first << ": " << x.second;
} }
for (auto x: favoritesIndexAllKeys) { for (auto x: favoritesIndexAllKeys) {
LOG(LogError) << "Favorites Index: " << x.first << ": " << x.second; LOG(LogInfo) << "Favorites Index: " << x.first << ": " << x.second;
} }
} }

View file

@ -45,6 +45,9 @@ public:
bool isFiltered() { return (filterByGenre || filterByPlayers || filterByPubDev || filterByRatings || filterByFavorites); }; bool isFiltered() { return (filterByGenre || filterByPlayers || filterByPubDev || filterByRatings || filterByFavorites); };
bool isKeyBeingFilteredBy(std::string key, FilterIndexType type); bool isKeyBeingFilteredBy(std::string key, FilterIndexType type);
std::vector<FilterDataDecl>& getFilterDataDecls(); std::vector<FilterDataDecl>& getFilterDataDecls();
void importIndex(FileFilterIndex* indexToImport);
void resetIndex();
private: private:
std::vector<FilterDataDecl> filterDataDecl; std::vector<FilterDataDecl> filterDataDecl;
std::string getIndexableKey(FileData* game, FilterIndexType type, bool getSecondary); std::string getIndexableKey(FileData* game, FilterIndexType type, bool getSecondary);

View file

@ -426,8 +426,11 @@ FileData* SystemData::getRandomGame()
{ {
std::vector<FileData*> list = mRootFolder->getFilesRecursive(GAME, true); std::vector<FileData*> list = mRootFolder->getFilesRecursive(GAME, true);
unsigned int total = list.size(); unsigned int total = list.size();
int target = 0;
// get random number in range // get random number in range
int target = std::round(((double)std::rand() / (double)RAND_MAX) * (total - 1)); if (total == 0)
return NULL;
target = std::round(((double)std::rand() / (double)RAND_MAX) * (total - 1));
return list.at(target); return list.at(target);
} }

View file

@ -1,8 +1,11 @@
#include "guis/GuiCollectionSystemsOptions.h" #include "guis/GuiCollectionSystemsOptions.h"
#include "guis/GuiMsgBox.h" #include "guis/GuiMsgBox.h"
#include "guis/GuiTextEditPopup.h"
#include "Settings.h" #include "Settings.h"
#include "views/ViewController.h" #include "views/ViewController.h"
#include "guis/GuiSettings.h"
#include "Util.h"
#include "components/TextComponent.h" #include "components/TextComponent.h"
#include "components/OptionListComponent.h" #include "components/OptionListComponent.h"
@ -15,66 +18,172 @@ void GuiCollectionSystemsOptions::initializeMenu()
{ {
addChild(&mMenu); addChild(&mMenu);
// get virtual systems // get collections
addSystemsToMenu(); addSystemsToMenu();
// add "Create New Custom Collection from Theme"
std::vector<std::string> unusedFolders = CollectionSystemManager::get()->getUnusedSystemsFromTheme();
if (unusedFolders.size() > 0)
{
addEntry("CREATE NEW CUSTOM COLLECTION FROM THEME", 0x777777FF, true,
[this, unusedFolders] {
auto s = new GuiSettings(mWindow, "SELECT THEME FOLDER");
std::shared_ptr< OptionListComponent<std::string> > folderThemes = std::make_shared< OptionListComponent<std::string> >(mWindow, "SELECT THEME FOLDER", true);
// add Custom Systems
for(auto it = unusedFolders.begin() ; it != unusedFolders.end() ; it++ )
{
ComponentListRow row;
std::string name = *it;
std::function<void()> createCollectionCall = [name, this, s] {
createCollection(name);
};
row.makeAcceptInputHandler(createCollectionCall);
auto themeFolder = std::make_shared<TextComponent>(mWindow, strToUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF);
row.addElement(themeFolder, true);
s->addRow(row);
}
mWindow->pushGui(s);
});
}
ComponentListRow row;
row.addElement(std::make_shared<TextComponent>(mWindow, "CREATE NEW CUSTOM COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
auto createCustomCollection = [this](const std::string& newVal) {
std::string name = newVal;
// we need to store the first Gui and remove it, as it'll be deleted by the actual Gui
Window* window = mWindow;
GuiComponent* topGui = window->peekGui();
window->removeGui(topGui);
createCollection(name);
};
row.makeAcceptInputHandler([this, createCustomCollection] {
mWindow->pushGui(new GuiTextEditPopup(mWindow, "New Collection Name", "", createCustomCollection, false));
});
mMenu.addRow(row);
bundleCustomCollections = std::make_shared<SwitchComponent>(mWindow);
bundleCustomCollections->setState(Settings::getInstance()->getBool("UseCustomCollectionsSystem"));
mMenu.addWithLabel("GROUP UNTHEMED CUSTOM COLLECTIONS", bundleCustomCollections);
sortAllSystemsSwitch = std::make_shared<SwitchComponent>(mWindow);
sortAllSystemsSwitch->setState(Settings::getInstance()->getBool("SortAllSystems"));
mMenu.addWithLabel("SORT CUSTOM COLLECTIONS AND SYSTEMS", sortAllSystemsSwitch);
if(CollectionSystemManager::get()->isEditing())
{
row.elements.clear();
row.addElement(std::make_shared<TextComponent>(mWindow, "FINISH EDITING '" + strToUpper(CollectionSystemManager::get()->getEditingCollection()) + "' COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
row.makeAcceptInputHandler(std::bind(&GuiCollectionSystemsOptions::exitEditMode, this));
mMenu.addRow(row);
}
mMenu.addButton("BACK", "back", std::bind(&GuiCollectionSystemsOptions::applySettings, this)); mMenu.addButton("BACK", "back", std::bind(&GuiCollectionSystemsOptions::applySettings, this));
mMenu.setPosition((Renderer::getScreenWidth() - mMenu.getSize().x()) / 2, Renderer::getScreenHeight() * 0.15f); mMenu.setPosition((Renderer::getScreenWidth() - mMenu.getSize().x()) / 2, Renderer::getScreenHeight() * 0.15f);
} }
void GuiCollectionSystemsOptions::addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func)
{
std::shared_ptr<Font> font = Font::get(FONT_SIZE_MEDIUM);
// populate the list
ComponentListRow row;
row.addElement(std::make_shared<TextComponent>(mWindow, name, font, color), true);
if(add_arrow)
{
std::shared_ptr<ImageComponent> bracket = makeArrow(mWindow);
row.addElement(bracket, false);
}
row.makeAcceptInputHandler(func);
mMenu.addRow(row);
}
void GuiCollectionSystemsOptions::createCollection(std::string inName) {
std::string name = CollectionSystemManager::get()->getValidNewCollectionName(inName);
SystemData* newSys = CollectionSystemManager::get()->addNewCustomCollection(name);
customOptionList->add(name, name, true);
std::string outAuto = vectorToCommaString(autoOptionList->getSelectedObjects());
std::string outCustom = vectorToCommaString(customOptionList->getSelectedObjects());
updateSettings(outAuto, outCustom);
ViewController::get()->goToSystemView(newSys);
Window* window = mWindow;
CollectionSystemManager::get()->setEditMode(name);
while(window->peekGui() && window->peekGui() != ViewController::get())
delete window->peekGui();
return;
}
void GuiCollectionSystemsOptions::exitEditMode()
{
CollectionSystemManager::get()->exitEditMode();
applySettings();
}
GuiCollectionSystemsOptions::~GuiCollectionSystemsOptions() GuiCollectionSystemsOptions::~GuiCollectionSystemsOptions()
{ {
//mSystemOptions.clear();
} }
void GuiCollectionSystemsOptions::addSystemsToMenu() void GuiCollectionSystemsOptions::addSystemsToMenu()
{ {
std::map<std::string, CollectionSystemData> vSystems = CollectionSystemManager::get()->getCollectionSystems(); std::map<std::string, CollectionSystemData> autoSystems = CollectionSystemManager::get()->getAutoCollectionSystems();
autoOptionList = std::make_shared< OptionListComponent<std::string> >(mWindow, "SELECT COLLECTIONS", true); autoOptionList = std::make_shared< OptionListComponent<std::string> >(mWindow, "SELECT COLLECTIONS", true);
// add Systems // add Auto Systems
ComponentListRow row; for(std::map<std::string, CollectionSystemData>::iterator it = autoSystems.begin() ; it != autoSystems.end() ; it++ )
for(std::map<std::string, CollectionSystemData>::iterator it = vSystems.begin() ; it != vSystems.end() ; it++ )
{ {
autoOptionList->add(it->second.decl.longName, it->second.decl.name, it->second.isEnabled); autoOptionList->add(it->second.decl.longName, it->second.decl.name, it->second.isEnabled);
} }
mMenu.addWithLabel("AUTOMATIC COLLECTIONS", autoOptionList); mMenu.addWithLabel("AUTOMATIC GAME COLLECTIONS", autoOptionList);
std::map<std::string, CollectionSystemData> customSystems = CollectionSystemManager::get()->getCustomCollectionSystems();
customOptionList = std::make_shared< OptionListComponent<std::string> >(mWindow, "SELECT COLLECTIONS", true);
// add Custom Systems
for(std::map<std::string, CollectionSystemData>::iterator it = customSystems.begin() ; it != customSystems.end() ; it++ )
{
customOptionList->add(it->second.decl.longName, it->second.decl.name, it->second.isEnabled);
}
mMenu.addWithLabel("CUSTOM GAME COLLECTIONS", customOptionList);
} }
void GuiCollectionSystemsOptions::applySettings() void GuiCollectionSystemsOptions::applySettings()
{ {
std::string out = commaStringToVector(autoOptionList->getSelectedObjects()); std::string outAuto = vectorToCommaString(autoOptionList->getSelectedObjects());
std::string prev = Settings::getInstance()->getString("CollectionSystemsAuto"); std::string prevAuto = Settings::getInstance()->getString("CollectionSystemsAuto");
if (out != "" && !CollectionSystemManager::get()->isThemeAutoCompatible()) std::string outCustom = vectorToCommaString(customOptionList->getSelectedObjects());
std::string prevCustom = Settings::getInstance()->getString("CollectionSystemsCustom");
bool outSort = sortAllSystemsSwitch->getState();
bool prevSort = Settings::getInstance()->getBool("SortAllSystems");
bool outBundle = bundleCustomCollections->getState();
bool prevBundle = Settings::getInstance()->getBool("UseCustomCollectionsSystem");
bool needUpdateSettings = prevAuto != outAuto || prevCustom != outCustom || outSort != prevSort || outBundle != prevBundle;
if (needUpdateSettings)
{ {
mWindow->pushGui(new GuiMsgBox(mWindow, updateSettings(outAuto, outCustom);
"Your theme does not support game collections. Please update your theme, or ensure that you use a theme that contains the folders:\n\n• auto-favorites\n• auto-lastplayed\n• auto-allgames\n\nDo you still want to enable collections?",
"YES", [this, out, prev] {
if (prev != out)
{
updateSettings(out);
}
delete this; },
"NO", [this] { delete this; }));
}
else
{
if (prev != out)
{
updateSettings(out);
} }
delete this; delete this;
}
} }
void GuiCollectionSystemsOptions::updateSettings(std::string newSettings) void GuiCollectionSystemsOptions::updateSettings(std::string newAutoSettings, std::string newCustomSettings)
{ {
Settings::getInstance()->setString("CollectionSystemsAuto", newSettings); Settings::getInstance()->setString("CollectionSystemsAuto", newAutoSettings);
Settings::getInstance()->setString("CollectionSystemsCustom", newCustomSettings);
Settings::getInstance()->setBool("SortAllSystems", sortAllSystemsSwitch->getState());
Settings::getInstance()->setBool("UseCustomCollectionsSystem", bundleCustomCollections->getState());
Settings::getInstance()->saveFile(); Settings::getInstance()->saveFile();
CollectionSystemManager::get()->loadEnabledListFromSettings(); CollectionSystemManager::get()->loadEnabledListFromSettings();
CollectionSystemManager::get()->updateSystemsList(); CollectionSystemManager::get()->updateSystemsList();

View file

@ -4,6 +4,7 @@
#include "SystemData.h" #include "SystemData.h"
#include "components/MenuComponent.h" #include "components/MenuComponent.h"
#include "CollectionSystemManager.h" #include "CollectionSystemManager.h"
#include "components/SwitchComponent.h"
#include "Log.h" #include "Log.h"
@ -24,8 +25,14 @@ private:
void initializeMenu(); void initializeMenu();
void applySettings(); void applySettings();
void addSystemsToMenu(); void addSystemsToMenu();
void updateSettings(std::string newSettings); void addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func);
void updateSettings(std::string newAutoSettings, std::string newCustomSettings);
void createCollection(std::string inName);
void exitEditMode();
std::shared_ptr< OptionListComponent<std::string> > autoOptionList; std::shared_ptr< OptionListComponent<std::string> > autoOptionList;
std::shared_ptr< OptionListComponent<std::string> > customOptionList;
std::shared_ptr<SwitchComponent> sortAllSystemsSwitch;
std::shared_ptr<SwitchComponent> bundleCustomCollections;
MenuComponent mMenu; MenuComponent mMenu;
SystemData* mSystem; SystemData* mSystem;
}; };

View file

@ -1,5 +1,6 @@
#include "GuiGamelistOptions.h" #include "GuiGamelistOptions.h"
#include "GuiMetaDataEd.h" #include "GuiMetaDataEd.h"
#include "Util.h"
#include "views/gamelist/IGameListView.h" #include "views/gamelist/IGameListView.h"
#include "views/ViewController.h" #include "views/ViewController.h"
#include "CollectionSystemManager.h" #include "CollectionSystemManager.h"
@ -54,6 +55,33 @@ GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : Gui
} }
mMenu.addWithLabel("SORT GAMES BY", mListSort); mMenu.addWithLabel("SORT GAMES BY", mListSort);
}
// show filtered menu
row.elements.clear();
row.addElement(std::make_shared<TextComponent>(mWindow, "FILTER GAMELIST", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
row.addElement(makeArrow(mWindow), false);
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openGamelistFilter, this));
mMenu.addRow(row);
std::map<std::string, CollectionSystemData> customCollections = CollectionSystemManager::get()->getCustomCollectionSystems();
if((customCollections.find(system->getName()) != customCollections.end() && CollectionSystemManager::get()->getEditingCollection() != system->getName()) ||
CollectionSystemManager::get()->getCustomCollectionsBundle()->getName() == system->getName())
{
row.elements.clear();
row.addElement(std::make_shared<TextComponent>(mWindow, "ADD/REMOVE GAMES TO THIS GAME COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::startEditMode, this));
mMenu.addRow(row);
}
if(CollectionSystemManager::get()->isEditing())
{
row.elements.clear();
row.addElement(std::make_shared<TextComponent>(mWindow, "FINISH EDITING '" + strToUpper(CollectionSystemManager::get()->getEditingCollection()) + "' COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::exitEditMode, this));
mMenu.addRow(row);
}
if (!fromPlaceholder && !(mSystem->isCollection() && file->getType() == FOLDER)) {
row.elements.clear(); row.elements.clear();
row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS GAME'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS GAME'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
@ -62,13 +90,6 @@ GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : Gui
mMenu.addRow(row); mMenu.addRow(row);
} }
// show filtered menu
row.elements.clear();
row.addElement(std::make_shared<TextComponent>(mWindow, "FILTER GAMELIST", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
row.addElement(makeArrow(mWindow), false);
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openGamelistFilter, this));
mMenu.addRow(row);
// center the menu // center the menu
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, (mSize.y() - mMenu.getSize().y()) / 2); mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, (mSize.y() - mMenu.getSize().y()) / 2);
@ -78,26 +99,19 @@ GuiGamelistOptions::~GuiGamelistOptions()
{ {
// apply sort // apply sort
if (!fromPlaceholder) { if (!fromPlaceholder) {
FileData* root = getGamelist()->getCursor()->getSystem()->getRootFolder(); FileData* root = mSystem->getRootFolder();
root->sort(*mListSort->getSelected()); // will also recursively sort children root->sort(*mListSort->getSelected()); // will also recursively sort children
// notify that the root folder was sorted // notify that the root folder was sorted
getGamelist()->onFileChanged(root, FILE_SORTED); getGamelist()->onFileChanged(root, FILE_SORTED);
} }
if (mFiltersChanged) if (mFiltersChanged)
{
if (!fromPlaceholder) {
FileData* root = getGamelist()->getCursor()->getSystem()->getRootFolder();
getGamelist()->onFileChanged(root, FILE_SORTED);
}
else
{ {
// only reload full view if we came from a placeholder // only reload full view if we came from a placeholder
// as we need to re-display the remaining elements for whatever new // as we need to re-display the remaining elements for whatever new
// game is selected // game is selected
ViewController::get()->reloadGameListView(mSystem); ViewController::get()->reloadGameListView(mSystem);
} }
}
} }
void GuiGamelistOptions::openGamelistFilter() void GuiGamelistOptions::openGamelistFilter()
@ -107,6 +121,34 @@ void GuiGamelistOptions::openGamelistFilter()
mWindow->pushGui(ggf); mWindow->pushGui(ggf);
} }
void GuiGamelistOptions::startEditMode()
{
std::string editingSystem = mSystem->getName();
// need to check if we're editing the collections bundle, as we will want to edit the selected collection within
if(editingSystem == CollectionSystemManager::get()->getCustomCollectionsBundle()->getName())
{
FileData* file = getGamelist()->getCursor();
// do we have the cursor on a specific collection?
if (file->getType() == FOLDER)
{
editingSystem = file->getName();
}
else
{
// we are inside a specific collection. We want to edit that one.
editingSystem = file->getSystem()->getName();
}
}
CollectionSystemManager::get()->setEditMode(editingSystem);
delete this;
}
void GuiGamelistOptions::exitEditMode()
{
CollectionSystemManager::get()->exitEditMode();
delete this;
}
void GuiGamelistOptions::openMetaDataEd() void GuiGamelistOptions::openMetaDataEd()
{ {
// open metadata editor // open metadata editor

View file

@ -19,6 +19,8 @@ public:
private: private:
void openGamelistFilter(); void openGamelistFilter();
void openMetaDataEd(); void openMetaDataEd();
void startEditMode();
void exitEditMode();
void jumpToLetter(); void jumpToLetter();
MenuComponent mMenu; MenuComponent mMenu;

View file

@ -234,7 +234,10 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
Settings::getInstance()->setString("ThemeSet", theme_set->getSelected()); Settings::getInstance()->setString("ThemeSet", theme_set->getSelected());
if(needReload) if(needReload)
{
CollectionSystemManager::get()->updateSystemsList();
ViewController::get()->reloadAll(); // TODO - replace this with some sort of signal-based implementation ViewController::get()->reloadAll(); // TODO - replace this with some sort of signal-based implementation
}
}); });
} }

View file

@ -194,7 +194,7 @@ void GuiMetaDataEd::save()
mSavedCallback(); mSavedCallback();
// update respective Collection Entries // update respective Collection Entries
CollectionSystemManager::get()->updateCollectionSystems(mScraperParams.game); CollectionSystemManager::get()->refreshCollectionSystems(mScraperParams.game);
} }
void GuiMetaDataEd::fetch() void GuiMetaDataEd::fetch()

View file

@ -376,6 +376,7 @@ int main(int argc, char* argv[])
delete window.peekGui(); delete window.peekGui();
window.deinit(); window.deinit();
CollectionSystemManager::deinit();
SystemData::deleteSystems(); SystemData::deleteSystems();
LOG(LogInfo) << "EmulationStation cleanly shutting down."; LOG(LogInfo) << "EmulationStation cleanly shutting down.";

View file

@ -271,6 +271,17 @@ void ViewController::launch(FileData* game, Eigen::Vector3f center)
} }
} }
void ViewController::removeGameListView(SystemData* system)
{
//if we already made one, return that one
auto exists = mGameListViews.find(system);
if(exists != mGameListViews.end())
{
exists->second.reset();
mGameListViews.erase(system);
}
}
std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* system) std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* system)
{ {
//if we already made one, return that one //if we already made one, return that one

View file

@ -77,6 +77,7 @@ public:
std::shared_ptr<IGameListView> getGameListView(SystemData* system); std::shared_ptr<IGameListView> getGameListView(SystemData* system);
std::shared_ptr<SystemView> getSystemListView(); std::shared_ptr<SystemView> getSystemListView();
void removeGameListView(SystemData* system);
private: private:
ViewController(Window* window); ViewController(Window* window);

View file

@ -42,10 +42,9 @@ void BasicGameListView::onFileChanged(FileData* file, FileChangeType change)
void BasicGameListView::populateList(const std::vector<FileData*>& files) void BasicGameListView::populateList(const std::vector<FileData*>& files)
{ {
mList.clear(); mList.clear();
mHeaderText.setText(mRoot->getSystem()->getFullName());
if (files.size() > 0) if (files.size() > 0)
{ {
mHeaderText.setText(files.at(0)->getSystem()->getFullName());
for(auto it = files.begin(); it != files.end(); it++) for(auto it = files.begin(); it != files.end(); it++)
{ {
mList.add((*it)->getName(), *it, ((*it)->getType() == FOLDER)); mList.add((*it)->getName(), *it, ((*it)->getType() == FOLDER));
@ -143,7 +142,10 @@ std::vector<HelpPrompt> BasicGameListView::getHelpPrompts()
prompts.push_back(HelpPrompt("b", "back")); prompts.push_back(HelpPrompt("b", "back"));
prompts.push_back(HelpPrompt("select", "options")); prompts.push_back(HelpPrompt("select", "options"));
prompts.push_back(HelpPrompt("x", "random")); prompts.push_back(HelpPrompt("x", "random"));
if(Settings::getInstance()->getString("CollectionSystemsAuto").find("favorites") != std::string::npos && mRoot->getSystem()->isGameSystem()) if(mRoot->getSystem()->isGameSystem())
prompts.push_back(HelpPrompt("y", "favorite")); {
const char* prompt = CollectionSystemManager::get()->getEditingCollection().c_str();
prompts.push_back(HelpPrompt("y", prompt));
}
return prompts; return prompts;
} }

View file

@ -93,6 +93,8 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
{ {
mCursorStack.push(cursor); mCursorStack.push(cursor);
populateList(cursor->getChildrenListToDisplay()); populateList(cursor->getChildrenListToDisplay());
FileData* cursor = getCursor();
setCursor(cursor);
} }
} }
@ -107,7 +109,12 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
Sound::getFromTheme(getTheme(), getName(), "back")->play(); Sound::getFromTheme(getTheme(), getName(), "back")->play();
}else{ }else{
onFocusLost(); onFocusLost();
ViewController::get()->goToSystemView(getCursor()->getSystem()); SystemData* systemToView = getCursor()->getSystem();
if (systemToView->isCollection())
{
systemToView = CollectionSystemManager::get()->getSystemToView(systemToView);
}
ViewController::get()->goToSystemView(systemToView);
} }
return true; return true;
@ -130,14 +137,17 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
}else if (config->isMappedTo("x", input)) }else if (config->isMappedTo("x", input))
{ {
// go to random system game // go to random system game
setCursor(mRoot->getSystem()->getRandomGame()); FileData* randomGame = getCursor()->getSystem()->getRandomGame();
//ViewController::get()->goToRandomGame(); if (randomGame)
{
setCursor(randomGame);
}
return true; return true;
}else if (config->isMappedTo("y", input)) }else if (config->isMappedTo("y", input))
{ {
if(Settings::getInstance()->getString("CollectionSystemsAuto").find("favorites") != std::string::npos && mRoot->getSystem()->isGameSystem()) if(mRoot->getSystem()->isGameSystem())
{ {
if(CollectionSystemManager::get()->toggleGameInCollection(getCursor(), "favorites")) if(CollectionSystemManager::get()->toggleGameInCollection(getCursor()))
{ {
return true; return true;
} }

View file

@ -99,6 +99,9 @@ void Settings::setDefaults()
// Audio out device for Video playback using OMX player. // Audio out device for Video playback using OMX player.
mStringMap["OMXAudioDev"] = "both"; mStringMap["OMXAudioDev"] = "both";
mStringMap["CollectionSystemsAuto"] = ""; mStringMap["CollectionSystemsAuto"] = "";
mStringMap["CollectionSystemsCustom"] = "";
mBoolMap["SortAllSystems"] = false;
mBoolMap["UseCustomCollectionsSystem"] = true;
// Audio out device for volume control // Audio out device for volume control
#ifdef _RPI_ #ifdef _RPI_

View file

@ -296,12 +296,14 @@ std::vector<std::string> commaStringToVector(std::string commaString)
// from a comma separated string, get a vector of strings // from a comma separated string, get a vector of strings
std::vector<std::string> strs; std::vector<std::string> strs;
boost::split(strs, commaString, boost::is_any_of(",")); boost::split(strs, commaString, boost::is_any_of(","));
std::sort(strs.begin(), strs.end());
return strs; return strs;
} }
std::string commaStringToVector(std::vector<std::string> stringVector) std::string vectorToCommaString(std::vector<std::string> stringVector)
{ {
std::string out = ""; std::string out = "";
std::sort(stringVector.begin(), stringVector.end());
// from a vector of system names get comma separated string // from a vector of system names get comma separated string
for(std::vector<std::string>::iterator it = stringVector.begin() ; it != stringVector.end() ; it++ ) for(std::vector<std::string>::iterator it = stringVector.begin() ; it != stringVector.end() ; it++ )
{ {

View file

@ -46,4 +46,4 @@ std::string removeParenthesis(const std::string& str);
std::vector<std::string> commaStringToVector(std::string commaString); std::vector<std::string> commaStringToVector(std::string commaString);
// turn a vector of strings into a comma-separated string // turn a vector of strings into a comma-separated string
std::string commaStringToVector(std::vector<std::string> stringVector); std::string vectorToCommaString(std::vector<std::string> stringVector);