mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-25 15:45:38 +00:00
New generic metadata backend.
This commit is contained in:
parent
dbcb9aed37
commit
421797929d
|
@ -127,6 +127,7 @@ set(ES_HEADERS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/InputManager.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/InputManager.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Log.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Log.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/MathExp.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/MathExp.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/MetaData.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/platform.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/platform.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Renderer.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Renderer.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Settings.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Settings.h
|
||||||
|
@ -169,6 +170,7 @@ set(ES_SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Log.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Log.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/MathExp.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/MathExp.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/MetaData.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/platform.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/platform.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Renderer_draw_gl.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Renderer_draw_gl.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Renderer_init.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Renderer_init.cpp
|
||||||
|
|
|
@ -10,8 +10,8 @@ class FileData
|
||||||
public:
|
public:
|
||||||
virtual ~FileData() { };
|
virtual ~FileData() { };
|
||||||
virtual bool isFolder() const = 0;
|
virtual bool isFolder() const = 0;
|
||||||
virtual const std::string & getName() const = 0;
|
virtual const std::string& getName() const = 0;
|
||||||
virtual const std::string & getPath() const = 0;
|
virtual const std::string& getPath() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -82,7 +82,7 @@ bool FolderData::compareRating(const FileData* file1, const FileData* file2)
|
||||||
const GameData * game1 = dynamic_cast<const GameData*>(file1);
|
const GameData * game1 = dynamic_cast<const GameData*>(file1);
|
||||||
const GameData * game2 = dynamic_cast<const GameData*>(file2);
|
const GameData * game2 = dynamic_cast<const GameData*>(file2);
|
||||||
if (game1 != nullptr && game2 != nullptr) {
|
if (game1 != nullptr && game2 != nullptr) {
|
||||||
return game1->getRating() < game2->getRating();
|
return const_cast<GameData*>(game1)->metadata()->getFloat("rating") < const_cast<GameData*>(game2)->metadata()->getFloat("rating");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ bool FolderData::compareUserRating(const FileData* file1, const FileData* file2)
|
||||||
const GameData * game1 = dynamic_cast<const GameData*>(file1);
|
const GameData * game1 = dynamic_cast<const GameData*>(file1);
|
||||||
const GameData * game2 = dynamic_cast<const GameData*>(file2);
|
const GameData * game2 = dynamic_cast<const GameData*>(file2);
|
||||||
if (game1 != nullptr && game2 != nullptr) {
|
if (game1 != nullptr && game2 != nullptr) {
|
||||||
return game1->getUserRating() < game2->getUserRating();
|
return const_cast<GameData*>(game1)->metadata()->getFloat("userrating") < const_cast<GameData*>(game2)->metadata()->getFloat("userrating");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ bool FolderData::compareTimesPlayed(const FileData* file1, const FileData* file2
|
||||||
const GameData * game1 = dynamic_cast<const GameData*>(file1);
|
const GameData * game1 = dynamic_cast<const GameData*>(file1);
|
||||||
const GameData * game2 = dynamic_cast<const GameData*>(file2);
|
const GameData * game2 = dynamic_cast<const GameData*>(file2);
|
||||||
if (game1 != nullptr && game2 != nullptr) {
|
if (game1 != nullptr && game2 != nullptr) {
|
||||||
return game1->getTimesPlayed() < game2->getTimesPlayed();
|
return const_cast<GameData*>(game1)->metadata()->getInt("playcount") < const_cast<GameData*>(game2)->metadata()->getInt("playcount");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ bool FolderData::compareLastPlayed(const FileData* file1, const FileData* file2)
|
||||||
const GameData * game1 = dynamic_cast<const GameData*>(file1);
|
const GameData * game1 = dynamic_cast<const GameData*>(file1);
|
||||||
const GameData * game2 = dynamic_cast<const GameData*>(file2);
|
const GameData * game2 = dynamic_cast<const GameData*>(file2);
|
||||||
if (game1 != nullptr && game2 != nullptr) {
|
if (game1 != nullptr && game2 != nullptr) {
|
||||||
return game1->getLastPlayed() < game2->getLastPlayed();
|
return const_cast<GameData*>(game1)->metadata()->getTime("lastplayed") < const_cast<GameData*>(game2)->metadata()->getTime("lastplayed");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
123
src/GameData.cpp
123
src/GameData.cpp
|
@ -1,23 +1,14 @@
|
||||||
#include "GameData.h"
|
#include "GameData.h"
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <ctime>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
GameData::GameData(SystemData* system, std::string path)
|
||||||
const std::string GameData::xmlTagGameList = "gameList";
|
: mSystem(system), mPath(path), mBaseName(boost::filesystem::path(path).stem().string()), mMetaData(MetaDataList::getDefaultGameMDD())
|
||||||
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::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), mUserRating(0.0f), mTimesPlayed(0), mLastPlayed(0)
|
|
||||||
{
|
{
|
||||||
|
if(mMetaData.get("name").empty())
|
||||||
|
mMetaData.set("name", mBaseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameData::isFolder() const
|
bool GameData::isFolder() const
|
||||||
|
@ -25,90 +16,20 @@ bool GameData::isFolder() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string & GameData::getName() const
|
const std::string& GameData::getName() const
|
||||||
{
|
{
|
||||||
return mName;
|
return mMetaData.get("name");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameData::setName(const std::string & name)
|
const std::string& GameData::getPath() const
|
||||||
{
|
|
||||||
mName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string & GameData::getPath() const
|
|
||||||
{
|
{
|
||||||
return mPath;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
float GameData::getRating() const
|
|
||||||
{
|
|
||||||
return mRating;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
std::string GameData::getBashPath() const
|
||||||
{
|
{
|
||||||
//a quick and dirty way to insert a backslash before most characters that would mess up a bash path
|
//a quick and dirty way to insert a backslash before most characters that would mess up a bash path
|
||||||
std::string path = mPath;
|
std::string path = getPath();
|
||||||
|
|
||||||
const char* invalidChars = " '\"\\!$^&*(){}[]?;<>";
|
const char* invalidChars = " '\"\\!$^&*(){}[]?;<>";
|
||||||
for(unsigned int i = 0; i < path.length(); i++)
|
for(unsigned int i = 0; i < path.length(); i++)
|
||||||
|
@ -133,6 +54,26 @@ std::string GameData::getBashPath() const
|
||||||
//returns the boost::filesystem stem of our path - e.g. for "/foo/bar.rom" returns "bar"
|
//returns the boost::filesystem stem of our path - e.g. for "/foo/bar.rom" returns "bar"
|
||||||
std::string GameData::getBaseName() const
|
std::string GameData::getBaseName() const
|
||||||
{
|
{
|
||||||
boost::filesystem::path path(mPath);
|
return mBaseName;
|
||||||
return path.stem().string();
|
}
|
||||||
|
|
||||||
|
void GameData::incTimesPlayed()
|
||||||
|
{
|
||||||
|
int timesPlayed = metadata()->getInt("playcount");
|
||||||
|
timesPlayed++;
|
||||||
|
|
||||||
|
std::stringstream ss();
|
||||||
|
metadata()->set("playcount", std::to_string(static_cast<long long>(timesPlayed)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameData::lastPlayedNow()
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::time(nullptr);
|
||||||
|
metadata()->set("lastplayed", ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaDataList* GameData::metadata()
|
||||||
|
{
|
||||||
|
return &mMetaData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,70 +2,44 @@
|
||||||
#define _GAMEDATA_H_
|
#define _GAMEDATA_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ctime>
|
|
||||||
|
|
||||||
#include "FileData.h"
|
#include "FileData.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
#include "MetaData.h"
|
||||||
|
|
||||||
//This class holds information about a game: at the least, its name, system, and path. Additional information is optional and read by other classes.
|
//This class holds information about a game: at the least, its name, system, and path. Additional information is optional and read by other classes.
|
||||||
class GameData : public FileData
|
class GameData : public FileData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//static tag names for reading/writing XML documents. This might fail in PUGIXML_WCHAR_MODE
|
GameData(SystemData* system, std::string path);
|
||||||
//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 xmlTagUserRating;
|
|
||||||
static const std::string xmlTagTimesPlayed;
|
|
||||||
static const std::string xmlTagLastPlayed;
|
|
||||||
|
|
||||||
GameData(SystemData* system, std::string path, std::string name);
|
const std::string& getName() const override;
|
||||||
|
const std::string& getPath() const override;
|
||||||
|
|
||||||
const std::string & getName() const;
|
void incTimesPlayed();
|
||||||
void setName(const std::string & name);
|
void lastPlayedNow();
|
||||||
|
|
||||||
const std::string & getPath() const;
|
|
||||||
void setPath(const std::string & path);
|
|
||||||
|
|
||||||
const std::string & getDescription() const;
|
|
||||||
void setDescription(const std::string & description);
|
|
||||||
|
|
||||||
const std::string & getImagePath() const;
|
|
||||||
void setImagePath(const std::string & imagePath);
|
|
||||||
|
|
||||||
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 getBashPath() const;
|
||||||
std::string getBaseName() const;
|
std::string getBaseName() const;
|
||||||
|
|
||||||
bool isFolder() const;
|
bool isFolder() const override;
|
||||||
|
|
||||||
|
MetaDataList* metadata();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SystemData* mSystem;
|
SystemData* mSystem;
|
||||||
std::string mPath;
|
const std::string mPath;
|
||||||
std::string mName;
|
const std::string mBaseName;
|
||||||
|
|
||||||
//extra data
|
//extra data
|
||||||
std::string mDescription;
|
/*std::string mDescription;
|
||||||
std::string mImagePath;
|
std::string mImagePath;
|
||||||
float mRating;
|
float mRating;
|
||||||
float mUserRating;
|
float mUserRating;
|
||||||
size_t mTimesPlayed;
|
size_t mTimesPlayed;
|
||||||
std::time_t mLastPlayed;
|
std::time_t mLastPlayed;*/
|
||||||
|
|
||||||
|
MetaDataList mMetaData;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -157,3 +157,12 @@ const Eigen::Affine3f GuiComponent::getTransform()
|
||||||
mTransform.translate(mPosition);
|
mTransform.translate(mPosition);
|
||||||
return mTransform;
|
return mTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GuiComponent::setValue(const std::string& value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GuiComponent::getValue() const
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
|
@ -19,10 +19,10 @@ public:
|
||||||
//Called when time passes. Default implementation also calls update(deltaTime) on children - so you should probably call GuiComponent::update(deltaTime) at some point.
|
//Called when time passes. Default implementation also calls update(deltaTime) on children - so you should probably call GuiComponent::update(deltaTime) at some point.
|
||||||
virtual void update(int deltaTime);
|
virtual void update(int deltaTime);
|
||||||
|
|
||||||
//Called when it's time to render. By default, just calls renderChildren(transform).
|
//Called when it's time to render. By default, just calls renderChildren(parentTrans * getTransform()).
|
||||||
//You probably want to override this like so:
|
//You probably want to override this like so:
|
||||||
//1. Calculate the new transform that your control will draw at with Eigen::Affine3f t = parentTrans * getTransform().
|
//1. Calculate the new transform that your control will draw at with Eigen::Affine3f t = parentTrans * getTransform().
|
||||||
//2. Set the renderer to use that new transform as the model matrix - Renderer::setModelMatrix(t.data());
|
//2. Set the renderer to use that new transform as the model matrix - Renderer::setMatrix(t);
|
||||||
//3. Draw your component.
|
//3. Draw your component.
|
||||||
//4. Tell your children to render, based on your component's transform - renderChildren(t).
|
//4. Tell your children to render, based on your component's transform - renderChildren(t).
|
||||||
virtual void render(const Eigen::Affine3f& parentTrans);
|
virtual void render(const Eigen::Affine3f& parentTrans);
|
||||||
|
@ -51,6 +51,9 @@ public:
|
||||||
|
|
||||||
const Eigen::Affine3f getTransform();
|
const Eigen::Affine3f getTransform();
|
||||||
|
|
||||||
|
virtual std::string getValue() const;
|
||||||
|
virtual void setValue(const std::string& value);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void renderChildren(const Eigen::Affine3f& transform) const;
|
void renderChildren(const Eigen::Affine3f& transform) const;
|
||||||
|
|
||||||
|
|
126
src/MetaData.cpp
Normal file
126
src/MetaData.cpp
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
#include "MetaData.h"
|
||||||
|
#include "components/TextComponent.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
MetaDataList::MetaDataList()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaDataList::MetaDataList(const std::vector<MetaDataDecl>& mdd)
|
||||||
|
{
|
||||||
|
for(auto iter = mdd.begin(); iter != mdd.end(); iter++)
|
||||||
|
set(iter->key, iter->defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<MetaDataDecl> MetaDataList::getDefaultGameMDD()
|
||||||
|
{
|
||||||
|
MetaDataDecl decls[] = {
|
||||||
|
{"name", MD_STRING, ""},
|
||||||
|
{"desc", MD_STRING, ""},
|
||||||
|
{"image", MD_IMAGE_PATH, ""},
|
||||||
|
{"rating", MD_RATING, "0"},
|
||||||
|
{"timesplayed", MD_INT, "0"},
|
||||||
|
{"playcount", MD_TIME, "0"}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<MetaDataDecl> mdd(decls, decls + sizeof(decls) / sizeof(decls[0]));
|
||||||
|
return mdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaDataList MetaDataList::createFromXML(const std::vector<MetaDataDecl>& mdd, pugi::xml_node node)
|
||||||
|
{
|
||||||
|
MetaDataList mdl;
|
||||||
|
|
||||||
|
for(auto iter = mdd.begin(); iter != mdd.end(); iter++)
|
||||||
|
{
|
||||||
|
pugi::xml_node md = node.child(iter->key.c_str());
|
||||||
|
if(md)
|
||||||
|
{
|
||||||
|
mdl.set(iter->key, md.text().get());
|
||||||
|
}else{
|
||||||
|
mdl.set(iter->key, iter->defaultValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mdl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetaDataList::appendToXML(pugi::xml_node parent, const std::vector<MetaDataDecl>& ignoreDefaults) const
|
||||||
|
{
|
||||||
|
for(auto iter = mMap.begin(); iter != mMap.end(); iter++)
|
||||||
|
{
|
||||||
|
bool write = true;
|
||||||
|
for(auto mddIter = ignoreDefaults.begin(); mddIter != ignoreDefaults.end(); mddIter++)
|
||||||
|
{
|
||||||
|
if(mddIter->key == iter->first)
|
||||||
|
{
|
||||||
|
if(iter->second == mddIter->defaultValue)
|
||||||
|
write = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(write)
|
||||||
|
parent.append_child(iter->first.c_str()).text().set(iter->second.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetaDataList::set(const std::string& key, const std::string& value)
|
||||||
|
{
|
||||||
|
mMap[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& MetaDataList::get(const std::string& key) const
|
||||||
|
{
|
||||||
|
return mMap.at(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int MetaDataList::getInt(const std::string& key) const
|
||||||
|
{
|
||||||
|
return atoi(get(key).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
float MetaDataList::getFloat(const std::string& key) const
|
||||||
|
{
|
||||||
|
return (float)atof(get(key).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::time_t MetaDataList::getTime(const std::string& key) const
|
||||||
|
{
|
||||||
|
return (std::time_t) atoi(get(key).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiComponent* MetaDataList::makeDisplay(Window* window, MetaDataType as)
|
||||||
|
{
|
||||||
|
switch(as)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
TextComponent* comp = new TextComponent(window);
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiComponent* MetaDataList::makeEditor(Window* window, MetaDataType as)
|
||||||
|
{
|
||||||
|
switch(as)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
TextComponent* comp = new TextComponent(window);
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiComponent* MetaDataList::makeDisplay(Window* window, MetaDataDecl from)
|
||||||
|
{
|
||||||
|
GuiComponent* comp = makeDisplay(window, from.type);
|
||||||
|
comp->setValue(get(from.key));
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiComponent* MetaDataList::makeEditor(Window* window, MetaDataDecl from)
|
||||||
|
{
|
||||||
|
GuiComponent* comp = makeEditor(window, from.type);
|
||||||
|
comp->setValue(get(from.key));
|
||||||
|
return comp;
|
||||||
|
}
|
73
src/MetaData.h
Normal file
73
src/MetaData.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pugiXML/pugixml.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include "GuiComponent.h"
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
enum MetaDataType
|
||||||
|
{
|
||||||
|
//generic types
|
||||||
|
MD_STRING,
|
||||||
|
MD_INT,
|
||||||
|
MD_FLOAT,
|
||||||
|
|
||||||
|
//specialized types
|
||||||
|
MD_IMAGE_PATH,
|
||||||
|
MD_RATING,
|
||||||
|
MD_TIME
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MetaDataDecl
|
||||||
|
{
|
||||||
|
std::string key;
|
||||||
|
MetaDataType type;
|
||||||
|
std::string defaultValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MetaDataList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::vector<MetaDataDecl> getDefaultGameMDD();
|
||||||
|
|
||||||
|
static MetaDataList createFromXML(const std::vector<MetaDataDecl>& mdd, pugi::xml_node node);
|
||||||
|
|
||||||
|
//MetaDataDecl required to set our defaults.
|
||||||
|
MetaDataList(const std::vector<MetaDataDecl>& mdd);
|
||||||
|
|
||||||
|
void set(const std::string& key, const std::string& value);
|
||||||
|
const std::string& get(const std::string& key) const;
|
||||||
|
int getInt(const std::string& key) const;
|
||||||
|
float getFloat(const std::string& key) const;
|
||||||
|
std::time_t getTime(const std::string& key) const;
|
||||||
|
|
||||||
|
GuiComponent* makeDisplay(Window* window, MetaDataType as);
|
||||||
|
GuiComponent* makeDisplay(Window* window, MetaDataDecl from);
|
||||||
|
|
||||||
|
GuiComponent* makeEditor(Window* window, MetaDataType as);
|
||||||
|
GuiComponent* makeEditor(Window* window, MetaDataDecl from);
|
||||||
|
|
||||||
|
void appendToXML(pugi::xml_node parent, const std::vector<MetaDataDecl>& ignoreDefaults = std::vector<MetaDataDecl>()) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MetaDataList();
|
||||||
|
|
||||||
|
std::map<std::string, std::string> mMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//options for storing metadata...
|
||||||
|
//store internally everything as a string - this is all going to be read to/from XML anyway, after all
|
||||||
|
//store using individual get/set functions ala Settings - this is a fair amount of work but the most explicit, for better or worse
|
||||||
|
|
||||||
|
//let's think about some of the special types we would like to support...
|
||||||
|
//image paths, sound paths, ratings, play counts
|
||||||
|
//these get represented behind-the-scenes as strings, floats, and integers, and are eventually saved as strings
|
||||||
|
//the only specialty is how they're edited and viewed, really
|
||||||
|
|
||||||
|
//so we need...
|
||||||
|
//to be able to iterate through the available metadata
|
||||||
|
//create components designed to either DISPLAY or EDIT a given piece of metadata
|
||||||
|
//save and load metadata
|
|
@ -96,8 +96,8 @@ void SystemData::launchGame(Window* window, GameData* game)
|
||||||
window->normalizeNextUpdate();
|
window->normalizeNextUpdate();
|
||||||
|
|
||||||
//update number of times the game has been launched and the time
|
//update number of times the game has been launched and the time
|
||||||
game->setTimesPlayed(game->getTimesPlayed() + 1);
|
game->incTimesPlayed();
|
||||||
game->setLastPlayed(std::time(nullptr));
|
game->lastPlayedNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemData::populateFolder(FolderData* folder)
|
void SystemData::populateFolder(FolderData* folder)
|
||||||
|
@ -145,7 +145,7 @@ void SystemData::populateFolder(FolderData* folder)
|
||||||
//if it matches, add it
|
//if it matches, add it
|
||||||
if(chkExt == extension)
|
if(chkExt == extension)
|
||||||
{
|
{
|
||||||
GameData* newGame = new GameData(this, filePath.generic_string(), filePath.stem().string());
|
GameData* newGame = new GameData(this, filePath.generic_string());
|
||||||
folder->pushFileData(newGame);
|
folder->pushFileData(newGame);
|
||||||
isGame = true;
|
isGame = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -90,11 +90,7 @@ GameData* createGameFromPath(std::string gameAbsPath, SystemData* system)
|
||||||
loops++;
|
loops++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GameData* game = new GameData(system, gameAbsPath);
|
||||||
//find gameName
|
|
||||||
std::string gameName = gamePath.substr(separator + 1, gamePath.find(".", separator) - separator - 1);
|
|
||||||
|
|
||||||
GameData* game = new GameData(system, gameAbsPath, gameName);
|
|
||||||
folder->pushFileData(game);
|
folder->pushFileData(game);
|
||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
@ -117,19 +113,19 @@ void parseGamelist(SystemData* system)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pugi::xml_node root = doc.child(GameData::xmlTagGameList.c_str());
|
pugi::xml_node root = doc.child("gameList");
|
||||||
if(!root)
|
if(!root)
|
||||||
{
|
{
|
||||||
LOG(LogError) << "Could not find <" << GameData::xmlTagGameList << "> node in gamelist \"" << xmlpath << "\"!";
|
LOG(LogError) << "Could not find <gameList> node in gamelist \"" << xmlpath << "\"!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(pugi::xml_node gameNode = root.child(GameData::xmlTagGame.c_str()); gameNode; gameNode = gameNode.next_sibling(GameData::xmlTagGame.c_str()))
|
for(pugi::xml_node gameNode = root.child("game"); gameNode; gameNode = gameNode.next_sibling("game"))
|
||||||
{
|
{
|
||||||
pugi::xml_node pathNode = gameNode.child(GameData::xmlTagPath.c_str());
|
pugi::xml_node pathNode = gameNode.child("path");
|
||||||
if(!pathNode)
|
if(!pathNode)
|
||||||
{
|
{
|
||||||
LOG(LogError) << "<" << GameData::xmlTagGame << "> node contains no <" << GameData::xmlTagPath << "> child!";
|
LOG(LogError) << "<game> node contains no <path> child!";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,11 +133,18 @@ void parseGamelist(SystemData* system)
|
||||||
boost::filesystem::path gamePath(pathNode.text().get());
|
boost::filesystem::path gamePath(pathNode.text().get());
|
||||||
std::string path = gamePath.generic_string();
|
std::string path = gamePath.generic_string();
|
||||||
|
|
||||||
//expand "."
|
//expand '.'
|
||||||
if(path[0] == '.')
|
if(path[0] == '.')
|
||||||
{
|
{
|
||||||
path.erase(0, 1);
|
path.erase(0, 1);
|
||||||
path.insert(0, system->getRootFolder()->getPath());
|
path.insert(0, boost::filesystem::path(xmlpath).parent_path().generic_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
//expand '~'
|
||||||
|
if(path[0] == '~')
|
||||||
|
{
|
||||||
|
path.erase(0, 1);
|
||||||
|
path.insert(0, getHomePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(boost::filesystem::exists(path))
|
if(boost::filesystem::exists(path))
|
||||||
|
@ -151,103 +154,36 @@ void parseGamelist(SystemData* system)
|
||||||
if(game == NULL)
|
if(game == NULL)
|
||||||
game = createGameFromPath(path, system);
|
game = createGameFromPath(path, system);
|
||||||
|
|
||||||
//actually gather the information in the XML doc, then pass it to the game's set method
|
//load the metadata
|
||||||
std::string newName, newDesc, newImage;
|
*(game->metadata()) = MetaDataList::createFromXML(MetaDataList::getDefaultGameMDD(), gameNode);
|
||||||
|
|
||||||
if(gameNode.child(GameData::xmlTagName.c_str()))
|
//make sure name gets set if one didn't exist
|
||||||
{
|
if(game->metadata()->get("name").empty())
|
||||||
game->setName(gameNode.child(GameData::xmlTagName.c_str()).text().get());
|
game->metadata()->set("name", game->getBaseName());
|
||||||
}
|
}else{
|
||||||
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] == '.')
|
|
||||||
{
|
|
||||||
newImage.erase(0, 1);
|
|
||||||
boost::filesystem::path pathname(xmlpath);
|
|
||||||
newImage.insert(0, pathname.parent_path().generic_string() );
|
|
||||||
}
|
|
||||||
|
|
||||||
//if the image exist, set it
|
|
||||||
if(boost::filesystem::exists(newImage))
|
|
||||||
{
|
|
||||||
game->setImagePath(newImage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//get rating and the times played from the XML doc
|
|
||||||
if(gameNode.child(GameData::xmlTagRating.c_str()))
|
|
||||||
{
|
|
||||||
float rating;
|
|
||||||
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!";
|
LOG(LogWarning) << "Game at \"" << path << "\" does not exist!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addGameDataNode(pugi::xml_node & parent, const GameData * game)
|
void addGameDataNode(pugi::xml_node& parent, const GameData* game)
|
||||||
{
|
{
|
||||||
//create game and add to parent node
|
//create game and add to parent node
|
||||||
pugi::xml_node newGame = parent.append_child(GameData::xmlTagGame.c_str());
|
pugi::xml_node newGame = parent.append_child("game");
|
||||||
//add values
|
|
||||||
if (!game->getPath().empty()) {
|
|
||||||
pugi::xml_node pathNode = newGame.append_child(GameData::xmlTagPath.c_str());
|
|
||||||
//store path with generic directory seperators
|
|
||||||
boost::filesystem::path gamePath(game->getPath());
|
|
||||||
pathNode.text().set(gamePath.generic_string().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((long double)game->getRating()).c_str());
|
|
||||||
|
|
||||||
pugi::xml_node userRatingNode = newGame.append_child(GameData::xmlTagUserRating.c_str());
|
//write metadata
|
||||||
userRatingNode.text().set(std::to_string((long double)game->getUserRating()).c_str());
|
const_cast<GameData*>(game)->metadata()->appendToXML(newGame, MetaDataList::getDefaultGameMDD());
|
||||||
|
|
||||||
pugi::xml_node timesPlayedNode = newGame.append_child(GameData::xmlTagTimesPlayed.c_str());
|
if(newGame.children().begin() == newGame.child("name") //first element is name
|
||||||
timesPlayedNode.text().set(std::to_string((unsigned long long)game->getTimesPlayed()).c_str());
|
&& ++newGame.children().begin() == newGame.children().end() //theres only one element
|
||||||
|
&& newGame.child("name").text().get() == game->getBaseName()) //the name is the default
|
||||||
pugi::xml_node lastPlayedNode = newGame.append_child(GameData::xmlTagLastPlayed.c_str());
|
{
|
||||||
lastPlayedNode.text().set(std::to_string((unsigned long long)game->getLastPlayed()).c_str());
|
//if the only info is the default name, don't bother with this node
|
||||||
|
parent.remove_child(newGame);
|
||||||
|
}else{
|
||||||
|
//there's something useful in there so we'll keep the node, add the path
|
||||||
|
newGame.prepend_child("path").text().set(game->getPath().c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateGamelist(SystemData* system)
|
void updateGamelist(SystemData* system)
|
||||||
|
@ -258,56 +194,64 @@ void updateGamelist(SystemData* system)
|
||||||
//we already have in the system from the XML, and then add it back from its GameData information...
|
//we already have in the system from the XML, and then add it back from its GameData information...
|
||||||
|
|
||||||
std::string xmlpath = system->getGamelistPath();
|
std::string xmlpath = system->getGamelistPath();
|
||||||
if(xmlpath.empty()) {
|
if(xmlpath.empty())
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\" before writing...";
|
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\" before writing...";
|
||||||
|
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
pugi::xml_parse_result result = doc.load_file(xmlpath.c_str());
|
pugi::xml_parse_result result = doc.load_file(xmlpath.c_str());
|
||||||
|
|
||||||
if(!result) {
|
if(!result)
|
||||||
|
{
|
||||||
LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n " << result.description();
|
LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n " << result.description();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pugi::xml_node root = doc.child(GameData::xmlTagGameList.c_str());
|
pugi::xml_node root = doc.child("gameList");
|
||||||
if(!root) {
|
if(!root)
|
||||||
LOG(LogError) << "Could not find <" << GameData::xmlTagGameList << "> node in gamelist \"" << xmlpath << "\"!";
|
{
|
||||||
|
LOG(LogError) << "Could not find <gameList> node in gamelist \"" << xmlpath << "\"!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//now we have all the information from the XML. now iterate through all our games and add information from there
|
//now we have all the information from the XML. now iterate through all our games and add information from there
|
||||||
FolderData * rootFolder = system->getRootFolder();
|
FolderData * rootFolder = system->getRootFolder();
|
||||||
if (rootFolder != nullptr) {
|
if (rootFolder != nullptr)
|
||||||
|
{
|
||||||
//get only files, no folders
|
//get only files, no folders
|
||||||
std::vector<FileData*> files = rootFolder->getFilesRecursive(true);
|
std::vector<FileData*> files = rootFolder->getFilesRecursive(true);
|
||||||
//iterate through all files, checking if they're already in the XML
|
//iterate through all files, checking if they're already in the XML
|
||||||
std::vector<FileData*>::const_iterator fit = files.cbegin();
|
std::vector<FileData*>::const_iterator fit = files.cbegin();
|
||||||
while(fit != files.cend()) {
|
while(fit != files.cend())
|
||||||
|
{
|
||||||
//try to cast to gamedata
|
//try to cast to gamedata
|
||||||
const GameData * game = dynamic_cast<const GameData*>(*fit);
|
const GameData * game = dynamic_cast<const GameData*>(*fit);
|
||||||
if (game != nullptr) {
|
if (game != nullptr)
|
||||||
|
{
|
||||||
//worked. check if this games' path can be found somewhere in the XML
|
//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())) {
|
for(pugi::xml_node gameNode = root.child("game"); gameNode; gameNode = gameNode.next_sibling("game"))
|
||||||
|
{
|
||||||
//get path from game node
|
//get path from game node
|
||||||
pugi::xml_node pathNode = gameNode.child(GameData::xmlTagPath.c_str());
|
pugi::xml_node pathNode = gameNode.child("path");
|
||||||
if(!pathNode)
|
if(!pathNode)
|
||||||
{
|
{
|
||||||
LOG(LogError) << "<" << GameData::xmlTagGame << "> node contains no <" << GameData::xmlTagPath << "> child!";
|
LOG(LogError) << "<game> node contains no <path> child!";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check paths. use the same directory separators
|
//check paths. use the same directory separators
|
||||||
boost::filesystem::path nodePath(pathNode.text().get());
|
boost::filesystem::path nodePath(pathNode.text().get());
|
||||||
boost::filesystem::path gamePath(game->getPath());
|
boost::filesystem::path gamePath(game->getPath());
|
||||||
if (nodePath.generic_string() == gamePath.generic_string()) {
|
if (nodePath.generic_string() == gamePath.generic_string())
|
||||||
|
{
|
||||||
//found the game. remove it. it will be added again later with updated values
|
//found the game. remove it. it will be added again later with updated values
|
||||||
root.remove_child(gameNode);
|
root.remove_child(gameNode);
|
||||||
//break node search loop
|
//break node search loop
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//either the game content was removed, because it needs to be updated,
|
//either the game content was removed, because it needs to be updated,
|
||||||
//or didn't exist in the first place, so just add it
|
//or didn't exist in the first place, so just add it
|
||||||
addGameDataNode(root, game);
|
addGameDataNode(root, game);
|
||||||
|
@ -316,10 +260,9 @@ void updateGamelist(SystemData* system)
|
||||||
}
|
}
|
||||||
//now write the file
|
//now write the file
|
||||||
if (!doc.save_file(xmlpath.c_str())) {
|
if (!doc.save_file(xmlpath.c_str())) {
|
||||||
LOG(LogError) << "Error saving XML file \"" << xmlpath << "\"!";
|
LOG(LogError) << "Error saving gamelist.xml file \"" << xmlpath << "\"!";
|
||||||
}
|
}
|
||||||
}
|
}else{
|
||||||
else {
|
|
||||||
LOG(LogError) << "Found no root folder for system \"" << system->getName() << "\"!";
|
LOG(LogError) << "Found no root folder for system \"" << system->getName() << "\"!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -353,11 +353,12 @@ void GuiGameList::updateDetailData()
|
||||||
//if we've selected a game
|
//if we've selected a game
|
||||||
if(mList.getSelectedObject() && !mList.getSelectedObject()->isFolder())
|
if(mList.getSelectedObject() && !mList.getSelectedObject()->isFolder())
|
||||||
{
|
{
|
||||||
|
GameData* game = (GameData*)mList.getSelectedObject();
|
||||||
//set image to either "not found" image or metadata image
|
//set image to either "not found" image or metadata image
|
||||||
if(((GameData*)mList.getSelectedObject())->getImagePath().empty())
|
if(game->metadata()->get("image").empty())
|
||||||
mScreenshot.setImage(mTheme->getString("imageNotFoundPath"));
|
mScreenshot.setImage(mTheme->getString("imageNotFoundPath"));
|
||||||
else
|
else
|
||||||
mScreenshot.setImage(((GameData*)mList.getSelectedObject())->getImagePath());
|
mScreenshot.setImage(game->metadata()->get("image"));
|
||||||
|
|
||||||
Eigen::Vector3f imgOffset = Eigen::Vector3f(Renderer::getScreenWidth() * 0.10f, 0, 0);
|
Eigen::Vector3f imgOffset = Eigen::Vector3f(Renderer::getScreenWidth() * 0.10f, 0, 0);
|
||||||
mScreenshot.setPosition(getImagePos() - imgOffset);
|
mScreenshot.setPosition(getImagePos() - imgOffset);
|
||||||
|
@ -372,7 +373,7 @@ void GuiGameList::updateDetailData()
|
||||||
|
|
||||||
mDescription.setPosition(0, 0);
|
mDescription.setPosition(0, 0);
|
||||||
mDescription.setSize(Eigen::Vector2f(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03f), 0));
|
mDescription.setSize(Eigen::Vector2f(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03f), 0));
|
||||||
mDescription.setText(((GameData*)mList.getSelectedObject())->getDescription());
|
mDescription.setText(game->metadata()->get("desc"));
|
||||||
}else{
|
}else{
|
||||||
mScreenshot.setImage("");
|
mScreenshot.setImage("");
|
||||||
mDescription.setText("");
|
mDescription.setText("");
|
||||||
|
|
|
@ -93,3 +93,13 @@ void TextComponent::calculateExtent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextComponent::setValue(const std::string& value)
|
||||||
|
{
|
||||||
|
setText(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TextComponent::getValue() const
|
||||||
|
{
|
||||||
|
return mText;
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,9 @@ public:
|
||||||
|
|
||||||
void render(const Eigen::Affine3f& parentTrans) override;
|
void render(const Eigen::Affine3f& parentTrans) override;
|
||||||
|
|
||||||
|
std::string getValue() const override;
|
||||||
|
void setValue(const std::string& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Font> getFont() const;
|
std::shared_ptr<Font> getFont() const;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue