From 1588a4254b7fc0eec7faf9950da25f799e2dea6a Mon Sep 17 00:00:00 2001 From: Pk11 Date: Wed, 20 Jan 2021 13:55:44 -0600 Subject: [PATCH] RTL fixes from TWiLight --- include/font.hpp | 14 +++++++------- source/font.cpp | 45 ++++++++++++++++++++++++--------------------- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/include/font.hpp b/include/font.hpp index 264c302..ccae92f 100644 --- a/include/font.hpp +++ b/include/font.hpp @@ -57,7 +57,7 @@ private: u16 charIndex(char16_t c); - void print(std::u16string_view text, int x, int y, bool top, int layer, Alignment align, int maxWidth, int color, float scaleX, float scaleY, Sprite *sprite); + void print(std::u16string_view text, int x, int y, bool top, int layer, Alignment align, int maxWidth, int color, float scaleX, float scaleY, bool rtl, Sprite *sprite); public: /** @@ -108,7 +108,7 @@ public: * @param scaleX (Optional) The scale on the X axis * @param scaleY (Optional) The scale on the Y axis */ - void print(int value, int x, int y, bool top, int layer = 2, Alignment align = Alignment::left, int maxWidth = 0, int color = 0, float scaleX = 1.0f, float scaleY = 1.0f) { print(utf8to16(std::to_string(value)), x, y, top, layer, align, maxWidth, scaleX, scaleY, color, nullptr); } + void print(int value, int x, int y, bool top, int layer = 2, Alignment align = Alignment::left, int maxWidth = 0, int color = 0, float scaleX = 1.0f, float scaleY = 1.0f) { print(utf8to16(std::to_string(value)), x, y, top, layer, align, maxWidth, scaleX, scaleY, color, false, nullptr); } /** * @brief Prints a string to a background layer @@ -123,8 +123,8 @@ public: * @param scaleY (Optional) The scale on the Y axis * @param color (Optional) The color to print in */ - void print(std::string_view text, int x, int y, bool top, int layer = 2, Alignment align = Alignment::left, int maxWidth = 0, int color = 0, float scaleX = 1.0f, float scaleY = 1.0f) { print(utf8to16(text), x, y, top, layer, align, maxWidth, color, scaleX, scaleY, nullptr); } - void print(std::u16string_view text, int x, int y, bool top, int layer = 2, Alignment align = Alignment::left, int maxWidth = 0, int color = 0, float scaleX = 1.0f, float scaleY = 1.0f) { print(text, x, y, top, layer, align, maxWidth, color, scaleX, scaleY, nullptr); } + void print(std::string_view text, int x, int y, bool top, int layer = 2, Alignment align = Alignment::left, int maxWidth = 0, int color = 0, float scaleX = 1.0f, float scaleY = 1.0f) { print(utf8to16(text), x, y, top, layer, align, maxWidth, color, scaleX, scaleY, false, nullptr); } + void print(std::u16string_view text, int x, int y, bool top, int layer = 2, Alignment align = Alignment::left, int maxWidth = 0, int color = 0, float scaleX = 1.0f, float scaleY = 1.0f) { print(text, x, y, top, layer, align, maxWidth, color, scaleX, scaleY, false, nullptr); } /** * @brief Prints an integer value to a sprite @@ -138,7 +138,7 @@ public: * @param scaleX (Optional) The scale on the X axis * @param scaleY (Optional) The scale on the Y axis */ - void print(int value, int x, int y, Sprite &sprite, Alignment align = Alignment::left, int maxWidth = 0, int color = 0, float scaleX = 1.0f, float scaleY = 1.0f) { print(utf8to16(std::to_string(value)), x, y, false, 0, align, maxWidth, color, scaleX, scaleY, nullptr); } + void print(int value, int x, int y, Sprite &sprite, Alignment align = Alignment::left, int maxWidth = 0, int color = 0, float scaleX = 1.0f, float scaleY = 1.0f) { print(utf8to16(std::to_string(value)), x, y, false, 0, align, maxWidth, color, scaleX, scaleY, false, nullptr); } /** * @brief Prints a string to a sprite @@ -152,8 +152,8 @@ public: * @param scaleX (Optional) The scale on the X axis * @param scaleY (Optional) The scale on the Y axis */ - void print(std::string_view text, int x, int y, Sprite &sprite, Alignment align = Alignment::left, int maxWidth = 0, int color = 0, float scaleX = 1.0f, float scaleY = 1.0f) { print(utf8to16(text), x, y, false, 0, align, maxWidth, color, scaleX, scaleY, &sprite); } - void print(std::u16string_view text, int x, int y, Sprite &sprite, Alignment align = Alignment::left, int maxWidth = 0, int color = 0, float scaleX = 1.0f, float scaleY = 1.0f) { print(text, x, y, false, 0, align, maxWidth, color, scaleX, scaleY, &sprite); } + void print(std::string_view text, int x, int y, Sprite &sprite, Alignment align = Alignment::left, int maxWidth = 0, int color = 0, float scaleX = 1.0f, float scaleY = 1.0f) { print(utf8to16(text), x, y, false, 0, align, maxWidth, color, scaleX, scaleY, false, &sprite); } + void print(std::u16string_view text, int x, int y, Sprite &sprite, Alignment align = Alignment::left, int maxWidth = 0, int color = 0, float scaleX = 1.0f, float scaleY = 1.0f) { print(text, x, y, false, 0, align, maxWidth, color, scaleX, scaleY, false, &sprite); } #ifdef TEXT_BUFFERED /** diff --git a/source/font.cpp b/source/font.cpp index 3d31bc9..8cb8de5 100644 --- a/source/font.cpp +++ b/source/font.cpp @@ -183,7 +183,16 @@ int Font::calcWidth(std::u16string_view text) { } ITCM_CODE void Font::print(std::u16string_view text, int x, int y, bool top, int layer, Alignment align, int maxWidth, - int color, float scaleX, float scaleY, Sprite *sprite) { + int color, float scaleX, float scaleY, bool rtl, Sprite *sprite) { + // If RTL isn't forced, check for RTL text + for(const auto c : text) { + if(c >= 0x0590 && c <= 0x05FF) { + rtl = true; + break; + } + } + auto ltrBegin = text.end(), ltrEnd = text.end(); + // Adjust x for alignment switch(align) { case Alignment::left: { @@ -192,7 +201,7 @@ ITCM_CODE void Font::print(std::u16string_view text, int x, int y, bool top, int case Alignment::center: { size_t newline = text.find('\n'); while(newline != text.npos) { - print(text.substr(0, newline), x, y, top, layer, align, maxWidth, color, scaleX, scaleY, sprite); + print(text.substr(0, newline), x, y, top, layer, align, maxWidth, color, scaleX, scaleY, rtl, sprite); text = text.substr(newline + 1); newline = text.find('\n'); y += tileHeight; @@ -205,7 +214,7 @@ ITCM_CODE void Font::print(std::u16string_view text, int x, int y, bool top, int size_t newline = text.find('\n'); while(newline != text.npos) { print(text.substr(0, newline), x - (calcWidth(text.substr(0, newline)) * scaleX), y, top, layer, - Alignment::left, maxWidth, color, scaleX, scaleY, sprite); + Alignment::left, maxWidth, color, scaleX, scaleY, rtl, sprite); text = text.substr(newline + 1); newline = text.find('\n'); y += tileHeight; @@ -219,21 +228,12 @@ ITCM_CODE void Font::print(std::u16string_view text, int x, int y, bool top, int if(maxWidth != 0) scaleX = std::min(scaleX, (float)maxWidth / (calcWidth(text) * scaleX)); - bool rtl = false; - for(const auto c : text) { - if(c >= 0x0590 && c <= 0x05FF) { - rtl = true; - break; - } - } - auto ltrBegin = text.end(), ltrEnd = text.end(); - // Loop through string and print it for(auto it = (rtl ? text.end() - 1 : text.begin()); true; it += (rtl ? -1 : 1)) { // If we hit the end of the string in an LTR section of an RTL // string, it may not be done, if so jump back to printing RTL if(it == (rtl ? text.begin() - 1 : text.end())) { - if(ltrBegin == text.end()) { + if(ltrBegin == text.end() || (ltrBegin == text.begin() && ltrEnd == text.end())) { break; } else { it = ltrBegin; @@ -242,7 +242,7 @@ ITCM_CODE void Font::print(std::u16string_view text, int x, int y, bool top, int } } - // If at the end of an LRT section within RTL, jump back to the RTL + // If at the end of an LTR section within RTL, jump back to the RTL if(it == ltrEnd && ltrBegin != text.end()) { if(ltrBegin == text.begin()) break; @@ -257,19 +257,22 @@ ITCM_CODE void Font::print(std::u16string_view text, int x, int y, bool top, int *it >= 127))) { // Save where we are as the end of the LTR section ltrEnd = it + 1; + // Go back until an RTL character or the start of the string while((*it < 0x0590 || *it > 0x05FF) && it != text.begin()) it--; + // Save where we are to return to after printing the LTR section ltrBegin = it; - // If not at the start, then we're on the first RTL right now, so add one - if(it != text.begin()) + + // If on an RTL char right now, add one + if(*it >= 0x0590 && *it <= 0x05FF) { it++; - // Skip all punctuation at the end if not at beginning - while(it != text.begin() && - (*it < '0' || (*it > '9' && *it < 'A') || (*it > 'Z' && *it < 'a') || (*it > 'z' && *it < 127))) { - it++; - ltrBegin++; + // And skip all punctuation at the end if not at beginning + while(*it < '0' || (*it > '9' && *it < 'A') || (*it > 'Z' && *it < 'a') || (*it > 'z' && *it < 127)) { + it++; + ltrBegin++; + } } rtl = false; }