commit 84bbabc5
Updated libsago
Changed files
diff --git a/src/sago/SagoDataHolder.hpp b/src/sago/SagoDataHolder.hpp
index 068650a..3c126aa 100644
--- a/src/sago/SagoDataHolder.hpp
+++ b/src/sago/SagoDataHolder.hpp
@@ -49,7 +49,7 @@ private:
};
-class MusicHandler {
+class MusicHandler final {
public:
MusicHandler() {};
MusicHandler(const SagoDataHolder* holder, const std::string &musicName);
@@ -62,7 +62,7 @@ private:
};
-class SoundHandler {
+class SoundHandler final {
public:
SoundHandler() {};
SoundHandler(const SagoDataHolder* holder, const std::string &soundName);
@@ -74,7 +74,7 @@ private:
Uint64 version = 0;
};
-class SagoDataHolder {
+class SagoDataHolder final {
public:
/**
* The renderer must be set before requesting a texture.
@@ -112,7 +112,7 @@ public:
* @return A globally unique number.
*/
Uint64 getVersion() const;
- virtual ~SagoDataHolder();
+ ~SagoDataHolder();
private:
SagoDataHolder(const SagoDataHolder& base) = delete;
SagoDataHolder& operator=(const SagoDataHolder& base) = delete;
diff --git a/src/sago/SagoSprite.hpp b/src/sago/SagoSprite.hpp
index c66fd87..688770a 100644
--- a/src/sago/SagoSprite.hpp
+++ b/src/sago/SagoSprite.hpp
@@ -29,7 +29,7 @@ SOFTWARE.
namespace sago {
-class SagoSprite {
+class SagoSprite final {
public:
SagoSprite();
SagoSprite(const SagoDataHolder &texHolder, const std::string &texture,const SDL_Rect& initImage,const int animationFrames, const int animationFrameLength);
@@ -76,7 +76,7 @@ public:
SagoSprite& operator=(const SagoSprite& base);
int GetWidth() const;
int GetHeight() const;
- virtual ~SagoSprite();
+ ~SagoSprite();
private:
struct SagoSpriteData;
SagoSpriteData *data;
diff --git a/src/sago/SagoSpriteHolder.cpp b/src/sago/SagoSpriteHolder.cpp
index 2b24e6a..d219487 100644
--- a/src/sago/SagoSpriteHolder.cpp
+++ b/src/sago/SagoSpriteHolder.cpp
@@ -73,7 +73,7 @@ static int getDefaultValue(const rapidjson::Value& value, const char* name, int
static std::string getDefaultValue(const rapidjson::Value& value, const char* name, std::string defaultValue) {
assert(value.IsObject());
const auto& t = value.GetObject().FindMember(name);
- if (t->value.IsString()) {
+ if (t != value.MemberEnd() && t->value.IsString()) {
defaultValue = t->value.GetString();
}
return defaultValue;
@@ -106,9 +106,6 @@ void SagoSpriteHolder::ReadSpriteFile(const std::string& filename) {
SDL_Rect origin = {};
origin.x = getDefaultValue(m.value, "originx",0);
origin.y = getDefaultValue(m.value, "originy",0);
- if (origin.x != 0) {
- cerr << "Origin: " << origin.x << ", " << origin.y << "\n";
- }
if (number_of_frames < 1) {
number_of_frames = 1;
}
diff --git a/src/sago/SagoSpriteHolder.hpp b/src/sago/SagoSpriteHolder.hpp
index 7e2924c..21b093e 100644
--- a/src/sago/SagoSpriteHolder.hpp
+++ b/src/sago/SagoSpriteHolder.hpp
@@ -30,10 +30,10 @@ SOFTWARE.
namespace sago {
-class SagoSpriteHolder {
+class SagoSpriteHolder final {
public:
explicit SagoSpriteHolder(const SagoDataHolder &texHolder);
- virtual ~SagoSpriteHolder();
+ ~SagoSpriteHolder();
void ReadSprites();
const sago::SagoSprite& GetSprite(const std::string &spritename) const;
const SagoDataHolder& GetDataHolder() const;
diff --git a/src/sago/SagoTextBox.cpp b/src/sago/SagoTextBox.cpp
index 01694ac..8a531bf 100644
--- a/src/sago/SagoTextBox.cpp
+++ b/src/sago/SagoTextBox.cpp
@@ -60,6 +60,10 @@ void SagoTextBox::SetText(const char* text) {
data->text = text;
}
+void SagoTextBox::SetText(const std::string& text) {
+ data->text = text;
+}
+
void SagoTextBox::SetColor(const SDL_Color& color) {
data->color = color;
}
@@ -93,14 +97,11 @@ void SagoTextBox::AppendLineToCache(const std::string& text) {
tf.SetFontSize(data->fontSize);
tf.SetColor(data->color);
tf.SetOutline(data->outline, data->outlineColor);
- tf.SetText(text.c_str());
+ tf.SetText(text);
}
void SagoTextBox::SplitAndAppendLineToCache(TTF_Font* font, const std::string& text) {
- if (text.length() == 0) {
- return;
- }
int width = data->maxWidth;
TTF_SizeUTF8(font, text.c_str(),&width, nullptr);
if (data->maxWidth <= 0 || width <= data->maxWidth || text.length() == 1) {
@@ -156,6 +157,10 @@ void SagoTextBox::SplitAndAppendLineToCache(TTF_Font* font, const std::string& t
}
void SagoTextBox::UpdateCache() {
+ if (!data->tex) {
+ std::cerr << "FATAL: SagoTextBox::UpdateCache - DataHolder not set!\n";
+ abort();
+ }
TTF_Font *font = data->tex->getFontPtr(data->fontName, data->fontSize);
const char delim = '\n';
const std::string& s = data->text;
diff --git a/src/sago/SagoTextBox.hpp b/src/sago/SagoTextBox.hpp
index 6fe19d9..906fae2 100644
--- a/src/sago/SagoTextBox.hpp
+++ b/src/sago/SagoTextBox.hpp
@@ -30,13 +30,20 @@ SOFTWARE.
namespace sago {
-class SagoTextBox {
+class SagoTextBox final {
public:
SagoTextBox();
- virtual ~SagoTextBox();
+ ~SagoTextBox();
void SetHolder(const SagoDataHolder* holder);
void SetText(const char* text);
+ void SetText(const std::string& text);
void SetColor(const SDL_Color& color);
+
+ /**
+ * Set the name of the font. Must be known to the data holder.
+ * The name could for instance be "freeserif".
+ * @param fontName Name of the font as required by SagoDataHolder
+ */
void SetFont(const char* fontName);
void SetFontSize(int fontSize);
void SetOutline(int outlineSize, const SDL_Color& color);
diff --git a/src/sago/SagoTextField.cpp b/src/sago/SagoTextField.cpp
index 831d3f1..2bb40f9 100644
--- a/src/sago/SagoTextField.cpp
+++ b/src/sago/SagoTextField.cpp
@@ -83,6 +83,22 @@ SagoTextField::SagoTextField(SagoTextField&& o) noexcept {
o.data = nullptr;
}
+SagoTextField& SagoTextField::CopyFrom(const SagoTextField& base) {
+ ClearCache();
+ try {
+ *data = *(base.data);
+ //Copy all data but do not reuse the cache as it would result in a double free
+ data->outlineTextSurface = nullptr;
+ data->outlineTexture = nullptr;
+ data->textSurface = nullptr;
+ data->texture = nullptr;
+ return *this;
+ } catch (...) {
+ delete data;
+ throw;
+ }
+}
+
SagoTextField::~SagoTextField() {
if(!data) {
return;
@@ -99,6 +115,10 @@ void SagoTextField::SetText(const char* text) {
data->text = text;
}
+void SagoTextField::SetText(const std::string& text) {
+ data->text = text;
+}
+
void SagoTextField::SetColor(const SDL_Color& color) {
data->color = color;
}
@@ -121,10 +141,6 @@ const std::string& SagoTextField::GetText() const {
}
void SagoTextField::ClearCache() {
- if (!data->tex) {
- std::cerr << "FATAL: DataHolder not set!\n";
- abort();
- }
if (data->texture) {
SDL_DestroyTexture(data->texture);
data->texture = nullptr;
@@ -144,12 +160,14 @@ void SagoTextField::ClearCache() {
}
void SagoTextField::UpdateCache(SDL_Renderer* target) {
+ if (!data->tex) {
+ std::cerr << "FATAL: DataHolder not set!\n";
+ abort();
+ }
ClearCache();
TTF_Font *font = data->tex->getFontPtr(data->fontName, data->fontSize);
data->textSurface = TTF_RenderUTF8_Blended (font, data->text.c_str(), data->color);
data->texture = SDL_CreateTextureFromSurface(target, data->textSurface);
- int textWidth = 0;
- SDL_QueryTexture(data->texture, NULL, NULL, &textWidth, NULL);
if (data->outline > 0) {
OutlineHandler oh(font, data->outline);
data->outlineTextSurface = TTF_RenderUTF8_Blended (font, data->text.c_str(), data->outlineColor);
@@ -160,7 +178,21 @@ void SagoTextField::UpdateCache(SDL_Renderer* target) {
data->renderedVersion = data->tex->getVersion();
}
-void SagoTextField::Draw(SDL_Renderer* target, int x, int y) {
+void SagoTextField::GetRenderedSize(const char* text, int* w, int* h) {
+ TTF_Font *font = data->tex->getFontPtr(data->fontName, data->fontSize);
+ int ret = TTF_SizeUTF8(font, text, w, h);
+ if (ret) {
+ if (w) {
+ *w = 0;
+ }
+ if (h) {
+ *h = 0;
+ }
+ std::cerr << "GetRenderedSize failed to find size of " << text << ". Error code: " << ret << "\n";
+ }
+}
+
+void SagoTextField::Draw(SDL_Renderer* target, int x, int y, Alignment alignment, VerticalAlignment verticalAlignment) {
if (data->text.empty()) {
return;
}
@@ -173,6 +205,18 @@ void SagoTextField::Draw(SDL_Renderer* target, int x, int y) {
int texW = 0;
int texH = 0;
SDL_QueryTexture(data->texture, NULL, NULL, &texW, &texH);
+ if (alignment == Alignment::center) {
+ x -= texW/2;
+ }
+ if (alignment == Alignment::right) {
+ y -= texW;
+ }
+ if (verticalAlignment == VerticalAlignment::center) {
+ y -= texH/2;
+ }
+ if (verticalAlignment == VerticalAlignment::bottom) {
+ y -= texH;
+ }
SDL_Rect dstrect = { x, y, texW, texH };
if (data->outlineTexture) {
int outlineTexW = 0;
diff --git a/src/sago/SagoTextField.hpp b/src/sago/SagoTextField.hpp
index ab05c49..902ee16 100644
--- a/src/sago/SagoTextField.hpp
+++ b/src/sago/SagoTextField.hpp
@@ -38,12 +38,21 @@ namespace sago {
* Normally all values will be set at the beginning before text is drawn.
* SetHolder MUST be called before the field is drawn!
*/
-class SagoTextField {
+class SagoTextField final {
public:
SagoTextField();
SagoTextField(SagoTextField&& o) noexcept;
SagoTextField& operator=(const SagoTextField&& base) = delete;
- virtual ~SagoTextField();
+ SagoTextField& operator=(const SagoTextField& base) = delete;
+ ~SagoTextField();
+ /**
+ * This method creates a copy of a given font.
+ * The cache will not be copied.
+ * This is ALMOST like the "= operator" but given its own name to prevent implicit calling.
+ * @param base The object to copy from
+ * @return A reference to this object.
+ */
+ SagoTextField& CopyFrom(const SagoTextField& base);
/**
* Sets the data holder. This is MANDATORY
* @param holder The data holder to fetch the fonts from
@@ -54,9 +63,15 @@ public:
* @param text The actual UTF-8 encoded text
*/
void SetText(const char* text);
+ /**
+ * Set the text to display.
+ * @param text The actual UTF-8 encoded text
+ */
+ void SetText(const std::string& text);
void SetColor(const SDL_Color& color);
/**
* Set the name of the font. Must be known to the data holder.
+ * The name could for instance be "freeserif".
* @param fontName Name of the font as required by SagoDataHolder
*/
void SetFont(const char* fontName);
@@ -72,7 +87,18 @@ public:
* @return The text
*/
const std::string& GetText() const;
- void Draw(SDL_Renderer* target, int x, int y);
+ /**
+ * A Shorthand for calling TTF_SizeUTF8 on the right font
+ * The size is measuered WITHOUT the outline!
+ * Will fail silently on error (except writing to stderr) and set w and h to 0 if they are not null.
+ * @param text The text to check the rendered size for
+ * @param w Pointer to an int where the width of the text will be stored. Maybe null.
+ * @param h Pointer to an int where the hight of the text will be stored. Maybe null.
+ */
+ void GetRenderedSize(const char* text, int* w = nullptr, int* h = nullptr);
+ enum class Alignment { left = 0, right=1, center = 2 };
+ enum class VerticalAlignment { top = 0, center = 1, bottom = 2};
+ void Draw(SDL_Renderer* target, int x, int y, Alignment alignment = Alignment::left, VerticalAlignment verticalAlignment = VerticalAlignment::top);
/**
* Updates the cache.
* You normally do not want to call this from the outside as it is done just in time.
@@ -88,7 +114,6 @@ public:
void ClearCache();
private:
SagoTextField(const SagoTextField& orig) = delete;
- SagoTextField& operator=(const SagoTextField& base) = delete;
struct SagoTextFieldData;
SagoTextFieldData *data;
};
diff --git a/src/sago/platform_folders.cpp b/src/sago/platform_folders.cpp
index 004ceac..34e6bae 100644
--- a/src/sago/platform_folders.cpp
+++ b/src/sago/platform_folders.cpp
@@ -30,17 +30,14 @@ SOFTWARE.
#include <iostream>
#include <stdexcept>
#include <string.h>
-#include <stdio.h>
+#include <cstdio>
#include <cstdlib>
#if defined(_WIN32)
#include <windows.h>
#include <shlobj.h>
-#define strtok_r strtok_s
-
-static std::string win32_utf16_to_utf8(const wchar_t* wstr)
-{
+static std::string win32_utf16_to_utf8(const wchar_t* wstr) {
std::string res;
// If the 6th parameter is 0 then WideCharToMultiByte returns the number of bytes needed to store the result.
int actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
@@ -52,7 +49,7 @@ static std::string win32_utf16_to_utf8(const wchar_t* wstr)
}
if (actualSize == 0) {
// WideCharToMultiByte return 0 for errors.
- std::string errorMsg = "UTF16 to UTF8 failed with error code: " + GetLastError();
+ const std::string errorMsg = "UTF16 to UTF8 failed with error code: " + GetLastError();
throw std::runtime_error(errorMsg.c_str());
}
return res;
@@ -61,8 +58,7 @@ static std::string win32_utf16_to_utf8(const wchar_t* wstr)
static std::string GetWindowsFolder(int folderId, const char* errorMsg) {
wchar_t szPath[MAX_PATH];
szPath[0] = 0;
- if ( !SUCCEEDED( SHGetFolderPathW( NULL, folderId, NULL, 0, szPath ) ) )
- {
+ if ( !SUCCEEDED( SHGetFolderPathW( NULL, folderId, NULL, 0, szPath ) ) ) {
throw std::runtime_error(errorMsg);
}
return win32_utf16_to_utf8(szPath);
@@ -101,12 +97,14 @@ static std::string GetMacFolder(OSType folderType, const char* errorMsg) {
#include <pwd.h>
#include <unistd.h>
#include <sys/types.h>
+// For strlen and strtok
+#include <cstring>
//Typically Linux. For easy reading the comments will just say Linux but should work with most *nixes
static void throwOnRelative(const char* envName, const char* envValue) {
if (envValue[0] != '/') {
char buffer[200];
- snprintf(buffer, sizeof(buffer), "Environment \"%s\" does not start with an '/'. XDG specifies that the value must be absolute. The current value is: \"%s\"", envName, envValue);
+ std::snprintf(buffer, sizeof(buffer), "Environment \"%s\" does not start with an '/'. XDG specifies that the value must be absolute. The current value is: \"%s\"", envName, envValue);
throw std::runtime_error(buffer);
}
}
@@ -120,13 +118,13 @@ static void throwOnRelative(const char* envName, const char* envValue) {
static std::string getHome() {
std::string res;
int uid = getuid();
- const char* homeEnv = getenv("HOME");
+ const char* homeEnv = std::getenv("HOME");
if ( uid != 0 && homeEnv) {
//We only acknowlegde HOME if not root.
res = homeEnv;
return res;
}
- struct passwd *pw = getpwuid(uid);
+ struct passwd* pw = getpwuid(uid);
if (!pw) {
throw std::runtime_error("Unable to get passwd struct.");
}
@@ -140,7 +138,7 @@ static std::string getHome() {
static std::string getLinuxFolderDefault(const char* envName, const char* defaultRelativePath) {
std::string res;
- const char* tempRes = getenv(envName);
+ const char* tempRes = std::getenv(envName);
if (tempRes) {
throwOnRelative(envName, tempRes);
res = tempRes;
@@ -151,9 +149,8 @@ static std::string getLinuxFolderDefault(const char* envName, const char* defaul
}
static void appendExtraFoldersTokenizer(const char* envName, const char* envValue, std::vector<std::string>& folders) {
- std::vector<char> buffer(envValue, envValue + strlen(envValue) + 1);
- char *saveptr;
- const char* p = strtok_r ( &buffer[0], ":", &saveptr);
+ std::vector<char> buffer(envValue, envValue + std::strlen(envValue) + 1);
+ char* p = std::strtok ( &buffer[0], ":");
while (p != NULL) {
if (p[0] == '/') {
folders.push_back(p);
@@ -163,12 +160,12 @@ static void appendExtraFoldersTokenizer(const char* envName, const char* envValu
//The XDG documentation indicates that the folder should be ignored but that the program should continue.
std::cerr << "Skipping path \"" << p << "\" in \"" << envName << "\" because it does not start with a \"/\"\n";
}
- p = strtok_r (NULL, ":", &saveptr);
+ p = std::strtok (NULL, ":");
}
}
static void appendExtraFolders(const char* envName, const char* defaultValue, std::vector<std::string>& folders) {
- const char* envValue = getenv(envName);
+ const char* envValue = std::getenv(envName);
if (!envValue) {
envValue = defaultValue;
}
@@ -206,7 +203,7 @@ std::string getCacheDir() {
#elif defined(__APPLE__)
return GetMacFolder(kCachedDataFolderType, "Failed to find the Application Support Folder");
#else
- return getLinuxFolderDefault("XDG_CONFIG_HOME", ".cache");
+ return getLinuxFolderDefault("XDG_CACHE_HOME", ".cache");
#endif
}
@@ -276,7 +273,8 @@ PlatformFolders::PlatformFolders() {
this->data = new PlatformFolders::PlatformFoldersData();
try {
PlatformFoldersFillData(data->folders);
- } catch (...) {
+ }
+ catch (...) {
delete this->data;
throw;
}
@@ -364,6 +362,33 @@ std::string PlatformFolders::getSaveGamesFolder1() const {
#endif
}
+std::string getDesktopFolder() {
+ return PlatformFolders().getDesktopFolder();
+}
+
+std::string getDocumentsFolder() {
+ return PlatformFolders().getDocumentsFolder();
+}
+
+std::string getDownloadFolder1() {
+ return PlatformFolders().getDownloadFolder1();
+}
+
+std::string getPicturesFolder() {
+ return PlatformFolders().getPicturesFolder();
+}
+
+std::string getMusicFolder() {
+ return PlatformFolders().getMusicFolder();
+}
+
+std::string getVideoFolder() {
+ return PlatformFolders().getVideoFolder();
+}
+
+std::string getSaveGamesFolder1() {
+ return PlatformFolders().getSaveGamesFolder1();
+}
} //namespace sago
diff --git a/src/sago/platform_folders.h b/src/sago/platform_folders.h
index 73fba85..bd6c0d5 100644
--- a/src/sago/platform_folders.h
+++ b/src/sago/platform_folders.h
@@ -48,6 +48,7 @@ namespace sago {
* @return The base folder for storring program data.
*/
std::string getDataHome();
+
/**
* Retrives the base folder for storring config files.
* You must add the program name yourself like this:
@@ -59,6 +60,7 @@ std::string getDataHome();
* @return The base folder for storring config data.
*/
std::string getConfigHome();
+
/**
* Retrives the base folder for storring cache files.
* You must add the program name yourself like this:
@@ -70,6 +72,7 @@ std::string getConfigHome();
* @return The base folder for storring data that do not need to be backed up.
*/
std::string getCacheDir();
+
/**
* This will append extra folders that your program should be looking for data files in.
* This does not normally include the path returned by GetDataHome().
@@ -87,6 +90,7 @@ std::string getCacheDir();
* @param homes A vector that extra folders will be appended to.
*/
void appendAdditionalDataDirectories(std::vector<std::string>& homes);
+
/**
* This will append extra folders that your program should be looking for config files in.
* This does not normally include the path returned by GetConfigHome().
@@ -106,6 +110,58 @@ void appendAdditionalDataDirectories(std::vector<std::string>& homes);
void appendAdditionalConfigDirectories(std::vector<std::string>& homes);
/**
+ * The folder that represents the desktop.
+ * Normally you should try not to use this folder.
+ * @return Absolute path to the user's desktop
+ */
+std::string getDesktopFolder();
+
+/**
+ * The folder to store user documents to
+ * @return Absolute path to the "Documents" folder
+ */
+std::string getDocumentsFolder();
+
+/**
+ * The folder where files are downloaded.
+ * @note Windows: This version is XP compatible and returns the Desktop. Vista and later has a dedicated folder.
+ * @return Absolute path to the folder where files are downloaded to.
+ */
+std::string getDownloadFolder1();
+
+/**
+ * The folder for storring the user's pictures.
+ * @return Absolute path to the "Picture" folder
+ */
+std::string getPicturesFolder();
+
+/**
+ * The folder where music is stored
+ * @return Absolute path to the music folder
+ */
+std::string getMusicFolder();
+
+/**
+ * The folder where video is stored
+ * @return Absolute path to the video folder
+ */
+std::string getVideoFolder();
+
+/**
+ * The base folder for storring saved games.
+ * You must add the program name to it like this:
+ * @code{.cpp}
+ * string saved_games_folder = sago::getSaveGamesFolder1()+"/My Program Name/";
+ * @endcode
+ * @note Windows: This is an XP compatible version and returns the path to "My Games" in Documents. Vista and later has an official folder.
+ * @note Linux: XDF does not define a folder for saved games. This will just return the same as GetDataHome()
+ * @return The folder base folder for storring save games.
+ */
+std::string getSaveGamesFolder1();
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+/**
* This class contains methods for finding the system depended special folders.
* For Windows these folders are either by convention or given by CSIDL.
* For Linux XDG convention is used.
@@ -166,10 +222,13 @@ private:
#elif defined(__APPLE__)
#else
struct PlatformFoldersData;
- PlatformFoldersData *data;
+ PlatformFoldersData* data;
#endif
};
+#endif // skip doxygen
+
+
} //namespace sago
#endif /* PLATFORM_FOLDERS_H */