diff --git a/src/sago/SagoTextBox.cpp b/src/sago/SagoTextBox.cpp new file mode 100644 index 0000000..7c621bf --- /dev/null +++ b/src/sago/SagoTextBox.cpp @@ -0,0 +1,119 @@ +/* +Copyright (c) 2018 Poul Sander + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "SagoTextBox.hpp" +#include "SagoTextField.hpp" +#include +#include + +namespace sago { + +struct SagoTextBox::SagoTextBoxData { + sago::SagoDataHolder* tex = nullptr; + std::string fontName = "freeserif"; + SDL_Color color = { 255, 255, 255, 0 }; + SDL_Color outlineColor = { 255, 255, 0, 0 }; + int fontSize = 16; + int outline = 0; + std::string text = ""; + std::string renderedText = ""; + std::vector lines; + int maxWidth = 0; +}; + +SagoTextBox::SagoTextBox() { + data = new SagoTextBoxData(); +} + +SagoTextBox::~SagoTextBox() { + delete data; +} + +void SagoTextBox::SetHolder(SagoDataHolder* holder) { + data->tex = holder; +} + +void SagoTextBox::SetText(const char* text) { + data->text = text; +} + +void SagoTextBox::SetColor(const SDL_Color& color) { + data->color = color; +} + +void SagoTextBox::SetFont(const char* fontName) { + data->fontName = fontName; +} + +void SagoTextBox::SetFontSize(int fontSize) { + data->fontSize = fontSize; +} + +void SagoTextBox::SetOutline(int outlineSize, const SDL_Color& color) { + data->outline = outlineSize; + data->outlineColor = color; +} + +const std::string& SagoTextBox::GetText() const { + return data->text; +} + +void SagoTextBox::AppendLineToCache(const std::string& text) { + data->lines.resize(data->lines.size()+1); + SagoTextField& tf = data->lines.back(); + tf.SetHolder(data->tex); + tf.SetFont(data->fontName.c_str()); + tf.SetFontSize(data->fontSize); + tf.SetColor(data->color); + tf.SetOutline(data->outline, data->outlineColor); + tf.SetText(text.c_str()); +} + +void SagoTextBox::UpdateCache() { + const char delim = '\n'; + const std::string& s = data->text; + auto start = 0U; + auto end = s.find(delim); + while (end != std::string::npos) + { + AppendLineToCache(s.substr(start, end - start)); + start = end + 1; + end = s.find(delim, start); + } + AppendLineToCache(s.substr(start, end)); + data->renderedText = data->text; +} + +void SagoTextBox::Draw(SDL_Renderer* target, int x, int y) { + if (data->text != data->renderedText) { + UpdateCache(); + } + TTF_Font *font = data->tex->getFontPtr(data->fontName, data->fontSize); + int lineSkip = TTF_FontLineSkip(font); + for (size_t i = 0; i < data->lines.size(); ++i) { + data->lines[i].Draw(target, x, y+i*lineSkip); + } +} + +} //namespace sago \ No newline at end of file diff --git a/src/sago/SagoTextBox.hpp b/src/sago/SagoTextBox.hpp new file mode 100644 index 0000000..ba7b850 --- /dev/null +++ b/src/sago/SagoTextBox.hpp @@ -0,0 +1,57 @@ +/* +Copyright (c) 2018 Poul Sander + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef SAGOTEXTBOX_HPP +#define SAGOTEXTBOX_HPP + +#include "SagoDataHolder.hpp" +#include "SagoTextField.hpp" + +namespace sago { + +class SagoTextBox { +public: + SagoTextBox(); + virtual ~SagoTextBox(); + void SetHolder(SagoDataHolder* holder); + void SetText(const char* text); + void SetColor(const SDL_Color& color); + void SetFont(const char* fontName); + void SetFontSize(int fontSize); + void SetOutline(int outlineSize, const SDL_Color& color); + const std::string& GetText() const; + void Draw(SDL_Renderer* target, int x, int y); + void UpdateCache(); +private: + void AppendLineToCache(const std::string& text); + SagoTextBox(const SagoTextBox& orig) = delete; + SagoTextBox& operator=(const SagoTextBox& base) = delete; + struct SagoTextBoxData; + SagoTextBoxData *data; +}; + +} //namespace sago + +#endif /* SAGOTEXTBOX_HPP */ + diff --git a/src/sago/SagoTextField.cpp b/src/sago/SagoTextField.cpp index 5181277..ce6cc23 100644 --- a/src/sago/SagoTextField.cpp +++ b/src/sago/SagoTextField.cpp @@ -77,7 +77,15 @@ SagoTextField::SagoTextField() { data = new SagoTextFieldData(); } +SagoTextField::SagoTextField(SagoTextField&& o) noexcept { + data = o.data; + o.data = nullptr; +} + SagoTextField::~SagoTextField() { + if(!data) { + return; + } ClearCache(); delete data; } @@ -107,7 +115,7 @@ void SagoTextField::SetOutline(int outlineSize, const SDL_Color& color) { data->outlineColor = color; } -std::string SagoTextField::GetText() const { +const std::string& SagoTextField::GetText() const { return data->text; } @@ -137,11 +145,13 @@ void SagoTextField::ClearCache() { void SagoTextField::UpdateCache(SDL_Renderer* target) { ClearCache(); TTF_Font *font = data->tex->getFontPtr(data->fontName, data->fontSize); - data->textSurface = TTF_RenderText_Blended (font, data->text.c_str(), data->color); + 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_RenderText_Blended (font, data->text.c_str(), data->outlineColor); + data->outlineTextSurface = TTF_RenderUTF8_Blended (font, data->text.c_str(), data->outlineColor); data->outlineTexture = SDL_CreateTextureFromSurface(target, data->outlineTextSurface); oh.reset(); } @@ -166,8 +176,8 @@ void SagoTextField::Draw(SDL_Renderer* target, int x, int y) { int outlineTexW = 0; int outlineTexH = 0; SDL_QueryTexture(data->outlineTexture, NULL, NULL, &outlineTexW, &outlineTexH); - SDL_Rect dstrect = { x-(outlineTexW-texW)/2, y-(outlineTexH-texH)/2, outlineTexW, outlineTexH }; - SDL_RenderCopy(target, data->outlineTexture, NULL, &dstrect); + SDL_Rect dstrectOutline = { x-(data->outline), y-(data->outline), outlineTexW, outlineTexH }; + SDL_RenderCopy(target, data->outlineTexture, NULL, &dstrectOutline); } SDL_RenderCopy(target, data->texture, NULL, &dstrect); } diff --git a/src/sago/SagoTextField.hpp b/src/sago/SagoTextField.hpp index c4db9ab..99aaf03 100644 --- a/src/sago/SagoTextField.hpp +++ b/src/sago/SagoTextField.hpp @@ -32,6 +32,8 @@ namespace sago { class SagoTextField { public: SagoTextField(); + SagoTextField(SagoTextField&& o) noexcept; + SagoTextField& operator=(const SagoTextField&& base) = delete; virtual ~SagoTextField(); void SetHolder(SagoDataHolder* holder); void SetText(const char* text); @@ -39,7 +41,7 @@ public: void SetFont(const char* fontName); void SetFontSize(int fontSize); void SetOutline(int outlineSize, const SDL_Color& color); - std::string GetText() const; + const std::string& GetText() const; void Draw(SDL_Renderer* target, int x, int y); void UpdateCache(SDL_Renderer* target); void ClearCache(); diff --git a/src/saland.cpp b/src/saland.cpp index f87003b..b383e8b 100644 --- a/src/saland.cpp +++ b/src/saland.cpp @@ -43,6 +43,7 @@ https://github.com/sago007/saland #include "sago/SagoMisc.hpp" #include "sago/platform_folders.h" #include "sagotmx/tmx_struct.h" +#include "sago/SagoTextBox.hpp" #if defined(_WIN32) #include @@ -62,6 +63,8 @@ public: TitleScreen() { textField.SetHolder(globalData.dataHolder); textField.SetFontSize(30); + textBox.SetHolder(globalData.dataHolder); + textBox.SetFontSize(16); } virtual bool IsActive() override { @@ -71,9 +74,12 @@ public: virtual void Draw(SDL_Renderer* target) override { - textField.SetText("Saland Adventures - The game that has a very long subtitle - to test the outline"); + textField.SetText("Saland Adventures - The game that has a very long subtitle to test the outline"); textField.SetOutline(3, SDL_Color{255,165,0,255}); textField.Draw(target, 10, 10); + textBox.SetText("This is some text. It is also quite long. \nIt must take several lines!\nEven 3 lines!\nand 4!\nAlso5\n\nAnd a blank one above!gg\ngg"); + textBox.SetOutline(1, SDL_Color{255,0,0,255}); + textBox.Draw(target, 300,300); circleRGBA(target, 150, 150, 75, 0, 0, 255, 255); @@ -102,6 +108,7 @@ public: private: bool isActive = true; sago::SagoTextField textField; + sago::SagoTextBox textBox; }; void RunGameState(sago::GameStateInterface& state ) {