updateGamelist now creates a gamelist.xml if one does not exist.

Added GuiMsgBoxOk and GuiMsgBoxYesNo, basic message boxes.
Added rating scraping to TheGamesDB scraper.
Added warning if platform ID is not set for a system the user has selected
to scrape.
This commit is contained in:
Aloshi 2013-10-16 17:05:02 -05:00
parent 12dd8b028d
commit 56b04aec4c
13 changed files with 149 additions and 15 deletions

View file

@ -178,6 +178,7 @@ set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiFastSelect.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMetaDataEd.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMsgBoxOk.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMsgBoxYesNo.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiGameList.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiGameScraper.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiInputConfig.h
@ -236,6 +237,7 @@ set(ES_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiFastSelect.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMetaDataEd.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMsgBoxOk.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMsgBoxYesNo.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiGameList.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiGameScraper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiInputConfig.cpp

View file

@ -34,9 +34,10 @@ void Settings::setDefaults()
mBoolMap["WINDOWED"] = false;
mBoolMap["DISABLESOUNDS"] = false;
mBoolMap["DisableGamelistWrites"] = false;
mBoolMap["ScrapeRatings"] = true;
mIntMap["DIMTIME"] = 30*1000;
mIntMap["ScraperResizeWidth"] = 450;
mIntMap["ScraperResizeWidth"] = 400;
mIntMap["ScraperResizeHeight"] = 0;
mIntMap["GameListSortIndex"] = 0;

View file

@ -198,20 +198,26 @@ void updateGamelist(SystemData* system)
return;
std::string xmlpath = system->getGamelistPath();
if(!boost::filesystem::exists(xmlpath))
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)
if(boost::filesystem::exists(xmlpath))
{
LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n " << result.description();
return;
//parse an existing file first
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\" before writing...";
pugi::xml_parse_result result = doc.load_file(xmlpath.c_str());
if(!result)
{
LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n " << result.description();
return;
}
}else{
//set up an empty gamelist to append to
doc.append_child("gameList");
}
pugi::xml_node root = doc.child("gameList");
if(!root)
{

View file

@ -1,6 +1,9 @@
#include "GuiMsgBoxOk.h"
#include "../Renderer.h"
#define MSG_WIDTH 0.8f
#define MSG_PADDING ((1 - MSG_WIDTH) / 2)
GuiMsgBoxOk::GuiMsgBoxOk(Window* window, const std::string& text, std::function<void()> callback) : GuiComponent(window),
mCallback(callback),
mText(window),
@ -8,17 +11,17 @@ GuiMsgBoxOk::GuiMsgBoxOk(Window* window, const std::string& text, std::function<
{
mText.setCentered(true);
mText.setColor(0x00BB00FF);
mText.setSize((float)Renderer::getScreenWidth(), 0);
mText.setSize(Renderer::getScreenWidth() * MSG_WIDTH, 0);
mText.setText(text);
mOkText.setCentered(true);
mOkText.setColor(0x0044BBFF);
mOkText.setFont(Font::get(FONT_SIZE_SMALL));
mOkText.setSize((float)Renderer::getScreenWidth(), 0);
mOkText.setSize(Renderer::getScreenWidth() * MSG_WIDTH, 0);
mOkText.setText("[A]");
mText.setPosition(0, (Renderer::getScreenHeight() - mText.getSize().y() - mOkText.getSize().y()) / 2);
mOkText.setPosition(0, mText.getPosition().y() + mText.getSize().y());
mText.setPosition(Renderer::getScreenWidth() * MSG_PADDING, (Renderer::getScreenHeight() - mText.getSize().y() - mOkText.getSize().y()) / 2);
mOkText.setPosition(Renderer::getScreenWidth() * MSG_PADDING, mText.getPosition().y() + mText.getSize().y());
}
bool GuiMsgBoxOk::input(InputConfig* config, Input input)

View file

@ -4,6 +4,8 @@
#include "TextComponent.h"
#include <functional>
//A simple popup message box with callbacks for when the user dismisses it.
//Make sure you remember to push it onto the window!
class GuiMsgBoxOk : public GuiComponent
{
public:

View file

@ -0,0 +1,59 @@
#include "GuiMsgBoxYesNo.h"
#include "../Renderer.h"
#define MSG_WIDTH 0.8f
#define MSG_PADDING ((1 - MSG_WIDTH) / 2)
GuiMsgBoxYesNo::GuiMsgBoxYesNo(Window* window, const std::string& text, std::function<void()> yesCallback, std::function<void()> noCallback) : GuiComponent(window),
mYesCallback(yesCallback),
mNoCallback(noCallback),
mText(window),
mInputText(window)
{
mText.setCentered(true);
mText.setColor(0x00BB00FF);
mText.setSize(Renderer::getScreenWidth() * MSG_WIDTH, 0);
mText.setText(text);
mInputText.setCentered(true);
mInputText.setColor(0x0044BBFF);
mInputText.setFont(Font::get(FONT_SIZE_SMALL));
mInputText.setSize(Renderer::getScreenWidth() * MSG_WIDTH, 0);
mInputText.setText("[A - yes] [B - no]");
mText.setPosition(Renderer::getScreenWidth() * MSG_PADDING, (Renderer::getScreenHeight() - mText.getSize().y() - mInputText.getSize().y()) / 2);
mInputText.setPosition(Renderer::getScreenWidth() * MSG_PADDING, mText.getPosition().y() + mText.getSize().y());
}
bool GuiMsgBoxYesNo::input(InputConfig* config, Input input)
{
if(input.value != 0)
{
if(config->isMappedTo("a", input))
{
if(mYesCallback)
mYesCallback();
delete this;
return true;
}else if(config->isMappedTo("b", input))
{
if(mNoCallback)
mNoCallback();
delete this;
return true;
}
}
return false;
}
void GuiMsgBoxYesNo::render(const Eigen::Affine3f& parentTrans)
{
float height = mText.getSize().y() + mInputText.getSize().y();
Renderer::setMatrix(parentTrans);
Renderer::drawRect(0, (int)((Renderer::getScreenHeight() - height) / 2), Renderer::getScreenWidth(), (int)height, 0x111111FF);
mText.render(parentTrans);
mInputText.render(parentTrans);
}

View file

@ -0,0 +1,22 @@
#pragma once
#include "../GuiComponent.h"
#include "TextComponent.h"
#include <functional>
//A simple "yes or no" popup box with callbacks for yes or no.
//Make sure you remember to push it onto the window!
class GuiMsgBoxYesNo : public GuiComponent
{
public:
GuiMsgBoxYesNo(Window* window, const std::string& msg, std::function<void()> yesCallback = nullptr, std::function<void()> noCallback = nullptr);
bool input(InputConfig* config, Input input) override;
void render(const Eigen::Affine3f& parentTrans) override;
private:
std::function<void()> mYesCallback, mNoCallback;
TextComponent mText;
TextComponent mInputText;
};

View file

@ -7,6 +7,8 @@
#include <boost/circular_buffer.hpp>
#include "TextComponent.h"
//A "terminal" of sorts for scraping.
//Doesn't accept input, but renders log-style messages and handles the callback chain for multi-game scraping.
class GuiScraperLog : public GuiComponent
{
public:

View file

@ -1,5 +1,6 @@
#include "GuiScraperStart.h"
#include "GuiScraperLog.h"
#include "GuiMsgBoxYesNo.h"
GuiScraperStart::GuiScraperStart(Window* window) : GuiComponent(window),
mBox(window, ":/frame.png"),
@ -44,7 +45,7 @@ GuiScraperStart::GuiScraperStart(Window* window) : GuiComponent(window),
mList.setEntry(Vector2i(1, 2), Vector2i(1, 1), &mManualSwitch, true, ComponentListComponent::AlignLeft);
mStartButton.setText("GO GO GO GO", 0x00FF00FF);
mStartButton.setPressedFunc(std::bind(&GuiScraperStart::start, this));
mStartButton.setPressedFunc(std::bind(&GuiScraperStart::pressedStart, this));
mList.setEntry(Vector2i(0, 3), Vector2i(2, 1), &mStartButton, true, ComponentListComponent::AlignCenter);
mList.setPosition(Renderer::getScreenWidth() / 2 - mList.getSize().x() / 2, Renderer::getScreenHeight() / 2 - mList.getSize().y() / 2);
@ -53,6 +54,22 @@ GuiScraperStart::GuiScraperStart(Window* window) : GuiComponent(window),
mBox.fitTo(mList.getSize(), mList.getPosition(), Eigen::Vector2f(8, 8));
}
void GuiScraperStart::pressedStart()
{
std::vector<SystemData*> sys = mSystemsOpt.getSelectedObjects();
for(auto it = sys.begin(); it != sys.end(); it++)
{
if((*it)->getPlatformId() == PlatformIds::PLATFORM_UNKNOWN)
{
mWindow->pushGui(new GuiMsgBoxYesNo(mWindow, "Warning: some of your selected systems do not have a platform ID set. Results may be even more inaccurate than usual!\nContinue anyway?",
std::bind(&GuiScraperStart::start, this)));
return;
}
}
start();
}
void GuiScraperStart::start()
{
std::queue<ScraperSearchParams> searches = getSearches(mSystemsOpt.getSelectedObjects(), mFiltersOpt.getSelectedObjects()[0]);

View file

@ -12,6 +12,9 @@
typedef std::function<bool(SystemData*, GameData*)> GameFilterFunc;
//The starting point for a multi-game scrape.
//Allows the user to set various parameters (to set filters, to set which systems to scrape, to enable manual mode).
//Generates a list of "searches" that will be carried out by GuiScraperLog.
class GuiScraperStart : public GuiComponent
{
public:
@ -20,6 +23,7 @@ public:
bool input(InputConfig* config, Input input) override;
private:
void pressedStart();
void start();
std::queue<ScraperSearchParams> getSearches(std::vector<SystemData*> systems, GameFilterFunc selector);

View file

@ -13,6 +13,12 @@ RatingComponent::RatingComponent(Window* window) : GuiComponent(window)
void RatingComponent::setValue(const std::string& value)
{
if(value.empty())
{
mValue = 0.0f;
return;
}
mValue = stof(value);
if(mValue > 1.0f)
mValue = 1.0f;

View file

@ -106,6 +106,14 @@ std::vector<MetaDataList> GamesDBScraper::parseReq(ScraperSearchParams params, s
boost::posix_time::ptime rd = string_to_ptime(game.child("ReleaseDate").text().get(), "%m/%d/%Y");
mdl.back().setTime("releasedate", rd);
if(Settings::getInstance()->getBool("ScrapeRatings") && game.child("Rating"))
{
float ratingVal = (game.child("Rating").text().as_int() / 10.0f);
std::stringstream ss;
ss << ratingVal;
mdl.back().set("rating", ss.str());
}
pugi::xml_node images = game.child("Images");
if(images)

View file

@ -48,6 +48,8 @@ std::vector<MetaDataList> TheArchiveScraper::parseReq(ScraperSearchParams params
mdl.back().set("name", game.child("title").text().get());
mdl.back().set("desc", game.child("description").text().get());
//Archive.search does not return ratings
pugi::xml_node image = game.child("box_front");
pugi::xml_node thumbnail = game.child("box_front_small");