mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-31 22:21:51 +00:00
Merge branch 'develop' into t-watch-ultra
This commit is contained in:
@@ -6,11 +6,9 @@
|
||||
#include "NodeListRenderer.h"
|
||||
#include "UIRenderer.h"
|
||||
#include "airtime.h"
|
||||
#include "configuration.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include "graphics/SharedUIDisplay.h"
|
||||
#include "graphics/TimeFormatters.h"
|
||||
#include "graphics/images.h"
|
||||
#include "main.h"
|
||||
#include "target_specific.h"
|
||||
@@ -28,6 +26,16 @@ namespace graphics
|
||||
NodeNum UIRenderer::currentFavoriteNodeNum = 0;
|
||||
std::vector<meshtastic_NodeInfoLite *> graphics::UIRenderer::favoritedNodes;
|
||||
|
||||
static inline void drawSatelliteIcon(OLEDDisplay *display, int16_t x, int16_t y)
|
||||
{
|
||||
int yOffset = (currentResolution == ScreenResolution::High) ? -5 : 1;
|
||||
if (currentResolution == ScreenResolution::High) {
|
||||
NodeListRenderer::drawScaledXBitmap16x16(x, y + yOffset, imgSatellite_width, imgSatellite_height, imgSatellite, display);
|
||||
} else {
|
||||
display->drawXbm(x + 1, y + yOffset, imgSatellite_width, imgSatellite_height, imgSatellite);
|
||||
}
|
||||
}
|
||||
|
||||
void graphics::UIRenderer::rebuildFavoritedNodes()
|
||||
{
|
||||
favoritedNodes.clear();
|
||||
@@ -55,7 +63,7 @@ extern uint32_t dopThresholds[5];
|
||||
void UIRenderer::drawGps(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gps)
|
||||
{
|
||||
// Draw satellite image
|
||||
if (isHighResolution) {
|
||||
if (currentResolution == ScreenResolution::High) {
|
||||
NodeListRenderer::drawScaledXBitmap16x16(x, y - 2, imgSatellite_width, imgSatellite_height, imgSatellite, display);
|
||||
} else {
|
||||
display->drawXbm(x + 1, y + 1, imgSatellite_width, imgSatellite_height, imgSatellite);
|
||||
@@ -75,7 +83,7 @@ void UIRenderer::drawGps(OLEDDisplay *display, int16_t x, int16_t y, const mesht
|
||||
} else {
|
||||
snprintf(textString, sizeof(textString), "%u sats", gps->getNumSatellites());
|
||||
}
|
||||
if (isHighResolution) {
|
||||
if (currentResolution == ScreenResolution::High) {
|
||||
display->drawString(x + 18, y, textString);
|
||||
} else {
|
||||
display->drawString(x + 11, y, textString);
|
||||
@@ -243,36 +251,36 @@ void UIRenderer::drawGpsCoordinates(OLEDDisplay *display, int16_t x, int16_t y,
|
||||
|
||||
// Draw nodes status
|
||||
void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::NodeStatus *nodeStatus, int node_offset,
|
||||
bool show_total, String additional_words)
|
||||
bool show_total, const char *additional_words)
|
||||
{
|
||||
char usersString[20];
|
||||
int nodes_online = (nodeStatus->getNumOnline() > 0) ? nodeStatus->getNumOnline() + node_offset : 0;
|
||||
|
||||
snprintf(usersString, sizeof(usersString), "%d %s", nodes_online, additional_words.c_str());
|
||||
snprintf(usersString, sizeof(usersString), "%d %s", nodes_online, additional_words);
|
||||
|
||||
if (show_total) {
|
||||
int nodes_total = (nodeStatus->getNumTotal() > 0) ? nodeStatus->getNumTotal() + node_offset : 0;
|
||||
snprintf(usersString, sizeof(usersString), "%d/%d %s", nodes_online, nodes_total, additional_words.c_str());
|
||||
snprintf(usersString, sizeof(usersString), "%d/%d %s", nodes_online, nodes_total, additional_words);
|
||||
}
|
||||
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
|
||||
defined(CO5300_CS)) && \
|
||||
defined(CO5300_CS) || defined(HACKADAY_COMMUNICATOR) || defined(USE_ST7796)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
|
||||
if (isHighResolution) {
|
||||
if (currentResolution == ScreenResolution::High) {
|
||||
NodeListRenderer::drawScaledXBitmap16x16(x, y - 1, 8, 8, imgUser, display);
|
||||
} else {
|
||||
display->drawFastImage(x, y + 3, 8, 8, imgUser);
|
||||
}
|
||||
#else
|
||||
if (isHighResolution) {
|
||||
if (currentResolution == ScreenResolution::High) {
|
||||
NodeListRenderer::drawScaledXBitmap16x16(x, y - 1, 8, 8, imgUser, display);
|
||||
} else {
|
||||
display->drawFastImage(x, y + 1, 8, 8, imgUser);
|
||||
}
|
||||
#endif
|
||||
int string_offset = (isHighResolution) ? 9 : 0;
|
||||
int string_offset = (currentResolution == ScreenResolution::High) ? 9 : 0;
|
||||
display->drawString(x + 10 + string_offset, y - 2, usersString);
|
||||
}
|
||||
|
||||
@@ -320,11 +328,12 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
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
|
||||
const char *username;
|
||||
if (currentResolution == ScreenResolution::UltraLow) {
|
||||
username = (node->has_user && node->user.long_name[0]) ? node->user.short_name : nullptr;
|
||||
} else {
|
||||
username = (node->has_user && node->user.long_name[0]) ? node->user.long_name : nullptr;
|
||||
}
|
||||
|
||||
if (username) {
|
||||
usernameStr = sanitizeString(username); // Sanitize the incoming long_name just in case
|
||||
@@ -384,17 +393,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
// === 4. Uptime (only show if metric is present) ===
|
||||
char uptimeStr[32] = "";
|
||||
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
||||
uint32_t uptime = node->device_metrics.uptime_seconds;
|
||||
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 (days)
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %ud %uh", days, hours);
|
||||
else if (hours)
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %uh %um", hours, mins);
|
||||
else
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %um", mins);
|
||||
getUptimeStr(node->device_metrics.uptime_seconds * 1000, " Up", uptimeStr, sizeof(uptimeStr));
|
||||
}
|
||||
if (uptimeStr[0] && line < 5) {
|
||||
display->drawString(x, getTextPositions(display)[line++], uptimeStr);
|
||||
@@ -510,7 +509,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
const int margin = 4;
|
||||
// --------- PATCH FOR EINK NAV BAR (ONLY CHANGE BELOW) -----------
|
||||
#if defined(USE_EINK)
|
||||
const int iconSize = (isHighResolution) ? 16 : 8;
|
||||
const int iconSize = (currentResolution == ScreenResolution::High) ? 16 : 8;
|
||||
const int navBarHeight = iconSize + 6;
|
||||
#else
|
||||
const int navBarHeight = 0;
|
||||
@@ -553,6 +552,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
// else show nothing
|
||||
}
|
||||
#endif
|
||||
graphics::drawCommonFooter(display, x, y);
|
||||
}
|
||||
|
||||
// ****************************
|
||||
@@ -567,11 +567,11 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
|
||||
// === Header ===
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
graphics::drawCommonHeader(display, x, y, "Home");
|
||||
#else
|
||||
graphics::drawCommonHeader(display, x, y, "");
|
||||
#endif
|
||||
if (currentResolution == ScreenResolution::UltraLow) {
|
||||
graphics::drawCommonHeader(display, x, y, "Home");
|
||||
} else {
|
||||
graphics::drawCommonHeader(display, x, y, "");
|
||||
}
|
||||
|
||||
// === Content below header ===
|
||||
|
||||
@@ -586,25 +586,15 @@ 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
|
||||
if (currentResolution == ScreenResolution::UltraLow) {
|
||||
drawNodes(display, x, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
||||
} else {
|
||||
drawNodes(display, x + 1, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
||||
}
|
||||
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
|
||||
if (currentResolution != ScreenResolution::UltraLow) {
|
||||
getUptimeStr(millis(), "Up", uptimeStr, sizeof(uptimeStr));
|
||||
}
|
||||
display->drawString(SCREEN_WIDTH - display->getStringWidth(uptimeStr), getTextPositions(display)[line++], uptimeStr);
|
||||
|
||||
// === Second Row: Satellites and Voltage ===
|
||||
@@ -618,15 +608,8 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
} else {
|
||||
displayLine = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT ? "No GPS" : "GPS off";
|
||||
}
|
||||
int yOffset = (isHighResolution) ? 3 : 1;
|
||||
if (isHighResolution) {
|
||||
NodeListRenderer::drawScaledXBitmap16x16(x, getTextPositions(display)[line] + yOffset - 5, imgSatellite_width,
|
||||
imgSatellite_height, imgSatellite, display);
|
||||
} else {
|
||||
display->drawXbm(x + 1, getTextPositions(display)[line] + yOffset, imgSatellite_width, imgSatellite_height,
|
||||
imgSatellite);
|
||||
}
|
||||
int xOffset = (isHighResolution) ? 6 : 0;
|
||||
drawSatelliteIcon(display, x, getTextPositions(display)[line]);
|
||||
int xOffset = (currentResolution == ScreenResolution::High) ? 6 : 0;
|
||||
display->drawString(x + 11 + xOffset, getTextPositions(display)[line], displayLine);
|
||||
} else {
|
||||
UIRenderer::drawGps(display, 0, getTextPositions(display)[line], gpsStatus);
|
||||
@@ -665,21 +648,22 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
char chUtilPercentage[10];
|
||||
snprintf(chUtilPercentage, sizeof(chUtilPercentage), "%2.0f%%", airTime->channelUtilizationPercent());
|
||||
|
||||
int chUtil_x = (isHighResolution) ? display->getStringWidth(chUtil) + 10 : display->getStringWidth(chUtil) + 5;
|
||||
int chUtil_x = (currentResolution == ScreenResolution::High) ? display->getStringWidth(chUtil) + 10
|
||||
: display->getStringWidth(chUtil) + 5;
|
||||
int chUtil_y = getTextPositions(display)[line] + 3;
|
||||
|
||||
int chutil_bar_width = (isHighResolution) ? 100 : 50;
|
||||
int chutil_bar_width = (currentResolution == ScreenResolution::High) ? 100 : 50;
|
||||
if (!config.bluetooth.enabled) {
|
||||
#if defined(USE_EINK)
|
||||
chutil_bar_width = (isHighResolution) ? 50 : 30;
|
||||
chutil_bar_width = (currentResolution == ScreenResolution::High) ? 50 : 30;
|
||||
#else
|
||||
chutil_bar_width = (isHighResolution) ? 80 : 40;
|
||||
chutil_bar_width = (currentResolution == ScreenResolution::High) ? 80 : 40;
|
||||
#endif
|
||||
}
|
||||
int chutil_bar_height = (isHighResolution) ? 12 : 7;
|
||||
int extraoffset = (isHighResolution) ? 6 : 3;
|
||||
int chutil_bar_height = (currentResolution == ScreenResolution::High) ? 12 : 7;
|
||||
int extraoffset = (currentResolution == ScreenResolution::High) ? 6 : 3;
|
||||
if (!config.bluetooth.enabled) {
|
||||
extraoffset = (isHighResolution) ? 6 : 1;
|
||||
extraoffset = (currentResolution == ScreenResolution::High) ? 6 : 1;
|
||||
}
|
||||
int chutil_percent = airTime->channelUtilizationPercent();
|
||||
|
||||
@@ -739,7 +723,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
// === Fourth & Fifth Rows: Node Identity ===
|
||||
int textWidth = 0;
|
||||
int nameX = 0;
|
||||
int yOffset = (isHighResolution) ? 0 : 5;
|
||||
int yOffset = (currentResolution == ScreenResolution::High) ? 0 : 5;
|
||||
std::string longNameStr;
|
||||
|
||||
if (ourNode && ourNode->has_user && strlen(ourNode->user.long_name) > 0) {
|
||||
@@ -772,11 +756,12 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
||||
}
|
||||
#endif
|
||||
graphics::drawCommonFooter(display, x, y);
|
||||
}
|
||||
|
||||
// Start Functions to write date/time to the screen
|
||||
// Helper function to check if a year is a leap year
|
||||
bool isLeapYear(int year)
|
||||
constexpr bool isLeapYear(int year)
|
||||
{
|
||||
return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
|
||||
}
|
||||
@@ -1007,15 +992,8 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
} else {
|
||||
displayLine = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT ? "No GPS" : "GPS off";
|
||||
}
|
||||
int yOffset = (isHighResolution) ? 3 : 1;
|
||||
if (isHighResolution) {
|
||||
NodeListRenderer::drawScaledXBitmap16x16(x, getTextPositions(display)[line] + yOffset - 5, imgSatellite_width,
|
||||
imgSatellite_height, imgSatellite, display);
|
||||
} else {
|
||||
display->drawXbm(x + 1, getTextPositions(display)[line] + yOffset, imgSatellite_width, imgSatellite_height,
|
||||
imgSatellite);
|
||||
}
|
||||
int xOffset = (isHighResolution) ? 6 : 0;
|
||||
drawSatelliteIcon(display, x, getTextPositions(display)[line]);
|
||||
int xOffset = (currentResolution == ScreenResolution::High) ? 6 : 0;
|
||||
display->drawString(x + 11 + xOffset, getTextPositions(display)[line++], displayLine);
|
||||
} else {
|
||||
// Onboard GPS
|
||||
@@ -1047,36 +1025,17 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
if (strcmp(displayLine, "GPS off") != 0 && strcmp(displayLine, "No GPS") != 0) {
|
||||
// === Second Row: Last GPS Fix ===
|
||||
if (gpsStatus->getLastFixMillis() > 0) {
|
||||
uint32_t delta = (millis() - gpsStatus->getLastFixMillis()) / 1000; // seconds since last fix
|
||||
uint32_t days = delta / 86400;
|
||||
uint32_t hours = (delta % 86400) / 3600;
|
||||
uint32_t mins = (delta % 3600) / 60;
|
||||
uint32_t secs = delta % 60;
|
||||
|
||||
char buf[32];
|
||||
uint32_t delta = millis() - gpsStatus->getLastFixMillis();
|
||||
char uptimeStr[32];
|
||||
#if defined(USE_EINK)
|
||||
// E-Ink: skip seconds, show only days/hours/mins
|
||||
if (days > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %ud %uh", days, hours);
|
||||
} else if (hours > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %uh %um", hours, mins);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "Last: %um", mins);
|
||||
}
|
||||
getUptimeStr(delta, "Last", uptimeStr, sizeof(uptimeStr), false);
|
||||
#else
|
||||
// Non E-Ink: include seconds where useful
|
||||
if (days > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %ud %uh", days, hours);
|
||||
} else if (hours > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %uh %um", hours, mins);
|
||||
} else if (mins > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %um %us", mins, secs);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "Last: %us", secs);
|
||||
}
|
||||
getUptimeStr(delta, "Last", uptimeStr, sizeof(uptimeStr), true);
|
||||
#endif
|
||||
|
||||
display->drawString(0, getTextPositions(display)[line++], buf);
|
||||
display->drawString(0, getTextPositions(display)[line++], uptimeStr);
|
||||
} else {
|
||||
display->drawString(0, getTextPositions(display)[line++], "Last: ?");
|
||||
}
|
||||
@@ -1184,6 +1143,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
}
|
||||
#endif
|
||||
#endif // HAS_GPS
|
||||
graphics::drawCommonFooter(display, x, y);
|
||||
}
|
||||
|
||||
#ifdef USERPREFS_OEM_TEXT
|
||||
@@ -1191,7 +1151,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
void UIRenderer::drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
static const uint8_t xbm[] = USERPREFS_OEM_IMAGE_DATA;
|
||||
if (isHighResolution) {
|
||||
if (currentResolution == ScreenResolution::High) {
|
||||
display->drawXbm(x + (SCREEN_WIDTH - USERPREFS_OEM_IMAGE_WIDTH) / 2,
|
||||
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - USERPREFS_OEM_IMAGE_HEIGHT) / 2 + 2, USERPREFS_OEM_IMAGE_WIDTH,
|
||||
USERPREFS_OEM_IMAGE_HEIGHT, xbm);
|
||||
@@ -1216,7 +1176,7 @@ void UIRenderer::drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, O
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
const char *title = USERPREFS_OEM_TEXT;
|
||||
if (isHighResolution) {
|
||||
if (currentResolution == ScreenResolution::High) {
|
||||
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
||||
}
|
||||
display->setFont(FONT_SMALL);
|
||||
@@ -1260,15 +1220,21 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
lastFrameChangeTime = millis();
|
||||
}
|
||||
|
||||
const int iconSize = isHighResolution ? 16 : 8;
|
||||
const int spacing = isHighResolution ? 8 : 4;
|
||||
const int bigOffset = isHighResolution ? 1 : 0;
|
||||
const int iconSize = (currentResolution == ScreenResolution::High) ? 16 : 8;
|
||||
const int spacing = (currentResolution == ScreenResolution::High) ? 8 : 4;
|
||||
const int bigOffset = (currentResolution == ScreenResolution::High) ? 1 : 0;
|
||||
|
||||
const size_t totalIcons = screen->indicatorIcons.size();
|
||||
if (totalIcons == 0)
|
||||
return;
|
||||
|
||||
const size_t iconsPerPage = (SCREEN_WIDTH + spacing) / (iconSize + spacing);
|
||||
const int navPadding = (currentResolution == ScreenResolution::High) ? 24 : 12; // padding per side
|
||||
|
||||
int usableWidth = SCREEN_WIDTH - (navPadding * 2);
|
||||
if (usableWidth < iconSize)
|
||||
usableWidth = iconSize;
|
||||
|
||||
const size_t iconsPerPage = usableWidth / (iconSize + spacing);
|
||||
const size_t currentPage = currentFrame / iconsPerPage;
|
||||
const size_t pageStart = currentPage * iconsPerPage;
|
||||
const size_t pageEnd = min(pageStart + iconsPerPage, totalIcons);
|
||||
@@ -1329,7 +1295,7 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
display->setColor(BLACK);
|
||||
}
|
||||
|
||||
if (isHighResolution) {
|
||||
if (currentResolution == ScreenResolution::High) {
|
||||
NodeListRenderer::drawScaledXBitmap16x16(x, y, 8, 8, icon, display);
|
||||
} else {
|
||||
display->drawXbm(x, y, iconSize, iconSize, icon);
|
||||
@@ -1339,6 +1305,47 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
display->setColor(WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Compact arrow drawer
|
||||
auto drawArrow = [&](bool rightSide) {
|
||||
display->setColor(WHITE);
|
||||
|
||||
const int offset = (currentResolution == ScreenResolution::High) ? 3 : 1;
|
||||
const int halfH = rectHeight / 2;
|
||||
|
||||
const int top = (y - 2) + (rectHeight - halfH) / 2;
|
||||
const int bottom = top + halfH - 1;
|
||||
const int midY = top + (halfH / 2);
|
||||
|
||||
const int maxW = 4;
|
||||
|
||||
// Determine left X coordinate
|
||||
int baseX = rightSide ? (rectX + rectWidth + offset) : // right arrow
|
||||
(rectX - offset - 1); // left arrow
|
||||
|
||||
for (int yy = top; yy <= bottom; yy++) {
|
||||
int dist = abs(yy - midY);
|
||||
int lineW = maxW - (dist * maxW / (halfH / 2));
|
||||
if (lineW < 1)
|
||||
lineW = 1;
|
||||
|
||||
if (rightSide) {
|
||||
display->drawHorizontalLine(baseX, yy, lineW);
|
||||
} else {
|
||||
display->drawHorizontalLine(baseX - lineW + 1, yy, lineW);
|
||||
}
|
||||
}
|
||||
};
|
||||
// Right arrow
|
||||
if (pageEnd < totalIcons) {
|
||||
drawArrow(true);
|
||||
}
|
||||
|
||||
// Left arrow
|
||||
if (pageStart > 0) {
|
||||
drawArrow(false);
|
||||
}
|
||||
|
||||
// Knock the corners off the square
|
||||
display->setColor(BLACK);
|
||||
display->drawRect(rectX, y - 2, 1, 1);
|
||||
@@ -1373,4 +1380,4 @@ std::string UIRenderer::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t mi
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
#endif // HAS_SCREEN
|
||||
#endif // HAS_SCREEN
|
||||
|
||||
Reference in New Issue
Block a user