mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-08 10:57:51 +00:00
Merge branch 'master' into develop
This commit is contained in:
@@ -277,12 +277,13 @@ void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
std::string uptime = UIRenderer::drawTimeDelta(days, hours, minutes, seconds);
|
||||
|
||||
// Line 1 (Still)
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(uptime.c_str()), y, uptime.c_str());
|
||||
if (config.display.heading_bold)
|
||||
display->drawString(x - 1 + SCREEN_WIDTH - display->getStringWidth(uptime.c_str()), y, uptime.c_str());
|
||||
|
||||
display->setColor(WHITE);
|
||||
|
||||
#endif
|
||||
// Setup string to assemble analogClock string
|
||||
std::string analogClock = "";
|
||||
|
||||
@@ -386,7 +387,11 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
char shortnameble[35];
|
||||
getMacAddr(dmac);
|
||||
snprintf(screen->ourId, sizeof(screen->ourId), "%02x%02x", dmac[4], dmac[5]);
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(shortnameble, sizeof(shortnameble), "%s", screen->ourId);
|
||||
#else
|
||||
snprintf(shortnameble, sizeof(shortnameble), "BLE: %s", screen->ourId);
|
||||
#endif
|
||||
int textWidth = display->getStringWidth(shortnameble);
|
||||
int nameX = (SCREEN_WIDTH - textWidth);
|
||||
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
||||
@@ -405,7 +410,11 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
char regionradiopreset[25];
|
||||
const char *region = myRegion ? myRegion->name : NULL;
|
||||
if (region != nullptr) {
|
||||
snprintf(regionradiopreset, sizeof(regionradiopreset), "Reg: %s/%s", region, mode);
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(regionradiopreset, sizeof(regionradiopreset), "%s", region);
|
||||
#else
|
||||
snprintf(regionradiopreset, sizeof(regionradiopreset), "%s/%s", region, mode);
|
||||
#endif
|
||||
}
|
||||
textWidth = display->getStringWidth(regionradiopreset);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
@@ -417,9 +426,17 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
float freq = RadioLibInterface::instance->getFreq();
|
||||
snprintf(freqStr, sizeof(freqStr), "%.3f", freq);
|
||||
if (config.lora.channel_num == 0) {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "%sMHz", freqStr);
|
||||
#else
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq: %sMHz", freqStr);
|
||||
#endif
|
||||
} else {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "%sMHz (%d)", freqStr, config.lora.channel_num);
|
||||
#else
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq/Ch: %sMHz (%d)", freqStr, config.lora.channel_num);
|
||||
#endif
|
||||
}
|
||||
size_t len = strlen(frequencyslot);
|
||||
if (len >= 4 && strcmp(frequencyslot + len - 4, " (0)") == 0) {
|
||||
@@ -429,7 +446,8 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line++], frequencyslot);
|
||||
|
||||
// === Fifth Row: Channel Utilization ===
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
// === Fourth Row: Channel Utilization ===
|
||||
const char *chUtil = "ChUtil:";
|
||||
char chUtilPercentage[10];
|
||||
snprintf(chUtilPercentage, sizeof(chUtilPercentage), "%2.0f%%", airTime->channelUtilizationPercent());
|
||||
@@ -485,6 +503,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
|
||||
display->drawString(starting_position + chUtil_x + chutil_bar_width + extraoffset, getTextPositions(display)[line++],
|
||||
chUtilPercentage);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ****************************
|
||||
@@ -510,8 +529,11 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
#ifdef USE_EINK
|
||||
barsOffset -= 12;
|
||||
#endif
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
const int barX = x + 45 + barsOffset;
|
||||
#else
|
||||
const int barX = x + 40 + barsOffset;
|
||||
|
||||
#endif
|
||||
auto drawUsageRow = [&](const char *label, uint32_t used, uint32_t total, bool isHeap = false) {
|
||||
if (total == 0)
|
||||
return;
|
||||
@@ -536,7 +558,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
// Label
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->drawString(labelX, getTextPositions(display)[line], label);
|
||||
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
// Bar
|
||||
int barY = getTextPositions(display)[line] + (FONT_HEIGHT_SMALL - barHeight) / 2;
|
||||
display->setColor(WHITE);
|
||||
@@ -544,7 +566,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
|
||||
display->fillRect(barX, barY, fillWidth, barHeight);
|
||||
display->setColor(WHITE);
|
||||
|
||||
#endif
|
||||
// Value string
|
||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display->drawString(SCREEN_WIDTH - 2, getTextPositions(display)[line], combinedStr);
|
||||
@@ -597,10 +619,16 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
line += 1;
|
||||
}
|
||||
line += 1;
|
||||
|
||||
char appversionstr[35];
|
||||
snprintf(appversionstr, sizeof(appversionstr), "Ver: %s", optstr(APP_VERSION));
|
||||
char appversionstr_formatted[40];
|
||||
char *lastDot = strrchr(appversionstr, '.');
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
if (lastDot != nullptr) {
|
||||
*lastDot = '\0'; // truncate string
|
||||
}
|
||||
#else
|
||||
if (lastDot) {
|
||||
size_t prefixLen = lastDot - appversionstr;
|
||||
strncpy(appversionstr_formatted, appversionstr, prefixLen);
|
||||
@@ -611,10 +639,12 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
strncpy(appversionstr, appversionstr_formatted, sizeof(appversionstr) - 1);
|
||||
appversionstr[sizeof(appversionstr) - 1] = '\0';
|
||||
}
|
||||
#endif
|
||||
int textWidth = display->getStringWidth(appversionstr);
|
||||
int nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line], appversionstr);
|
||||
|
||||
display->drawString(nameX, getTextPositions(display)[line], appversionstr);
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line < 4)) { // Only show uptime if the screen can show it
|
||||
line += 1;
|
||||
char uptimeStr[32] = "";
|
||||
@@ -633,6 +663,34 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line], uptimeStr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// ****************************
|
||||
// * Chirpy Screen *
|
||||
// ****************************
|
||||
void drawChirpy(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->clear();
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
int line = 1;
|
||||
int iconX = SCREEN_WIDTH - chirpy_width - (chirpy_width / 3);
|
||||
int iconY = (SCREEN_HEIGHT - chirpy_height) / 2;
|
||||
int textX_offset = 10;
|
||||
if (isHighResolution) {
|
||||
iconX = SCREEN_WIDTH - chirpy_width_hirez - (chirpy_width_hirez / 3);
|
||||
iconY = (SCREEN_HEIGHT - chirpy_height_hirez) / 2;
|
||||
textX_offset = textX_offset * 4;
|
||||
display->drawXbm(iconX, iconY, chirpy_width_hirez, chirpy_height_hirez, chirpy_hirez);
|
||||
} else {
|
||||
display->drawXbm(iconX, iconY, chirpy_width, chirpy_height, chirpy);
|
||||
}
|
||||
|
||||
int textX = (display->getWidth() / 2) - textX_offset - (display->getStringWidth("Hello") / 2);
|
||||
display->drawString(textX, getTextPositions(display)[line++], "Hello");
|
||||
textX = (display->getWidth() / 2) - textX_offset - (display->getStringWidth("World!") / 2);
|
||||
display->drawString(textX, getTextPositions(display)[line++], "World!");
|
||||
}
|
||||
|
||||
// ****************************
|
||||
|
||||
@@ -102,7 +102,11 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
||||
"NP_865",
|
||||
"BR_902"};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "LoRa Region";
|
||||
#else
|
||||
bannerOptions.message = "Set the LoRa region";
|
||||
#endif
|
||||
bannerOptions.durationMs = duration;
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 27;
|
||||
@@ -317,7 +321,11 @@ void menuHandler::TZPicker()
|
||||
|
||||
void menuHandler::clockMenu()
|
||||
{
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
static const char *optionsArray[] = {"Back", "Time Format", "Timezone"};
|
||||
#else
|
||||
static const char *optionsArray[] = {"Back", "Clock Face", "Time Format", "Timezone"};
|
||||
#endif
|
||||
enum optionsNumbers { Back = 0, Clock = 1, Time = 2, Timezone = 3 };
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "Clock Action";
|
||||
@@ -341,8 +349,11 @@ void menuHandler::clockMenu()
|
||||
void menuHandler::messageResponseMenu()
|
||||
{
|
||||
enum optionsNumbers { Back = 0, Dismiss = 1, Preset = 2, Freetext = 3, Aloud = 4, enumEnd = 5 };
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
static const char *optionsArray[enumEnd] = {"Back", "Dismiss", "Reply Preset"};
|
||||
#else
|
||||
static const char *optionsArray[enumEnd] = {"Back", "Dismiss", "Reply via Preset"};
|
||||
#endif
|
||||
static int optionsEnumArray[enumEnd] = {Back, Dismiss, Preset};
|
||||
int options = 3;
|
||||
|
||||
@@ -356,7 +367,11 @@ void menuHandler::messageResponseMenu()
|
||||
optionsEnumArray[options++] = Aloud;
|
||||
#endif
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Message";
|
||||
#else
|
||||
bannerOptions.message = "Message Action";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
bannerOptions.optionsCount = options;
|
||||
@@ -409,7 +424,11 @@ void menuHandler::homeBaseMenu()
|
||||
optionsArray[options] = "Send Node Info";
|
||||
}
|
||||
optionsEnumArray[options++] = Position;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
optionsArray[options] = "New Preset";
|
||||
#else
|
||||
optionsArray[options] = "New Preset Msg";
|
||||
#endif
|
||||
optionsEnumArray[options++] = Preset;
|
||||
if (kb_found) {
|
||||
optionsArray[options] = "New Freetext Msg";
|
||||
@@ -417,7 +436,11 @@ void menuHandler::homeBaseMenu()
|
||||
}
|
||||
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Home";
|
||||
#else
|
||||
bannerOptions.message = "Home Action";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
bannerOptions.optionsCount = options;
|
||||
@@ -456,6 +479,11 @@ void menuHandler::homeBaseMenu()
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
}
|
||||
|
||||
void menuHandler::textMessageMenu()
|
||||
{
|
||||
cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST);
|
||||
}
|
||||
|
||||
void menuHandler::textMessageBaseMenu()
|
||||
{
|
||||
enum optionsNumbers { Back, Preset, Freetext, enumEnd };
|
||||
@@ -502,11 +530,17 @@ void menuHandler::systemBaseMenu()
|
||||
|
||||
optionsArray[options] = "Frame Visiblity Toggle";
|
||||
optionsEnumArray[options++] = FrameToggles;
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
optionsArray[options] = "Bluetooth";
|
||||
#else
|
||||
optionsArray[options] = "Bluetooth Toggle";
|
||||
#endif
|
||||
optionsEnumArray[options++] = Bluetooth;
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
optionsArray[options] = "Power";
|
||||
#else
|
||||
optionsArray[options] = "Reboot/Shutdown";
|
||||
#endif
|
||||
optionsEnumArray[options++] = PowerMenu;
|
||||
|
||||
if (test_enabled) {
|
||||
@@ -515,7 +549,11 @@ void menuHandler::systemBaseMenu()
|
||||
}
|
||||
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "System";
|
||||
#else
|
||||
bannerOptions.message = "System Action";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = options;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
@@ -551,7 +589,11 @@ void menuHandler::systemBaseMenu()
|
||||
void menuHandler::favoriteBaseMenu()
|
||||
{
|
||||
enum optionsNumbers { Back, Preset, Freetext, Remove, TraceRoute, enumEnd };
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
static const char *optionsArray[enumEnd] = {"Back", "New Preset"};
|
||||
#else
|
||||
static const char *optionsArray[enumEnd] = {"Back", "New Preset Msg"};
|
||||
#endif
|
||||
static int optionsEnumArray[enumEnd] = {Back, Preset};
|
||||
int options = 2;
|
||||
|
||||
@@ -559,13 +601,19 @@ void menuHandler::favoriteBaseMenu()
|
||||
optionsArray[options] = "New Freetext Msg";
|
||||
optionsEnumArray[options++] = Freetext;
|
||||
}
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
optionsArray[options] = "Trace Route";
|
||||
optionsEnumArray[options++] = TraceRoute;
|
||||
#endif
|
||||
optionsArray[options] = "Remove Favorite";
|
||||
optionsEnumArray[options++] = Remove;
|
||||
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Favorites";
|
||||
#else
|
||||
bannerOptions.message = "Favorites Action";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
bannerOptions.optionsCount = options;
|
||||
@@ -624,11 +672,19 @@ void menuHandler::positionBaseMenu()
|
||||
void menuHandler::nodeListMenu()
|
||||
{
|
||||
enum optionsNumbers { Back, Favorite, TraceRoute, Verify, Reset, enumEnd };
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
static const char *optionsArray[] = {"Back", "Add Favorite", "Reset Node"};
|
||||
#else
|
||||
static const char *optionsArray[] = {"Back", "Add Favorite", "Trace Route", "Key Verification", "Reset NodeDB"};
|
||||
#endif
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "Node Action";
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.optionsCount = 3;
|
||||
#else
|
||||
bannerOptions.optionsCount = 5;
|
||||
#endif
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == Favorite) {
|
||||
menuQueue = add_favorite;
|
||||
@@ -776,7 +832,11 @@ void menuHandler::BluetoothToggleMenu()
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "Enabled", "Disabled"};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Bluetooth";
|
||||
#else
|
||||
bannerOptions.message = "Toggle Bluetooth";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 3;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
@@ -968,7 +1028,11 @@ void menuHandler::rebootMenu()
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "Confirm"};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Reboot";
|
||||
#else
|
||||
bannerOptions.message = "Reboot Device?";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 2;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
@@ -988,7 +1052,11 @@ void menuHandler::shutdownMenu()
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "Confirm"};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Shutdown";
|
||||
#else
|
||||
bannerOptions.message = "Shutdown Device?";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 2;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
@@ -1005,7 +1073,12 @@ void menuHandler::shutdownMenu()
|
||||
|
||||
void menuHandler::addFavoriteMenu()
|
||||
{
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
screen->showNodePicker("Node Favorite", 30000, [](uint32_t nodenum) -> void {
|
||||
#else
|
||||
screen->showNodePicker("Node To Favorite", 30000, [](uint32_t nodenum) -> void {
|
||||
|
||||
#endif
|
||||
LOG_WARN("Nodenum: %u", nodenum);
|
||||
nodeDB->set_favorite(true, nodenum);
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||
@@ -1218,7 +1291,11 @@ void menuHandler::powerMenu()
|
||||
#endif
|
||||
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Power";
|
||||
#else
|
||||
bannerOptions.message = "Reboot / Shutdown";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = options;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
|
||||
@@ -84,6 +84,7 @@ class menuHandler
|
||||
static void screenOptionsMenu();
|
||||
static void powerMenu();
|
||||
static void FrameToggles_menu();
|
||||
static void textMessageMenu();
|
||||
|
||||
private:
|
||||
static void saveUIConfig();
|
||||
|
||||
@@ -181,12 +181,19 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
display->clear();
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
const int fixedTopHeight = 24;
|
||||
const int windowX = 0;
|
||||
const int windowY = fixedTopHeight;
|
||||
const int windowWidth = 64;
|
||||
const int windowHeight = SCREEN_HEIGHT - fixedTopHeight;
|
||||
#else
|
||||
const int navHeight = FONT_HEIGHT_SMALL;
|
||||
const int scrollBottom = SCREEN_HEIGHT - navHeight;
|
||||
const int usableHeight = scrollBottom;
|
||||
const int textWidth = SCREEN_WIDTH;
|
||||
|
||||
#endif
|
||||
bool isInverted = (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_INVERTED);
|
||||
bool isBold = config.display.heading_bold;
|
||||
|
||||
@@ -201,7 +208,11 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||
const char *messageString = "No messages";
|
||||
int center_text = (SCREEN_WIDTH / 2) - (display->getStringWidth(messageString) / 2);
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
display->drawString(center_text, windowY + (windowHeight / 2) - (FONT_HEIGHT_SMALL / 2) - 5, messageString);
|
||||
#else
|
||||
display->drawString(center_text, getTextPositions(display)[2], messageString);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -209,6 +220,10 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp));
|
||||
char headerStr[80];
|
||||
const char *sender = "???";
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
if (node && node->has_user)
|
||||
sender = node->user.short_name;
|
||||
#else
|
||||
if (node && node->has_user) {
|
||||
if (SCREEN_WIDTH >= 200 && strlen(node->user.long_name) > 0) {
|
||||
sender = node->user.long_name;
|
||||
@@ -216,6 +231,7 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
sender = node->user.short_name;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
uint32_t seconds = sinceReceived(&mp), minutes = seconds / 60, hours = minutes / 60, days = hours / 24;
|
||||
uint8_t timestampHours, timestampMinutes;
|
||||
int32_t daysAgo;
|
||||
@@ -235,10 +251,61 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
sender);
|
||||
}
|
||||
} else {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(headerStr, sizeof(headerStr), "%s from %s", UIRenderer::drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
||||
sender);
|
||||
#else
|
||||
snprintf(headerStr, sizeof(headerStr), "%s ago from %s", UIRenderer::drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
||||
sender);
|
||||
#endif
|
||||
}
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||
int headerY = getTextPositions(display)[1];
|
||||
display->drawString(x, headerY, headerStr);
|
||||
for (int separatorX = 0; separatorX < SCREEN_WIDTH; separatorX += 2) {
|
||||
display->setPixel(separatorX, fixedTopHeight - 1);
|
||||
}
|
||||
cachedLines.clear();
|
||||
std::string fullMsg(messageBuf);
|
||||
std::string currentLine;
|
||||
for (size_t i = 0; i < fullMsg.size();) {
|
||||
unsigned char c = fullMsg[i];
|
||||
size_t charLen = 1;
|
||||
if ((c & 0xE0) == 0xC0)
|
||||
charLen = 2;
|
||||
else if ((c & 0xF0) == 0xE0)
|
||||
charLen = 3;
|
||||
else if ((c & 0xF8) == 0xF0)
|
||||
charLen = 4;
|
||||
std::string nextChar = fullMsg.substr(i, charLen);
|
||||
std::string testLine = currentLine + nextChar;
|
||||
if (display->getStringWidth(testLine.c_str()) > windowWidth) {
|
||||
cachedLines.push_back(currentLine);
|
||||
currentLine = nextChar;
|
||||
} else {
|
||||
currentLine = testLine;
|
||||
}
|
||||
|
||||
i += charLen;
|
||||
}
|
||||
if (!currentLine.empty())
|
||||
cachedLines.push_back(currentLine);
|
||||
cachedHeights = calculateLineHeights(cachedLines, emotes);
|
||||
int yOffset = windowY;
|
||||
int linesDrawn = 0;
|
||||
for (size_t i = 0; i < cachedLines.size(); ++i) {
|
||||
if (linesDrawn >= 2)
|
||||
break;
|
||||
int lineHeight = cachedHeights[i];
|
||||
if (yOffset + lineHeight > windowY + windowHeight)
|
||||
break;
|
||||
drawStringWithEmotes(display, windowX, yOffset, cachedLines[i], emotes, numEmotes);
|
||||
yOffset += lineHeight;
|
||||
linesDrawn++;
|
||||
}
|
||||
screen->forceDisplay();
|
||||
#else
|
||||
uint32_t now = millis();
|
||||
#ifndef EXCLUDE_EMOJI
|
||||
// === Bounce animation setup ===
|
||||
@@ -355,6 +422,7 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
|
||||
// Draw header at the end to sort out overlapping elements
|
||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::string> generateLines(OLEDDisplay *display, const char *headerStr, const char *messageBuf, int textWidth)
|
||||
|
||||
@@ -21,6 +21,10 @@ extern bool haveGlyphs(const char *str);
|
||||
// Global screen instance
|
||||
extern graphics::Screen *screen;
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
static uint32_t lastSwitchTime = 0;
|
||||
#else
|
||||
#endif
|
||||
namespace graphics
|
||||
{
|
||||
namespace NodeListRenderer
|
||||
@@ -393,9 +397,11 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
{
|
||||
const int COMMON_HEADER_HEIGHT = FONT_HEIGHT_SMALL - 1;
|
||||
const int rowYOffset = FONT_HEIGHT_SMALL - 3;
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
int columnWidth = display->getWidth();
|
||||
#else
|
||||
int columnWidth = display->getWidth() / 2;
|
||||
|
||||
#endif
|
||||
display->clear();
|
||||
|
||||
// Draw the battery/time header
|
||||
@@ -408,8 +414,11 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
int totalRowsAvailable = (display->getHeight() - y) / rowYOffset;
|
||||
|
||||
int visibleNodeRows = totalRowsAvailable;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
int totalColumns = 1;
|
||||
#else
|
||||
int totalColumns = 2;
|
||||
|
||||
#endif
|
||||
int startIndex = scrollIndex * visibleNodeRows * totalColumns;
|
||||
if (nodeDB->getMeshNodeByIndex(startIndex)->num == nodeDB->getNodeNum()) {
|
||||
startIndex++; // skip own node
|
||||
@@ -445,12 +454,14 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
// Draw column separator
|
||||
if (shownCount > 0) {
|
||||
const int firstNodeY = y + 3;
|
||||
drawColumnSeparator(display, x, firstNodeY, lastNodeY);
|
||||
}
|
||||
|
||||
#endif
|
||||
const int scrollStartY = y + 3;
|
||||
drawScrollbar(display, visibleNodeRows, totalEntries, scrollIndex, 2, scrollStartY);
|
||||
}
|
||||
@@ -468,6 +479,13 @@ void drawDynamicNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
display->clear();
|
||||
if (now - lastSwitchTime >= 3000) {
|
||||
display->display();
|
||||
lastSwitchTime = now;
|
||||
}
|
||||
#endif
|
||||
// On very first call (on boot or state enter)
|
||||
if (lastRenderedMode == MODE_COUNT) {
|
||||
currentMode = MODE_LAST_HEARD;
|
||||
@@ -522,6 +540,14 @@ void drawNodeListWithCompasses(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
double lat = DegD(ourNode->position.latitude_i);
|
||||
double lon = DegD(ourNode->position.longitude_i);
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
display->clear();
|
||||
uint32_t now = millis();
|
||||
if (now - lastSwitchTime >= 2000) {
|
||||
display->display();
|
||||
lastSwitchTime = now;
|
||||
}
|
||||
#endif
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) {
|
||||
#if HAS_GPS
|
||||
if (screen->hasHeading()) {
|
||||
|
||||
@@ -491,6 +491,135 @@ void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplay
|
||||
// count lines
|
||||
|
||||
uint16_t boxWidth = hPadding * 2 + maxWidth;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
if (needs_bell) {
|
||||
if (isHighResolution && boxWidth <= 150)
|
||||
boxWidth += 26;
|
||||
if (!isHighResolution && boxWidth <= 100)
|
||||
boxWidth += 20;
|
||||
}
|
||||
|
||||
uint16_t screenHeight = display->height();
|
||||
uint8_t effectiveLineHeight = FONT_HEIGHT_SMALL - 3;
|
||||
uint8_t visibleTotalLines = std::min<uint8_t>(lineCount, (screenHeight - vPadding * 2) / effectiveLineHeight);
|
||||
uint16_t contentHeight = visibleTotalLines * effectiveLineHeight;
|
||||
uint16_t boxHeight = contentHeight + vPadding * 2;
|
||||
if (visibleTotalLines == 1)
|
||||
boxHeight += (isHighResolution ? 4 : 3);
|
||||
|
||||
int16_t boxLeft = (display->width() / 2) - (boxWidth / 2);
|
||||
if (totalLines > visibleTotalLines)
|
||||
boxWidth += (isHighResolution ? 4 : 2);
|
||||
int16_t boxTop = (display->height() / 2) - (boxHeight / 2);
|
||||
|
||||
if (visibleTotalLines == 1) {
|
||||
boxTop += 25;
|
||||
}
|
||||
if (alertBannerOptions < 3) {
|
||||
int missingLines = 3 - alertBannerOptions;
|
||||
int moveUp = missingLines * (effectiveLineHeight / 2);
|
||||
boxTop -= moveUp;
|
||||
if (boxTop < 0)
|
||||
boxTop = 0;
|
||||
}
|
||||
|
||||
// === Draw Box ===
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(boxLeft, boxTop, boxWidth, boxHeight);
|
||||
display->setColor(WHITE);
|
||||
display->drawRect(boxLeft, boxTop, boxWidth, boxHeight);
|
||||
display->fillRect(boxLeft, boxTop - 2, boxWidth, 1);
|
||||
display->fillRect(boxLeft - 2, boxTop, 1, boxHeight);
|
||||
display->fillRect(boxLeft + boxWidth + 1, boxTop, 1, boxHeight);
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(boxLeft, boxTop, 1, 1);
|
||||
display->fillRect(boxLeft + boxWidth - 1, boxTop, 1, 1);
|
||||
display->fillRect(boxLeft, boxTop + boxHeight - 1, 1, 1);
|
||||
display->fillRect(boxLeft + boxWidth - 1, boxTop + boxHeight - 1, 1, 1);
|
||||
display->setColor(WHITE);
|
||||
int16_t lineY = boxTop + vPadding;
|
||||
int swingRange = 8;
|
||||
static int swingOffset = 0;
|
||||
static bool swingRight = true;
|
||||
static unsigned long lastSwingTime = 0;
|
||||
unsigned long now = millis();
|
||||
int swingSpeedMs = 10 / (swingRange * 2);
|
||||
if (now - lastSwingTime >= (unsigned long)swingSpeedMs) {
|
||||
lastSwingTime = now;
|
||||
if (swingRight) {
|
||||
swingOffset++;
|
||||
if (swingOffset >= swingRange)
|
||||
swingRight = false;
|
||||
} else {
|
||||
swingOffset--;
|
||||
if (swingOffset <= 0)
|
||||
swingRight = true;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
bool isTitle = (i == 0);
|
||||
int globalOptionIndex = (i - 1) + firstOptionToShow;
|
||||
bool isSelectedOption = (!isTitle && globalOptionIndex >= 0 && globalOptionIndex == curSelected);
|
||||
|
||||
uint16_t visibleWidth = 64 - hPadding * 2;
|
||||
if (totalLines > visibleTotalLines)
|
||||
visibleWidth -= 6;
|
||||
char lineBuffer[lineLengths[i] + 1];
|
||||
strncpy(lineBuffer, lines[i], lineLengths[i]);
|
||||
lineBuffer[lineLengths[i]] = '\0';
|
||||
|
||||
if (isTitle) {
|
||||
if (visibleTotalLines == 1) {
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(boxLeft, boxTop, boxWidth, effectiveLineHeight);
|
||||
display->setColor(WHITE);
|
||||
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, boxTop, lineBuffer);
|
||||
} else {
|
||||
display->setColor(WHITE);
|
||||
display->fillRect(boxLeft, boxTop, boxWidth, effectiveLineHeight);
|
||||
display->setColor(BLACK);
|
||||
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, boxTop, lineBuffer);
|
||||
display->setColor(WHITE);
|
||||
if (needs_bell) {
|
||||
int bellY = boxTop + (FONT_HEIGHT_SMALL - 8) / 2;
|
||||
display->drawXbm(boxLeft + (boxWidth - lineWidths[i]) / 2 - 10, bellY, 8, 8, bell_alert);
|
||||
display->drawXbm(boxLeft + (boxWidth + lineWidths[i]) / 2 + 2, bellY, 8, 8, bell_alert);
|
||||
}
|
||||
}
|
||||
lineY = boxTop + effectiveLineHeight + 1;
|
||||
} else if (isSelectedOption) {
|
||||
display->setColor(WHITE);
|
||||
display->fillRect(boxLeft, lineY, boxWidth, effectiveLineHeight);
|
||||
display->setColor(BLACK);
|
||||
if (lineLengths[i] > 15 && lineWidths[i] > visibleWidth) {
|
||||
int textX = boxLeft + hPadding + swingOffset;
|
||||
display->drawString(textX, lineY - 1, lineBuffer);
|
||||
} else {
|
||||
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, lineY - 1, lineBuffer);
|
||||
}
|
||||
display->setColor(WHITE);
|
||||
lineY += effectiveLineHeight;
|
||||
} else {
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(boxLeft, lineY, boxWidth, effectiveLineHeight);
|
||||
display->setColor(WHITE);
|
||||
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, lineY, lineBuffer);
|
||||
lineY += effectiveLineHeight;
|
||||
}
|
||||
}
|
||||
if (totalLines > visibleTotalLines) {
|
||||
const uint8_t scrollBarWidth = 5;
|
||||
int16_t scrollBarX = boxLeft + boxWidth - scrollBarWidth - 2;
|
||||
int16_t scrollBarY = boxTop + vPadding + effectiveLineHeight;
|
||||
uint16_t scrollBarHeight = boxHeight - vPadding * 2 - effectiveLineHeight;
|
||||
float ratio = (float)visibleTotalLines / totalLines;
|
||||
uint16_t indicatorHeight = std::max((int)(scrollBarHeight * ratio), 4);
|
||||
float scrollRatio = (float)(firstOptionToShow + lineCount - visibleTotalLines) / (totalLines - visibleTotalLines);
|
||||
uint16_t indicatorY = scrollBarY + scrollRatio * (scrollBarHeight - indicatorHeight);
|
||||
display->drawRect(scrollBarX, scrollBarY, scrollBarWidth, scrollBarHeight);
|
||||
display->fillRect(scrollBarX + 1, indicatorY, scrollBarWidth - 2, indicatorHeight);
|
||||
}
|
||||
#else
|
||||
if (needs_bell) {
|
||||
if (isHighResolution && boxWidth <= 150)
|
||||
boxWidth += 26;
|
||||
@@ -579,6 +708,7 @@ void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplay
|
||||
display->drawRect(scrollBarX, scrollBarY, scrollBarWidth, scrollBarHeight);
|
||||
display->fillRect(scrollBarX + 1, indicatorY, scrollBarWidth - 2, indicatorHeight);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Draw the last text message we received
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
// External variables
|
||||
extern graphics::Screen *screen;
|
||||
|
||||
static uint32_t lastSwitchTime = 0;
|
||||
namespace graphics
|
||||
{
|
||||
NodeNum UIRenderer::currentFavoriteNodeNum = 0;
|
||||
@@ -232,7 +232,6 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes
|
||||
// **********************
|
||||
void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
|
||||
if (favoritedNodes.empty())
|
||||
return;
|
||||
|
||||
@@ -244,8 +243,15 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
meshtastic_NodeInfoLite *node = favoritedNodes[nodeIndex];
|
||||
if (!node || node->num == nodeDB->getNodeNum() || !node->is_favorite)
|
||||
return;
|
||||
|
||||
uint32_t now = millis();
|
||||
display->clear();
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
if (now - lastSwitchTime >= 10000) // 10000 ms = 10 秒
|
||||
{
|
||||
display->display();
|
||||
lastSwitchTime = now;
|
||||
}
|
||||
#endif
|
||||
currentFavoriteNodeNum = node->num;
|
||||
// === Create the shortName and title string ===
|
||||
const char *shortName = (node->has_user && haveGlyphs(node->user.short_name)) ? node->user.short_name : "Node";
|
||||
@@ -264,9 +270,13 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
// List of available macro Y positions in order, from top to bottom.
|
||||
int line = 1; // which slot to use next
|
||||
std::string usernameStr;
|
||||
|
||||
// === 1. Long Name (always try to show first) ===
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
const char *username = (node->has_user && node->user.long_name[0]) ? node->user.short_name : nullptr;
|
||||
#else
|
||||
const char *username = (node->has_user && node->user.long_name[0]) ? node->user.long_name : nullptr;
|
||||
#endif
|
||||
|
||||
if (username) {
|
||||
usernameStr = sanitizeString(username); // Sanitize the incoming long_name just in case
|
||||
// Print node's long name (e.g. "Backpack Node")
|
||||
@@ -321,7 +331,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
if (seenStr[0] && line < 5) {
|
||||
display->drawString(x, getTextPositions(display)[line++], seenStr);
|
||||
}
|
||||
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
// === 4. Uptime (only show if metric is present) ===
|
||||
char uptimeStr[32] = "";
|
||||
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
||||
@@ -493,6 +503,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
}
|
||||
// else show nothing
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// ****************************
|
||||
@@ -506,7 +517,11 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
int line = 1;
|
||||
|
||||
// === Header ===
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
graphics::drawCommonHeader(display, x, y, "Home");
|
||||
#else
|
||||
graphics::drawCommonHeader(display, x, y, "");
|
||||
#endif
|
||||
|
||||
// === Content below header ===
|
||||
|
||||
@@ -521,20 +536,25 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
config.display.heading_bold = false;
|
||||
|
||||
// Display Region and Channel Utilization
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
drawNodes(display, x, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
||||
#else
|
||||
drawNodes(display, x + 1, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
||||
|
||||
#endif
|
||||
char uptimeStr[32] = "";
|
||||
uint32_t uptime = millis() / 1000;
|
||||
uint32_t days = uptime / 86400;
|
||||
uint32_t hours = (uptime % 86400) / 3600;
|
||||
uint32_t mins = (uptime % 3600) / 60;
|
||||
// Show as "Up: 2d 3h", "Up: 5h 14m", or "Up: 37m"
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
if (days)
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %ud %uh", days, hours);
|
||||
else if (hours)
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %uh %um", hours, mins);
|
||||
else
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %um", mins);
|
||||
#endif
|
||||
display->drawString(SCREEN_WIDTH - display->getStringWidth(uptimeStr), getTextPositions(display)[line++], uptimeStr);
|
||||
|
||||
// === Second Row: Satellites and Voltage ===
|
||||
@@ -563,6 +583,21 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
line += 1;
|
||||
|
||||
// === Node Identity ===
|
||||
int textWidth = 0;
|
||||
int nameX = 0;
|
||||
char shortnameble[35];
|
||||
snprintf(shortnameble, sizeof(shortnameble), "%s",
|
||||
graphics::UIRenderer::haveGlyphs(owner.short_name) ? owner.short_name : "");
|
||||
|
||||
// === ShortName Centered ===
|
||||
textWidth = display->getStringWidth(shortnameble);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
||||
#else
|
||||
if (powerStatus->getHasBattery()) {
|
||||
char batStr[20];
|
||||
int batV = powerStatus->getBatteryVoltageMv() / 1000;
|
||||
@@ -688,6 +723,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Start Functions to write date/time to the screen
|
||||
@@ -846,6 +882,28 @@ void UIRenderer::drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLED
|
||||
// needs to be drawn relative to x and y
|
||||
|
||||
// draw centered icon left to right and centered above the one line of app text
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
display->drawXbm(x + (SCREEN_WIDTH - 50) / 2, y + (SCREEN_HEIGHT - 28) / 2, icon_width, icon_height, icon_bits);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
// Draw region in upper left
|
||||
if (upperMsg) {
|
||||
int msgWidth = display->getStringWidth(upperMsg);
|
||||
int msgX = x + (SCREEN_WIDTH - msgWidth) / 2;
|
||||
int msgY = y;
|
||||
display->drawString(msgX, msgY, upperMsg);
|
||||
}
|
||||
// Draw version and short name in bottom middle
|
||||
char buf[25];
|
||||
snprintf(buf, sizeof(buf), "%s %s", xstr(APP_VERSION_SHORT),
|
||||
graphics::UIRenderer::haveGlyphs(owner.short_name) ? owner.short_name : "");
|
||||
|
||||
display->drawString(x + getStringCenteredX(buf), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, buf);
|
||||
screen->forceDisplay();
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code
|
||||
#else
|
||||
display->drawXbm(x + (SCREEN_WIDTH - icon_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - icon_height) / 2 + 2,
|
||||
icon_width, icon_height, icon_bits);
|
||||
|
||||
@@ -854,7 +912,6 @@ void UIRenderer::drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLED
|
||||
const char *title = "meshtastic.org";
|
||||
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
// Draw region in upper left
|
||||
if (upperMsg)
|
||||
display->drawString(x + 0, y + 0, upperMsg);
|
||||
@@ -869,6 +926,7 @@ void UIRenderer::drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLED
|
||||
screen->forceDisplay();
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code
|
||||
#endif
|
||||
}
|
||||
|
||||
// ****************************
|
||||
@@ -1011,8 +1069,9 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
snprintf(DisplayLineTwo, sizeof(DisplayLineTwo), "Alt: %.0im", geoCoord.getAltitude());
|
||||
}
|
||||
display->drawString(x, getTextPositions(display)[line++], DisplayLineTwo);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
// === Draw Compass if heading is valid ===
|
||||
if (validHeading) {
|
||||
// --- Compass Rendering: landscape (wide) screens use original side-aligned logic ---
|
||||
@@ -1095,6 +1154,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USERPREFS_OEM_TEXT
|
||||
@@ -1251,7 +1311,6 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
display->setColor(WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Knock the corners off the square
|
||||
display->setColor(BLACK);
|
||||
display->drawRect(rectX, y - 2, 1, 1);
|
||||
|
||||
Reference in New Issue
Block a user