From 941156a291bdabfc9e6af685ef77d1a72873484a Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 Date: Sun, 5 Sep 2021 19:16:46 +0200 Subject: [PATCH] Implemented rich text rendering --- CMakeLists.txt | 2 + src/richtextrenderer.cpp | 129 +++++++++++++++++++++++++++++++++++++++ src/richtextrenderer.h | 18 ++++++ src/widgets/label.cpp | 3 +- 4 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 src/richtextrenderer.cpp create mode 100644 src/richtextrenderer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 53864b4..f9598f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ set(headers src/iconinterface.h src/menudisplay.h src/menuitem.h + src/richtextrenderer.h src/screenmanager.h src/tftinstance.h src/textinterface.h @@ -39,6 +40,7 @@ set(sources src/changevaluedisplay_sntp_sync_mode_t.cpp src/menudisplay.cpp src/screenmanager.cpp + src/richtextrenderer.cpp src/tftinstance.cpp src/icons/back.cpp src/icons/checked.cpp diff --git a/src/richtextrenderer.cpp b/src/richtextrenderer.cpp new file mode 100644 index 0000000..5224948 --- /dev/null +++ b/src/richtextrenderer.cpp @@ -0,0 +1,129 @@ +#include "richtextrenderer.h" + +// system includes +#include + +// 3rdparty lib includes +#include + +namespace espgui { + +void richTextEscape(std::string &subject) +{ + cpputils::stringReplaceAll('&', "&&", subject); +} + +std::string richTextEscape(std::string_view subject) +{ + return cpputils::stringReplaceAll('&', "&&", subject); +} + +int16_t renderRichText(std::string_view str, int32_t poX, int32_t poY) +{ + return renderRichText(str, poX, poY, tft.textfont); +} + +int16_t renderRichText(std::string_view str, int32_t poX, int32_t poY, uint8_t font) +{ + if (str.empty()) + return 0; + + const auto oldColor = tft.textcolor; + + int16_t width{}; + +again: + if (const auto index = str.find('&'); index != std::string_view::npos) + { + { + std::string_view tempStr{std::begin(str), index}; + if (!tempStr.empty()) + { + const auto addedWith = tft.drawString(tempStr, poX, poY, font); + poX += addedWith; + width += addedWith; + } + } + + auto newIter = std::begin(str) + index + 1; + if (newIter != std::end(str)) + { + switch (const auto controlChar = *newIter) + { + case '0': + case '1': + case '2': + { + const auto color = [&controlChar](){ + switch (controlChar) + { + case '0': return TFT_RED; + case '1': return TFT_GREEN; + case '2': return TFT_BLUE; + } + __builtin_unreachable(); + }(); + + tft.setTextColor(color, tft.textbgcolor); + + auto newNewIter = newIter + 1; + if (newNewIter != std::end(str)) + { + str = std::string_view(newNewIter, std::distance(newNewIter, std::end(str))); + goto again; + } + break; + } +// case '&': +// { +// const char buf[1] = { '&' }; +// const auto addedWith = tft.drawString(std::string_view{buf, std::size(buf)}, poX, poY, font); +// poX += addedWith; +// width += addedWith; + +// auto newNewIter = newIter + 1; +// if (newNewIter != std::end(str)) +// { +// str = std::string_view(newNewIter, std::distance(newNewIter, std::end(str))); +// goto again; +// } +// break; +// } + default: + { + const char buf[2] = { '&', controlChar }; + const auto addedWith = tft.drawString(std::string_view{buf, std::size(buf)}, poX, poY, font); + poX += addedWith; + width += addedWith; + + auto newNewIter = newIter + 1; + if (newNewIter != std::end(str)) + { + str = std::string_view(newNewIter, std::distance(newNewIter, std::end(str))); + goto again; + } + break; + } + } + } + else + { + const char buf[1] = { '&' }; + const auto addedWith = tft.drawString(std::string_view{buf, std::size(buf)}, poX, poY, font); + poX += addedWith; + width += addedWith; + } + } + else if (!str.empty()) + { + const auto addedWith = tft.drawString(str, poX, poY, font); + poX += addedWith; + width += addedWith; + } + + tft.setTextColor(oldColor, tft.textbgcolor); + + return width; +} + +} // namespace espgui diff --git a/src/richtextrenderer.h b/src/richtextrenderer.h new file mode 100644 index 0000000..5d36b36 --- /dev/null +++ b/src/richtextrenderer.h @@ -0,0 +1,18 @@ +#pragma once + +// system includes +#include +#include + +// local includes +#include "tftinstance.h" + +namespace espgui { + +void richTextEscape(std::string &subject); +std::string richTextEscape(std::string_view subject); + +int16_t renderRichText(std::string_view str, int32_t poX, int32_t poY); +int16_t renderRichText(std::string_view str, int32_t poX, int32_t poY, uint8_t font); + +} // namespace espgui diff --git a/src/widgets/label.cpp b/src/widgets/label.cpp index d0c11a2..cf0ed0f 100644 --- a/src/widgets/label.cpp +++ b/src/widgets/label.cpp @@ -2,6 +2,7 @@ // local includes #include "tftinstance.h" +#include "richtextrenderer.h" namespace espgui { Label::Label(int x, int y) : @@ -28,7 +29,7 @@ void Label::redraw(std::string_view str, bool forceRedraw) !forceRedraw) return; - const auto renderedWidth = str.empty() ? 0 : tft.drawString(str.data(), m_x, m_y); + const auto renderedWidth = renderRichText(str, m_x, m_y); const auto renderedHeight = tft.fontHeight(); if (renderedWidth < m_lastWidth)