diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 492ff2ae9..f94a8d991 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -31,6 +31,7 @@ along with this program. If not, see .
#include "TimeFormatters.h"
#include "draw/ClockRenderer.h"
#include "draw/DebugRenderer.h"
+#include "draw/MenuHandler.h"
#include "draw/MessageRenderer.h"
#include "draw/NodeListRenderer.h"
#include "draw/NotificationRenderer.h"
@@ -560,7 +561,7 @@ int32_t Screen::runOnce()
if (displayHeight == 0) {
displayHeight = dispdev->getHeight();
}
- handleMenuSwitch();
+ menuHandler::handleMenuSwitch();
// Show boot screen for first logo_timeout seconds, then switch to normal operation.
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
@@ -589,7 +590,7 @@ int32_t Screen::runOnce()
#ifndef DISABLE_WELCOME_UNSET
if (!NotificationRenderer::isOverlayBannerShowing() && config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
- LoraRegionPicker(0);
+ menuHandler::LoraRegionPicker(0);
}
#endif
if (!NotificationRenderer::isOverlayBannerShowing() && rebootAtMsec != 0) {
@@ -1213,7 +1214,7 @@ int Screen::handleInputEvent(const InputEvent *event)
setFastFramerate(); // Draw ASAP
ui->update();
- handleMenuSwitch();
+ menuHandler::handleMenuSwitch();
return 0;
}
/*
@@ -1315,12 +1316,12 @@ int Screen::handleInputEvent(const InputEvent *event)
: 2); // set inital selection
#endif
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.clock) {
- clockMenu();
+ menuHandler::clockMenu();
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.lora) {
- LoraRegionPicker();
+ menuHandler::LoraRegionPicker();
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage &&
devicestate.rx_text_message.from) {
- messageResponseMenu();
+ menuHandler::messageResponseMenu();
} else if (framesetInfo.positions.firstFavorite != 255 &&
this->ui->getUiState()->currentFrame >= framesetInfo.positions.firstFavorite &&
this->ui->getUiState()->currentFrame <= framesetInfo.positions.lastFavorite) {
@@ -1375,231 +1376,6 @@ bool Screen::isOverlayBannerShowing()
return NotificationRenderer::isOverlayBannerShowing();
}
-void Screen::LoraRegionPicker(uint32_t duration)
-{
- static const char *optionsArray[] = {"Back",
- "US",
- "EU_433",
- "EU_868",
- "CN",
- "JP",
- "ANZ",
- "KR",
- "TW",
- "RU",
- "IN",
- "NZ_865",
- "TH",
- "LORA_24",
- "UA_433",
- "UA_868",
- "MY_433",
- "MY_"
- "919",
- "SG_"
- "923",
- "PH_433",
- "PH_868",
- "PH_915",
- "ANZ_433"};
- showOverlayBanner(
- "Set the LoRa region", duration, optionsArray, 23,
- [](int selected) -> void {
- if (selected != 0 && config.lora.region != _meshtastic_Config_LoRaConfig_RegionCode(selected)) {
- config.lora.region = _meshtastic_Config_LoRaConfig_RegionCode(selected);
- // This is needed as we wait til picking the LoRa region to generate keys for the first time.
- if (!owner.is_licensed) {
- bool keygenSuccess = false;
- if (config.security.private_key.size == 32) {
- // public key is derived from private, so this will always have the same result.
- if (crypto->regeneratePublicKey(config.security.public_key.bytes, config.security.private_key.bytes)) {
- keygenSuccess = true;
- }
- } else {
- LOG_INFO("Generate new PKI keys");
- crypto->generateKeyPair(config.security.public_key.bytes, config.security.private_key.bytes);
- keygenSuccess = true;
- }
- if (keygenSuccess) {
- config.security.public_key.size = 32;
- config.security.private_key.size = 32;
- owner.public_key.size = 32;
- memcpy(owner.public_key.bytes, config.security.public_key.bytes, 32);
- }
- }
- config.lora.tx_enabled = true;
- initRegion();
- if (myRegion->dutyCycle < 100) {
- config.lora.ignore_mqtt = true; // Ignore MQTT by default if region has a duty cycle limit
- }
- service->reloadConfig(SEGMENT_CONFIG);
- rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
- }
- },
- 0);
-}
-
-void Screen::TwelveHourPicker()
-{
- static const char *optionsArray[] = {"Back", "12-hour", "24-hour"};
- showOverlayBanner("12/24 display?", 30000, optionsArray, 3, [](int selected) -> void {
- if (selected == 0) {
- screen->menuQueue = screen->clock_menu;
- } else if (selected == 1) {
- config.display.use_12h_clock = true;
- } else {
- config.display.use_12h_clock = false;
- }
- service->reloadConfig(SEGMENT_CONFIG);
- });
-}
-
-void Screen::TZPicker()
-{
- static const char *optionsArray[] = {"Back",
- "US/Hawaii",
- "US/Alaska",
- "US/Pacific",
- "US/Mountain",
- "US/Central",
- "US/Eastern",
- "UTC",
- "EU/Western",
- "EU/"
- "Central",
- "EU/Eastern",
- "Asia/Kolkata",
- "Asia/Hong_Kong",
- "AU/AWST",
- "AU/ACST",
- "AU/AEST",
- "Pacific/NZ"};
- showOverlayBanner("Pick Timezone", 30000, optionsArray, 17, [](int selected) -> void {
- if (selected == 0) {
- screen->menuQueue = screen->clock_menu;
- } else if (selected == 1) { // Hawaii
- strncpy(config.device.tzdef, "HST10", sizeof(config.device.tzdef));
- } else if (selected == 2) { // Alaska
- strncpy(config.device.tzdef, "AKST9AKDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
- } else if (selected == 3) { // Pacific
- strncpy(config.device.tzdef, "PST8PDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
- } else if (selected == 4) { // Mountain
- strncpy(config.device.tzdef, "MST7MDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
- } else if (selected == 5) { // Central
- strncpy(config.device.tzdef, "CST6CDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
- } else if (selected == 6) { // Eastern
- strncpy(config.device.tzdef, "EST5EDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
- } else if (selected == 7) { // UTC
- strncpy(config.device.tzdef, "UTC", sizeof(config.device.tzdef));
- } else if (selected == 8) { // EU/Western
- strncpy(config.device.tzdef, "GMT0BST,M3.5.0/1,M10.5.0", sizeof(config.device.tzdef));
- } else if (selected == 9) { // EU/Central
- strncpy(config.device.tzdef, "CET-1CEST,M3.5.0,M10.5.0/3", sizeof(config.device.tzdef));
- } else if (selected == 10) { // EU/Eastern
- strncpy(config.device.tzdef, "EET-2EEST,M3.5.0/3,M10.5.0/4", sizeof(config.device.tzdef));
- } else if (selected == 11) { // Asia/Kolkata
- strncpy(config.device.tzdef, "IST-5:30", sizeof(config.device.tzdef));
- } else if (selected == 12) { // China
- strncpy(config.device.tzdef, "HKT-8", sizeof(config.device.tzdef));
- } else if (selected == 13) { // AU/AWST
- strncpy(config.device.tzdef, "AWST-8", sizeof(config.device.tzdef));
- } else if (selected == 14) { // AU/ACST
- strncpy(config.device.tzdef, "ACST-9:30ACDT,M10.1.0,M4.1.0/3", sizeof(config.device.tzdef));
- } else if (selected == 15) { // AU/AEST
- strncpy(config.device.tzdef, "AEST-10AEDT,M10.1.0,M4.1.0/3", sizeof(config.device.tzdef));
- } else if (selected == 16) { // NZ
- strncpy(config.device.tzdef, "NZST-12NZDT,M9.5.0,M4.1.0/3", sizeof(config.device.tzdef));
- }
- if (selected != 0) {
- setenv("TZ", config.device.tzdef, 1);
- service->reloadConfig(SEGMENT_CONFIG);
- }
- });
-}
-
-void Screen::clockMenu()
-{
- static const char *optionsArray[] = {"Back", "12-hour", "Timezone"};
- showOverlayBanner("Clock Menu", 30000, optionsArray, 3, [](int selected) -> void {
- if (selected == 1) {
- screen->menuQueue = screen->twelve_hour_picker;
- screen->setInterval(0);
- runASAP = true;
- } else if (selected == 2) {
- screen->menuQueue = screen->TZ_picker;
- screen->setInterval(0);
- runASAP = true;
- }
- });
-}
-
-void Screen::messageResponseMenu()
-{
-
- static const char **optionsArrayPtr;
- int options;
- if (kb_found) {
- const char *optionsArray[] = {"Back", "Dismiss", "Reply via Preset", "Reply via Freetext"};
- optionsArrayPtr = optionsArray;
- options = 4;
- } else {
- const char *optionsArray[] = {"Back", "Dismiss", "Reply via Preset"};
- optionsArrayPtr = optionsArray;
- options = 3;
- }
-#ifdef HAS_I2S
- const char *optionsArray[] = {"Back", "Dismiss", "Reply via Preset", "Reply via Freetext", "Read Aloud"};
- optionsArrayPtr = optionsArray;
- options = 5;
-#endif
- showOverlayBanner("Message Action?", 30000, optionsArrayPtr, options, [](int selected) -> void {
- if (selected == 1) {
- screen->dismissCurrentFrame();
- } else if (selected == 2) {
- if (devicestate.rx_text_message.to == NODENUM_BROADCAST) {
- cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST, devicestate.rx_text_message.channel);
- } else {
- cannedMessageModule->LaunchWithDestination(devicestate.rx_text_message.from);
- }
- } else if (selected == 3) {
- if (devicestate.rx_text_message.to == NODENUM_BROADCAST) {
- cannedMessageModule->LaunchFreetextWithDestination(NODENUM_BROADCAST, devicestate.rx_text_message.channel);
- } else {
- cannedMessageModule->LaunchFreetextWithDestination(devicestate.rx_text_message.from);
- }
- }
-#ifdef HAS_I2S
- else if (selected == 4) {
- const meshtastic_MeshPacket &mp = devicestate.rx_text_message;
- const char *msg = reinterpret_cast(mp.decoded.payload.bytes);
-
- audioThread->readAloud(msg);
- }
-#endif
- });
-}
-
-void Screen::handleMenuSwitch()
-{
- switch (menuQueue) {
- case menu_none:
- break;
- case lora_picker:
- LoraRegionPicker();
- break;
- case TZ_picker:
- TZPicker();
- break;
- case twelve_hour_picker:
- TwelveHourPicker();
- break;
- case clock_menu:
- clockMenu();
- break;
- }
- menuQueue = menu_none;
-}
-
} // namespace graphics
#else
diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h
index 6c339475c..8a1a71334 100644
--- a/src/graphics/Screen.h
+++ b/src/graphics/Screen.h
@@ -201,9 +201,6 @@ class Screen : public concurrency::OSThread
size_t frameCount = 0; // Total number of active frames
~Screen();
- enum screenMenus { menu_none, lora_picker, TZ_picker, twelve_hour_picker, clock_menu };
- screenMenus menuQueue = menu_none;
-
// Which frame we want to be displayed, after we regen the frameset by calling setFrames
enum FrameFocus : uint8_t {
FOCUS_DEFAULT, // No specific frame
@@ -604,12 +601,6 @@ class Screen : public concurrency::OSThread
void handleShowNextFrame();
void handleShowPrevFrame();
void handleStartFirmwareUpdateScreen();
- void handleMenuSwitch();
- void clockMenu();
- void TZPicker();
- void TwelveHourPicker();
- void LoraRegionPicker(uint32_t duration = 30000);
- void messageResponseMenu();
// Info collected by setFrames method.
// Index location of specific frames.
@@ -685,5 +676,6 @@ class Screen : public concurrency::OSThread
// Extern declarations for function symbols used in UIRenderer
extern std::vector functionSymbol;
extern std::string functionSymbolString;
+extern graphics::Screen *screen;
#endif
\ No newline at end of file
diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp
new file mode 100644
index 000000000..c68ebfcc2
--- /dev/null
+++ b/src/graphics/draw/MenuHandler.cpp
@@ -0,0 +1,242 @@
+#include "configuration.h"
+#if HAS_SCREEN
+#include "MenuHandler.h"
+#include "MeshRadio.h"
+#include "MeshService.h"
+#include "NodeDB.h"
+#include "graphics/Screen.h"
+#include "main.h"
+#include "modules/CannedMessageModule.h"
+
+namespace graphics
+{
+menuHandler::screenMenus menuHandler::menuQueue = menu_none;
+
+void menuHandler::LoraRegionPicker(uint32_t duration)
+{
+ static const char *optionsArray[] = {"Back",
+ "US",
+ "EU_433",
+ "EU_868",
+ "CN",
+ "JP",
+ "ANZ",
+ "KR",
+ "TW",
+ "RU",
+ "IN",
+ "NZ_865",
+ "TH",
+ "LORA_24",
+ "UA_433",
+ "UA_868",
+ "MY_433",
+ "MY_"
+ "919",
+ "SG_"
+ "923",
+ "PH_433",
+ "PH_868",
+ "PH_915",
+ "ANZ_433"};
+ screen->showOverlayBanner(
+ "Set the LoRa region", duration, optionsArray, 23,
+ [](int selected) -> void {
+ if (selected != 0 && config.lora.region != _meshtastic_Config_LoRaConfig_RegionCode(selected)) {
+ config.lora.region = _meshtastic_Config_LoRaConfig_RegionCode(selected);
+ // This is needed as we wait til picking the LoRa region to generate keys for the first time.
+ if (!owner.is_licensed) {
+ bool keygenSuccess = false;
+ if (config.security.private_key.size == 32) {
+ // public key is derived from private, so this will always have the same result.
+ if (crypto->regeneratePublicKey(config.security.public_key.bytes, config.security.private_key.bytes)) {
+ keygenSuccess = true;
+ }
+ } else {
+ LOG_INFO("Generate new PKI keys");
+ crypto->generateKeyPair(config.security.public_key.bytes, config.security.private_key.bytes);
+ keygenSuccess = true;
+ }
+ if (keygenSuccess) {
+ config.security.public_key.size = 32;
+ config.security.private_key.size = 32;
+ owner.public_key.size = 32;
+ memcpy(owner.public_key.bytes, config.security.public_key.bytes, 32);
+ }
+ }
+ config.lora.tx_enabled = true;
+ initRegion();
+ if (myRegion->dutyCycle < 100) {
+ config.lora.ignore_mqtt = true; // Ignore MQTT by default if region has a duty cycle limit
+ }
+ service->reloadConfig(SEGMENT_CONFIG);
+ rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
+ }
+ },
+ 0);
+}
+
+void menuHandler::TwelveHourPicker()
+{
+ static const char *optionsArray[] = {"Back", "12-hour", "24-hour"};
+ screen->showOverlayBanner("12/24 display?", 30000, optionsArray, 3, [](int selected) -> void {
+ if (selected == 0) {
+ menuHandler::menuQueue = menuHandler::clock_menu;
+ } else if (selected == 1) {
+ config.display.use_12h_clock = true;
+ } else {
+ config.display.use_12h_clock = false;
+ }
+ service->reloadConfig(SEGMENT_CONFIG);
+ });
+}
+
+void menuHandler::TZPicker()
+{
+ static const char *optionsArray[] = {"Back",
+ "US/Hawaii",
+ "US/Alaska",
+ "US/Pacific",
+ "US/Mountain",
+ "US/Central",
+ "US/Eastern",
+ "UTC",
+ "EU/Western",
+ "EU/"
+ "Central",
+ "EU/Eastern",
+ "Asia/Kolkata",
+ "Asia/Hong_Kong",
+ "AU/AWST",
+ "AU/ACST",
+ "AU/AEST",
+ "Pacific/NZ"};
+ screen->showOverlayBanner("Pick Timezone", 30000, optionsArray, 17, [](int selected) -> void {
+ if (selected == 0) {
+ menuHandler::menuQueue = menuHandler::clock_menu;
+ } else if (selected == 1) { // Hawaii
+ strncpy(config.device.tzdef, "HST10", sizeof(config.device.tzdef));
+ } else if (selected == 2) { // Alaska
+ strncpy(config.device.tzdef, "AKST9AKDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
+ } else if (selected == 3) { // Pacific
+ strncpy(config.device.tzdef, "PST8PDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
+ } else if (selected == 4) { // Mountain
+ strncpy(config.device.tzdef, "MST7MDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
+ } else if (selected == 5) { // Central
+ strncpy(config.device.tzdef, "CST6CDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
+ } else if (selected == 6) { // Eastern
+ strncpy(config.device.tzdef, "EST5EDT,M3.2.0,M11.1.0", sizeof(config.device.tzdef));
+ } else if (selected == 7) { // UTC
+ strncpy(config.device.tzdef, "UTC", sizeof(config.device.tzdef));
+ } else if (selected == 8) { // EU/Western
+ strncpy(config.device.tzdef, "GMT0BST,M3.5.0/1,M10.5.0", sizeof(config.device.tzdef));
+ } else if (selected == 9) { // EU/Central
+ strncpy(config.device.tzdef, "CET-1CEST,M3.5.0,M10.5.0/3", sizeof(config.device.tzdef));
+ } else if (selected == 10) { // EU/Eastern
+ strncpy(config.device.tzdef, "EET-2EEST,M3.5.0/3,M10.5.0/4", sizeof(config.device.tzdef));
+ } else if (selected == 11) { // Asia/Kolkata
+ strncpy(config.device.tzdef, "IST-5:30", sizeof(config.device.tzdef));
+ } else if (selected == 12) { // China
+ strncpy(config.device.tzdef, "HKT-8", sizeof(config.device.tzdef));
+ } else if (selected == 13) { // AU/AWST
+ strncpy(config.device.tzdef, "AWST-8", sizeof(config.device.tzdef));
+ } else if (selected == 14) { // AU/ACST
+ strncpy(config.device.tzdef, "ACST-9:30ACDT,M10.1.0,M4.1.0/3", sizeof(config.device.tzdef));
+ } else if (selected == 15) { // AU/AEST
+ strncpy(config.device.tzdef, "AEST-10AEDT,M10.1.0,M4.1.0/3", sizeof(config.device.tzdef));
+ } else if (selected == 16) { // NZ
+ strncpy(config.device.tzdef, "NZST-12NZDT,M9.5.0,M4.1.0/3", sizeof(config.device.tzdef));
+ }
+ if (selected != 0) {
+ setenv("TZ", config.device.tzdef, 1);
+ service->reloadConfig(SEGMENT_CONFIG);
+ }
+ });
+}
+
+void menuHandler::clockMenu()
+{
+ static const char *optionsArray[] = {"Back", "12-hour", "Timezone"};
+ screen->showOverlayBanner("Clock Menu", 30000, optionsArray, 3, [](int selected) -> void {
+ if (selected == 1) {
+ menuHandler::menuQueue = menuHandler::twelve_hour_picker;
+ screen->setInterval(0);
+ runASAP = true;
+ } else if (selected == 2) {
+ menuHandler::menuQueue = menuHandler::TZ_picker;
+ screen->setInterval(0);
+ runASAP = true;
+ }
+ });
+}
+
+void menuHandler::messageResponseMenu()
+{
+
+ static const char **optionsArrayPtr;
+ int options;
+ if (kb_found) {
+ const char *optionsArray[] = {"Back", "Dismiss", "Reply via Preset", "Reply via Freetext"};
+ optionsArrayPtr = optionsArray;
+ options = 4;
+ } else {
+ const char *optionsArray[] = {"Back", "Dismiss", "Reply via Preset"};
+ optionsArrayPtr = optionsArray;
+ options = 3;
+ }
+#ifdef HAS_I2S
+ const char *optionsArray[] = {"Back", "Dismiss", "Reply via Preset", "Reply via Freetext", "Read Aloud"};
+ optionsArrayPtr = optionsArray;
+ options = 5;
+#endif
+ screen->showOverlayBanner("Message Action?", 30000, optionsArrayPtr, options, [](int selected) -> void {
+ if (selected == 1) {
+ screen->dismissCurrentFrame();
+ } else if (selected == 2) {
+ if (devicestate.rx_text_message.to == NODENUM_BROADCAST) {
+ cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST, devicestate.rx_text_message.channel);
+ } else {
+ cannedMessageModule->LaunchWithDestination(devicestate.rx_text_message.from);
+ }
+ } else if (selected == 3) {
+ if (devicestate.rx_text_message.to == NODENUM_BROADCAST) {
+ cannedMessageModule->LaunchFreetextWithDestination(NODENUM_BROADCAST, devicestate.rx_text_message.channel);
+ } else {
+ cannedMessageModule->LaunchFreetextWithDestination(devicestate.rx_text_message.from);
+ }
+ }
+#ifdef HAS_I2S
+ else if (selected == 4) {
+ const meshtastic_MeshPacket &mp = devicestate.rx_text_message;
+ const char *msg = reinterpret_cast(mp.decoded.payload.bytes);
+
+ audioThread->readAloud(msg);
+ }
+#endif
+ });
+}
+
+void menuHandler::handleMenuSwitch()
+{
+ switch (menuQueue) {
+ case menu_none:
+ break;
+ case lora_picker:
+ LoraRegionPicker();
+ break;
+ case TZ_picker:
+ TZPicker();
+ break;
+ case twelve_hour_picker:
+ TwelveHourPicker();
+ break;
+ case clock_menu:
+ clockMenu();
+ break;
+ }
+ menuQueue = menu_none;
+}
+
+} // namespace graphics
+
+#endif
\ No newline at end of file
diff --git a/src/graphics/draw/MenuHandler.h b/src/graphics/draw/MenuHandler.h
new file mode 100644
index 000000000..a4c9d6fe6
--- /dev/null
+++ b/src/graphics/draw/MenuHandler.h
@@ -0,0 +1,19 @@
+#include "configuration.h"
+namespace graphics
+{
+
+class menuHandler
+{
+ public:
+ enum screenMenus { menu_none, lora_picker, TZ_picker, twelve_hour_picker, clock_menu };
+ static screenMenus menuQueue;
+
+ static void LoraRegionPicker(uint32_t duration = 30000);
+ static void handleMenuSwitch();
+ static void clockMenu();
+ static void TZPicker();
+ static void TwelveHourPicker();
+ static void messageResponseMenu();
+};
+
+} // namespace graphics
\ No newline at end of file