diff --git a/src/ScraperCmdLine.cpp b/src/ScraperCmdLine.cpp index 2092f3c28..31f79c438 100644 --- a/src/ScraperCmdLine.cpp +++ b/src/ScraperCmdLine.cpp @@ -138,7 +138,7 @@ int run_scraper_cmdline() out << "Alright, let's do this thing!\n"; out << "=============================\n"; - Scraper* scraper = Settings::getInstance()->getScraper(); + std::shared_ptr scraper = Settings::getInstance()->getScraper(); for(auto sysIt = systems.begin(); sysIt != systems.end(); sysIt++) { std::vector files = (*sysIt)->getRootFolder()->getFilesRecursive(true); diff --git a/src/Settings.cpp b/src/Settings.cpp index 169a640d4..d5d34bb16 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -4,11 +4,10 @@ #include "platform.h" #include #include "scrapers/GamesDBScraper.h" -#include "scrapers/TheArchiveScraper.h" Settings* Settings::sInstance = NULL; -Settings::Settings() : mScraper(NULL) +Settings::Settings() { setDefaults(); loadFile(); @@ -41,10 +40,7 @@ void Settings::setDefaults() mIntMap["GameListSortIndex"] = 0; - if(mScraper) - delete mScraper; - - mScraper = new GamesDBScraper(); //TODO + mScraper = std::shared_ptr(new GamesDBScraper()); } template @@ -68,6 +64,9 @@ void Settings::saveFile() saveMap(doc, mIntMap, "int"); saveMap(doc, mFloatMap, "float"); + pugi::xml_node scraperNode = doc.append_child("scraper"); + scraperNode.append_attribute("value").set_value(mScraper->getName()); + doc.save_file(path.c_str()); } @@ -92,13 +91,25 @@ void Settings::loadFile() setInt(node.attribute("name").as_string(), node.attribute("value").as_int()); for(pugi::xml_node node = doc.child("float"); node; node = node.next_sibling()) setFloat(node.attribute("name").as_string(), node.attribute("value").as_float()); + + if(doc.child("scraper")) + { + std::shared_ptr scr = createScraperByName(doc.child("scraper").attribute("value").as_string()); + if(scr) + mScraper = scr; + } } -Scraper* Settings::getScraper() +std::shared_ptr Settings::getScraper() { return mScraper; } +void Settings::setScraper(std::shared_ptr scraper) +{ + mScraper = scraper; +} + //Print a warning message if the setting we're trying to get doesn't already exist in the map, then return the value in the map. #define SETTINGS_GETSET(type, mapName, getMethodName, setMethodName) type Settings::getMethodName(const std::string& name) \ { \ diff --git a/src/Settings.h b/src/Settings.h index fad641a6e..9f7e69d24 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -23,7 +23,8 @@ public: void setInt(const std::string& name, int value); void setFloat(const std::string& name, float value); - Scraper* getScraper(); + std::shared_ptr getScraper(); + void setScraper(std::shared_ptr scraper); private: static Settings* sInstance; @@ -35,7 +36,7 @@ private: std::map mBoolMap; std::map mIntMap; std::map mFloatMap; - Scraper* mScraper; + std::shared_ptr mScraper; }; #endif diff --git a/src/components/ComponentListComponent.cpp b/src/components/ComponentListComponent.cpp index 5b8bf4a12..8dc894996 100644 --- a/src/components/ComponentListComponent.cpp +++ b/src/components/ComponentListComponent.cpp @@ -419,6 +419,18 @@ void ComponentListComponent::update(int deltaTime) void ComponentListComponent::render(const Eigen::Affine3f& parentTrans) { Eigen::Affine3f trans = parentTrans * getTransform(); + + //draw cursor + if(cursorValid()) + { + ComponentEntry* entry = getCell(mCursor.x(), mCursor.y()); + Eigen::Affine3f entryTrans = trans * entry->component->getTransform(); + Renderer::setMatrix(entryTrans); + + Renderer::drawRect(0, 0, 4, 4, 0xFF0000FF); + Renderer::drawRect(0, 0, (int)entry->component->getSize().x(), (int)entry->component->getSize().y(), 0x0000AA22); + } + for(auto iter = mEntries.begin(); iter != mEntries.end(); iter++) { (*iter)->component->render(trans); @@ -444,16 +456,7 @@ void ComponentListComponent::render(const Eigen::Affine3f& parentTrans) pos[0] += getColumnWidth(x); }*/ - //draw cursor - if(cursorValid()) - { - ComponentEntry* entry = getCell(mCursor.x(), mCursor.y()); - Eigen::Affine3f entryTrans = trans * entry->component->getTransform(); - Renderer::setMatrix(entryTrans); - - Renderer::drawRect(0, 0, 4, 4, 0xFF0000FF); - Renderer::drawRect(0, 0, (int)entry->component->getSize().x(), (int)entry->component->getSize().y(), 0x0000AA22); - } + } void ComponentListComponent::textInput(const char* text) diff --git a/src/components/GuiSettingsMenu.cpp b/src/components/GuiSettingsMenu.cpp index 30a3bd2d2..e67a58fa9 100644 --- a/src/components/GuiSettingsMenu.cpp +++ b/src/components/GuiSettingsMenu.cpp @@ -65,7 +65,7 @@ GuiSettingsMenu::GuiSettingsMenu(Window* window) : GuiComponent(window), scrapers.push_back(std::shared_ptr(new GamesDBScraper())); scrapers.push_back(std::shared_ptr(new TheArchiveScraper())); mScraperOptList.populate(scrapers, [&] (const std::shared_ptr& s) { - return mScraperOptList.makeEntry(s->getName(), 0x00FF00FF, s); + return mScraperOptList.makeEntry(s->getName(), 0x00FF00FF, s, s->getName() == Settings::getInstance()->getScraper()->getName()); } ); mList.setEntry(Vector2i(1, 3), Vector2i(1, 1), &mScraperOptList, true, ComponentListComponent::AlignCenter); @@ -131,5 +131,8 @@ void GuiSettingsMenu::applyStates() s->setBool("DISABLESOUNDS", mDisableSoundsSwitch.getState()); + if(mScraperOptList.getSelected().size() > 0) + s->setScraper(mScraperOptList.getSelected()[0]->object); + s->saveFile(); } diff --git a/src/components/OptionListComponent.h b/src/components/OptionListComponent.h index 7e4956764..02ed9dd4d 100644 --- a/src/components/OptionListComponent.h +++ b/src/components/OptionListComponent.h @@ -5,7 +5,7 @@ #include #include #include "../Renderer.h" -#include "../Window.h" +#include "NinePatchComponent.h" //Used to display a list of options. //Can select one or multiple options. @@ -14,8 +14,8 @@ template class OptionListComponent : public GuiComponent { public: - OptionListComponent(Window* window) : GuiComponent(window), - mClosedCallback(nullptr), mCursor(0), mScrollOffset(0) + OptionListComponent(Window* window, bool multiSelect = false) : GuiComponent(window), + mCursor(0), mScrollOffset(0), mMultiSelect(multiSelect), mEditing(false), mBox(window, ":/textbox.png") { } @@ -28,11 +28,6 @@ public: }; - void setClosedCallback(std::function)> callback) - { - mClosedCallback = callback; - } - bool input(InputConfig* config, Input input) { if(input.value != 0) @@ -44,26 +39,32 @@ public: } if(config->isMappedTo("a", input)) { - select(mCursor); + if(mEditing) + { + select(mCursor); + if(!mMultiSelect) + close(); + }else{ + open(); + } + return true; } - if(mEntries.size() > 1) + if(mEditing && mEntries.size() > 1) { if(config->isMappedTo("up", input)) { if(mCursor > 0) - { mCursor--; - return true; - } + + return true; } if(config->isMappedTo("down", input)) { if(mCursor < mEntries.size() - 1) - { mCursor++; - return true; - } + + return true; } } } @@ -73,33 +74,84 @@ public: void render(const Eigen::Affine3f& parentTrans) { - Eigen::Affine3f trans = parentTrans * getTransform(); - std::shared_ptr font = getFont(); - Renderer::pushClipRect(Eigen::Vector2i((int)trans.translation().x(), (int)trans.translation().y()), - Eigen::Vector2i((int)getSize().x(), (int)getSize().y())); - - for(unsigned int i = mScrollOffset; i < mTextCaches.size(); i++) + //draw the option list + if(mEditing) { + Eigen::Affine3f trans = parentTrans * getTransform(); + + unsigned int renderCount = mTextCaches.size() - mScrollOffset; + + float height = (float)renderCount * font->getHeight(); + trans.translate(Eigen::Vector3f(0, -height / 2 + font->getHeight() * 0.5f, 0)); + + mBox.fitTo(Eigen::Vector2f(mSize.x(), height)); + mBox.render(trans); + Renderer::setMatrix(trans); + Renderer::drawRect(0, 0, (int)getSize().x(), (int)height, 0xFFFFFFFF); - if(i == mCursor) - Renderer::drawRect(0, 0, (int)mSize.x(), font->getHeight(), 0x000000FF); + for(unsigned int i = mScrollOffset; i < renderCount; i++) + { + Renderer::setMatrix(trans); - font->renderTextCache(mTextCaches.at(i)); - trans = trans.translate(Eigen::Vector3f(0, (float)font->getHeight(), 0)); + char rectOpacity = 0x00; + if(i == mCursor) + rectOpacity += 0x22; + if(mEntries.at(i).selected) + rectOpacity += 0x44; + + Renderer::drawRect(0, 0, (int)mSize.x(), font->getHeight(), 0x00000000 | rectOpacity); + + Renderer::setMatrix(trans); + font->renderTextCache(mTextCaches.at(i)); + + trans = trans.translate(Eigen::Vector3f(0, (float)font->getHeight(), 0)); + } + }else{ + Renderer::setMatrix(parentTrans * getTransform()); + + unsigned int color = 0x000000FF; + + if(mMultiSelect) + { + //draw "# selected" + unsigned int selectedCount = 0; + for(auto it = mEntries.begin(); it != mEntries.end(); it++) + { + if(it->selected) + selectedCount++; + } + + std::stringstream ss; + ss << selectedCount << " selected"; + font->drawText(ss.str(), Eigen::Vector2f(0, 0), color); + + }else{ + //draw selected option + bool found = false; + for(auto it = mEntries.begin(); it != mEntries.end(); it++) + { + if(it->selected) + { + font->drawText(it->text, Eigen::Vector2f(0, 0), color); + found = true; + break; + } + } + + if(!found) + font->drawText("Not set", Eigen::Vector2f(0, 0), color); + } } - Renderer::popClipRect(); - - trans = parentTrans * getTransform(); - renderChildren(trans); + renderChildren(parentTrans * getTransform()); } - ListEntry makeEntry(const std::string& name, unsigned int color, T obj) const + ListEntry makeEntry(const std::string& name, unsigned int color, T obj, bool selected = false) const { - ListEntry e = {name, color, false, obj}; + ListEntry e = {name, color, selected, obj}; return e; } @@ -138,14 +190,22 @@ private: if(i >= mEntries.size()) return; + if(!mMultiSelect) + for(auto it = mEntries.begin(); it != mEntries.end(); it++) + it->selected = false; + mEntries.at(i).selected = !mEntries.at(i).selected; updateTextCaches(); } void close() { - if(mClosedCallback) - mClosedCallback(getSelected()); + mEditing = false; + } + + void open() + { + mEditing = true; } void updateTextCaches() @@ -159,7 +219,7 @@ private: TextCache* cache; std::shared_ptr font = getFont(); Eigen::Vector2f newSize = getSize(); - newSize[1] = 0; + newSize[1] = (float)font->getHeight(); for(unsigned int i = 0; i < mEntries.size(); i++) { cache = font->buildTextCache(mEntries.at(i).text, 0, 0, mEntries.at(i).color); @@ -167,23 +227,24 @@ private: if(cache->metrics.size.x() > newSize.x()) newSize[0] = cache->metrics.size.x(); - - newSize[1] += cache->metrics.size.y(); } + setSize(newSize); } std::shared_ptr getFont() { - return Font::get(FONT_SIZE_SMALL); + return Font::get(FONT_SIZE_MEDIUM); } - std::function)> mClosedCallback; unsigned int mCursor; unsigned int mScrollOffset; + bool mMultiSelect; + bool mEditing; + + NinePatchComponent mBox; std::vector mEntries; std::vector mTextCaches; }; - diff --git a/src/scrapers/Scraper.cpp b/src/scrapers/Scraper.cpp index e6f7f76ab..5e4837e0d 100644 --- a/src/scrapers/Scraper.cpp +++ b/src/scrapers/Scraper.cpp @@ -6,6 +6,9 @@ #include #include +#include "GamesDBScraper.h" +#include "TheArchiveScraper.h" + std::vector Scraper::getResults(ScraperSearchParams params) { std::shared_ptr req = makeHttpReq(params); @@ -157,3 +160,14 @@ std::string getSaveAsPath(const std::string& subdirectory, const std::string& na path += name + ext; return path; } + + +std::shared_ptr createScraperByName(const std::string& name) +{ + if(name == "TheGamesDB") + return std::shared_ptr(new GamesDBScraper()); + else if(name == "TheArchive") + return std::shared_ptr(new TheArchiveScraper()); + + return nullptr; +} diff --git a/src/scrapers/Scraper.h b/src/scrapers/Scraper.h index 7d11af471..9243f6396 100644 --- a/src/scrapers/Scraper.h +++ b/src/scrapers/Scraper.h @@ -30,6 +30,8 @@ private: virtual std::vector parseReq(ScraperSearchParams params, std::shared_ptr) = 0; }; +std::shared_ptr createScraperByName(const std::string& name); + //About the same as "~/.emulationstation/downloaded_images/[subdirectory]/[name].[url's extension]". //Will create the "downloaded_images" and "subdirectory" directories if they do not exist. std::string getSaveAsPath(const std::string& subdirectory, const std::string& name, const std::string& url); diff --git a/src/scrapers/TheArchiveScraper.cpp b/src/scrapers/TheArchiveScraper.cpp index 61a5e03ca..ca22ad21e 100644 --- a/src/scrapers/TheArchiveScraper.cpp +++ b/src/scrapers/TheArchiveScraper.cpp @@ -4,7 +4,7 @@ #include "../Log.h" #include "../pugiXML/pugixml.hpp" -const char* TheArchiveScraper::getName() { return "TheArchiveVG"; } +const char* TheArchiveScraper::getName() { return "TheArchive"; } std::shared_ptr TheArchiveScraper::makeHttpReq(ScraperSearchParams params) {