diff --git a/src/PowderToy.cpp b/src/PowderToy.cpp index 32a28f8b1..a6ea6aeae 100644 --- a/src/PowderToy.cpp +++ b/src/PowderToy.cpp @@ -101,16 +101,14 @@ void BlueScreen(String detailMessage) String errorTitle = "ERROR"; String errorDetails = "Details: " + detailMessage; String errorHelp = String("An unrecoverable fault has occurred, please report the error by visiting the website below\n") + SCHEME + SERVER; - int currentY = 0, width, height; - int errorWidth = 0; - Graphics::textsize(errorTitle, errorWidth, height); - engine.g->BlendText(engine.g->Size() / 2 - Vec2(errorWidth / 2, 100 - currentY), errorTitle, 0xFFFFFF_rgb .WithAlpha(0xFF)); - currentY += height + 4; - Graphics::textsize(errorDetails, width, height); - engine.g->BlendText(engine.g->Size() / 2 - Vec2(errorWidth / 2, 100 - currentY), errorDetails, 0xFFFFFF_rgb .WithAlpha(0xFF)); - currentY += height + 4; - Graphics::textsize(errorHelp, width, height); - engine.g->BlendText(engine.g->Size() / 2 - Vec2(errorWidth / 2, 100 - currentY), errorHelp, 0xFFFFFF_rgb .WithAlpha(0xFF)); + + // We use the width of errorHelp to center, but heights of the individual texts for vertical spacing + auto pos = engine.g->Size() / 2 - Vec2(Graphics::TextSize(errorHelp).X / 2, 100); + engine.g->BlendText(pos, errorTitle, 0xFFFFFF_rgb .WithAlpha(0xFF)); + pos.Y += 4 + Graphics::TextSize(errorTitle).Y; + engine.g->BlendText(pos, errorDetails, 0xFFFFFF_rgb .WithAlpha(0xFF)); + pos.Y += 4 + Graphics::TextSize(errorDetails).Y; + engine.g->BlendText(pos, errorHelp, 0xFFFFFF_rgb .WithAlpha(0xFF)); //Death loop SDL_Event event; diff --git a/src/graphics/Graphics.cpp b/src/graphics/Graphics.cpp index c5507479f..3c770e7eb 100644 --- a/src/graphics/Graphics.cpp +++ b/src/graphics/Graphics.cpp @@ -169,97 +169,19 @@ Graphics::Graphics() int Graphics::textwidth(const String &str) { - int x = 0; - for (size_t i = 0; i < str.length(); i++) - { - if (str[i] == '\b') - { - if (str.length() <= i+1) - break; - i++; - continue; - } - else if (str[i] == '\x0F') - { - if (str.length() <= i+3) - break; - i += 3; - continue; - } - x += FontReader(str[i]).GetWidth(); - } - return x-1; -} - -int Graphics::CharWidth(String::value_type c) -{ - return FontReader(c).GetWidth(); + return TextSize(str).X; } int Graphics::textwidthx(const String &str, int w) { - int x = 0,n = 0,cw = 0; - for (size_t i = 0; i < str.length(); i++) - { - if (str[i] == '\b') - { - if (str.length() <= i+1) - break; - i++; - continue; - } else if (str[i] == '\x0F') { - if (str.length() <= i+3) - break; - i += 3; - continue; - } - cw = FontReader(str[i]).GetWidth(); - if (x+(cw/2) >= w) - break; - x += cw; - n++; - } - return n; + return TextFit(str, w) - str.begin(); } void Graphics::textsize(const String &str, int & width, int & height) { - if(!str.size()) - { - width = 0; - height = FONT_H-2; - return; - } - - int cHeight = FONT_H-2, cWidth = 0, lWidth = 0; - for (size_t i = 0; i < str.length(); i++) - { - if (str[i] == '\n') - { - cWidth = 0; - cHeight += FONT_H; - } - else if (str[i] == '\x0F') - { - if (str.length() <= i+3) - break; - i += 3; - } - else if (str[i] == '\b') - { - if (str.length() <= i+1) - break; - i++; - } - else - { - cWidth += FontReader(str[i]).GetWidth(); - if(cWidth>lWidth) - lWidth = cWidth; - } - } - width = lWidth; - height = cHeight; + auto size = TextSize(str); + width = size.X; + height = size.Y; } void Graphics::draw_icon(int x, int y, Icon icon, unsigned char alpha, bool invert) diff --git a/src/graphics/Graphics.h b/src/graphics/Graphics.h index 80b0fb3cc..b775b7935 100644 --- a/src/graphics/Graphics.h +++ b/src/graphics/Graphics.h @@ -95,9 +95,11 @@ public: static std::vector Gradient(std::vector stops, int resolution); //Font/text metrics - static int CharWidth(String::value_type c); + [[deprecated("Use TextFit()")]] static int textwidthx(const String &s, int w); + [[deprecated("Use TextSize().X")]] static int textwidth(const String &s); + [[deprecated("Use TextSize()")]] static void textsize(const String &s, int & width, int & height); VideoBuffer DumpFrame(); diff --git a/src/graphics/RasterDrawMethods.h b/src/graphics/RasterDrawMethods.h index ccfbcdb22..83add64d3 100644 --- a/src/graphics/RasterDrawMethods.h +++ b/src/graphics/RasterDrawMethods.h @@ -50,6 +50,14 @@ struct RasterDrawMethods Vec2 BlendTextOutline(Vec2, String const &, RGBA); + static int CharWidth(String::value_type); + // Considers the first line to be FONT_H-2 tall with successive lines adding + // FONT_H each + static Vec2 TextSize(String const &); + // Return iterator to the end of an initial portion of text that fits in + // the given width + static String::const_iterator TextFit(String const &, int width); + void Clear(); [[deprecated("Use BlendTextOutline")]] diff --git a/src/graphics/RasterDrawMethodsImpl.h b/src/graphics/RasterDrawMethodsImpl.h index 5aaaff225..a177a41d2 100644 --- a/src/graphics/RasterDrawMethodsImpl.h +++ b/src/graphics/RasterDrawMethodsImpl.h @@ -324,6 +324,83 @@ void RasterDrawMethods::Clear() std::fill_n(video.data(), video.Size().X * video.Size().Y, 0x000000_rgb .Pack()); } +template +int RasterDrawMethods::CharWidth(String::value_type ch) +{ + return FontReader(ch).GetWidth(); +} + +template +Vec2 RasterDrawMethods::TextSize(String const &str) +{ + Vec2 size = Vec2(0, FONT_H - 2); + int curX = -1; // characters have 1px of spacing between them + for (size_t i = 0; i < str.length(); i++) + { + if (str[i] == '\n') + { + size.X = std::max(curX, size.X); + size.Y += FONT_H; + curX = 0; + } + else if (str[i] == '\x0F') + { + if (str.length() <= i + 3) + break; + i += 3; + } + else if (str[i] == '\x0E') + continue; + else if (str[i] == '\x01') + continue; + else if (str[i] == '\b') + { + if (str.length() <= i + 1) + break; + i++; + } + else + curX += CharWidth(str[i]); + } + size.X = std::max(curX, size.X); + return size; +} + +template +String::const_iterator RasterDrawMethods::TextFit(String const &str, int width) +{ + int curX = 0; + for (size_t i = 0; i < str.length(); i++) + { + if (str[i] == '\n') + curX = 0; + else if (str[i] == '\x0F') + { + if (str.length() <= i + 3) + break; + i += 3; + } + else if (str[i] == '\x0E') + continue; + else if (str[i] == '\x01') + continue; + else if (str[i] == '\b') + { + if (str.length() <= i + 1) + break; + i++; + } + else + { + int dx = CharWidth(str[i]); + if (curX + dx / 2 >= width) + return str.begin() + i; + curX += dx; + } + } + return str.end(); +} + template int RasterDrawMethods::drawtext_outline(int x, int y, const String &s, int r, int g, int b, int a) {