Files
MeshCore-Solo/examples/companion_radio/ui-new/CharTestScreen.h
T
JakubandClaude Sonnet 4.6 acc062718f fix: dynamic layout and pixel-accurate word-wrap in companion radio UI
- All menu screens (Tools, Bot, Settings) now derive item height from
  display.getLineHeight() instead of hardcoded constants, preventing
  item overflow on 64px OLED displays
- ToolsScreen caps rendered items to screen height so Char Test is visible
- FullscreenMsgView word-wrap now uses display.getTextWidth() per candidate
  line instead of fixed char count, correctly handles variable-width and
  multi-byte UTF-8 glyphs; FS_CHARS_MAX increased 32→80
- CharTestScreen: fix v-arrow y-position; remove stale "→ blocks █" comments

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:26:11 +02:00

70 lines
2.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
// Test screen that displays sample characters from various alphabets/scripts.
// Useful for verifying transliteration and font coverage on experimental fonts.
class CharTestScreen : public UIScreen {
UITask* _task;
int _scroll;
int _visible; // updated each render, used by handleInput
struct TestLine { const char* label; const char* sample; };
static const int LINE_COUNT = 11;
static const TestLine LINES[LINE_COUNT];
public:
CharTestScreen(UITask* task) : _task(task), _scroll(0), _visible(6) {}
void enter() { _scroll = 0; }
int render(DisplayDriver& display) override {
display.setTextSize(1);
display.setColor(DisplayDriver::LIGHT);
display.drawTextCentered(display.width() / 2, 0, "CHAR TEST");
display.fillRect(0, 10, display.width(), 1);
const int lineH = display.getLineHeight();
const int startY = 12;
_visible = (display.height() - startY) / lineH;
for (int i = 0; i < _visible && (_scroll + i) < LINE_COUNT; i++) {
char buf[80];
snprintf(buf, sizeof(buf), "%s:%s", LINES[_scroll + i].label, LINES[_scroll + i].sample);
display.setCursor(2, startY + i * lineH);
display.print(buf);
}
if (_scroll > 0) {
display.setCursor(display.width() - 6, startY);
display.print("^");
}
if (_scroll + _visible < LINE_COUNT) {
display.setCursor(display.width() - 6, startY + (_visible - 1) * lineH);
display.print("v");
}
return 500;
}
bool handleInput(char c) override {
if (c == KEY_UP && _scroll > 0) { _scroll--; return true; }
if (c == KEY_DOWN && _scroll + _visible < LINE_COUNT) { _scroll++; return true; }
if (c == KEY_CANCEL || c == KEY_CONTEXT_MENU) { _task->gotoToolsScreen(); return true; }
return false;
}
};
// Sample strings are printed as raw UTF-8 (no transliteration) to test native font coverage.
// Lemon font covers U+0020U+04FF: Latin, Greek and Cyrillic all render natively.
const CharTestScreen::TestLine CharTestScreen::LINES[CharTestScreen::LINE_COUNT] = {
{ "PL", "ąćęłńóśźżĄĆĘŁŃ" }, // Polish
{ "DE", "äöüÄÖÜß" }, // German
{ "CS", "čďěňřšťžůýČŘŠŤŽ" }, // Czech/Slovak
{ "FR", "àâçèêëîïôùûÿ" }, // French
{ "NO", "åæøÅÆØðþÐÞ" }, // Nordic/Icelandic
{ "HU", "áéíőúűÁÉÍŐÚŰ" }, // Hungarian
{ "HR", "čćđšžČĆĐŠŽ" }, // Croatian
{ "TR", "çğışöüİŞĞ" }, // Turkish
{ "LT", "āēīūģķļņŗėįų" }, // Baltic (Latvian/Lithuanian)
{ "RU", "АБВГДЕЖЗабвгдеж" }, // Cyrillic
{ "GR", "\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4\xCE\xB5\xCE\xB6\xCE\xB7\xCE\xB8\xCE\xB9\xCE\xBA" }, // Greek αβγδεζηθικ
};