diff --git a/CMakeLists.txt b/CMakeLists.txt index 02276c0..a74b5f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,8 +47,6 @@ set(headers src/textinterface.h src/textwithvaluehelper.h src/tftcolors.h - src/tftespiimpl.h - src/tftinterface.h src/titleinterface.h src/visibleinterface.h src/widgets/graph.h @@ -98,6 +96,8 @@ set(dependencies espwifistack fmt TFT_eSPI + esptftlib + espfontlib ) idf_component_register( diff --git a/src/changevaluedisplay.cpp b/src/changevaluedisplay.cpp index ec11195..38e1620 100644 --- a/src/changevaluedisplay.cpp +++ b/src/changevaluedisplay.cpp @@ -2,6 +2,7 @@ // 3rdparty lib includes #include +#include // local includes #include "tftinterface.h" @@ -12,21 +13,23 @@ void ChangeValueDisplayInterface::initScreen(TftInterface &tft) { Base::initScreen(tft); + FontRenderer fontRenderer{tft}; + tft.drawRoundRect(35, 65, 190, 65, 8, TFT_WHITE); m_valueLabel.start(tft); if (espgui::isLandscape(tft)) { - tft.drawString("Change value and press", 10, 152, TFT_WHITE, TFT_BLACK, 4); - tft.drawString("button to confirm and", 10, 177, TFT_WHITE, TFT_BLACK, 4); - tft.drawString("go back", 10, 202, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("Change value and press", 10, 152, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("button to confirm and", 10, 177, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("go back", 10, 202, TFT_WHITE, TFT_BLACK, 4); } else { - tft.drawString("Change value and", 10, 160, TFT_WHITE, TFT_BLACK, 4); - tft.drawString("press button to", 10, 185, TFT_WHITE, TFT_BLACK, 4); - tft.drawString("confirm and go", 10, 210, TFT_WHITE, TFT_BLACK, 4); - tft.drawString("back.", 10, 235, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("Change value and", 10, 160, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("press button to", 10, 185, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("confirm and go", 10, 210, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("back.", 10, 235, TFT_WHITE, TFT_BLACK, 4); } } diff --git a/src/changevaluedisplay_chrono.h b/src/changevaluedisplay_chrono.h index 002cd81..f4b04f3 100644 --- a/src/changevaluedisplay_chrono.h +++ b/src/changevaluedisplay_chrono.h @@ -5,6 +5,7 @@ // 3rdparty lib includes #include +#include // local includes #include "changevaluedisplay.h" @@ -60,21 +61,23 @@ void ChangeValueDisplayChrono::initScreen(TftInterface &tft) { Base::initScreen(tft); + FontRenderer fontRenderer{tft}; + tft.drawRoundRect(32, 65, 190, 34, 8, TFT_WHITE); m_valueLabel.start(tft); if (espgui::isLandscape(tft)) { - tft.drawString("Change value and press", 10, 152, TFT_WHITE, TFT_BLACK, 4); - tft.drawString("button to confirm and", 10, 177, TFT_WHITE, TFT_BLACK, 4); - tft.drawString("go back", 10, 202, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("Change value and press", 10, 152, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("button to confirm and", 10, 177, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("go back", 10, 202, TFT_WHITE, TFT_BLACK, 4); } else { - tft.drawString("Change value and", 10, 160, TFT_WHITE, TFT_BLACK, 4); - tft.drawString("press button to", 10, 185, TFT_WHITE, TFT_BLACK, 4); - tft.drawString("confirm and go", 10, 210, TFT_WHITE, TFT_BLACK, 4); - tft.drawString("back.", 10, 235, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("Change value and", 10, 160, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("press button to", 10, 185, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("confirm and go", 10, 210, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString("back.", 10, 235, TFT_WHITE, TFT_BLACK, 4); } } diff --git a/src/changevaluedisplay_ip_address_t.cpp b/src/changevaluedisplay_ip_address_t.cpp index 28cf173..00ca221 100644 --- a/src/changevaluedisplay_ip_address_t.cpp +++ b/src/changevaluedisplay_ip_address_t.cpp @@ -1,5 +1,8 @@ #include "changevaluedisplay_ip_address_t.h" +// 3rdparty lib includes +#include + // local includes #include "tftinterface.h" #include "tftcolors.h" @@ -19,7 +22,9 @@ void ChangeValueDisplay::initScreen(TftInterface &tft) { Base::initScreen(tft); - tft.drawString("Change IP Address", 0, 50, TFT_WHITE, TFT_BLACK, 4); + FontRenderer fontRenderer{tft}; + + fontRenderer.drawString("Change IP Address", 0, 50, TFT_WHITE, TFT_BLACK, 4); for(int i = 0; i <= 3; i++) { @@ -30,9 +35,9 @@ void ChangeValueDisplay::initScreen(TftInterface &tft) for (auto &label : m_labels) label.start(tft); - tft.drawString(".", spacing+boxWidth+spacing/4, y, TFT_WHITE, TFT_BLACK, 4); - tft.drawString(".", spacing*2+boxWidth*2+spacing/4, y, TFT_WHITE, TFT_BLACK, 4); - tft.drawString(".", spacing*3+boxWidth*3+spacing/4, y, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString(".", spacing+boxWidth+spacing/4, y, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString(".", spacing*2+boxWidth*2+spacing/4, y, TFT_WHITE, TFT_BLACK, 4); + fontRenderer.drawString(".", spacing*3+boxWidth*3+spacing/4, y, TFT_WHITE, TFT_BLACK, 4); drawRect(tft, m_currentIndex, 1, TFT_YELLOW); drawRect(tft, m_currentIndex, 2, TFT_YELLOW); diff --git a/src/changevaluedisplay_string.cpp b/src/changevaluedisplay_string.cpp index 03ab320..20817ce 100644 --- a/src/changevaluedisplay_string.cpp +++ b/src/changevaluedisplay_string.cpp @@ -2,6 +2,7 @@ // 3rdparty lib includes #include +#include // local includes #include "tftinterface.h" @@ -41,21 +42,23 @@ void espgui::ChangeValueDisplay::redraw(TftInterface &tft) { Base::redraw(tft); + FontRenderer fontRenderer{tft}; + const auto now_ts = espchrono::millis_clock::now().time_since_epoch(); - const auto char_width = tft.textWidth(m_value, 4) / ((!m_value.empty()) ? m_value.size() : 1); + const auto char_width = fontRenderer.textWidth(m_value, 4) / ((!m_value.empty()) ? m_value.size() : 1); const auto maxChars = (tft.width() - 40) / char_width; const auto substr_from = std::max(0U, m_value.size() < maxChars ? 0 : static_cast(m_value.size()) - maxChars); const auto string = m_value.substr(substr_from); if (m_needsClear) { - tft.drawRect(m_valueLabel.x() + tft.textWidth(*m_needsClear, 4) + 3, m_valueLabel.y(), 2, tft.fontHeight(4), TFT_BLACK); + tft.drawRect(m_valueLabel.x() + fontRenderer.textWidth(*m_needsClear, 4) + 3, m_valueLabel.y(), 2, fontRenderer.fontHeight(4), TFT_BLACK); m_needsClear = std::nullopt; } m_valueLabel.redraw(tft, string, TFT_WHITE, TFT_BLACK, 4); - tft.drawRect(m_valueLabel.x() + tft.textWidth(string, 4) + 3, m_valueLabel.y(), 2, tft.fontHeight(4), (now_ts % 1000ms < 500ms) ? TFT_WHITE : TFT_BLACK); + tft.drawRect(m_valueLabel.x() + fontRenderer.textWidth(string, 4) + 3, m_valueLabel.y(), 2, fontRenderer.fontHeight(4), (now_ts % 1000ms < 500ms) ? TFT_WHITE : TFT_BLACK); m_keyboard.redraw(tft); diff --git a/src/keyboardhelper.h b/src/keyboardhelper.h index 02a4a1d..1a3cac0 100644 --- a/src/keyboardhelper.h +++ b/src/keyboardhelper.h @@ -6,6 +6,7 @@ // 3rdparty lib includes #include #include +#include // local includes #include "tftinterface.h" @@ -122,6 +123,8 @@ void Keyboard::nextScreen() template void Keyboard::drawKeyboard(TftInterface &tft, bool dont_draw_string) { + FontRenderer fontRenderer{tft}; + constexpr const int FONT = 4; size_t char_index{0}; @@ -140,7 +143,7 @@ void Keyboard::drawKeyboard(TftInterface &tft, bool dont_draw_string) for (size_t i = 0; i < keyboard_lines.size(); i++) { - const int32_t y = m_keyboard_start_y + (i * tft.fontHeight(FONT) + 9); + const int32_t y = m_keyboard_start_y + (i * fontRenderer.fontHeight(FONT) + 9); std::string line = keyboard_lines[i]; const int16_t x = tft.width() / (line.size() + 1); for (size_t j = 0; j < line.size(); j++) @@ -149,8 +152,8 @@ void Keyboard::drawKeyboard(TftInterface &tft, bool dont_draw_string) const int32_t x_pos = x * (j + 1); const int32_t y_pos = y; - const auto width = tft.textWidth(_char, FONT) + 2; - const auto height = tft.fontHeight(FONT) + 4; + const auto width = fontRenderer.textWidth(_char, FONT) + 2; + const auto height = fontRenderer.fontHeight(FONT) + 4; tft.drawRoundRect(x_pos-width/2-1, y_pos-height/2, width+2, height-4, 3, espgui::TFT_BLACK); @@ -159,61 +162,61 @@ void Keyboard::drawKeyboard(TftInterface &tft, bool dont_draw_string) if (!dont_draw_string || char_index == m_char_index || char_index == m_last_char_index) { - tft.drawString(_char, x_pos, y_pos, (char_index == m_char_index ? espgui::TFT_WHITE : espgui::TFT_GREY), espgui::TFT_BLACK, FONT, 4); // 4 = center + fontRenderer.drawString(_char, x_pos, y_pos, (char_index == m_char_index ? espgui::TFT_WHITE : espgui::TFT_GREY), espgui::TFT_BLACK, FONT, 4); // 4 = center } char_index++; } } // draw 3 extra buttons, back, space and enter (x=10, x=tft.width()/2, x=tft.width()-10) - const int32_t y = m_keyboard_start_y + (keyboard_lines.size() * tft.fontHeight(FONT)); + const int32_t y = m_keyboard_start_y + (keyboard_lines.size() * fontRenderer.fontHeight(FONT)); if (isLandscape(tft)) { // align left (SHIFT, SPACE) - tft.drawRoundRect(15 - 2, y - 1, tft.textWidth(SHIFT, FONT) + 4, tft.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); - tft.drawRoundRect(30 + tft.textWidth(SHIFT, FONT) - 2, y - 1, tft.textWidth(SPACE, FONT) + 4, tft.fontHeight(FONT) + 2, 3, + tft.drawRoundRect(15 - 2, y - 1, fontRenderer.textWidth(SHIFT, FONT) + 4, fontRenderer.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); + tft.drawRoundRect(30 + fontRenderer.textWidth(SHIFT, FONT) - 2, y - 1, fontRenderer.textWidth(SPACE, FONT) + 4, fontRenderer.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); // align right (BACKSPACE, ENTER); align from tft.width() - tft.drawRoundRect(tft.width() - 30 - tft.textWidth(ENTER, FONT) - tft.textWidth(BACKSPACE, FONT) - 2, y - 1, - tft.textWidth(BACKSPACE, FONT) + 4, tft.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); - tft.drawRoundRect(tft.width() - 15 - tft.textWidth(ENTER, FONT) - 2, y - 1, tft.textWidth(ENTER, FONT) + 4, - tft.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); + tft.drawRoundRect(tft.width() - 30 - fontRenderer.textWidth(ENTER, FONT) - fontRenderer.textWidth(BACKSPACE, FONT) - 2, y - 1, + fontRenderer.textWidth(BACKSPACE, FONT) + 4, fontRenderer.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); + tft.drawRoundRect(tft.width() - 15 - fontRenderer.textWidth(ENTER, FONT) - 2, y - 1, fontRenderer.textWidth(ENTER, FONT) + 4, + fontRenderer.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); // if (!dont_draw_string) { // align left (SHIFT, SPACE) - tft.drawString(SHIFT, 15, y, (m_char_index == m_char_length ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); - tft.drawString(SPACE, 30 + tft.textWidth(SHIFT, FONT), y, (m_char_index == m_char_length + 1 ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length +1 ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); + fontRenderer.drawString(SHIFT, 15, y, (m_char_index == m_char_length ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); + fontRenderer.drawString(SPACE, 30 + fontRenderer.textWidth(SHIFT, FONT), y, (m_char_index == m_char_length + 1 ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length +1 ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); // align right (BACKSPACE, ENTER); align from tft.width() - tft.drawString(BACKSPACE, tft.width() - 30 - tft.textWidth(ENTER, FONT) - tft.textWidth(BACKSPACE, FONT), y, (m_char_index == m_char_length + 2 ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length + 2 ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); - tft.drawString(ENTER, tft.width() - 15 - tft.textWidth(ENTER, FONT), y, (m_char_index == m_char_length + 3 ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length + 3 ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); + fontRenderer.drawString(BACKSPACE, tft.width() - 30 - fontRenderer.textWidth(ENTER, FONT) - fontRenderer.textWidth(BACKSPACE, FONT), y, (m_char_index == m_char_length + 2 ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length + 2 ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); + fontRenderer.drawString(ENTER, tft.width() - 15 - fontRenderer.textWidth(ENTER, FONT), y, (m_char_index == m_char_length + 3 ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length + 3 ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); } } else { - const int32_t y_2 = y + tft.fontHeight(FONT) + 4; + const int32_t y_2 = y + fontRenderer.fontHeight(FONT) + 4; // align left (SHIFT, SPACE) - tft.drawRoundRect(15 - 2, y - 1, tft.textWidth(SHIFT, FONT) + 4, tft.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); - tft.drawRoundRect(15 - 2, y_2 - 1, tft.textWidth(SPACE, FONT) + 4, tft.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); + tft.drawRoundRect(15 - 2, y - 1, fontRenderer.textWidth(SHIFT, FONT) + 4, fontRenderer.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); + tft.drawRoundRect(15 - 2, y_2 - 1, fontRenderer.textWidth(SPACE, FONT) + 4, fontRenderer.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); // align right (BACKSPACE, ENTER); align from tft.width() - tft.drawRoundRect(tft.width() - 15 - tft.textWidth(ENTER, FONT) - 2, y - 1, tft.textWidth(ENTER, FONT) + 4, - tft.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); - tft.drawRoundRect(tft.width() - 15 - tft.textWidth(BACKSPACE, FONT) - 2, y_2 - 1, tft.textWidth(BACKSPACE, FONT) + 4, - tft.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); + tft.drawRoundRect(tft.width() - 15 - fontRenderer.textWidth(ENTER, FONT) - 2, y - 1, fontRenderer.textWidth(ENTER, FONT) + 4, + fontRenderer.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); + tft.drawRoundRect(tft.width() - 15 - fontRenderer.textWidth(BACKSPACE, FONT) - 2, y_2 - 1, fontRenderer.textWidth(BACKSPACE, FONT) + 4, + fontRenderer.fontHeight(FONT) + 2, 3, espgui::TFT_DARKGREY); // if (!dont_draw_string) { // align left (SHIFT, SPACE) - tft.drawString(SHIFT, 15, y, (m_char_index == m_char_length ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); - tft.drawString(SPACE, 15, y_2, (m_char_index == m_char_length + 1 ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length + 1 ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); + fontRenderer.drawString(SHIFT, 15, y, (m_char_index == m_char_length ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); + fontRenderer.drawString(SPACE, 15, y_2, (m_char_index == m_char_length + 1 ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length + 1 ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); // align right (BACKSPACE, ENTER); align from tft.width() - tft.drawString(BACKSPACE, tft.width() - 15 - tft.textWidth(BACKSPACE, FONT), y_2, (m_char_index == m_char_length + 2 ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length + 2 ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); - tft.drawString(ENTER, tft.width() - 15 - tft.textWidth(ENTER, FONT), y, (m_char_index == m_char_length + 3 ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length + 3 ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); + fontRenderer.drawString(BACKSPACE, tft.width() - 15 - fontRenderer.textWidth(BACKSPACE, FONT), y_2, (m_char_index == m_char_length + 2 ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length + 2 ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); + fontRenderer.drawString(ENTER, tft.width() - 15 - fontRenderer.textWidth(ENTER, FONT), y, (m_char_index == m_char_length + 3 ? espgui::TFT_BLACK : espgui::TFT_WHITE), (m_char_index == m_char_length + 3 ? espgui::TFT_WHITE : espgui::TFT_BLACK), FONT); } } } diff --git a/src/messagepopupdisplay.cpp b/src/messagepopupdisplay.cpp index 555faf7..f608e6e 100644 --- a/src/messagepopupdisplay.cpp +++ b/src/messagepopupdisplay.cpp @@ -6,6 +6,7 @@ // 3rdparty lib includes #include #include +#include // local includes #include "tftinterface.h" @@ -36,6 +37,8 @@ void MessagePopupDisplay::buttonPressed(Button button) void MessagePopupDisplay::initOverlay(TftInterface &tft) { + FontRenderer fontRenderer{tft}; + const auto leftMargin = 20; const auto rightMargin = leftMargin; const auto topMargin = tft.height() > 300 ? 50 : 20; @@ -61,12 +64,12 @@ void MessagePopupDisplay::initOverlay(TftInterface &tft) if (c == '\n' || x > tft.width() - rightMargin - 10) { x = leftMargin + 5; - y += tft.fontHeight(4); + y += fontRenderer.fontHeight(4); } if (c != '\n') { - const auto addedWidth = tft.drawString(std::string_view{&c, 1}, x, y, TFT_WHITE, color565(30, 30, 30), 4); + const auto addedWidth = fontRenderer.drawString(std::string_view{&c, 1}, x, y, TFT_WHITE, color565(30, 30, 30), 4); x += addedWidth; } @@ -83,7 +86,7 @@ void MessagePopupDisplay::initOverlay(TftInterface &tft) color565(100, 100, 100), color565(170, 170, 170)); - tft.drawString("Retry", leftMargin + 18, bottom - 37, TFT_BLACK, color565(170, 170, 170), 4); + fontRenderer.drawString("Retry", leftMargin + 18, bottom - 37, TFT_BLACK, color565(170, 170, 170), 4); } tft.drawSunkenRect(leftMargin + 15 + ((width - 15 - 30 - 15) / 2) + 15, bottom - 40, @@ -93,7 +96,7 @@ void MessagePopupDisplay::initOverlay(TftInterface &tft) color565(100, 100, 100), color565(170, 170, 170)); - tft.drawString("Ok", leftMargin + 18 + ((width - 15 - 30 - 15) / 2) + 15 + 1, bottom - 37, TFT_BLACK, color565(170, 170, 170), 4); + fontRenderer.drawString("Ok", leftMargin + 18 + ((width - 15 - 30 - 15) / 2) + 15 + 1, bottom - 37, TFT_BLACK, color565(170, 170, 170), 4); } } // namespace espgui diff --git a/src/richtextrenderer.cpp b/src/richtextrenderer.cpp index 95466b8..a657fd7 100644 --- a/src/richtextrenderer.cpp +++ b/src/richtextrenderer.cpp @@ -5,6 +5,7 @@ // 3rdparty lib includes #include +#include // local includes #include "tftinterface.h" @@ -24,22 +25,24 @@ std::string richTextEscape(std::string_view subject) int16_t renderRichText(TftInterface &tft, std::string_view str, int32_t poX, int32_t poY, uint16_t color, uint16_t bgcolor, uint8_t font) { + FontRenderer fontRenderer{tft}; + if (str.empty()) return 0; - const int16_t fontHeight = tft.fontHeight(font); + const int16_t fontHeight = fontRenderer.fontHeight(font); const uint16_t oldColor = color; const uint8_t oldFont = font; int16_t width{}; - const auto drawString = [&tft, &poX, &poY, &color, &bgcolor, &font, &width, &fontHeight, &oldFont](std::string_view str) { - const auto addedWith = tft.drawString(str, poX, poY, color, bgcolor, font); + const auto drawString = [&tft, &fontRenderer, &poX, &poY, &color, &bgcolor, &font, &width, &fontHeight, &oldFont](std::string_view str) { + const auto addedWith = fontRenderer.drawString(str, poX, poY, color, bgcolor, font); if (font != oldFont) { - if (const int16_t newFontHeight = tft.fontHeight(font); newFontHeight < fontHeight) + if (const int16_t newFontHeight = fontRenderer.fontHeight(font); newFontHeight < fontHeight) { tft.fillRect(poX, poY + newFontHeight, addedWith, fontHeight - newFontHeight, diff --git a/src/tftespiimpl.h b/src/tftespiimpl.h deleted file mode 100644 index 528beca..0000000 --- a/src/tftespiimpl.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -// 3rdparty lib includes -#include "TFT_eSPI.h" - -// local includes -#include "tftinterface.h" - -namespace espgui { - -class TftESpiImpl : public TftInterface -{ -public: - void init() { m_tft.init(); } - - void drawPixel(int32_t x, int32_t y, uint16_t color) override { m_tft.drawPixel(x, y, color); } - void drawChar(int32_t x, int32_t y, uint16_t c, uint16_t color, uint16_t bg, uint8_t size) override { m_tft.drawChar(x, y, c, color, bg, size); } - void drawLine(int32_t xs, int32_t ys, int32_t xe, int32_t ye, uint16_t color) override { m_tft.drawLine(xs, ys, xe, ye, color); } - void drawFastVLine(int32_t x, int32_t y, int32_t h, uint16_t color) override { m_tft.drawFastVLine(x, y, h, color); } - void drawFastHLine(int32_t x, int32_t y, int32_t w, uint16_t color) override { m_tft.drawFastHLine(x, y, w, color); } - void fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color) override { m_tft.fillRect(x, y, w, h, color); } - - int16_t drawChar(uint16_t uniCode, int32_t x, int32_t y, uint16_t color, uint16_t bgcolor, uint8_t font) override { return m_tft.drawChar(uniCode, x, y, color, bgcolor, font); } - int16_t height() const override { return m_tft.height(); } - int16_t width() const override { return m_tft.width(); } - - void setRotation(uint8_t r) override { m_tft.setRotation(r); } - uint8_t getRotation(void) const { return m_tft.getRotation(); } - - void setTextSize(uint8_t s) override { m_tft.setTextSize(s); } - - // Graphics drawing - void fillScreen(uint32_t color) override { m_tft.fillScreen(color); } - void drawRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) override { m_tft.drawRect(x, y, w, h, color); } - void drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color) override { m_tft.drawRoundRect(x, y, w, h, radius, color); } - void fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color) override { m_tft.fillRoundRect(x, y, w, h, radius, color); } - - void fillRectVGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2) override { m_tft.fillRectVGradient(x, y, w, h, color1, color2); } - void fillRectHGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2) override { m_tft.fillRectHGradient(x, y, w, h, color1, color2); } - - void drawSpot(float ax, float ay, float r, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF) override { m_tft.drawSpot(ax, ay, r, fg_color, bg_color); } - - void fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color, uint32_t bg_color = 0x00FFFFFF) override { m_tft.fillSmoothCircle(x, y, r, color, bg_color); } - - void fillSmoothRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color, uint32_t bg_color = 0x00FFFFFF) override { m_tft.fillSmoothRoundRect(x, y, w, h, radius, color, bg_color); } - - void drawWideLine(float ax, float ay, float bx, float by, float wd, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF) override { m_tft.drawWideLine(ax, ay, bx, by, wd, fg_color, bg_color); } - - void drawWedgeLine(float ax, float ay, float bx, float by, float aw, float bw, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF) override { m_tft.drawWedgeLine(ax, ay, bx, by, aw, bw, fg_color, bg_color); } - - void drawSunkenRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color0, uint32_t color1, uint32_t color2) override { m_tft.drawSunkenRect(x, y, w, h, color0, color1, color2); } - - void drawCircle(int32_t x, int32_t y, int32_t r, uint32_t color) override { m_tft.drawCircle(x, y, r, color); } - void drawCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, uint32_t color) override { m_tft.drawCircleHelper(x, y, r, cornername, color); } - void fillCircle(int32_t x, int32_t y, int32_t r, uint32_t color) override { m_tft.fillCircle(x, y, r, color); } - void fillCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, int32_t delta, uint32_t color) override { m_tft.fillCircleHelper(x, y, r, cornername, delta, color); } - - void drawEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color) override { m_tft.drawEllipse(x, y, rx, ry, color); } - void fillEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color) override { m_tft.fillEllipse(x, y, rx, ry, color); } - - void drawTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color) override { m_tft.drawTriangle(x1, y1, x2, y2, x3, y3, color); } - void fillTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color) override { m_tft.fillTriangle(x1, y1, x2, y2, x3, y3, color); } - - int16_t textWidth(std::string_view string, uint8_t font) override { return m_tft.textWidth(string, font); } - int16_t fontHeight(int16_t font) override { return m_tft.fontHeight(font); } - - int16_t drawString(std::string_view string, int32_t x, int32_t y, uint16_t color, uint16_t bgcolor, uint8_t font, uint8_t datum = 0) override { return m_tft.drawString(string, x, y, color, bgcolor, font, datum); } - int16_t drawCentreString(std::string_view string, int32_t x, int32_t y, uint16_t color, uint16_t bgcolor, uint8_t font) override { return m_tft.drawCentreString(string, x, y, color, bgcolor, font); } - int16_t drawRightString(std::string_view string, int32_t x, int32_t y, uint16_t color, uint16_t bgcolor, uint8_t font) override { return m_tft.drawRightString(string, x, y, color, bgcolor, font); } - - void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) { m_tft.pushImage(x, y, w, h, data); } - void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data, uint16_t transparent) { m_tft.pushImage(x, y, w, h, data, transparent); } - - void startWrite(void) override { m_tft.startWrite(); } - void writeColor(uint16_t color, uint32_t len) override { m_tft.writeColor(color, len); } - void endWrite(void) override { m_tft.endWrite(); } - - void pushColor(uint16_t color, uint32_t len) override { m_tft.pushColor(color, len); } - - void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) override { m_tft.setAddrWindow(xs, ys, w, h); } -private: - TFT_eSPI m_tft; -}; - -} // namespace espgui diff --git a/src/tftinterface.h b/src/tftinterface.h deleted file mode 100644 index 1b2dafa..0000000 --- a/src/tftinterface.h +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once - -// system includes -#include -#include - -namespace espgui { -class TftInterface -{ -public: - explicit TftInterface() = default; - virtual ~TftInterface() = default; - - virtual void drawPixel(int32_t x, int32_t y, uint16_t color) = 0; - virtual void drawChar(int32_t x, int32_t y, uint16_t c, uint16_t color, uint16_t bg, uint8_t size) = 0; - virtual void drawLine(int32_t xs, int32_t ys, int32_t xe, int32_t ye, uint16_t color) = 0; - virtual void drawFastVLine(int32_t x, int32_t y, int32_t h, uint16_t color) = 0; - virtual void drawFastHLine(int32_t x, int32_t y, int32_t w, uint16_t color) = 0; - virtual void fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color) = 0; - - virtual int16_t drawChar(uint16_t uniCode, int32_t x, int32_t y, uint16_t color, uint16_t bgcolor, uint8_t font) = 0; - virtual int16_t height(void) const = 0; - virtual int16_t width(void) const = 0; - - virtual void setRotation(uint8_t r) = 0; // Set the display image orientation to 0, 1, 2 or 3 - virtual uint8_t getRotation(void) const = 0; // Read the current rotation - - virtual void setTextSize(uint8_t size) = 0; // Set character size multiplier (this increases pixel size) - - // Graphics drawing - virtual void fillScreen(uint32_t color) = 0; - virtual void drawRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) = 0; - virtual void drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color) = 0; - virtual void fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color) = 0; - - virtual void fillRectVGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2) = 0; - virtual void fillRectHGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2) = 0; - - // Draw a small anti-aliased filled circle at ax,ay with radius r (uses drawWideLine) - // If bg_color is not included the background pixel colour will be read from TFT or sprite - virtual void drawSpot(float ax, float ay, float r, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF) = 0; - - // Draw an anti-aliased filled circle at x, y with radius r - // If bg_color is not included the background pixel colour will be read from TFT or sprite - virtual void fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color, uint32_t bg_color = 0x00FFFFFF) = 0; - - virtual void fillSmoothRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color, uint32_t bg_color = 0x00FFFFFF) = 0; - - // Draw an anti-aliased wide line from ax,ay to bx,by width wd with radiused ends (radius is wd/2) - // If bg_color is not included the background pixel colour will be read from TFT or sprite - virtual void drawWideLine(float ax, float ay, float bx, float by, float wd, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF) = 0; - - // Draw an anti-aliased wide line from ax,ay to bx,by with different width at each end aw, bw and with radiused ends - // If bg_color is not included the background pixel colour will be read from TFT or sprite - virtual void drawWedgeLine(float ax, float ay, float bx, float by, float aw, float bw, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF) = 0; - - virtual void drawSunkenRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color0, uint32_t color1, uint32_t color2) = 0; - - virtual void drawCircle(int32_t x, int32_t y, int32_t r, uint32_t color) = 0; - virtual void drawCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, uint32_t color) = 0; - virtual void fillCircle(int32_t x, int32_t y, int32_t r, uint32_t color) = 0; - virtual void fillCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, int32_t delta, uint32_t color) = 0; - - virtual void drawEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color) = 0; - virtual void fillEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color) = 0; - - // Corner 1 Corner 2 Corner 3 - virtual void drawTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color) = 0; - virtual void fillTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color) = 0; - - virtual int16_t textWidth(std::string_view string, uint8_t font) = 0; // Returns pixel width of string in specified font - virtual int16_t fontHeight(int16_t font) = 0; // Returns pixel height of string in specified font - - // Handle char arrays - // Use with setTextDatum() to position string on TFT, and setTextPadding() to blank old displayed strings - virtual int16_t drawString(std::string_view string, int32_t x, int32_t y, uint16_t color, uint16_t bgcolor, uint8_t font, uint8_t datum = 0) = 0; // Draw string using specifed font number - virtual int16_t drawCentreString(std::string_view string, int32_t x, int32_t y, uint16_t color, uint16_t bgcolor, uint8_t font) = 0; // Deprecated, use setTextDatum() and drawString() - virtual int16_t drawRightString(std::string_view string, int32_t x, int32_t y, uint16_t color, uint16_t bgcolor, uint8_t font) = 0; // Deprecated, use setTextDatum() and drawString() - - // These are used to render images or sprites stored in RAM arrays (used by Sprite class for 16bpp Sprites) - virtual void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) = 0; - virtual void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data, uint16_t transparent) = 0; - - // Bare metal functions - virtual void startWrite(void) = 0; - virtual void writeColor(uint16_t color, uint32_t len) = 0; - virtual void endWrite(void) = 0; - - // Push (aka write pixel) colours to the set window - virtual void pushColor(uint16_t color, uint32_t len) = 0; - - // The TFT_eSprite class inherits the following functions (not all are useful to Sprite class - virtual void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) = 0; -}; - -inline bool isLandscape(const TftInterface &tft) -{ - return (tft.getRotation() == 1 || tft.getRotation() == 3); -} -} // namespace espgui diff --git a/src/widgets/label.cpp b/src/widgets/label.cpp index 7cc3ff1..bdb4dbe 100644 --- a/src/widgets/label.cpp +++ b/src/widgets/label.cpp @@ -1,5 +1,8 @@ #include "label.h" +// 3rdparty lib includes +#include + // local includes #include "tftinterface.h" #include "richtextrenderer.h" @@ -22,6 +25,12 @@ void Label::start(TftInterface &tft) } void Label::redraw(TftInterface &tft, std::string_view str, uint16_t color, uint16_t bgcolor, uint8_t font, bool forceRedraw) +{ + espgui::FontRenderer fontRenderer{tft}; + redraw(tft, fontRenderer, str, color, bgcolor, font, forceRedraw); +} + +void Label::redraw(TftInterface &tft, FontRenderer &fontRenderer, std::string_view str, uint16_t color, uint16_t bgcolor, uint8_t font, bool forceRedraw) { if (m_lastStr == str && m_lastColor == color && @@ -30,7 +39,7 @@ void Label::redraw(TftInterface &tft, std::string_view str, uint16_t color, uint return; const auto renderedWidth = renderRichText(tft, str, m_x, m_y, color, bgcolor, font); - const auto renderedHeight = tft.fontHeight(font); + const auto renderedHeight = fontRenderer.fontHeight(font); if (renderedWidth < m_lastWidth) tft.fillRect(m_x + renderedWidth, m_y, diff --git a/src/widgets/label.h b/src/widgets/label.h index 149cdf1..1ea94ea 100644 --- a/src/widgets/label.h +++ b/src/widgets/label.h @@ -6,6 +6,7 @@ // forward declares namespace espgui { class TftInterface; +class FontRenderer; } // namespace espgui namespace espgui { @@ -19,6 +20,7 @@ public: void start(TftInterface &tft); void redraw(TftInterface &tft, std::string_view str, uint16_t color, uint16_t bgcolor, uint8_t font, bool forceRedraw = false); + void redraw(TftInterface &tft, FontRenderer &fontRenderer, std::string_view str, uint16_t color, uint16_t bgcolor, uint8_t font, bool forceRedraw = false); void clear(TftInterface &tft, uint16_t bgcolor); private: diff --git a/src/widgets/verticalmeter.cpp b/src/widgets/verticalmeter.cpp index 08f7380..dd784fa 100644 --- a/src/widgets/verticalmeter.cpp +++ b/src/widgets/verticalmeter.cpp @@ -2,6 +2,7 @@ // 3rdparty lib includes #include +#include // local includes #include "tftinterface.h" @@ -15,10 +16,12 @@ VerticalMeter::VerticalMeter(const char *text, const char *format, int x, int y) void VerticalMeter::start(TftInterface &tft) { + FontRenderer fontRenderer{tft}; + int w = 36; tft.drawRect(m_x, m_y, w, 155, TFT_GREY); tft.fillRect(m_x + 2, m_y + 19, w - 3, 155 - 38, TFT_WHITE); - tft.drawCentreString(m_text, m_x + w / 2, m_y + 2, TFT_CYAN, TFT_BLACK, 2); + fontRenderer.drawCentreString(m_text, m_x + w / 2, m_y + 2, TFT_CYAN, TFT_BLACK, 2); for (int i = 0; i < 110; i += 10) tft.drawFastHLine(m_x + 20, m_y + 27 + i, 6, TFT_BLACK); @@ -29,14 +32,16 @@ void VerticalMeter::start(TftInterface &tft) tft.fillTriangle(m_x + 3, m_y + 127, m_x + 3 + 16, m_y + 127, m_x + 3, m_y + 127 - 5, TFT_RED); tft.fillTriangle(m_x + 3, m_y + 127, m_x + 3 + 16, m_y + 127, m_x + 3, m_y + 127 + 5, TFT_RED); - tft.drawCentreString("---", m_x + w / 2, m_y + 155 - 18, TFT_CYAN, TFT_BLACK, 2); + fontRenderer.drawCentreString("---", m_x + w / 2, m_y + 155 - 18, TFT_CYAN, TFT_BLACK, 2); } void VerticalMeter::redraw(TftInterface &tft, float value, float min, float max) { + FontRenderer fontRenderer{tft}; + char buf[16]; snprintf(&buf[0], 16, m_format, value); - tft.drawRightString(buf, m_x + 36 - 5, 187 - 27 + 155 - 18, TFT_GREEN, TFT_BLACK, 2); + fontRenderer.drawRightString(buf, m_x + 36 - 5, 187 - 27 + 155 - 18, TFT_GREEN, TFT_BLACK, 2); const int dx = 3 + m_x; value = cpputils::mapValueClamped(value, min, max, 0.f, 100.f); diff --git a/src/widgets/vumeter.cpp b/src/widgets/vumeter.cpp index b771362..6b2c511 100644 --- a/src/widgets/vumeter.cpp +++ b/src/widgets/vumeter.cpp @@ -6,6 +6,7 @@ // 3rdparty lib includes #include #include +#include // local includes #include "tftinterface.h" @@ -14,6 +15,8 @@ namespace espgui { void VuMeter::start(TftInterface &tft) { + FontRenderer fontRenderer{tft}; + ltx = 0; osx = 120; osy = 120; @@ -79,11 +82,11 @@ void VuMeter::start(TftInterface &tft) x0 = sx * (100 + tl + 10) + 120; y0 = sy * (100 + tl + 10) + 140; switch (i / 25) { - case -2: tft.drawCentreString("0", x0, y0 - 12, TFT_BLACK, TFT_BLACK, 2); break; - case -1: tft.drawCentreString("7.5", x0, y0 - 9, TFT_BLACK, TFT_BLACK, 2); break; - case 0: tft.drawCentreString("15", x0, y0 - 6, TFT_BLACK, TFT_BLACK, 2); break; - case 1: tft.drawCentreString("22.5", x0, y0 - 9, TFT_BLACK, TFT_BLACK, 2); break; - case 2: tft.drawCentreString("30", x0, y0 - 12, TFT_BLACK, TFT_BLACK, 2); break; + case -2: fontRenderer.drawCentreString("0", x0, y0 - 12, TFT_BLACK, TFT_BLACK, 2); break; + case -1: fontRenderer.drawCentreString("7.5", x0, y0 - 9, TFT_BLACK, TFT_BLACK, 2); break; + case 0: fontRenderer.drawCentreString("15", x0, y0 - 6, TFT_BLACK, TFT_BLACK, 2); break; + case 1: fontRenderer.drawCentreString("22.5", x0, y0 - 9, TFT_BLACK, TFT_BLACK, 2); break; + case 2: fontRenderer.drawCentreString("30", x0, y0 - 12, TFT_BLACK, TFT_BLACK, 2); break; } } @@ -96,15 +99,17 @@ void VuMeter::start(TftInterface &tft) if (i < 50) tft.drawLine(x0, y0, x1, y1, TFT_BLACK); } - tft.drawString("KM/h", 5 + 230 - 40, 119 - 20, TFT_BLACK, TFT_BLACK, 2); // Units at bottom right - tft.drawCentreString("KM/h", 120, 70, TFT_BLACK, TFT_BLACK, 4); // Comment out to avoid font 4 + fontRenderer.drawString("KM/h", 5 + 230 - 40, 119 - 20, TFT_BLACK, TFT_BLACK, 2); // Units at bottom right + fontRenderer.drawCentreString("KM/h", 120, 70, TFT_BLACK, TFT_BLACK, 4); // Comment out to avoid font 4 tft.drawRect(5, 3, 230, 119, TFT_BLACK); // Draw bezel line } void VuMeter::redraw(TftInterface &tft, float value) { + FontRenderer fontRenderer{tft}; + char buf[8]; dtostrf(value, 4, 0, buf); - tft.drawRightString(buf, 50, 119 - 25, TFT_BLACK, TFT_WHITE, 4); + fontRenderer.drawRightString(buf, 50, 119 - 25, TFT_BLACK, TFT_WHITE, 4); if (value < -3) value = -3; // Limit value to emulate needle end stops if (value > 33) value = 33; @@ -123,7 +128,7 @@ void VuMeter::redraw(TftInterface &tft, float value) tft.drawLine(120 + 20 * ltx + 1, 140 - 20, osx + 1, osy, TFT_WHITE); // Re-plot text under needle - tft.drawCentreString("KM/h", 120, 70, TFT_BLACK, TFT_BLACK, 4); // // Comment out to avoid font 4 + fontRenderer.drawCentreString("KM/h", 120, 70, TFT_BLACK, TFT_BLACK, 4); // // Comment out to avoid font 4 // Store new needle end coords for next erase ltx = tx;