mirror of
https://github.com/meshtastic/firmware.git
synced 2025-08-10 23:47:12 +00:00
Node list cleanup and unification
This commit is contained in:
parent
2b7bc6696f
commit
ae47de152c
@ -1939,93 +1939,11 @@ void drawColumnSeparator(OLEDDisplay *display, int16_t x, int16_t yStart, int16_
|
|||||||
display->drawLine(separatorX, yStart, separatorX, yEnd);
|
display->drawLine(separatorX, yStart, separatorX, yEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draws node name with how long ago it was last heard from
|
|
||||||
void drawEntryLastHeard(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth)
|
|
||||||
{
|
|
||||||
int screenWidth = display->getWidth();
|
|
||||||
bool isLeftCol = (x < screenWidth / 2);
|
|
||||||
|
|
||||||
// Adjust offset based on column and screen width
|
|
||||||
int timeOffset =
|
|
||||||
(screenWidth > 128)
|
|
||||||
? (isLeftCol ? 41 : 45)
|
|
||||||
: (isLeftCol ? 24 : 30); // offset large screen (?Left:Right column), offset small screen (?Left:Right column)
|
|
||||||
|
|
||||||
String nodeName = getSafeNodeName(node);
|
|
||||||
|
|
||||||
char timeStr[10];
|
|
||||||
uint32_t seconds = sinceLastSeen(node);
|
|
||||||
if (seconds == 0 || seconds == UINT32_MAX) {
|
|
||||||
snprintf(timeStr, sizeof(timeStr), "? ");
|
|
||||||
} else {
|
|
||||||
uint32_t minutes = seconds / 60, hours = minutes / 60, days = hours / 24;
|
|
||||||
snprintf(timeStr, sizeof(timeStr), (days > 365 ? "?" : "%d%c"),
|
|
||||||
(days ? days
|
|
||||||
: hours ? hours
|
|
||||||
: minutes),
|
|
||||||
(days ? 'd'
|
|
||||||
: hours ? 'h'
|
|
||||||
: 'm'));
|
|
||||||
}
|
|
||||||
|
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
|
||||||
display->setFont(FONT_SMALL);
|
|
||||||
display->drawString(x, y, nodeName);
|
|
||||||
display->drawString(x + columnWidth - timeOffset, y, timeStr);
|
|
||||||
}
|
|
||||||
// Draws each node's name, hop count, and signal bars
|
|
||||||
void drawEntryHopSignal(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth)
|
|
||||||
{
|
|
||||||
int screenWidth = display->getWidth();
|
|
||||||
bool isLeftCol = (x < screenWidth / 2);
|
|
||||||
|
|
||||||
int nameMaxWidth = columnWidth - 25;
|
|
||||||
int barsOffset =
|
|
||||||
(screenWidth > 128)
|
|
||||||
? (isLeftCol ? 26 : 30)
|
|
||||||
: (isLeftCol ? 17 : 19); // offset large screen (?Left:Right column), offset small screen (?Left:Right column)
|
|
||||||
int hopOffset =
|
|
||||||
(screenWidth > 128)
|
|
||||||
? (isLeftCol ? 32 : 38)
|
|
||||||
: (isLeftCol ? 18 : 20); // offset large screen (?Left:Right column), offset small screen (?Left:Right column)
|
|
||||||
|
|
||||||
int barsXOffset = columnWidth - barsOffset;
|
|
||||||
|
|
||||||
String nodeName = getSafeNodeName(node);
|
|
||||||
|
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
|
||||||
display->setFont(FONT_SMALL);
|
|
||||||
display->drawStringMaxWidth(x, y, nameMaxWidth, nodeName);
|
|
||||||
|
|
||||||
char hopStr[6] = "";
|
|
||||||
if (node->has_hops_away && node->hops_away > 0)
|
|
||||||
snprintf(hopStr, sizeof(hopStr), "[%d]", node->hops_away);
|
|
||||||
|
|
||||||
if (hopStr[0] != '\0') {
|
|
||||||
int hopX = x + columnWidth - hopOffset - display->getStringWidth(hopStr);
|
|
||||||
display->drawString(hopX, y, hopStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal bars based on SNR
|
|
||||||
int bars = (node->snr > 5) ? 4 : (node->snr > 0) ? 3 : (node->snr > -5) ? 2 : (node->snr > -10) ? 1 : 0;
|
|
||||||
int barWidth = 2;
|
|
||||||
int barStartX = x + barsXOffset;
|
|
||||||
int barStartY = y + (FONT_HEIGHT_SMALL / 2) + 2;
|
|
||||||
|
|
||||||
for (int b = 0; b < 4; b++) {
|
|
||||||
if (b < bars) {
|
|
||||||
int height = (b * 2);
|
|
||||||
display->fillRect(barStartX + (b * (barWidth + 1)), barStartY - height, barWidth, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Typedef for passing different render functions into one reusable screen function
|
|
||||||
typedef void (*EntryRenderer)(OLEDDisplay *, meshtastic_NodeInfoLite *, int16_t, int16_t, int);
|
typedef void (*EntryRenderer)(OLEDDisplay *, meshtastic_NodeInfoLite *, int16_t, int16_t, int);
|
||||||
|
typedef void (*NodeExtrasRenderer)(OLEDDisplay *, meshtastic_NodeInfoLite *, int16_t, int16_t, int columnWidth, float heading, double lat, double lon);
|
||||||
|
|
||||||
// Shared function that renders all node screens (LastHeard, Hop/Signal)
|
void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y,
|
||||||
void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *title,
|
const char *title, EntryRenderer renderer, NodeExtrasRenderer extras = nullptr)
|
||||||
EntryRenderer renderer)
|
|
||||||
{
|
{
|
||||||
const int COMMON_HEADER_HEIGHT = FONT_HEIGHT_SMALL - 1;
|
const int COMMON_HEADER_HEIGHT = FONT_HEIGHT_SMALL - 1;
|
||||||
const int rowYOffset = FONT_HEIGHT_SMALL - 3;
|
const int rowYOffset = FONT_HEIGHT_SMALL - 3;
|
||||||
@ -2101,171 +2019,95 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
|||||||
drawScrollbar(display, visibleNodeRows, totalEntries, scrollIndex, 2, scrollStartY);
|
drawScrollbar(display, visibleNodeRows, totalEntries, scrollIndex, 2, scrollStartY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ****************************
|
||||||
// Public screen function: shows how recently nodes were heard
|
// * Last Heard Screen *
|
||||||
static void drawLastHeardScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
// ****************************
|
||||||
{
|
void drawEntryLastHeard(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth)
|
||||||
drawNodeListScreen(display, state, x, y, "Node List", drawEntryLastHeard);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Public screen function: shows hop count + signal strength
|
|
||||||
static void drawHopSignalScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
|
||||||
{
|
|
||||||
drawNodeListScreen(display, state, x, y, "Hop|Sig", drawEntryHopSignal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function: Draw a single node entry for Node List (Modified for Compass Screen)
|
|
||||||
void drawEntryCompass(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth)
|
|
||||||
{
|
{
|
||||||
int screenWidth = display->getWidth();
|
int screenWidth = display->getWidth();
|
||||||
bool isLeftCol = (x < screenWidth / 2);
|
bool isLeftCol = (x < screenWidth / 2);
|
||||||
|
|
||||||
// Adjust max text width depending on column and screen width
|
// Adjust offset based on column and screen width
|
||||||
int nameMaxWidth = columnWidth - (screenWidth > 128 ? (isLeftCol ? 25 : 28) : (isLeftCol ? 20 : 22));
|
int timeOffset =
|
||||||
|
(screenWidth > 128)
|
||||||
|
? (isLeftCol ? 41 : 45)
|
||||||
|
: (isLeftCol ? 24 : 30); // offset large screen (?Left:Right column), offset small screen (?Left:Right column)
|
||||||
|
|
||||||
|
String nodeName = getSafeNodeName(node);
|
||||||
|
|
||||||
|
char timeStr[10];
|
||||||
|
uint32_t seconds = sinceLastSeen(node);
|
||||||
|
if (seconds == 0 || seconds == UINT32_MAX) {
|
||||||
|
snprintf(timeStr, sizeof(timeStr), "? ");
|
||||||
|
} else {
|
||||||
|
uint32_t minutes = seconds / 60, hours = minutes / 60, days = hours / 24;
|
||||||
|
snprintf(timeStr, sizeof(timeStr), (days > 365 ? "?" : "%d%c"),
|
||||||
|
(days ? days
|
||||||
|
: hours ? hours
|
||||||
|
: minutes),
|
||||||
|
(days ? 'd'
|
||||||
|
: hours ? 'h'
|
||||||
|
: 'm'));
|
||||||
|
}
|
||||||
|
|
||||||
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
display->setFont(FONT_SMALL);
|
||||||
|
display->drawString(x, y, nodeName);
|
||||||
|
display->drawString(x + columnWidth - timeOffset, y, timeStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ****************************
|
||||||
|
// * Hops / Signal Screen *
|
||||||
|
// ****************************
|
||||||
|
void drawEntryHopSignal(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth)
|
||||||
|
{
|
||||||
|
int screenWidth = display->getWidth();
|
||||||
|
bool isLeftCol = (x < screenWidth / 2);
|
||||||
|
|
||||||
|
int nameMaxWidth = columnWidth - 25;
|
||||||
|
int barsOffset =
|
||||||
|
(screenWidth > 128)
|
||||||
|
? (isLeftCol ? 26 : 30)
|
||||||
|
: (isLeftCol ? 17 : 19); // offset large screen (?Left:Right column), offset small screen (?Left:Right column)
|
||||||
|
int hopOffset =
|
||||||
|
(screenWidth > 128)
|
||||||
|
? (isLeftCol ? 32 : 38)
|
||||||
|
: (isLeftCol ? 18 : 20); // offset large screen (?Left:Right column), offset small screen (?Left:Right column)
|
||||||
|
|
||||||
|
int barsXOffset = columnWidth - barsOffset;
|
||||||
|
|
||||||
String nodeName = getSafeNodeName(node);
|
String nodeName = getSafeNodeName(node);
|
||||||
|
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
display->drawStringMaxWidth(x, y, nameMaxWidth, nodeName);
|
display->drawStringMaxWidth(x, y, nameMaxWidth, nodeName);
|
||||||
}
|
|
||||||
|
|
||||||
// Extra compass element drawer (injects compass arrows)
|
char hopStr[6] = "";
|
||||||
typedef void (*CompassExtraRenderer)(OLEDDisplay *, meshtastic_NodeInfoLite *, int16_t, int16_t, int columnWidth, float myHeading,
|
if (node->has_hops_away && node->hops_away > 0)
|
||||||
double userLat, double userLon);
|
snprintf(hopStr, sizeof(hopStr), "[%d]", node->hops_away);
|
||||||
|
|
||||||
void drawCompassArrow(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth, float myHeading,
|
if (hopStr[0] != '\0') {
|
||||||
double userLat, double userLon)
|
int hopX = x + columnWidth - hopOffset - display->getStringWidth(hopStr);
|
||||||
{
|
display->drawString(hopX, y, hopStr);
|
||||||
if (!nodeDB->hasValidPosition(node))
|
|
||||||
return;
|
|
||||||
|
|
||||||
int screenWidth = display->getWidth();
|
|
||||||
bool isLeftCol = (x < screenWidth / 2);
|
|
||||||
|
|
||||||
double nodeLat = node->position.latitude_i * 1e-7;
|
|
||||||
double nodeLon = node->position.longitude_i * 1e-7;
|
|
||||||
float bearingToNode = calculateBearing(userLat, userLon, nodeLat, nodeLon);
|
|
||||||
float relativeBearing = fmod((bearingToNode - myHeading + 360), 360);
|
|
||||||
float arrowAngle = relativeBearing * DEG_TO_RAD;
|
|
||||||
|
|
||||||
// Adaptive offset for compass icon based on screen width + column
|
|
||||||
int arrowXOffset = (screenWidth > 128) ? (isLeftCol ? 22 : 24) : (isLeftCol ? 12 : 18);
|
|
||||||
|
|
||||||
int compassX = x + columnWidth - arrowXOffset;
|
|
||||||
int compassY = y + FONT_HEIGHT_SMALL / 2;
|
|
||||||
int size = FONT_HEIGHT_SMALL / 2 - 2;
|
|
||||||
int arrowLength = size - 2;
|
|
||||||
|
|
||||||
int xEnd = compassX + arrowLength * cos(arrowAngle);
|
|
||||||
int yEnd = compassY - arrowLength * sin(arrowAngle);
|
|
||||||
|
|
||||||
display->fillCircle(compassX, compassY, size);
|
|
||||||
display->drawCircle(compassX, compassY, size);
|
|
||||||
display->drawLine(compassX, compassY, xEnd, yEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic node+compass renderer (like drawNodeListScreen but with compass support)
|
|
||||||
void drawNodeListWithExtrasScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *title,
|
|
||||||
EntryRenderer renderer, CompassExtraRenderer extras)
|
|
||||||
{
|
|
||||||
const int COMMON_HEADER_HEIGHT = FONT_HEIGHT_SMALL - 1;
|
|
||||||
const int rowYOffset = FONT_HEIGHT_SMALL - 3;
|
|
||||||
|
|
||||||
int columnWidth = display->getWidth() / 2;
|
|
||||||
int screenWidth = display->getWidth();
|
|
||||||
|
|
||||||
display->clear();
|
|
||||||
|
|
||||||
// === Draw common header (battery + time)
|
|
||||||
drawCommonHeader(display, x, y);
|
|
||||||
|
|
||||||
// === Draw title inside header (centered)
|
|
||||||
const int highlightHeight = COMMON_HEADER_HEIGHT;
|
|
||||||
const int textY = y + 2 + (highlightHeight - FONT_HEIGHT_SMALL) / 2;
|
|
||||||
const int centerX = x + screenWidth / 2;
|
|
||||||
|
|
||||||
display->setFont(FONT_SMALL);
|
|
||||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
|
||||||
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED)
|
|
||||||
display->setColor(BLACK);
|
|
||||||
|
|
||||||
display->drawString(centerX, textY, title);
|
|
||||||
if (config.display.heading_bold)
|
|
||||||
display->drawString(centerX + 1, textY, title);
|
|
||||||
|
|
||||||
display->setColor(WHITE);
|
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
|
||||||
|
|
||||||
// === Space below header
|
|
||||||
y += COMMON_HEADER_HEIGHT;
|
|
||||||
|
|
||||||
std::vector<NodeEntry> nodeList;
|
|
||||||
retrieveAndSortNodes(nodeList);
|
|
||||||
|
|
||||||
int totalEntries = nodeList.size();
|
|
||||||
int totalRowsAvailable = (display->getHeight() - y) / rowYOffset;
|
|
||||||
int visibleNodeRows = totalRowsAvailable;
|
|
||||||
|
|
||||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
|
||||||
double userLat = 0.0, userLon = 0.0;
|
|
||||||
bool hasUserPosition = nodeDB->hasValidPosition(ourNode);
|
|
||||||
if (hasUserPosition) {
|
|
||||||
userLat = ourNode->position.latitude_i * 1e-7;
|
|
||||||
userLon = ourNode->position.longitude_i * 1e-7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float myHeading = screen->hasHeading() ? screen->getHeading() : 0.0f;
|
// Signal bars based on SNR
|
||||||
|
int bars = (node->snr > 5) ? 4 : (node->snr > 0) ? 3 : (node->snr > -5) ? 2 : (node->snr > -10) ? 1 : 0;
|
||||||
|
int barWidth = 2;
|
||||||
|
int barStartX = x + barsXOffset;
|
||||||
|
int barStartY = y + (FONT_HEIGHT_SMALL / 2) + 2;
|
||||||
|
|
||||||
int startIndex = scrollIndex * visibleNodeRows * 2;
|
for (int b = 0; b < 4; b++) {
|
||||||
int endIndex = std::min(startIndex + visibleNodeRows * 2, totalEntries);
|
if (b < bars) {
|
||||||
|
int height = (b * 2);
|
||||||
int yOffset = 0;
|
display->fillRect(barStartX + (b * (barWidth + 1)), barStartY - height, barWidth, height);
|
||||||
int col = 0;
|
|
||||||
int lastNodeY = y;
|
|
||||||
int shownCount = 0;
|
|
||||||
|
|
||||||
for (int i = startIndex; i < endIndex; ++i) {
|
|
||||||
int xPos = x + (col * columnWidth);
|
|
||||||
int yPos = y + yOffset;
|
|
||||||
|
|
||||||
renderer(display, nodeList[i].node, xPos, yPos, columnWidth);
|
|
||||||
|
|
||||||
if (hasUserPosition && extras) {
|
|
||||||
extras(display, nodeList[i].node, xPos, yPos, columnWidth, myHeading, userLat, userLon);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastNodeY = std::max(lastNodeY, yPos + FONT_HEIGHT_SMALL);
|
|
||||||
yOffset += rowYOffset;
|
|
||||||
shownCount++;
|
|
||||||
|
|
||||||
if (y + yOffset > display->getHeight() - FONT_HEIGHT_SMALL) {
|
|
||||||
yOffset = 0;
|
|
||||||
col++;
|
|
||||||
if (col > 1)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Draw column separator
|
|
||||||
if (shownCount > 0) {
|
|
||||||
const int firstNodeY = y + 3; // where the first node row starts
|
|
||||||
drawColumnSeparator(display, x, firstNodeY, lastNodeY);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int scrollStartY = y + 3;
|
|
||||||
drawScrollbar(display, visibleNodeRows, totalEntries, scrollIndex, 2, scrollStartY);
|
|
||||||
}
|
|
||||||
// Public screen entry for compass
|
|
||||||
static void drawNodeListWithCompasses(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
|
||||||
{
|
|
||||||
drawNodeListWithExtrasScreen(display, state, x, y, "Bearings", drawEntryCompass, drawCompassArrow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ********************************
|
// **************************
|
||||||
// * Node List Distance Screen *
|
// * Distance Screen *
|
||||||
// ********************************
|
// **************************
|
||||||
|
|
||||||
void drawNodeDistance(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth)
|
void drawNodeDistance(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth)
|
||||||
{
|
{
|
||||||
int screenWidth = display->getWidth();
|
int screenWidth = display->getWidth();
|
||||||
@ -2322,11 +2164,71 @@ void drawNodeDistance(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawDistanceScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
// Public screen function: shows how recently nodes were heard
|
||||||
{
|
static void drawLastHeardScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) {
|
||||||
|
drawNodeListScreen(display, state, x, y, "Node List", drawEntryLastHeard);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public screen function: shows hop count + signal strength
|
||||||
|
static void drawHopSignalScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) {
|
||||||
|
drawNodeListScreen(display, state, x, y, "Hop|Sig", drawEntryHopSignal);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drawDistanceScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) {
|
||||||
drawNodeListScreen(display, state, x, y, "Distances", drawNodeDistance);
|
drawNodeListScreen(display, state, x, y, "Distances", drawNodeDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function: Draw a single node entry for Node List (Modified for Compass Screen)
|
||||||
|
void drawEntryCompass(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth)
|
||||||
|
{
|
||||||
|
int screenWidth = display->getWidth();
|
||||||
|
bool isLeftCol = (x < screenWidth / 2);
|
||||||
|
|
||||||
|
// Adjust max text width depending on column and screen width
|
||||||
|
int nameMaxWidth = columnWidth - (screenWidth > 128 ? (isLeftCol ? 25 : 28) : (isLeftCol ? 20 : 22));
|
||||||
|
|
||||||
|
String nodeName = getSafeNodeName(node);
|
||||||
|
|
||||||
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
display->setFont(FONT_SMALL);
|
||||||
|
display->drawStringMaxWidth(x, y, nameMaxWidth, nodeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawCompassArrow(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth, float myHeading,
|
||||||
|
double userLat, double userLon)
|
||||||
|
{
|
||||||
|
if (!nodeDB->hasValidPosition(node))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int screenWidth = display->getWidth();
|
||||||
|
bool isLeftCol = (x < screenWidth / 2);
|
||||||
|
|
||||||
|
double nodeLat = node->position.latitude_i * 1e-7;
|
||||||
|
double nodeLon = node->position.longitude_i * 1e-7;
|
||||||
|
float bearingToNode = calculateBearing(userLat, userLon, nodeLat, nodeLon);
|
||||||
|
float relativeBearing = fmod((bearingToNode - myHeading + 360), 360);
|
||||||
|
float arrowAngle = relativeBearing * DEG_TO_RAD;
|
||||||
|
|
||||||
|
// Adaptive offset for compass icon based on screen width + column
|
||||||
|
int arrowXOffset = (screenWidth > 128) ? (isLeftCol ? 22 : 24) : (isLeftCol ? 12 : 18);
|
||||||
|
|
||||||
|
int compassX = x + columnWidth - arrowXOffset;
|
||||||
|
int compassY = y + FONT_HEIGHT_SMALL / 2;
|
||||||
|
int size = FONT_HEIGHT_SMALL / 2 - 2;
|
||||||
|
int arrowLength = size - 2;
|
||||||
|
|
||||||
|
int xEnd = compassX + arrowLength * cos(arrowAngle);
|
||||||
|
int yEnd = compassY - arrowLength * sin(arrowAngle);
|
||||||
|
|
||||||
|
display->fillCircle(compassX, compassY, size);
|
||||||
|
display->drawCircle(compassX, compassY, size);
|
||||||
|
display->drawLine(compassX, compassY, xEnd, yEnd);
|
||||||
|
}
|
||||||
|
// Public screen entry for compass
|
||||||
|
static void drawNodeListWithCompasses(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) {
|
||||||
|
drawNodeListScreen(display, state, x, y, "Bearings", drawEntryCompass, drawCompassArrow);
|
||||||
|
}
|
||||||
|
|
||||||
// ****************************
|
// ****************************
|
||||||
// * Device Focused Screen *
|
// * Device Focused Screen *
|
||||||
// ****************************
|
// ****************************
|
||||||
@ -3420,22 +3322,22 @@ void Screen::setFrames(FrameFocus focus)
|
|||||||
normalFrames[numframes++] = drawCompassAndLocationScreen;
|
normalFrames[numframes++] = drawCompassAndLocationScreen;
|
||||||
normalFrames[numframes++] = drawMemoryScreen;
|
normalFrames[numframes++] = drawMemoryScreen;
|
||||||
|
|
||||||
// then all the nodes
|
// then all the nodes
|
||||||
// We only show a few nodes in our scrolling list - because meshes with many nodes would have too many screens
|
// We only show a few nodes in our scrolling list - because meshes with many nodes would have too many screens
|
||||||
// size_t numToShow = min(numMeshNodes, 4U);
|
size_t numToShow = min(numMeshNodes, 4U);
|
||||||
// for (size_t i = 0; i < numToShow; i++)
|
for (size_t i = 0; i < numToShow; i++)
|
||||||
// normalFrames[numframes++] = drawNodeInfo;
|
normalFrames[numframes++] = drawNodeInfo;
|
||||||
|
|
||||||
// then the debug info
|
// then the debug info
|
||||||
//
|
|
||||||
// Since frames are basic function pointers, we have to use a helper to
|
|
||||||
// call a method on debugInfo object.
|
|
||||||
// fsi.positions.log = numframes;
|
|
||||||
// normalFrames[numframes++] = &Screen::drawDebugInfoTrampoline;
|
|
||||||
|
|
||||||
// call a method on debugInfoScreen object (for more details)
|
// Since frames are basic function pointers, we have to use a helper to
|
||||||
// fsi.positions.settings = numframes;
|
// call a method on debugInfo object.
|
||||||
// normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline;
|
fsi.positions.log = numframes;
|
||||||
|
normalFrames[numframes++] = &Screen::drawDebugInfoTrampoline;
|
||||||
|
|
||||||
|
// call a method on debugInfoScreen object (for more details)
|
||||||
|
fsi.positions.settings = numframes;
|
||||||
|
normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline;
|
||||||
|
|
||||||
fsi.positions.wifi = numframes;
|
fsi.positions.wifi = numframes;
|
||||||
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||||||
|
Loading…
Reference in New Issue
Block a user