Skip to content

BaseUI Show/Hide Frame Functionality #7382

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 74 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
42516f5
Rename System Frame (from Memory) and add Dismiss Frame
Xaositek Jul 19, 2025
3d53ead
Dismissing more menus now available
Xaositek Jul 19, 2025
964afd0
Add dismissing the GPS screen
Xaositek Jul 19, 2025
ff8275e
Move Dismiss into a Generic Confirmation
Xaositek Jul 19, 2025
7e067f5
Create LoRa Menu, move Region Picker into submenu, add Dismiss Frame …
Xaositek Jul 19, 2025
e6be655
Dismiss Clock Frame
Xaositek Jul 19, 2025
c871775
Add Restore All Frames option
Xaositek Jul 19, 2025
da8e70f
Rename "Dismissed" to "Hidden" and relabeled menu options
Xaositek Jul 19, 2025
8bede6d
Hide Frame should be last option
Xaositek Jul 19, 2025
4badb1c
Fix misspelling in EInk
Xaositek Jul 19, 2025
a7ce4f2
Consistent Language Throughout - Restore All Frames
Xaositek Jul 19, 2025
799e6bc
Merge branch 'master' into dismiss_frames
Xaositek Jul 19, 2025
eb6d9a1
Merge branch 'master' into dismiss_frames
Xaositek Jul 20, 2025
efdd24b
Merge branch 'master' into dismiss_frames
Xaositek Jul 20, 2025
5a65b40
Merge branch 'master' into dismiss_frames
Xaositek Jul 20, 2025
51c1bcf
Merge branch 'master' into dismiss_frames
Xaositek Jul 20, 2025
1881a85
Switch to concise menu to manage show/hide
Xaositek Jul 20, 2025
228656b
Counting is hard sometimes
Xaositek Jul 20, 2025
f84217a
Restore menu options necessary to fundamentally dismiss items
Xaositek Jul 21, 2025
a60002a
Merge branch 'master' into dismiss_frames
Xaositek Jul 21, 2025
a97e40d
Show/Hide Favorites as an option
Xaositek Jul 21, 2025
1b3b3cf
Merge branch 'master' into dismiss_frames
Xaositek Jul 21, 2025
7834f59
Merge branch 'master' into dismiss_frames
Xaositek Jul 21, 2025
adce124
Merge branch 'master' into dismiss_frames
Xaositek Jul 21, 2025
2bd31cb
Merge branch 'master' into dismiss_frames
Xaositek Jul 21, 2025
8eb6859
Don't return to top of the list when toggling values
Xaositek Jul 21, 2025
d30cb59
Merge branch 'master' into dismiss_frames
Xaositek Jul 22, 2025
019a6dc
Merge branch 'master' into dismiss_frames
Xaositek Jul 22, 2025
6e41969
Merge branch 'master' into dismiss_frames
Xaositek Jul 22, 2025
4637197
Merge branch 'master' into dismiss_frames
Xaositek Jul 23, 2025
760b583
Merge branch 'master' into dismiss_frames
Xaositek Jul 23, 2025
6612b6d
Don't change VSCode Settings
Xaositek Jul 23, 2025
2c538a0
Merge branch 'master' into dismiss_frames
Xaositek Jul 23, 2025
1d5cb20
Merge branch 'master' into dismiss_frames
Xaositek Jul 24, 2025
c5db9fc
Merge branch 'master' into dismiss_frames
Xaositek Jul 24, 2025
ebe0a07
Merge branch 'master' into dismiss_frames
Xaositek Jul 25, 2025
c21b8ee
Merge branch 'master' into dismiss_frames
Xaositek Jul 25, 2025
d7773ba
Merge branch 'master' into dismiss_frames
Xaositek Jul 26, 2025
52eaf89
Merge branch 'master' into dismiss_frames
Xaositek Jul 27, 2025
3b28b16
Merge branch 'master' into dismiss_frames
Xaositek Jul 28, 2025
7d7e58b
Merge branch 'master' into dismiss_frames
Xaositek Jul 28, 2025
d825bb3
Merge branch 'master' into dismiss_frames
Xaositek Jul 30, 2025
f3ffc47
Merge branch 'master' into dismiss_frames
Xaositek Jul 31, 2025
b4d618e
Merge branch 'master' into dismiss_frames
Xaositek Jul 31, 2025
aab0ecc
Merge branch 'master' into dismiss_frames
Xaositek Jul 31, 2025
4a88c24
Merge branch 'master' into dismiss_frames
Xaositek Aug 4, 2025
efd7064
Merge branch 'master' into dismiss_frames
Xaositek Aug 4, 2025
f416f3c
Merge branch 'master' into dismiss_frames
Xaositek Aug 5, 2025
4b755a9
Merge branch 'master' into dismiss_frames
Xaositek Aug 6, 2025
13f8514
Merge branch 'master' into dismiss_frames
Xaositek Aug 7, 2025
5939787
Merge branch 'master' into dismiss_frames
Xaositek Aug 10, 2025
ba3172c
Merge branch 'master' into dismiss_frames
Xaositek Aug 11, 2025
0768c0e
Merge branch 'master' into dismiss_frames
Xaositek Aug 11, 2025
f22ad15
Merge branch 'master' into dismiss_frames
Xaositek Aug 12, 2025
e08c037
Merge branch 'master' into dismiss_frames
Xaositek Aug 12, 2025
ea58069
Merge branch 'master' into dismiss_frames
Xaositek Aug 12, 2025
1fe3b2e
Merge branch 'master' into dismiss_frames
Xaositek Aug 13, 2025
6de9b2e
Merge branch 'master' into dismiss_frames
Xaositek Aug 13, 2025
940fe17
Merge branch 'master' into dismiss_frames
Xaositek Aug 15, 2025
1ffa908
Merge branch 'master' into dismiss_frames
Xaositek Aug 15, 2025
9fcca78
Merge branch 'master' into dismiss_frames
Xaositek Aug 16, 2025
657af45
Merge branch 'master' into dismiss_frames
Xaositek Aug 16, 2025
358227a
Merge branch 'master' into dismiss_frames
Xaositek Aug 17, 2025
3de8ab0
Finalize merge conflict fix
Xaositek Aug 17, 2025
77ee859
Merge branch 'master' into dismiss_frames
Xaositek Aug 18, 2025
8e3beb6
Merge branch 'master' into dismiss_frames
Xaositek Aug 19, 2025
98298ce
Merge branch 'master' into dismiss_frames
Xaositek Aug 19, 2025
85637cc
Merge branch 'master' into dismiss_frames
Xaositek Aug 20, 2025
51f2ac9
Merge branch 'master' into dismiss_frames
Xaositek Aug 20, 2025
5bcd09e
Merge branch 'master' into dismiss_frames
Xaositek Aug 20, 2025
9ef9ce8
Merge branch 'master' into dismiss_frames
Xaositek Aug 21, 2025
ee5ce78
Merge remote-tracking branch 'origin/develop' into dismiss_frames
Xaositek Aug 21, 2025
2b92fb7
Tweak wording for Send Position vs Node Info if the device has GPS
Xaositek Aug 23, 2025
fcc1985
Only hide GPS related options when GPS is not present
Xaositek Aug 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 152 additions & 69 deletions src/graphics/Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -941,71 +941,86 @@ void Screen::setFrames(FrameFocus focus)
}

#if defined(DISPLAY_CLOCK_FRAME)
fsi.positions.clock = numframes;
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
: graphics::ClockRenderer::drawDigitalClockFrame;
indicatorIcons.push_back(digital_icon_clock);
if (!hiddenFrames.clock) {
fsi.positions.clock = numframes;
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
: graphics::ClockRenderer::drawDigitalClockFrame;
indicatorIcons.push_back(digital_icon_clock);
}
#endif

// Declare this early so it’s available in FOCUS_PRESERVE block
bool willInsertTextMessage = shouldDrawMessage(&devicestate.rx_text_message);

fsi.positions.home = numframes;
normalFrames[numframes++] = graphics::UIRenderer::drawDeviceFocused;
indicatorIcons.push_back(icon_home);
if (!hiddenFrames.home) {
fsi.positions.home = numframes;
normalFrames[numframes++] = graphics::UIRenderer::drawDeviceFocused;
indicatorIcons.push_back(icon_home);
}

fsi.positions.textMessage = numframes;
normalFrames[numframes++] = graphics::MessageRenderer::drawTextMessageFrame;
indicatorIcons.push_back(icon_mail);

#ifndef USE_EINK
fsi.positions.nodelist = numframes;
normalFrames[numframes++] = graphics::NodeListRenderer::drawDynamicNodeListScreen;
indicatorIcons.push_back(icon_nodes);
if (!hiddenFrames.nodelist) {
fsi.positions.nodelist = numframes;
normalFrames[numframes++] = graphics::NodeListRenderer::drawDynamicNodeListScreen;
indicatorIcons.push_back(icon_nodes);
}
#endif

// Show detailed node views only on E-Ink builds
#ifdef USE_EINK
fsi.positions.nodelist_lastheard = numframes;
normalFrames[numframes++] = graphics::NodeListRenderer::drawLastHeardScreen;
indicatorIcons.push_back(icon_nodes);

fsi.positions.nodelist_hopsignal = numframes;
normalFrames[numframes++] = graphics::NodeListRenderer::drawHopSignalScreen;
indicatorIcons.push_back(icon_signal);

fsi.positions.nodelist_distance = numframes;
normalFrames[numframes++] = graphics::NodeListRenderer::drawDistanceScreen;
indicatorIcons.push_back(icon_distance);
if (!hiddenFrames.nodelist_lastheard) {
fsi.positions.nodelist_lastheard = numframes;
normalFrames[numframes++] = graphics::NodeListRenderer::drawLastHeardScreen;
indicatorIcons.push_back(icon_nodes);
}
if (!hiddenFrames.nodelist_hopsignal) {
fsi.positions.nodelist_hopsignal = numframes;
normalFrames[numframes++] = graphics::NodeListRenderer::drawHopSignalScreen;
indicatorIcons.push_back(icon_signal);
}
if (!hiddenFrames.nodelist_distance) {
fsi.positions.nodelist_distance = numframes;
normalFrames[numframes++] = graphics::NodeListRenderer::drawDistanceScreen;
indicatorIcons.push_back(icon_distance);
}
#endif
#if HAS_GPS
fsi.positions.nodelist_bearings = numframes;
normalFrames[numframes++] = graphics::NodeListRenderer::drawNodeListWithCompasses;
indicatorIcons.push_back(icon_list);

fsi.positions.gps = numframes;
normalFrames[numframes++] = graphics::UIRenderer::drawCompassAndLocationScreen;
indicatorIcons.push_back(icon_compass);
if (!hiddenFrames.nodelist_bearings) {
fsi.positions.nodelist_bearings = numframes;
normalFrames[numframes++] = graphics::NodeListRenderer::drawNodeListWithCompasses;
indicatorIcons.push_back(icon_list);
}
if (!hiddenFrames.gps) {
fsi.positions.gps = numframes;
normalFrames[numframes++] = graphics::UIRenderer::drawCompassAndLocationScreen;
indicatorIcons.push_back(icon_compass);
}
#endif
if (RadioLibInterface::instance) {
if (RadioLibInterface::instance && !hiddenFrames.lora) {
fsi.positions.lora = numframes;
normalFrames[numframes++] = graphics::DebugRenderer::drawLoRaFocused;
indicatorIcons.push_back(icon_radio);
}
if (!dismissedFrames.memory) {
fsi.positions.memory = numframes;
normalFrames[numframes++] = graphics::DebugRenderer::drawMemoryUsage;
indicatorIcons.push_back(icon_memory);
if (!hiddenFrames.system) {
fsi.positions.system = numframes;
normalFrames[numframes++] = graphics::DebugRenderer::drawSystemScreen;
indicatorIcons.push_back(icon_system);
}
#if !defined(DISPLAY_CLOCK_FRAME)
fsi.positions.clock = numframes;
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
: graphics::ClockRenderer::drawDigitalClockFrame;
indicatorIcons.push_back(digital_icon_clock);
if (!hiddenFrames.clock) {
fsi.positions.clock = numframes;
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
: graphics::ClockRenderer::drawDigitalClockFrame;
indicatorIcons.push_back(digital_icon_clock);
}
#endif

#if HAS_WIFI && !defined(ARCH_PORTDUINO)
if (!dismissedFrames.wifi && isWifiAvailable()) {
if (!hiddenFrames.wifi && isWifiAvailable()) {
fsi.positions.wifi = numframes;
normalFrames[numframes++] = graphics::DebugRenderer::drawDebugInfoWiFiTrampoline;
indicatorIcons.push_back(icon_wifi);
Expand Down Expand Up @@ -1047,27 +1062,29 @@ void Screen::setFrames(FrameFocus focus)
if (numMeshNodes > 0)
numMeshNodes--;

// Temporary array to hold favorite node frames
std::vector<FrameCallback> favoriteFrames;
if (!hiddenFrames.show_favorites) {
// Temporary array to hold favorite node frames
std::vector<FrameCallback> favoriteFrames;

for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) {
favoriteFrames.push_back(graphics::UIRenderer::drawNodeInfo);
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) {
favoriteFrames.push_back(graphics::UIRenderer::drawNodeInfo);
}
}
}

// Insert favorite frames *after* collecting them all
if (!favoriteFrames.empty()) {
fsi.positions.firstFavorite = numframes;
for (const auto &f : favoriteFrames) {
normalFrames[numframes++] = f;
indicatorIcons.push_back(icon_node);
// Insert favorite frames *after* collecting them all
if (!favoriteFrames.empty()) {
fsi.positions.firstFavorite = numframes;
for (const auto &f : favoriteFrames) {
normalFrames[numframes++] = f;
indicatorIcons.push_back(icon_node);
}
fsi.positions.lastFavorite = numframes - 1;
} else {
fsi.positions.firstFavorite = 255;
fsi.positions.lastFavorite = 255;
}
fsi.positions.lastFavorite = numframes - 1;
} else {
fsi.positions.firstFavorite = 255;
fsi.positions.lastFavorite = 255;
}

fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE
Expand Down Expand Up @@ -1106,7 +1123,7 @@ void Screen::setFrames(FrameFocus focus)
ui->switchToFrame(fsi.positions.clock);
break;
case FOCUS_SYSTEM:
ui->switchToFrame(fsi.positions.memory);
ui->switchToFrame(fsi.positions.system);
break;

case FOCUS_PRESERVE:
Expand Down Expand Up @@ -1134,30 +1151,96 @@ void Screen::setFrameImmediateDraw(FrameCallback *drawFrames)
setFastFramerate();
}

void Screen::toggleFrameVisibility(const std::string &frameName)
{
#ifndef USE_EINK
if (frameName == "nodelist") {
hiddenFrames.nodelist = !hiddenFrames.nodelist;
}
#endif
#ifdef USE_EINK
if (frameName == "nodelist_lastheard") {
hiddenFrames.nodelist_lastheard = !hiddenFrames.nodelist_lastheard;
}
if (frameName == "nodelist_hopsignal") {
hiddenFrames.nodelist_hopsignal = !hiddenFrames.nodelist_hopsignal;
}
if (frameName == "nodelist_distance") {
hiddenFrames.nodelist_distance = !hiddenFrames.nodelist_distance;
}
#endif
#if HAS_GPS
if (frameName == "nodelist_bearings") {
hiddenFrames.nodelist_bearings = !hiddenFrames.nodelist_bearings;
}
if (frameName == "gps") {
hiddenFrames.gps = !hiddenFrames.gps;
}
#endif
if (frameName == "lora") {
hiddenFrames.lora = !hiddenFrames.lora;
}
if (frameName == "clock") {
hiddenFrames.clock = !hiddenFrames.clock;
}
if (frameName == "show_favorites") {
hiddenFrames.show_favorites = !hiddenFrames.show_favorites;
}
}

bool Screen::isFrameHidden(const std::string &frameName) const
{
#ifndef USE_EINK
if (frameName == "nodelist")
return hiddenFrames.nodelist;
#endif
#ifdef USE_EINK
if (frameName == "nodelist_lastheard")
return hiddenFrames.nodelist_lastheard;
if (frameName == "nodelist_hopsignal")
return hiddenFrames.nodelist_hopsignal;
if (frameName == "nodelist_distance")
return hiddenFrames.nodelist_distance;
#endif
#if HAS_GPS
if (frameName == "nodelist_bearings")
return hiddenFrames.nodelist_bearings;
if (frameName == "gps")
return hiddenFrames.gps;
#endif
if (frameName == "lora")
return hiddenFrames.lora;
if (frameName == "clock")
return hiddenFrames.clock;
if (frameName == "show_favorites")
return hiddenFrames.show_favorites;

return false;
}

// Dismisses the currently displayed screen frame, if possible
// Relevant for text message, waypoint, others in future?
// Triggered with a CardKB keycombo
void Screen::dismissCurrentFrame()
void Screen::hideCurrentFrame()
{
uint8_t currentFrame = ui->getUiState()->currentFrame;
bool dismissed = false;

if (currentFrame == framesetInfo.positions.textMessage && devicestate.has_rx_text_message) {
LOG_INFO("Dismiss Text Message");
LOG_INFO("Hide Text Message");
devicestate.has_rx_text_message = false;
memset(&devicestate.rx_text_message, 0, sizeof(devicestate.rx_text_message));
} else if (currentFrame == framesetInfo.positions.waypoint && devicestate.has_rx_waypoint) {
LOG_DEBUG("Dismiss Waypoint");
LOG_DEBUG("Hide Waypoint");
devicestate.has_rx_waypoint = false;
dismissedFrames.waypoint = true;
hiddenFrames.waypoint = true;
dismissed = true;
} else if (currentFrame == framesetInfo.positions.wifi) {
LOG_DEBUG("Dismiss WiFi Screen");
dismissedFrames.wifi = true;
LOG_DEBUG("Hide WiFi Screen");
hiddenFrames.wifi = true;
dismissed = true;
} else if (currentFrame == framesetInfo.positions.memory) {
LOG_INFO("Dismiss Memory");
dismissedFrames.memory = true;
} else if (currentFrame == framesetInfo.positions.lora) {
LOG_INFO("Hide LoRa");
hiddenFrames.lora = true;
dismissed = true;
}

Expand Down Expand Up @@ -1309,7 +1392,7 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
// Outgoing message (likely sent from phone)
devicestate.has_rx_text_message = false;
memset(&devicestate.rx_text_message, 0, sizeof(devicestate.rx_text_message));
dismissedFrames.textMessage = true;
hiddenFrames.textMessage = true;
hasUnreadMessage = false; // Clear unread state when user replies

setFrames(FOCUS_PRESERVE); // Stay on same frame, silently update frame list
Expand Down Expand Up @@ -1439,7 +1522,7 @@ int Screen::handleInputEvent(const InputEvent *event)
} else if (event->inputEvent == INPUT_BROKER_SELECT) {
if (this->ui->getUiState()->currentFrame == framesetInfo.positions.home) {
menuHandler::homeBaseMenu();
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.memory) {
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.system) {
menuHandler::systemBaseMenu();
#if HAS_GPS
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.gps && gps) {
Expand All @@ -1448,7 +1531,7 @@ int Screen::handleInputEvent(const InputEvent *event)
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.clock) {
menuHandler::clockMenu();
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.lora) {
menuHandler::LoraRegionPicker();
menuHandler::loraMenu();
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage) {
if (devicestate.rx_text_message.from) {
menuHandler::messageResponseMenu();
Expand Down
30 changes: 25 additions & 5 deletions src/graphics/Screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,11 @@ class Screen : public concurrency::OSThread
void setSSLFrames();

// Dismiss the currently focussed frame, if possible (e.g. text message, waypoint)
void dismissCurrentFrame();
void hideCurrentFrame();

// Menu-driven Show / Hide Toggle
void toggleFrameVisibility(const std::string &frameName);
bool isFrameHidden(const std::string &frameName) const;

#ifdef USE_EINK
/// Draw an image to remain on E-Ink display after screen off
Expand Down Expand Up @@ -655,7 +659,7 @@ class Screen : public concurrency::OSThread
uint8_t settings = 255;
uint8_t wifi = 255;
uint8_t deviceFocused = 255;
uint8_t memory = 255;
uint8_t system = 255;
uint8_t gps = 255;
uint8_t home = 255;
uint8_t textMessage = 255;
Expand All @@ -673,12 +677,28 @@ class Screen : public concurrency::OSThread
uint8_t frameCount = 0;
} framesetInfo;

struct DismissedFrames {
struct hiddenFrames {
bool textMessage = false;
bool waypoint = false;
bool wifi = false;
bool memory = false;
} dismissedFrames;
bool system = false;
bool home = false;
bool clock = false;
#ifndef USE_EINK
bool nodelist = false;
#endif
#ifdef USE_EINK
bool nodelist_lastheard = false;
bool nodelist_hopsignal = false;
bool nodelist_distance = false;
#endif
#if HAS_GPS
bool nodelist_bearings = false;
bool gps = false;
#endif
bool lora = false;
bool show_favorites = false;
} hiddenFrames;

/// Try to start drawing ASAP
void setFastFramerate();
Expand Down
2 changes: 1 addition & 1 deletion src/graphics/draw/DebugRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
// ****************************
// * System Screen *
// ****************************
void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->clear();
display->setFont(FONT_SMALL);
Expand Down
4 changes: 2 additions & 2 deletions src/graphics/draw/DebugRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ void drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state
// LoRa information display
void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);

// Memory screen display
void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
// System screen display
void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
} // namespace DebugRenderer

} // namespace graphics
Loading