mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-13 05:17:34 +00:00
Compare commits
11 Commits
develop
...
baseui_nod
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac7e399919 | ||
|
|
f945eb38bf | ||
|
|
2b69fa1044 | ||
|
|
8d4a75faeb | ||
|
|
45f6f8b1a8 | ||
|
|
9cccf0240d | ||
|
|
888668b480 | ||
|
|
a629c43aaf | ||
|
|
b0c130562d | ||
|
|
974cb8ccad | ||
|
|
58cb7f2617 |
@@ -59,6 +59,7 @@ BannerOverlayOptions createStaticBannerOptions(const char *message, const MenuOp
|
||||
} // namespace
|
||||
|
||||
menuHandler::screenMenus menuHandler::menuQueue = menu_none;
|
||||
uint32_t menuHandler::pickedNodeNum = 0;
|
||||
bool test_enabled = false;
|
||||
uint8_t test_count = 0;
|
||||
|
||||
@@ -1213,20 +1214,13 @@ void menuHandler::positionBaseMenu()
|
||||
|
||||
void menuHandler::nodeListMenu()
|
||||
{
|
||||
enum optionsNumbers { Back, Favorite, TraceRoute, Verify, Reset, NodeNameLength, enumEnd };
|
||||
enum optionsNumbers { Back, NodePicker, TraceRoute, Verify, Reset, NodeNameLength, enumEnd };
|
||||
static const char *optionsArray[enumEnd] = {"Back"};
|
||||
static int optionsEnumArray[enumEnd] = {Back};
|
||||
int options = 1;
|
||||
|
||||
optionsArray[options] = "Add Favorite";
|
||||
optionsEnumArray[options++] = Favorite;
|
||||
optionsArray[options] = "Trace Route";
|
||||
optionsEnumArray[options++] = TraceRoute;
|
||||
|
||||
if (currentResolution != ScreenResolution::UltraLow) {
|
||||
optionsArray[options] = "Key Verification";
|
||||
optionsEnumArray[options++] = Verify;
|
||||
}
|
||||
optionsArray[options] = "Node Actions / Settings";
|
||||
optionsEnumArray[options++] = NodePicker;
|
||||
|
||||
if (currentResolution != ScreenResolution::UltraLow) {
|
||||
optionsArray[options] = "Show Long/Short Name";
|
||||
@@ -1241,18 +1235,12 @@ void menuHandler::nodeListMenu()
|
||||
bannerOptions.optionsCount = options;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == Favorite) {
|
||||
menuQueue = add_favorite;
|
||||
screen->runNow();
|
||||
} else if (selected == Verify) {
|
||||
menuQueue = key_verification_init;
|
||||
if (selected == NodePicker) {
|
||||
menuQueue = NodePicker_menu;
|
||||
screen->runNow();
|
||||
} else if (selected == Reset) {
|
||||
menuQueue = reset_node_db_menu;
|
||||
screen->runNow();
|
||||
} else if (selected == TraceRoute) {
|
||||
menuQueue = trace_route_menu;
|
||||
screen->runNow();
|
||||
} else if (selected == NodeNameLength) {
|
||||
menuHandler::menuQueue = menuHandler::node_name_length_menu;
|
||||
screen->runNow();
|
||||
@@ -1261,6 +1249,159 @@ void menuHandler::nodeListMenu()
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
}
|
||||
|
||||
void menuHandler::NodePicker()
|
||||
{
|
||||
const char *NODE_PICKER_TITLE;
|
||||
if (currentResolution == ScreenResolution::UltraLow) {
|
||||
NODE_PICKER_TITLE = "Pick Node";
|
||||
} else {
|
||||
NODE_PICKER_TITLE = "Node To Manage";
|
||||
}
|
||||
screen->showNodePicker(NODE_PICKER_TITLE, 30000, [](uint32_t nodenum) -> void {
|
||||
LOG_INFO("Nodenum: %u", nodenum);
|
||||
// Store the selection so the Manage Node menu knows which node to operate on
|
||||
menuHandler::pickedNodeNum = nodenum;
|
||||
// Keep UI favorite context in sync (used elsewhere for some node-based actions)
|
||||
graphics::UIRenderer::currentFavoriteNodeNum = nodenum;
|
||||
menuQueue = Manage_Node_menu;
|
||||
screen->runNow();
|
||||
});
|
||||
}
|
||||
|
||||
void menuHandler::ManageNodeMenu()
|
||||
{
|
||||
// If we don't have a node selected yet, go fast exit
|
||||
auto node = nodeDB->getMeshNode(menuHandler::pickedNodeNum);
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
enum optionsNumbers { Back, Favorite, Mute, TraceRoute, KeyVerification, Ignore, enumEnd };
|
||||
static const char *optionsArray[enumEnd] = {"Back"};
|
||||
static int optionsEnumArray[enumEnd] = {Back};
|
||||
int options = 1;
|
||||
|
||||
if (node->is_favorite) {
|
||||
optionsArray[options] = "Unfavorite";
|
||||
} else {
|
||||
optionsArray[options] = "Favorite";
|
||||
}
|
||||
optionsEnumArray[options++] = Favorite;
|
||||
|
||||
bool isMuted = (node->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0;
|
||||
if (isMuted) {
|
||||
optionsArray[options] = "Unmute Notifications";
|
||||
} else {
|
||||
optionsArray[options] = "Mute Notifications";
|
||||
}
|
||||
optionsEnumArray[options++] = Mute;
|
||||
|
||||
optionsArray[options] = "Trace Route";
|
||||
optionsEnumArray[options++] = TraceRoute;
|
||||
|
||||
optionsArray[options] = "Key Verification";
|
||||
optionsEnumArray[options++] = KeyVerification;
|
||||
|
||||
if (node->is_ignored) {
|
||||
optionsArray[options] = "Unignore Node";
|
||||
} else {
|
||||
optionsArray[options] = "Ignore Node";
|
||||
}
|
||||
optionsEnumArray[options++] = Ignore;
|
||||
|
||||
BannerOverlayOptions bannerOptions;
|
||||
|
||||
std::string title = "";
|
||||
if (node->has_user && node->user.long_name && node->user.long_name[0]) {
|
||||
title += sanitizeString(node->user.long_name).substr(0, 15);
|
||||
} else {
|
||||
char buf[20];
|
||||
snprintf(buf, sizeof(buf), "%08X", (unsigned int)node->num);
|
||||
title += buf;
|
||||
}
|
||||
bannerOptions.message = title.c_str();
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = options;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == Back) {
|
||||
menuQueue = node_base_menu;
|
||||
screen->runNow();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected == Favorite) {
|
||||
auto n = nodeDB->getMeshNode(menuHandler::pickedNodeNum);
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
if (n->is_favorite) {
|
||||
LOG_INFO("Removing node %08X from favorites", menuHandler::pickedNodeNum);
|
||||
nodeDB->set_favorite(false, menuHandler::pickedNodeNum);
|
||||
} else {
|
||||
LOG_INFO("Adding node %08X to favorites", menuHandler::pickedNodeNum);
|
||||
nodeDB->set_favorite(true, menuHandler::pickedNodeNum);
|
||||
}
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected == Mute) {
|
||||
auto n = nodeDB->getMeshNode(menuHandler::pickedNodeNum);
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (n->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) {
|
||||
n->bitfield &= ~NODEINFO_BITFIELD_IS_MUTED_MASK;
|
||||
LOG_INFO("Unmuted node %08X", menuHandler::pickedNodeNum);
|
||||
} else {
|
||||
n->bitfield |= NODEINFO_BITFIELD_IS_MUTED_MASK;
|
||||
LOG_INFO("Muted node %08X", menuHandler::pickedNodeNum);
|
||||
}
|
||||
nodeDB->notifyObservers(true);
|
||||
nodeDB->saveToDisk();
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected == TraceRoute) {
|
||||
LOG_INFO("Starting traceroute to %08X", menuHandler::pickedNodeNum);
|
||||
if (traceRouteModule) {
|
||||
traceRouteModule->startTraceRoute(menuHandler::pickedNodeNum);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected == KeyVerification) {
|
||||
LOG_INFO("Initiating key verification with %08X", menuHandler::pickedNodeNum);
|
||||
if (keyVerificationModule) {
|
||||
keyVerificationModule->sendInitialRequest(menuHandler::pickedNodeNum);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected == Ignore) {
|
||||
auto n = nodeDB->getMeshNode(menuHandler::pickedNodeNum);
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (n->is_ignored) {
|
||||
n->is_ignored = false;
|
||||
LOG_INFO("Unignoring node %08X", menuHandler::pickedNodeNum);
|
||||
} else {
|
||||
n->is_ignored = true;
|
||||
LOG_INFO("Ignoring node %08X", menuHandler::pickedNodeNum);
|
||||
}
|
||||
nodeDB->notifyObservers(true);
|
||||
nodeDB->saveToDisk();
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||
return;
|
||||
}
|
||||
};
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
}
|
||||
|
||||
void menuHandler::nodeNameLengthMenu()
|
||||
{
|
||||
static const NodeNameOption nodeNameOptions[] = {
|
||||
@@ -1958,21 +2099,6 @@ void menuHandler::shutdownMenu()
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
}
|
||||
|
||||
void menuHandler::addFavoriteMenu()
|
||||
{
|
||||
const char *NODE_PICKER_TITLE;
|
||||
if (currentResolution == ScreenResolution::UltraLow) {
|
||||
NODE_PICKER_TITLE = "Node Favorite";
|
||||
} else {
|
||||
NODE_PICKER_TITLE = "Node To Favorite";
|
||||
}
|
||||
screen->showNodePicker(NODE_PICKER_TITLE, 30000, [](uint32_t nodenum) -> void {
|
||||
LOG_WARN("Nodenum: %u", nodenum);
|
||||
nodeDB->set_favorite(true, nodenum);
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||
});
|
||||
}
|
||||
|
||||
void menuHandler::removeFavoriteMenu()
|
||||
{
|
||||
|
||||
@@ -2484,8 +2610,11 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
||||
case shutdown_menu:
|
||||
shutdownMenu();
|
||||
break;
|
||||
case add_favorite:
|
||||
addFavoriteMenu();
|
||||
case NodePicker_menu:
|
||||
NodePicker();
|
||||
break;
|
||||
case Manage_Node_menu:
|
||||
ManageNodeMenu();
|
||||
break;
|
||||
case remove_favorite:
|
||||
removeFavoriteMenu();
|
||||
|
||||
@@ -33,7 +33,8 @@ class menuHandler
|
||||
brightness_picker,
|
||||
reboot_menu,
|
||||
shutdown_menu,
|
||||
add_favorite,
|
||||
NodePicker_menu,
|
||||
Manage_Node_menu,
|
||||
remove_favorite,
|
||||
test_menu,
|
||||
number_test,
|
||||
@@ -55,6 +56,7 @@ class menuHandler
|
||||
DisplayUnits
|
||||
};
|
||||
static screenMenus menuQueue;
|
||||
static uint32_t pickedNodeNum; // node selected by NodePicker for ManageNodeMenu
|
||||
|
||||
static void OnboardMessage();
|
||||
static void LoraRegionPicker(uint32_t duration = 30000);
|
||||
@@ -90,6 +92,8 @@ class menuHandler
|
||||
static void BrightnessPickerMenu();
|
||||
static void rebootMenu();
|
||||
static void shutdownMenu();
|
||||
static void NodePicker();
|
||||
static void ManageNodeMenu();
|
||||
static void addFavoriteMenu();
|
||||
static void removeFavoriteMenu();
|
||||
static void traceRouteMenu();
|
||||
@@ -149,6 +153,7 @@ using GPSToggleOption = MenuOption<meshtastic_Config_PositionConfig_GpsMode>;
|
||||
using GPSFormatOption = MenuOption<meshtastic_DeviceUIConfig_GpsCoordinateFormat>;
|
||||
using NodeNameOption = MenuOption<bool>;
|
||||
using PositionMenuOption = MenuOption<int>;
|
||||
using ManageNodeOption = MenuOption<int>;
|
||||
using ClockFaceOption = MenuOption<bool>;
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
@@ -205,9 +205,11 @@ void drawScrollbar(OLEDDisplay *display, int visibleNodeRows, int totalEntries,
|
||||
void drawEntryLastHeard(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth)
|
||||
{
|
||||
bool isLeftCol = (x < SCREEN_WIDTH / 2);
|
||||
int nameMaxWidth = columnWidth - 25;
|
||||
int timeOffset = (currentResolution == ScreenResolution::High) ? (isLeftCol ? 7 : 10) : (isLeftCol ? 3 : 7);
|
||||
|
||||
const char *nodeName = getSafeNodeName(display, node, columnWidth);
|
||||
bool isMuted = (node->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0;
|
||||
|
||||
char timeStr[10];
|
||||
uint32_t seconds = sinceLastSeen(node);
|
||||
@@ -234,6 +236,13 @@ void drawEntryLastHeard(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int
|
||||
display->drawXbm(x, y + 5, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint);
|
||||
}
|
||||
}
|
||||
if (node->is_ignored || isMuted) {
|
||||
if (currentResolution == ScreenResolution::High) {
|
||||
display->drawLine(x + 8, y + 8, (isLeftCol ? 0 : x - 4) + nameMaxWidth - 17, y + 8);
|
||||
} else {
|
||||
display->drawLine(x + 4, y + 6, (isLeftCol ? 0 : x - 3) + nameMaxWidth - 4, y + 6);
|
||||
}
|
||||
}
|
||||
|
||||
int rightEdge = x + columnWidth - timeOffset;
|
||||
if (timeStr[strlen(timeStr) - 1] == 'm') // Fix the fact that our fonts don't line up well all the time
|
||||
@@ -253,6 +262,7 @@ void drawEntryHopSignal(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int
|
||||
int barsXOffset = columnWidth - barsOffset;
|
||||
|
||||
const char *nodeName = getSafeNodeName(display, node, columnWidth);
|
||||
bool isMuted = (node->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0;
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
@@ -265,6 +275,13 @@ void drawEntryHopSignal(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int
|
||||
display->drawXbm(x, y + 5, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint);
|
||||
}
|
||||
}
|
||||
if (node->is_ignored || isMuted) {
|
||||
if (currentResolution == ScreenResolution::High) {
|
||||
display->drawLine(x + 8, y + 8, (isLeftCol ? 0 : x - 4) + nameMaxWidth - 17, y + 8);
|
||||
} else {
|
||||
display->drawLine(x + 4, y + 6, (isLeftCol ? 0 : x - 3) + nameMaxWidth - 4, y + 6);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw signal strength bars
|
||||
int bars = (node->snr > 5) ? 4 : (node->snr > 0) ? 3 : (node->snr > -5) ? 2 : (node->snr > -10) ? 1 : 0;
|
||||
@@ -298,6 +315,7 @@ void drawNodeDistance(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16
|
||||
columnWidth - ((currentResolution == ScreenResolution::High) ? (isLeftCol ? 25 : 28) : (isLeftCol ? 20 : 22));
|
||||
|
||||
const char *nodeName = getSafeNodeName(display, node, columnWidth);
|
||||
bool isMuted = (node->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0;
|
||||
char distStr[10] = "";
|
||||
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
@@ -358,6 +376,13 @@ void drawNodeDistance(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16
|
||||
display->drawXbm(x, y + 5, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint);
|
||||
}
|
||||
}
|
||||
if (node->is_ignored || isMuted) {
|
||||
if (currentResolution == ScreenResolution::High) {
|
||||
display->drawLine(x + 8, y + 8, (isLeftCol ? 0 : x - 4) + nameMaxWidth - 17, y + 8);
|
||||
} else {
|
||||
display->drawLine(x + 4, y + 6, (isLeftCol ? 0 : x - 3) + nameMaxWidth - 4, y + 6);
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(distStr) > 0) {
|
||||
int offset = (currentResolution == ScreenResolution::High)
|
||||
@@ -392,6 +417,7 @@ void drawEntryCompass(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16
|
||||
columnWidth - ((currentResolution == ScreenResolution::High) ? (isLeftCol ? 25 : 28) : (isLeftCol ? 20 : 22));
|
||||
|
||||
const char *nodeName = getSafeNodeName(display, node, columnWidth);
|
||||
bool isMuted = (node->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0;
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
@@ -403,6 +429,13 @@ void drawEntryCompass(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16
|
||||
display->drawXbm(x, y + 5, smallbulletpoint_width, smallbulletpoint_height, smallbulletpoint);
|
||||
}
|
||||
}
|
||||
if (node->is_ignored || isMuted) {
|
||||
if (currentResolution == ScreenResolution::High) {
|
||||
display->drawLine(x + 8, y + 8, (isLeftCol ? 0 : x - 4) + nameMaxWidth - 17, y + 8);
|
||||
} else {
|
||||
display->drawLine(x + 4, y + 6, (isLeftCol ? 0 : x - 3) + nameMaxWidth - 4, y + 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawCompassArrow(OLEDDisplay *display, meshtastic_NodeInfoLite *node, int16_t x, int16_t y, int columnWidth, float myHeading,
|
||||
|
||||
Reference in New Issue
Block a user