From 3a93355d98e0825dd4ada23e3f2e9091234937eb Mon Sep 17 00:00:00 2001 From: jpirnay Date: Thu, 7 May 2026 20:02:35 +0200 Subject: [PATCH] Proper linewrap and centering --- .../network/WifiSelectionActivity.cpp | 74 ++++++------------- .../settings/ClearCacheActivity.cpp | 18 ++++- src/activities/settings/OtaUpdateActivity.cpp | 8 +- .../settings/SdFirmwareUpdateActivity.cpp | 8 +- 4 files changed, 52 insertions(+), 56 deletions(-) diff --git a/src/activities/network/WifiSelectionActivity.cpp b/src/activities/network/WifiSelectionActivity.cpp index 0046b862..d373506b 100644 --- a/src/activities/network/WifiSelectionActivity.cpp +++ b/src/activities/network/WifiSelectionActivity.cpp @@ -862,7 +862,14 @@ void WifiSelectionActivity::renderForgetPrompt() const { } renderer.drawCenteredText(UI_10_FONT_ID, top, ssidInfo.c_str()); - renderer.drawCenteredText(UI_10_FONT_ID, top + 40, tr(STR_FORGET_AND_REMOVE)); + const auto& metrics = UITheme::getInstance().getMetrics(); + const int hintWidth = pageWidth - 2 * metrics.contentSidePadding; + const auto forgetLines = renderer.wrappedText(UI_10_FONT_ID, tr(STR_FORGET_AND_REMOVE), hintWidth, 3); + int forgetY = top + 40; + for (const auto& line : forgetLines) { + renderer.drawCenteredText(UI_10_FONT_ID, forgetY, line.c_str()); + forgetY += height; + } // Draw Cancel/Forget network buttons const int buttonY = top + 80; @@ -904,34 +911,15 @@ void WifiSelectionActivity::renderCaptivePortal() const { const int sp = metrics.verticalSpacing; constexpr int QR_SIZE = 320; - // Pre-compute URL line count so we can vertically centre everything - const char* url = captivePortalUrl.c_str(); - int urlLineCount = 0; - { - int rem = static_cast(captivePortalUrl.size()); - int off = 0; - while (rem > 0) { - int lo = 1, hi = rem; - while (lo < hi) { - const int mid = (lo + hi + 1) / 2; - char tmp[512]; - snprintf(tmp, sizeof(tmp), "%.*s", mid, url + off); - if (renderer.getTextWidth(SMALL_FONT_ID, tmp) <= maxWidth) - lo = mid; - else - hi = mid - 1; - } - urlLineCount++; - off += lo; - rem -= lo; - } - } + // Pre-compute wrapped hint and URL lines so we can vertically centre everything + const std::string hintText = std::string(tr(STR_CAPTIVE_PORTAL_HINT_1)) + " " + tr(STR_CAPTIVE_PORTAL_HINT_2); + const auto hintLines = renderer.wrappedText(UI_10_FONT_ID, hintText.c_str(), maxWidth, 4); + const auto urlLines = renderer.wrappedText(SMALL_FONT_ID, captivePortalUrl.c_str(), maxWidth, 10); - const int totalHeight = lh12 + sp // title - + lh10 // hint line 1 - + lh10 + sp // hint line 2 - + QR_SIZE + sp // QR code - + urlLineCount * lhSmall; + const int totalHeight = lh12 + sp // title + + static_cast(hintLines.size()) * lh10 + sp // hint + + QR_SIZE + sp // QR code + + static_cast(urlLines.size()) * lhSmall; // contentRect covers the full screen minus button hints; subtract the header // and sub-header that render() always draws above us. @@ -941,35 +929,19 @@ void WifiSelectionActivity::renderCaptivePortal() const { renderer.drawCenteredText(UI_12_FONT_ID, y, tr(STR_CAPTIVE_PORTAL_DETECTED), true, EpdFontFamily::BOLD); y += lh12 + sp; - renderer.drawCenteredText(UI_10_FONT_ID, y, tr(STR_CAPTIVE_PORTAL_HINT_1)); - y += lh10; - renderer.drawCenteredText(UI_10_FONT_ID, y, tr(STR_CAPTIVE_PORTAL_HINT_2)); - y += lh10 + sp; + for (const auto& line : hintLines) { + renderer.drawCenteredText(UI_10_FONT_ID, y, line.c_str()); + y += lh10; + } + y += sp; const int qrX = contentRect.x + (contentRect.width - QR_SIZE) / 2; QrUtils::drawQrCode(renderer, Rect{qrX, y, QR_SIZE, QR_SIZE}, captivePortalUrl); y += QR_SIZE + sp; - // Split URL into as many lines as needed - int remaining = static_cast(captivePortalUrl.size()); - int offset = 0; - while (remaining > 0) { - int lo = 1, hi = remaining; - while (lo < hi) { - const int mid = (lo + hi + 1) / 2; - char tmp[512]; - snprintf(tmp, sizeof(tmp), "%.*s", mid, url + offset); - if (renderer.getTextWidth(SMALL_FONT_ID, tmp) <= maxWidth) - lo = mid; - else - hi = mid - 1; - } - char line[512]; - snprintf(line, sizeof(line), "%.*s", lo, url + offset); - renderer.drawCenteredText(SMALL_FONT_ID, y, line); + for (const auto& line : urlLines) { + renderer.drawCenteredText(SMALL_FONT_ID, y, line.c_str()); y += lhSmall; - offset += lo; - remaining -= lo; } const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_CAPTIVE_PORTAL_DONE), "", ""); diff --git a/src/activities/settings/ClearCacheActivity.cpp b/src/activities/settings/ClearCacheActivity.cpp index 34216aba..698e0a46 100644 --- a/src/activities/settings/ClearCacheActivity.cpp +++ b/src/activities/settings/ClearCacheActivity.cpp @@ -28,11 +28,23 @@ void ClearCacheActivity::render(RenderLock&&) { tr(STR_CLEAR_READING_CACHE)); const int midY = contentRect.y + contentRect.height / 2; + const int lineHeight = renderer.getLineHeight(UI_10_FONT_ID); + const int warnWidth = contentRect.width - 2 * metrics.contentSidePadding; if (state == WARNING) { - renderer.drawCenteredText(UI_10_FONT_ID, midY - 60, tr(STR_CLEAR_CACHE_WARNING_1), true); + const auto warn1Lines = renderer.wrappedText(UI_10_FONT_ID, tr(STR_CLEAR_CACHE_WARNING_1), warnWidth, 3); + int y = midY - 60; + for (const auto& line : warn1Lines) { + renderer.drawCenteredText(UI_10_FONT_ID, y, line.c_str()); + y += lineHeight; + } renderer.drawCenteredText(UI_10_FONT_ID, midY - 30, tr(STR_CLEAR_CACHE_WARNING_2), true, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_10_FONT_ID, midY + 10, tr(STR_CLEAR_CACHE_WARNING_3), true); - renderer.drawCenteredText(UI_10_FONT_ID, midY + 30, tr(STR_CLEAR_CACHE_WARNING_4), true); + const std::string warn34 = std::string(tr(STR_CLEAR_CACHE_WARNING_3)) + " " + tr(STR_CLEAR_CACHE_WARNING_4); + const auto warn34Lines = renderer.wrappedText(UI_10_FONT_ID, warn34.c_str(), warnWidth, 3); + y = midY + 10; + for (const auto& line : warn34Lines) { + renderer.drawCenteredText(UI_10_FONT_ID, y, line.c_str()); + y += lineHeight; + } const auto labels = mappedInput.mapLabels(tr(STR_CANCEL), tr(STR_CLEAR_BUTTON), "", ""); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); diff --git a/src/activities/settings/OtaUpdateActivity.cpp b/src/activities/settings/OtaUpdateActivity.cpp index 4a8ff8db..d2943679 100644 --- a/src/activities/settings/OtaUpdateActivity.cpp +++ b/src/activities/settings/OtaUpdateActivity.cpp @@ -160,7 +160,13 @@ void OtaUpdateActivity::render(RenderLock&&) { GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); } else if (state == FINISHED) { renderer.drawCenteredText(UI_10_FONT_ID, top, tr(STR_UPDATE_COMPLETE), true, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_10_FONT_ID, top + height + metrics.verticalSpacing, tr(STR_POWER_ON_HINT)); + const int hintWidth = contentRect.width - 2 * metrics.contentSidePadding; + const auto hintLines = renderer.wrappedText(UI_10_FONT_ID, tr(STR_POWER_ON_HINT), hintWidth, 4); + int hintY = top + height + metrics.verticalSpacing; + for (const auto& line : hintLines) { + renderer.drawCenteredText(UI_10_FONT_ID, hintY, line.c_str()); + hintY += height; + } } renderer.displayBuffer(); diff --git a/src/activities/settings/SdFirmwareUpdateActivity.cpp b/src/activities/settings/SdFirmwareUpdateActivity.cpp index 971f6d2d..1ffb72af 100644 --- a/src/activities/settings/SdFirmwareUpdateActivity.cpp +++ b/src/activities/settings/SdFirmwareUpdateActivity.cpp @@ -230,7 +230,13 @@ void SdFirmwareUpdateActivity::render(RenderLock&&) { } else { // PICKING / CONFIRMING: a sub-activity is on top, nothing to draw. if (recoveryMode) { - renderer.drawCenteredText(UI_10_FONT_ID, top, tr(STR_RECOVERY_MODE_HINT)); + const int hintWidth = pageWidth - 2 * metrics.contentSidePadding; + const auto hintLines = renderer.wrappedText(UI_10_FONT_ID, tr(STR_RECOVERY_MODE_HINT), hintWidth, 4); + int hintY = top; + for (const auto& line : hintLines) { + renderer.drawCenteredText(UI_10_FONT_ID, hintY, line.c_str()); + hintY += lineHeight; + } } }