mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-03-30 17:05:52 +00:00
Merge pull request #730 from michaelhart/node-displayname-improvements
Adds name filtering and text truncation for display in HomeScreen
This commit is contained in:
@@ -90,6 +90,7 @@ class HomeScreen : public UIScreen {
|
||||
bool _shutdown_init;
|
||||
AdvertPath recent[UI_RECENT_LIST_SIZE];
|
||||
|
||||
|
||||
void renderBatteryIndicator(DisplayDriver& display, uint16_t batteryMilliVolts) {
|
||||
// Convert millivolts to percentage
|
||||
const int minMilliVolts = 3000; // Minimum voltage (e.g., 3.0V)
|
||||
@@ -157,10 +158,12 @@ public:
|
||||
int render(DisplayDriver& display) override {
|
||||
char tmp[80];
|
||||
// node name
|
||||
display.setCursor(0, 0);
|
||||
display.setTextSize(1);
|
||||
display.setColor(DisplayDriver::GREEN);
|
||||
display.print(_node_prefs->node_name);
|
||||
char filtered_name[sizeof(_node_prefs->node_name)];
|
||||
display.translateUTF8ToBlocks(filtered_name, _node_prefs->node_name, sizeof(filtered_name));
|
||||
display.setCursor(0, 0);
|
||||
display.print(filtered_name);
|
||||
|
||||
// battery voltage
|
||||
renderBatteryIndicator(display, _task->getBattMilliVolts());
|
||||
@@ -199,8 +202,6 @@ public:
|
||||
for (int i = 0; i < UI_RECENT_LIST_SIZE; i++, y += 11) {
|
||||
auto a = &recent[i];
|
||||
if (a->name[0] == 0) continue; // empty slot
|
||||
display.setCursor(0, y);
|
||||
display.print(a->name);
|
||||
int secs = _rtc->getCurrentTime() - a->recv_timestamp;
|
||||
if (secs < 60) {
|
||||
sprintf(tmp, "%ds", secs);
|
||||
@@ -209,7 +210,14 @@ public:
|
||||
} else {
|
||||
sprintf(tmp, "%dh", secs / (60*60));
|
||||
}
|
||||
display.setCursor(display.width() - display.getTextWidth(tmp) - 1, y);
|
||||
|
||||
int timestamp_width = display.getTextWidth(tmp);
|
||||
int max_name_width = display.width() - timestamp_width - 1;
|
||||
|
||||
char filtered_recent_name[sizeof(a->name)];
|
||||
display.translateUTF8ToBlocks(filtered_recent_name, a->name, sizeof(filtered_recent_name));
|
||||
display.drawTextEllipsized(0, y, max_name_width, filtered_recent_name);
|
||||
display.setCursor(display.width() - timestamp_width - 1, y);
|
||||
display.print(tmp);
|
||||
}
|
||||
} else if (_page == HomePage::RADIO) {
|
||||
@@ -427,11 +435,15 @@ public:
|
||||
|
||||
display.setCursor(0, 14);
|
||||
display.setColor(DisplayDriver::YELLOW);
|
||||
display.print(p->origin);
|
||||
char filtered_origin[sizeof(p->origin)];
|
||||
display.translateUTF8ToBlocks(filtered_origin, p->origin, sizeof(filtered_origin));
|
||||
display.print(filtered_origin);
|
||||
|
||||
display.setCursor(0, 25);
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
display.printWordWrap(p->msg, display.width());
|
||||
char filtered_msg[sizeof(p->msg)];
|
||||
display.translateUTF8ToBlocks(filtered_msg, p->msg, sizeof(filtered_msg));
|
||||
display.printWordWrap(filtered_msg, display.width());
|
||||
|
||||
#if AUTO_OFF_MILLIS==0 // probably e-ink
|
||||
return 10000; // 10 s
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
class DisplayDriver {
|
||||
int _w, _h;
|
||||
@@ -31,5 +32,60 @@ public:
|
||||
setCursor(mid_x - w/2, y);
|
||||
print(str);
|
||||
}
|
||||
|
||||
// convert UTF-8 characters to displayable block characters for compatibility
|
||||
virtual void translateUTF8ToBlocks(char* dest, const char* src, size_t dest_size) {
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; src[i] != 0 && j < dest_size - 1; i++) {
|
||||
unsigned char c = (unsigned char)src[i];
|
||||
if (c >= 32 && c <= 126) {
|
||||
dest[j++] = c; // ASCII printable
|
||||
} else if (c >= 0x80) {
|
||||
dest[j++] = '\xDB'; // CP437 full block █
|
||||
while (src[i+1] && (src[i+1] & 0xC0) == 0x80)
|
||||
i++; // skip UTF-8 continuation bytes
|
||||
}
|
||||
}
|
||||
dest[j] = 0;
|
||||
}
|
||||
|
||||
// draw text with ellipsis if it exceeds max_width
|
||||
virtual void drawTextEllipsized(int x, int y, int max_width, const char* str) {
|
||||
char temp_str[256]; // reasonable buffer size
|
||||
size_t len = strlen(str);
|
||||
if (len >= sizeof(temp_str)) len = sizeof(temp_str) - 1;
|
||||
memcpy(temp_str, str, len);
|
||||
temp_str[len] = 0;
|
||||
|
||||
if (getTextWidth(temp_str) <= max_width) {
|
||||
setCursor(x, y);
|
||||
print(temp_str);
|
||||
return;
|
||||
}
|
||||
|
||||
// for variable-width fonts (GxEPD), add space after ellipsis
|
||||
// for fixed-width fonts (OLED), keep tight spacing to save precious characters
|
||||
const char* ellipsis;
|
||||
// use a simple heuristic: if 'i' and 'l' have different widths, it's variable-width
|
||||
int i_width = getTextWidth("i");
|
||||
int l_width = getTextWidth("l");
|
||||
if (i_width != l_width) {
|
||||
ellipsis = "... "; // variable-width fonts: add space
|
||||
} else {
|
||||
ellipsis = "..."; // fixed-width fonts: no space
|
||||
}
|
||||
|
||||
int ellipsis_width = getTextWidth(ellipsis);
|
||||
int str_len = strlen(temp_str);
|
||||
|
||||
while (str_len > 0 && getTextWidth(temp_str) > max_width - ellipsis_width) {
|
||||
temp_str[--str_len] = 0;
|
||||
}
|
||||
strcat(temp_str, ellipsis);
|
||||
|
||||
setCursor(x, y);
|
||||
print(temp_str);
|
||||
}
|
||||
|
||||
virtual void endFrame() = 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user