mirror of
https://github.com/m5stack/meshtastic-pure-m5stack.git
synced 2026-05-20 11:42:48 -07:00
2.7 fixes w2 (#7148)
* Initial work on splitting notification renderer into components for reuse * More progress * Fix notification popup * more fix, less crash * Adjustments for OLED on keeping menus tidy, added Bluetooth Toggle to Home frame. Also widen the frame slightly if you have a scroll bar * Small changes for EInk to not crowd elements * Change System frame menu over to better match actions; added color picker for T114 * Fix build errors and add T190 for testing * Logic gates are hard sometimes * Screen Color Picker changes, defined Yellow as a Color. * Additional colors and tuning * Abandon std::sort in NodeDB, and associated fixes (#7175) * Generate short name for nodes that don't have user yet * Add reboot menu * Sort fixes * noop sort option to avoid infinite loop * Refactor Overlay Banner * Continuing work on Color Picker * Add BaseUI menus to add and remove Favorited Nodes * Create TFT_MESH_OVERRIDE for variants.h and defined colors * Trigger a NodeStatus update at the end of setup() to get fresh data on display at boot. * T114 defaults to White, Yellow is now bright Yellow * Revert "T114 defaults to White, Yellow is now bright Yellow" This reverts commit 8d05e17f11eb48c42460176317893a50abd2eeb2. * Only show OEM text if not OLED * Adjust OEM logo to maximize visible area * Start plumbing in Color Picker changes * Finished plumbing * Fix warning * Revert "Fix warning" This reverts commit 2e8aecd52d6f5b9058e0bde09b72ece43a5f3a48. * Fix display not fully redrawing * T-Deck should get color too * Emote Revamp * Update emotes.cpp * Poo Emote fix * Trunk fix * Add secret test menu and number picker * Missed bits * Save colors between reboots * Save Clock Face election to protobuf * Make reboot first, then settings * Add padding for single line pop-ups * Compass saving and faster menus * Resolve build issue with Excluding GPS * Resolve issue with memory bars on EInk * Add brightness settings for supported screen (#7182) * Add brightness menu. * add loop destination selection. * Bring back color (and sanity) to the menus! * Trunk --------- Co-authored-by: Ben Meadors <benmmeadors@gmail.com> Co-authored-by: Jason P <applewiz@mac.com> Co-authored-by: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Co-authored-by: Wilson <m.tools@qq.com>
This commit is contained in:
co-authored by
Ben Meadors
Jason P
HarukiToreda
Wilson
parent
3fdefe8289
commit
a6be2e46ed
+1
-1
Submodule protobufs updated: 5ef7aec959...386fa53c15
+2
-1
@@ -13,5 +13,6 @@ enum class Cmd {
|
||||
START_FIRMWARE_UPDATE_SCREEN,
|
||||
STOP_BOOT_SCREEN,
|
||||
SHOW_PREV_FRAME,
|
||||
SHOW_NEXT_FRAME
|
||||
SHOW_NEXT_FRAME,
|
||||
NOOP
|
||||
};
|
||||
+120
-41
@@ -69,6 +69,8 @@ using graphics::Emote;
|
||||
using graphics::emotes;
|
||||
using graphics::numEmotes;
|
||||
|
||||
extern uint16_t TFT_MESH;
|
||||
|
||||
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#endif
|
||||
@@ -135,10 +137,66 @@ extern bool hasUnreadMessage;
|
||||
// Displays a temporary centered banner message (e.g., warning, status, etc.)
|
||||
// The banner appears in the center of the screen and disappears after the specified duration
|
||||
|
||||
// Called to trigger a banner with custom message and duration
|
||||
void Screen::showOverlayBanner(const char *message, uint32_t durationMs, const char **optionsArrayPtr, uint8_t options,
|
||||
std::function<void(int)> bannerCallback, int8_t InitialSelected)
|
||||
void Screen::showSimpleBanner(const char *message, uint32_t durationMs)
|
||||
{
|
||||
BannerOverlayOptions options;
|
||||
options.message = message;
|
||||
options.durationMs = durationMs;
|
||||
options.notificationType = notificationTypeEnum::text_banner;
|
||||
showOverlayBanner(options);
|
||||
}
|
||||
|
||||
// Called to trigger a banner with custom message and duration
|
||||
void Screen::showOverlayBanner(BannerOverlayOptions banner_overlay_options)
|
||||
{
|
||||
#ifdef USE_EINK
|
||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip full refresh for all overlay menus
|
||||
#endif
|
||||
// Store the message and set the expiration timestamp
|
||||
strncpy(NotificationRenderer::alertBannerMessage, banner_overlay_options.message, 255);
|
||||
NotificationRenderer::alertBannerMessage[255] = '\0'; // Ensure null termination
|
||||
NotificationRenderer::alertBannerUntil =
|
||||
(banner_overlay_options.durationMs == 0) ? 0 : millis() + banner_overlay_options.durationMs;
|
||||
NotificationRenderer::optionsArrayPtr = banner_overlay_options.optionsArrayPtr;
|
||||
NotificationRenderer::optionsEnumPtr = banner_overlay_options.optionsEnumPtr;
|
||||
NotificationRenderer::alertBannerOptions = banner_overlay_options.optionsCount;
|
||||
NotificationRenderer::alertBannerCallback = banner_overlay_options.bannerCallback;
|
||||
NotificationRenderer::curSelected = banner_overlay_options.InitialSelected;
|
||||
NotificationRenderer::pauseBanner = false;
|
||||
NotificationRenderer::current_notification_type = notificationTypeEnum::selection_picker;
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
ui->setTargetFPS(60);
|
||||
ui->update();
|
||||
}
|
||||
|
||||
// Called to trigger a banner with custom message and duration
|
||||
void Screen::showNodePicker(const char *message, uint32_t durationMs, std::function<void(int)> bannerCallback)
|
||||
{
|
||||
#ifdef USE_EINK
|
||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip full refresh for all overlay menus
|
||||
#endif
|
||||
nodeDB->pause_sort(true);
|
||||
// Store the message and set the expiration timestamp
|
||||
strncpy(NotificationRenderer::alertBannerMessage, message, 255);
|
||||
NotificationRenderer::alertBannerMessage[255] = '\0'; // Ensure null termination
|
||||
NotificationRenderer::alertBannerUntil = (durationMs == 0) ? 0 : millis() + durationMs;
|
||||
NotificationRenderer::alertBannerCallback = bannerCallback;
|
||||
NotificationRenderer::pauseBanner = false;
|
||||
NotificationRenderer::curSelected = 0;
|
||||
NotificationRenderer::current_notification_type = notificationTypeEnum::node_picker;
|
||||
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
ui->setTargetFPS(60);
|
||||
ui->update();
|
||||
}
|
||||
|
||||
// Called to trigger a banner with custom message and duration
|
||||
void Screen::showNumberPicker(const char *message, uint32_t durationMs, uint8_t digits,
|
||||
std::function<void(uint32_t)> bannerCallback)
|
||||
{
|
||||
LOG_WARN("Show Number Picker");
|
||||
#ifdef USE_EINK
|
||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip full refresh for all overlay menus
|
||||
#endif
|
||||
@@ -146,14 +204,16 @@ void Screen::showOverlayBanner(const char *message, uint32_t durationMs, const c
|
||||
strncpy(NotificationRenderer::alertBannerMessage, message, 255);
|
||||
NotificationRenderer::alertBannerMessage[255] = '\0'; // Ensure null termination
|
||||
NotificationRenderer::alertBannerUntil = (durationMs == 0) ? 0 : millis() + durationMs;
|
||||
NotificationRenderer::optionsArrayPtr = optionsArrayPtr;
|
||||
NotificationRenderer::alertBannerOptions = options;
|
||||
NotificationRenderer::alertBannerCallback = bannerCallback;
|
||||
NotificationRenderer::curSelected = InitialSelected;
|
||||
NotificationRenderer::pauseBanner = false;
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawAlertBannerOverlay};
|
||||
NotificationRenderer::curSelected = 0;
|
||||
NotificationRenderer::current_notification_type = notificationTypeEnum::number_picker;
|
||||
NotificationRenderer::numDigits = digits;
|
||||
NotificationRenderer::currentNumber = 0;
|
||||
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
setFastFramerate(); // Draw ASAP
|
||||
ui->setTargetFPS(60);
|
||||
ui->update();
|
||||
}
|
||||
|
||||
@@ -230,6 +290,20 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32)
|
||||
{
|
||||
graphics::normalFrames = new FrameCallback[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
|
||||
|
||||
LOG_INFO("Protobuf Value uiconfig.screen_rgb_color: %d", uiconfig.screen_rgb_color);
|
||||
int32_t rawRGB = uiconfig.screen_rgb_color;
|
||||
if (rawRGB > 0 && rawRGB <= 255255255) {
|
||||
uint8_t r = (rawRGB >> 16) & 0xFF;
|
||||
uint8_t g = (rawRGB >> 8) & 0xFF;
|
||||
uint8_t b = rawRGB & 0xFF;
|
||||
LOG_INFO("Values of r,g,b: %d, %d, %d", r, g, b);
|
||||
|
||||
if (r <= 255 && g <= 255 && b <= 255) {
|
||||
TFT_MESH = COLOR565(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
|
||||
dispdev = new SH1106Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
@@ -239,7 +313,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
ST7789_MISO, ST7789_SCK);
|
||||
#else
|
||||
dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
|
||||
static_cast<ST7789Spi *>(dispdev)->setRGB(COLOR565(255, 255, 128));
|
||||
static_cast<ST7789Spi *>(dispdev)->setRGB(TFT_MESH);
|
||||
#endif
|
||||
#elif defined(USE_SSD1306)
|
||||
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
|
||||
@@ -386,9 +460,22 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
|
||||
void Screen::setup()
|
||||
{
|
||||
|
||||
// === Enable display rendering ===
|
||||
useDisplay = true;
|
||||
|
||||
// === Load saved brightness from UI config ===
|
||||
// For OLED displays (SSD1306), default brightness is 255 if not set
|
||||
if (uiconfig.screen_brightness == 0) {
|
||||
#if defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
||||
brightness = 255; // Default for OLED
|
||||
#else
|
||||
brightness = BRIGHTNESS_DEFAULT;
|
||||
#endif
|
||||
} else {
|
||||
brightness = uiconfig.screen_brightness;
|
||||
}
|
||||
|
||||
// === Detect OLED subtype (if supported by board variant) ===
|
||||
#ifdef AutoOLEDWire_h
|
||||
if (isAUTOOled)
|
||||
@@ -416,6 +503,14 @@ void Screen::setup()
|
||||
ui->disableAllIndicators(); // Disable page indicator dots
|
||||
ui->getUiState()->userData = this; // Allow static callbacks to access Screen instance
|
||||
|
||||
// === Apply loaded brightness ===
|
||||
#if defined(ST7789_CS)
|
||||
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
|
||||
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
||||
dispdev->setBrightness(brightness);
|
||||
#endif
|
||||
LOG_INFO("Applied screen brightness: %d", brightness);
|
||||
|
||||
// === Set custom overlay callbacks ===
|
||||
static OverlayCallback overlays[] = {
|
||||
graphics::UIRenderer::drawNavigationBar // Custom indicator icons for each frame
|
||||
@@ -562,7 +657,7 @@ int32_t Screen::runOnce()
|
||||
if (displayHeight == 0) {
|
||||
displayHeight = dispdev->getHeight();
|
||||
}
|
||||
menuHandler::handleMenuSwitch();
|
||||
menuHandler::handleMenuSwitch(dispdev);
|
||||
|
||||
// Show boot screen for first logo_timeout seconds, then switch to normal operation.
|
||||
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
|
||||
@@ -595,7 +690,7 @@ int32_t Screen::runOnce()
|
||||
}
|
||||
#endif
|
||||
if (!NotificationRenderer::isOverlayBannerShowing() && rebootAtMsec != 0) {
|
||||
showOverlayBanner("Rebooting...", 0);
|
||||
showSimpleBanner("Rebooting...", 0);
|
||||
}
|
||||
|
||||
// Process incoming commands.
|
||||
@@ -642,6 +737,8 @@ int32_t Screen::runOnce()
|
||||
EINK_ADD_FRAMEFLAG(dispdev, COSMETIC); // E-Ink: Explicitly use full-refresh for next frame
|
||||
setFrames();
|
||||
break;
|
||||
case Cmd::NOOP:
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Invalid screen cmd");
|
||||
}
|
||||
@@ -785,8 +882,8 @@ void Screen::setFrames(FrameFocus focus)
|
||||
|
||||
#if defined(DISPLAY_CLOCK_FRAME)
|
||||
fsi.positions.clock = numframes;
|
||||
normalFrames[numframes++] = graphics::ClockRenderer::digitalWatchFace ? graphics::ClockRenderer::drawDigitalClockFrame
|
||||
: &graphics::ClockRenderer::drawAnalogClockFrame;
|
||||
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
|
||||
: graphics::ClockRenderer::drawDigitalClockFrame;
|
||||
indicatorIcons.push_back(digital_icon_clock);
|
||||
#endif
|
||||
|
||||
@@ -842,8 +939,8 @@ void Screen::setFrames(FrameFocus focus)
|
||||
}
|
||||
#if !defined(DISPLAY_CLOCK_FRAME)
|
||||
fsi.positions.clock = numframes;
|
||||
normalFrames[numframes++] = graphics::ClockRenderer::digitalWatchFace ? graphics::ClockRenderer::drawDigitalClockFrame
|
||||
: graphics::ClockRenderer::drawAnalogClockFrame;
|
||||
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
|
||||
: graphics::ClockRenderer::drawDigitalClockFrame;
|
||||
indicatorIcons.push_back(digital_icon_clock);
|
||||
#endif
|
||||
|
||||
@@ -909,7 +1006,7 @@ void Screen::setFrames(FrameFocus focus)
|
||||
ui->disableAllIndicators();
|
||||
|
||||
// Add overlays: frame icons and alert banner)
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawAlertBannerOverlay};
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
|
||||
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
|
||||
@@ -937,6 +1034,9 @@ void Screen::setFrames(FrameFocus focus)
|
||||
// If no module requested focus, will show the first frame instead
|
||||
ui->switchToFrame(fsi.positions.clock);
|
||||
break;
|
||||
case FOCUS_SYSTEM:
|
||||
ui->switchToFrame(fsi.positions.memory);
|
||||
break;
|
||||
|
||||
case FOCUS_PRESERVE:
|
||||
// No more adjustment — force stay on same index
|
||||
@@ -1180,7 +1280,7 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
|
||||
}
|
||||
}
|
||||
|
||||
screen->showOverlayBanner(banner, 3000);
|
||||
screen->showSimpleBanner(banner, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1220,30 +1320,14 @@ int Screen::handleInputEvent(const InputEvent *event)
|
||||
#endif
|
||||
if (NotificationRenderer::isOverlayBannerShowing()) {
|
||||
NotificationRenderer::inEvent = event->inputEvent;
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar,
|
||||
NotificationRenderer::drawAlertBannerOverlay};
|
||||
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
setFastFramerate(); // Draw ASAP
|
||||
ui->update();
|
||||
|
||||
menuHandler::handleMenuSwitch();
|
||||
menuHandler::handleMenuSwitch(dispdev);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
#if defined(DISPLAY_CLOCK_FRAME)
|
||||
// For the T-Watch, intercept touches to the 'toggle digital/analog watch face' button
|
||||
uint8_t watchFaceFrame = error_code ? 1 : 0;
|
||||
|
||||
if (this->ui->getUiState()->currentFrame == watchFaceFrame && event->touchX >= 204 && event->touchX <= 240 &&
|
||||
event->touchY >= 204 && event->touchY <= 240) {
|
||||
screen->digitalWatchFace = !screen->digitalWatchFace;
|
||||
|
||||
setFrames();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
// Use left or right input from a keyboard to move between frames,
|
||||
// so long as a mesh module isn't using these events for some other purpose
|
||||
@@ -1265,13 +1349,8 @@ int Screen::handleInputEvent(const InputEvent *event)
|
||||
} else if (event->inputEvent == INPUT_BROKER_SELECT) {
|
||||
if (this->ui->getUiState()->currentFrame == framesetInfo.positions.home) {
|
||||
menuHandler::homeBaseMenu();
|
||||
#if HAS_TFT
|
||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.memory) {
|
||||
menuHandler::switchToMUIMenu();
|
||||
#else
|
||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.memory) {
|
||||
menuHandler::BuzzerModeMenu();
|
||||
#endif
|
||||
menuHandler::systemBaseMenu();
|
||||
#if HAS_GPS
|
||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.gps && gps) {
|
||||
menuHandler::positionBaseMenu();
|
||||
|
||||
+32
-8
@@ -5,10 +5,26 @@
|
||||
#include "detect/ScanI2C.h"
|
||||
#include "mesh/generated/meshtastic/config.pb.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
|
||||
namespace graphics
|
||||
{
|
||||
enum notificationTypeEnum { none, text_banner, selection_picker, node_picker, number_picker };
|
||||
|
||||
struct BannerOverlayOptions {
|
||||
const char *message;
|
||||
uint32_t durationMs = 30000;
|
||||
const char **optionsArrayPtr = nullptr;
|
||||
const int *optionsEnumPtr = nullptr;
|
||||
uint8_t optionsCount = 0;
|
||||
std::function<void(int)> bannerCallback = nullptr;
|
||||
int8_t InitialSelected = 0;
|
||||
notificationTypeEnum notificationType = notificationTypeEnum::text_banner;
|
||||
};
|
||||
} // namespace graphics
|
||||
|
||||
#if !HAS_SCREEN
|
||||
#include "power.h"
|
||||
@@ -25,6 +41,7 @@ class Screen
|
||||
FOCUS_TEXTMESSAGE,
|
||||
FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus
|
||||
FOCUS_CLOCK,
|
||||
FOCUS_SYSTEM,
|
||||
};
|
||||
|
||||
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
|
||||
@@ -39,10 +56,8 @@ class Screen
|
||||
void setFunctionSymbol(std::string) {}
|
||||
void removeFunctionSymbol(std::string) {}
|
||||
void startAlert(const char *) {}
|
||||
void showOverlayBanner(const char *message, uint32_t durationMs = 3000, const char **optionsArrayPtr = nullptr,
|
||||
uint8_t options = 0, std::function<void(int)> bannerCallback = NULL, int8_t InitialSelected = 0)
|
||||
{
|
||||
}
|
||||
void showSimpleBanner(const char *message, uint32_t durationMs = 0) {}
|
||||
void showOverlayBanner(BannerOverlayOptions) {}
|
||||
void setFrames(FrameFocus focus) {}
|
||||
void endAlert() {}
|
||||
};
|
||||
@@ -199,6 +214,7 @@ class Screen : public concurrency::OSThread
|
||||
CallbackObserver<Screen, AdminModule_ObserverData *>(this, &Screen::handleAdminMessage);
|
||||
|
||||
public:
|
||||
OLEDDisplay *getDisplayDevice() { return dispdev; }
|
||||
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
|
||||
size_t frameCount = 0; // Total number of active frames
|
||||
~Screen();
|
||||
@@ -211,6 +227,7 @@ class Screen : public concurrency::OSThread
|
||||
FOCUS_TEXTMESSAGE,
|
||||
FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus
|
||||
FOCUS_CLOCK,
|
||||
FOCUS_SYSTEM,
|
||||
};
|
||||
|
||||
// Regenerate the normal set of frames, focusing a specific frame if requested
|
||||
@@ -225,8 +242,6 @@ class Screen : public concurrency::OSThread
|
||||
meshtastic_Config_DisplayConfig_OledType model;
|
||||
OLEDDISPLAY_GEOMETRY geometry;
|
||||
|
||||
bool ignoreCompass = false;
|
||||
|
||||
bool isOverlayBannerShowing();
|
||||
|
||||
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
|
||||
@@ -290,8 +305,11 @@ class Screen : public concurrency::OSThread
|
||||
enqueueCmd(cmd);
|
||||
}
|
||||
|
||||
void showOverlayBanner(const char *message, uint32_t durationMs = 3000, const char **optionsArrayPtr = nullptr,
|
||||
uint8_t options = 0, std::function<void(int)> bannerCallback = NULL, int8_t InitialSelected = 0);
|
||||
void showSimpleBanner(const char *message, uint32_t durationMs = 0);
|
||||
void showOverlayBanner(BannerOverlayOptions);
|
||||
|
||||
void showNodePicker(const char *message, uint32_t durationMs, std::function<void(int)> bannerCallback);
|
||||
void showNumberPicker(const char *message, uint32_t durationMs, uint8_t digits, std::function<void(uint32_t)> bannerCallback);
|
||||
|
||||
void startFirmwareUpdateScreen()
|
||||
{
|
||||
@@ -325,6 +343,12 @@ class Screen : public concurrency::OSThread
|
||||
/// Stops showing the boot screen.
|
||||
void stopBootScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BOOT_SCREEN}); }
|
||||
|
||||
void runNow()
|
||||
{
|
||||
setFastFramerate();
|
||||
enqueueCmd(ScreenCmd{.cmd = Cmd::NOOP});
|
||||
}
|
||||
|
||||
/// Overrides the default utf8 character conversion, to replace empty space with question marks
|
||||
static char customFontTableLookup(const uint8_t ch)
|
||||
{
|
||||
|
||||
@@ -343,4 +343,30 @@ const int *getTextPositions(OLEDDisplay *display)
|
||||
return textPositions;
|
||||
}
|
||||
|
||||
bool isAllowedPunctuation(char c)
|
||||
{
|
||||
const std::string allowed = ".,!?;:-_()[]{}'\"@#$/\\&+=%~^ ";
|
||||
return allowed.find(c) != std::string::npos;
|
||||
}
|
||||
|
||||
std::string sanitizeString(const std::string &input)
|
||||
{
|
||||
std::string output;
|
||||
bool inReplacement = false;
|
||||
|
||||
for (char c : input) {
|
||||
if (std::isalnum(static_cast<unsigned char>(c)) || isAllowedPunctuation(c)) {
|
||||
output += c;
|
||||
inReplacement = false;
|
||||
} else {
|
||||
if (!inReplacement) {
|
||||
output += 0xbf; // ISO-8859-1 for inverted question mark
|
||||
inReplacement = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <OLEDDisplay.h>
|
||||
#include <string>
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
@@ -52,4 +53,8 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
|
||||
const int *getTextPositions(OLEDDisplay *display);
|
||||
|
||||
bool isAllowedPunctuation(char c);
|
||||
|
||||
std::string sanitizeString(const std::string &input);
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
@@ -14,8 +15,10 @@
|
||||
extern SX1509 gpioExtender;
|
||||
#endif
|
||||
|
||||
#ifndef TFT_MESH
|
||||
#define TFT_MESH COLOR565(0x67, 0xEA, 0x94)
|
||||
#ifdef TFT_MESH_OVERRIDE
|
||||
uint16_t TFT_MESH = TFT_MESH_OVERRIDE;
|
||||
#else
|
||||
uint16_t TFT_MESH = COLOR565(0x67, 0xEA, 0x94);
|
||||
#endif
|
||||
|
||||
#if defined(ST7735S)
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace graphics
|
||||
|
||||
namespace ClockRenderer
|
||||
{
|
||||
bool digitalWatchFace = true;
|
||||
|
||||
void drawSegmentedDisplayColon(OLEDDisplay *display, int x, int y, float scale)
|
||||
{
|
||||
|
||||
@@ -11,8 +11,6 @@ class Screen;
|
||||
|
||||
namespace ClockRenderer
|
||||
{
|
||||
// Whether we are showing the digital watch face or the analog one
|
||||
extern bool digitalWatchFace;
|
||||
|
||||
// Clock frame functions
|
||||
void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
|
||||
@@ -50,7 +50,7 @@ void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY,
|
||||
radius += 4;
|
||||
}
|
||||
Point north(0, -radius);
|
||||
if (!config.display.compass_north_top)
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FIXED_RING)
|
||||
north.rotate(-myHeading);
|
||||
north.translate(compassX, compassY);
|
||||
|
||||
|
||||
@@ -501,7 +501,10 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
int line = 1;
|
||||
const int barHeight = 6;
|
||||
const int labelX = x;
|
||||
const int barsOffset = (isHighResolution) ? 24 : 0;
|
||||
int barsOffset = (isHighResolution) ? 24 : 0;
|
||||
#ifdef USE_EINK
|
||||
barsOffset -= 12;
|
||||
#endif
|
||||
const int barX = x + 40 + barsOffset;
|
||||
|
||||
auto drawUsageRow = [&](const char *label, uint32_t used, uint32_t total, bool isHeap = false) {
|
||||
|
||||
+562
-143
File diff suppressed because it is too large
Load Diff
@@ -17,26 +17,43 @@ class menuHandler
|
||||
gps_toggle_menu,
|
||||
#endif
|
||||
compass_point_north_menu,
|
||||
reset_node_db_menu
|
||||
reset_node_db_menu,
|
||||
buzzermodemenupicker,
|
||||
mui_picker,
|
||||
tftcolormenupicker,
|
||||
brightness_picker,
|
||||
reboot_menu,
|
||||
add_favorite,
|
||||
remove_favorite,
|
||||
test_menu,
|
||||
number_test
|
||||
};
|
||||
static screenMenus menuQueue;
|
||||
|
||||
static void LoraRegionPicker(uint32_t duration = 30000);
|
||||
static void handleMenuSwitch();
|
||||
static void handleMenuSwitch(OLEDDisplay *display);
|
||||
static void clockMenu();
|
||||
static void TZPicker();
|
||||
static void TwelveHourPicker();
|
||||
static void ClockFacePicker();
|
||||
static void messageResponseMenu();
|
||||
static void homeBaseMenu();
|
||||
static void systemBaseMenu();
|
||||
static void favoriteBaseMenu();
|
||||
static void positionBaseMenu();
|
||||
static void compassNorthMenu();
|
||||
static void GPSToggleMenu();
|
||||
static void BuzzerModeMenu();
|
||||
static void switchToMUIMenu();
|
||||
static void TFTColorPickerMenu(OLEDDisplay *display);
|
||||
static void nodeListMenu();
|
||||
static void resetNodeDBMenu();
|
||||
static void BrightnessPickerMenu();
|
||||
static void rebootMenu();
|
||||
static void addFavoriteMenu();
|
||||
static void removeFavoriteMenu();
|
||||
static void testMenu();
|
||||
static void numberTest();
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
@@ -66,10 +66,10 @@ const char *getSafeNodeName(meshtastic_NodeInfoLite *node)
|
||||
strncpy(nodeName, name, sizeof(nodeName) - 1);
|
||||
nodeName[sizeof(nodeName) - 1] = '\0';
|
||||
} else {
|
||||
snprintf(nodeName, sizeof(nodeName), "%04X", (uint16_t)(node->num & 0xFFFF));
|
||||
snprintf(nodeName, sizeof(nodeName), "(%04X)", (uint16_t)(node->num & 0xFFFF));
|
||||
}
|
||||
} else {
|
||||
strcpy(nodeName, "?");
|
||||
snprintf(nodeName, sizeof(nodeName), "(%04X)", (uint16_t)(node->num & 0xFFFF));
|
||||
}
|
||||
return nodeName;
|
||||
}
|
||||
@@ -522,7 +522,7 @@ void drawNodeListWithCompasses(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
double lat = DegD(ourNode->position.latitude_i);
|
||||
double lon = DegD(ourNode->position.longitude_i);
|
||||
|
||||
if (!screen->ignoreCompass) {
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) {
|
||||
#if HAS_GPS
|
||||
if (screen->hasHeading()) {
|
||||
heading = screen->getHeading(); // degrees
|
||||
|
||||
@@ -32,8 +32,21 @@ char NotificationRenderer::alertBannerMessage[256] = {0};
|
||||
uint32_t NotificationRenderer::alertBannerUntil = 0; // 0 is a special case meaning forever
|
||||
uint8_t NotificationRenderer::alertBannerOptions = 0; // last x lines are seelctable options
|
||||
const char **NotificationRenderer::optionsArrayPtr = nullptr;
|
||||
const int *NotificationRenderer::optionsEnumPtr = nullptr;
|
||||
std::function<void(int)> NotificationRenderer::alertBannerCallback = NULL;
|
||||
bool NotificationRenderer::pauseBanner = false;
|
||||
notificationTypeEnum NotificationRenderer::current_notification_type = notificationTypeEnum::none;
|
||||
uint32_t NotificationRenderer::numDigits = 0;
|
||||
uint32_t NotificationRenderer::currentNumber = 0;
|
||||
|
||||
uint32_t pow_of_10(uint32_t n)
|
||||
{
|
||||
uint32_t ret = 1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
ret *= 10;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Used on boot when a certificate is being created
|
||||
void NotificationRenderer::drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
@@ -55,29 +68,214 @@ void NotificationRenderer::drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiStat
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
void NotificationRenderer::resetBanner()
|
||||
{
|
||||
alertBannerMessage[0] = '\0';
|
||||
current_notification_type = notificationTypeEnum::none;
|
||||
nodeDB->pause_sort(false);
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawBannercallback(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
{
|
||||
if (!isOverlayBannerShowing() || pauseBanner)
|
||||
return;
|
||||
switch (current_notification_type) {
|
||||
case notificationTypeEnum::text_banner:
|
||||
case notificationTypeEnum::selection_picker:
|
||||
drawAlertBannerOverlay(display, state);
|
||||
break;
|
||||
case notificationTypeEnum::node_picker:
|
||||
drawNodePicker(display, state);
|
||||
break;
|
||||
case notificationTypeEnum::number_picker:
|
||||
drawNumberPicker(display, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawNumberPicker(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
{
|
||||
const char *lineStarts[MAX_LINES + 1] = {0};
|
||||
uint16_t lineCount = 0;
|
||||
|
||||
// Parse lines
|
||||
char *alertEnd = alertBannerMessage + strnlen(alertBannerMessage, sizeof(alertBannerMessage));
|
||||
lineStarts[lineCount] = alertBannerMessage;
|
||||
|
||||
// Find lines
|
||||
while ((lineCount < MAX_LINES) && (lineStarts[lineCount] < alertEnd)) {
|
||||
lineStarts[lineCount + 1] = std::find((char *)lineStarts[lineCount], alertEnd, '\n');
|
||||
if (lineStarts[lineCount + 1][0] == '\n')
|
||||
lineStarts[lineCount + 1] += 1;
|
||||
lineCount++;
|
||||
}
|
||||
// modulo to extract
|
||||
uint8_t this_digit = (currentNumber % (pow_of_10(numDigits - curSelected))) / (pow_of_10(numDigits - curSelected - 1));
|
||||
// Handle input
|
||||
if (inEvent == INPUT_BROKER_UP || inEvent == INPUT_BROKER_ALT_PRESS) {
|
||||
if (this_digit == 9) {
|
||||
currentNumber -= 9 * (pow_of_10(numDigits - curSelected - 1));
|
||||
} else {
|
||||
currentNumber += (pow_of_10(numDigits - curSelected - 1));
|
||||
}
|
||||
} else if (inEvent == INPUT_BROKER_DOWN || inEvent == INPUT_BROKER_USER_PRESS) {
|
||||
if (this_digit == 0) {
|
||||
currentNumber += 9 * (pow_of_10(numDigits - curSelected - 1));
|
||||
} else {
|
||||
currentNumber -= (pow_of_10(numDigits - curSelected - 1));
|
||||
}
|
||||
} else if (inEvent == INPUT_BROKER_SELECT || inEvent == INPUT_BROKER_RIGHT) {
|
||||
curSelected++;
|
||||
} else if (inEvent == INPUT_BROKER_LEFT) {
|
||||
curSelected--;
|
||||
} else if ((inEvent == INPUT_BROKER_CANCEL || inEvent == INPUT_BROKER_ALT_LONG) && alertBannerUntil != 0) {
|
||||
resetBanner();
|
||||
}
|
||||
if (curSelected == numDigits) {
|
||||
resetBanner();
|
||||
alertBannerCallback(currentNumber);
|
||||
}
|
||||
|
||||
inEvent = INPUT_BROKER_NONE;
|
||||
if (alertBannerMessage[0] == '\0')
|
||||
return;
|
||||
|
||||
uint16_t totalLines = lineCount + 2;
|
||||
const char *linePointers[totalLines + 1] = {0}; // this is sort of a dynamic allocation
|
||||
|
||||
// copy the linestarts to display to the linePointers holder
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
linePointers[i] = lineStarts[i];
|
||||
}
|
||||
std::string digits = " ";
|
||||
std::string arrowPointer = " ";
|
||||
for (int i = 0; i < numDigits; i++) {
|
||||
// Modulo minus modulo to return just the current number
|
||||
digits += std::to_string((currentNumber % (pow_of_10(numDigits - i))) / (pow_of_10(numDigits - i - 1))) + " ";
|
||||
if (curSelected == i) {
|
||||
arrowPointer += "^ ";
|
||||
} else {
|
||||
arrowPointer += "_ ";
|
||||
}
|
||||
}
|
||||
|
||||
linePointers[lineCount++] = digits.c_str();
|
||||
linePointers[lineCount++] = arrowPointer.c_str();
|
||||
|
||||
drawNotificationBox(display, state, linePointers, totalLines, 0);
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawNodePicker(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
{
|
||||
static uint32_t selectedNodenum = 0;
|
||||
|
||||
// === Layout Configuration ===
|
||||
constexpr uint16_t hPadding = 5;
|
||||
constexpr uint16_t vPadding = 2;
|
||||
constexpr uint8_t lineSpacing = 1;
|
||||
alertBannerOptions = nodeDB->getNumMeshNodes() - 1;
|
||||
|
||||
bool needs_bell = (strstr(alertBannerMessage, "Alert Received") != nullptr);
|
||||
// let the box drawing function calculate the widths?
|
||||
|
||||
// Setup font and alignment
|
||||
display->setFont(FONT_SMALL);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
const char *lineStarts[MAX_LINES + 1] = {0};
|
||||
uint16_t lineCount = 0;
|
||||
|
||||
// Parse lines
|
||||
char *alertEnd = alertBannerMessage + strnlen(alertBannerMessage, sizeof(alertBannerMessage));
|
||||
lineStarts[lineCount] = alertBannerMessage;
|
||||
|
||||
while ((lineCount < MAX_LINES) && (lineStarts[lineCount] < alertEnd)) {
|
||||
lineStarts[lineCount + 1] = std::find((char *)lineStarts[lineCount], alertEnd, '\n');
|
||||
if (lineStarts[lineCount + 1][0] == '\n')
|
||||
lineStarts[lineCount + 1] += 1;
|
||||
lineCount++;
|
||||
}
|
||||
|
||||
// Handle input
|
||||
if (inEvent == INPUT_BROKER_UP || inEvent == INPUT_BROKER_ALT_PRESS) {
|
||||
curSelected--;
|
||||
} else if (inEvent == INPUT_BROKER_DOWN || inEvent == INPUT_BROKER_USER_PRESS) {
|
||||
curSelected++;
|
||||
} else if (inEvent == INPUT_BROKER_SELECT) {
|
||||
resetBanner();
|
||||
alertBannerCallback(selectedNodenum);
|
||||
|
||||
} else if ((inEvent == INPUT_BROKER_CANCEL || inEvent == INPUT_BROKER_ALT_LONG) && alertBannerUntil != 0) {
|
||||
resetBanner();
|
||||
}
|
||||
|
||||
if (curSelected == -1)
|
||||
curSelected = alertBannerOptions - 1;
|
||||
if (curSelected == alertBannerOptions)
|
||||
curSelected = 0;
|
||||
|
||||
inEvent = INPUT_BROKER_NONE;
|
||||
if (alertBannerMessage[0] == '\0')
|
||||
return;
|
||||
|
||||
uint16_t totalLines = lineCount + alertBannerOptions;
|
||||
uint16_t screenHeight = display->height();
|
||||
uint8_t effectiveLineHeight = FONT_HEIGHT_SMALL - 3;
|
||||
uint8_t visibleTotalLines = std::min<uint8_t>(totalLines, (screenHeight - vPadding * 2) / effectiveLineHeight);
|
||||
uint8_t linesShown = lineCount;
|
||||
const char *linePointers[visibleTotalLines + 1] = {0}; // this is sort of a dynamic allocation
|
||||
|
||||
// copy the linestarts to display to the linePointers holder
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
linePointers[i] = lineStarts[i];
|
||||
}
|
||||
char scratchLineBuffer[visibleTotalLines - lineCount][40];
|
||||
|
||||
uint8_t firstOptionToShow = 0;
|
||||
if (curSelected > 1 && alertBannerOptions > visibleTotalLines - lineCount) {
|
||||
if (curSelected > alertBannerOptions - visibleTotalLines + lineCount)
|
||||
firstOptionToShow = alertBannerOptions - visibleTotalLines + lineCount;
|
||||
else
|
||||
firstOptionToShow = curSelected - 1;
|
||||
} else {
|
||||
firstOptionToShow = 0;
|
||||
}
|
||||
int scratchLineNum = 0;
|
||||
for (int i = firstOptionToShow; i < alertBannerOptions && linesShown < visibleTotalLines; i++, linesShown++) {
|
||||
char temp_name[16] = {0};
|
||||
if (nodeDB->getMeshNodeByIndex(i + 1)->has_user) {
|
||||
std::string sanitized = sanitizeString(nodeDB->getMeshNodeByIndex(i + 1)->user.long_name);
|
||||
strncpy(temp_name, sanitized.c_str(), sizeof(temp_name) - 1);
|
||||
|
||||
} else {
|
||||
snprintf(temp_name, sizeof(temp_name), "(%04X)", (uint16_t)(nodeDB->getMeshNodeByIndex(i + 1)->num & 0xFFFF));
|
||||
}
|
||||
// make temp buffer for name
|
||||
// fi
|
||||
if (i == curSelected) {
|
||||
selectedNodenum = nodeDB->getMeshNodeByIndex(i + 1)->num;
|
||||
if (isHighResolution) {
|
||||
strncpy(scratchLineBuffer[scratchLineNum], "> ", 3);
|
||||
strncpy(scratchLineBuffer[scratchLineNum] + 2, temp_name, 36);
|
||||
strncpy(scratchLineBuffer[scratchLineNum] + strlen(temp_name) + 2, " <", 3);
|
||||
} else {
|
||||
strncpy(scratchLineBuffer[scratchLineNum], ">", 2);
|
||||
strncpy(scratchLineBuffer[scratchLineNum] + 1, temp_name, 37);
|
||||
strncpy(scratchLineBuffer[scratchLineNum] + strlen(temp_name) + 1, "<", 2);
|
||||
}
|
||||
scratchLineBuffer[scratchLineNum][39] = '\0';
|
||||
} else {
|
||||
strncpy(scratchLineBuffer[scratchLineNum], temp_name, 36);
|
||||
}
|
||||
linePointers[linesShown] = scratchLineBuffer[scratchLineNum++];
|
||||
}
|
||||
drawNotificationBox(display, state, linePointers, totalLines, firstOptionToShow);
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
{
|
||||
// === Layout Configuration ===
|
||||
constexpr uint16_t vPadding = 2;
|
||||
|
||||
constexpr int MAX_LINES = 5;
|
||||
uint16_t optionWidths[alertBannerOptions] = {0};
|
||||
uint16_t maxWidth = 0;
|
||||
uint16_t arrowsWidth = display->getStringWidth("> <", 4, true);
|
||||
uint16_t lineWidths[MAX_LINES] = {0};
|
||||
uint16_t lineLengths[MAX_LINES] = {0};
|
||||
char *lineStarts[MAX_LINES + 1];
|
||||
const char *lineStarts[MAX_LINES + 1] = {0};
|
||||
uint16_t lineCount = 0;
|
||||
char lineBuffer[40] = {0};
|
||||
|
||||
@@ -86,7 +284,7 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
lineStarts[lineCount] = alertBannerMessage;
|
||||
|
||||
while ((lineCount < MAX_LINES) && (lineStarts[lineCount] < alertEnd)) {
|
||||
lineStarts[lineCount + 1] = std::find(lineStarts[lineCount], alertEnd, '\n');
|
||||
lineStarts[lineCount + 1] = std::find((char *)lineStarts[lineCount], alertEnd, '\n');
|
||||
lineLengths[lineCount] = lineStarts[lineCount + 1] - lineStarts[lineCount];
|
||||
if (lineStarts[lineCount + 1][0] == '\n')
|
||||
lineStarts[lineCount + 1] += 1;
|
||||
@@ -112,10 +310,15 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
} else if (inEvent == INPUT_BROKER_DOWN || inEvent == INPUT_BROKER_USER_PRESS) {
|
||||
curSelected++;
|
||||
} else if (inEvent == INPUT_BROKER_SELECT) {
|
||||
alertBannerCallback(curSelected);
|
||||
alertBannerMessage[0] = '\0';
|
||||
if (optionsEnumPtr != nullptr) {
|
||||
alertBannerCallback(optionsEnumPtr[curSelected]);
|
||||
optionsEnumPtr = nullptr;
|
||||
} else {
|
||||
alertBannerCallback(curSelected);
|
||||
}
|
||||
resetBanner();
|
||||
} else if ((inEvent == INPUT_BROKER_CANCEL || inEvent == INPUT_BROKER_ALT_LONG) && alertBannerUntil != 0) {
|
||||
alertBannerMessage[0] = '\0';
|
||||
resetBanner();
|
||||
}
|
||||
|
||||
if (curSelected == -1)
|
||||
@@ -124,7 +327,7 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
curSelected = 0;
|
||||
} else {
|
||||
if (inEvent == INPUT_BROKER_SELECT || inEvent == INPUT_BROKER_ALT_LONG || inEvent == INPUT_BROKER_CANCEL) {
|
||||
alertBannerMessage[0] = '\0';
|
||||
resetBanner();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +335,91 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
if (alertBannerMessage[0] == '\0')
|
||||
return;
|
||||
|
||||
// === Box Size Calculation ===
|
||||
uint16_t totalLines = lineCount + alertBannerOptions;
|
||||
|
||||
uint16_t screenHeight = display->height();
|
||||
uint8_t effectiveLineHeight = FONT_HEIGHT_SMALL - 3;
|
||||
uint8_t visibleTotalLines = std::min<uint8_t>(totalLines, (screenHeight - vPadding * 2) / effectiveLineHeight);
|
||||
uint8_t linesShown = lineCount;
|
||||
const char *linePointers[visibleTotalLines + 1] = {0}; // this is sort of a dynamic allocation
|
||||
|
||||
// copy the linestarts to display to the linePointers holder
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
linePointers[i] = lineStarts[i];
|
||||
}
|
||||
|
||||
uint8_t firstOptionToShow = 0;
|
||||
if (alertBannerOptions > 0) {
|
||||
if (curSelected > 1 && alertBannerOptions > visibleTotalLines - lineCount) {
|
||||
if (curSelected > alertBannerOptions - visibleTotalLines + lineCount)
|
||||
firstOptionToShow = alertBannerOptions - visibleTotalLines + lineCount;
|
||||
else
|
||||
firstOptionToShow = curSelected - 1;
|
||||
} else {
|
||||
firstOptionToShow = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = firstOptionToShow; i < alertBannerOptions && linesShown < visibleTotalLines; i++, linesShown++) {
|
||||
if (i == curSelected) {
|
||||
if (isHighResolution) {
|
||||
strncpy(lineBuffer, "> ", 3);
|
||||
strncpy(lineBuffer + 2, optionsArrayPtr[i], 36);
|
||||
strncpy(lineBuffer + strlen(optionsArrayPtr[i]) + 2, " <", 3);
|
||||
} else {
|
||||
strncpy(lineBuffer, ">", 2);
|
||||
strncpy(lineBuffer + 1, optionsArrayPtr[i], 37);
|
||||
strncpy(lineBuffer + strlen(optionsArrayPtr[i]) + 1, "<", 2);
|
||||
}
|
||||
lineBuffer[39] = '\0';
|
||||
linePointers[linesShown] = lineBuffer;
|
||||
} else {
|
||||
linePointers[linesShown] = optionsArrayPtr[i];
|
||||
}
|
||||
}
|
||||
if (alertBannerOptions > 0) {
|
||||
drawNotificationBox(display, state, linePointers, totalLines, firstOptionToShow, maxWidth);
|
||||
} else {
|
||||
drawNotificationBox(display, state, linePointers, totalLines, firstOptionToShow);
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplayUiState *state, const char *lines[],
|
||||
uint16_t totalLines, uint8_t firstOptionToShow, uint16_t maxWidth)
|
||||
{
|
||||
|
||||
bool is_picker = false;
|
||||
uint16_t lineCount = 0;
|
||||
// === Layout Configuration ===
|
||||
constexpr uint16_t hPadding = 5;
|
||||
constexpr uint16_t vPadding = 2;
|
||||
bool needs_bell = false;
|
||||
uint16_t lineWidths[totalLines] = {0};
|
||||
uint16_t lineLengths[totalLines] = {0};
|
||||
|
||||
if (maxWidth != 0)
|
||||
is_picker = true;
|
||||
|
||||
// Setup font and alignment
|
||||
display->setFont(FONT_SMALL);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
while (lines[lineCount] != nullptr) {
|
||||
auto newlinePointer = strchr(lines[lineCount], '\n');
|
||||
if (newlinePointer)
|
||||
lineLengths[lineCount] = (newlinePointer - lines[lineCount]); // Check for newlines first
|
||||
else // if the newline wasn't found, then pull string length from strlen
|
||||
lineLengths[lineCount] = strlen(lines[lineCount]);
|
||||
lineWidths[lineCount] = display->getStringWidth(lines[lineCount], lineLengths[lineCount], true);
|
||||
if (!is_picker) {
|
||||
needs_bell |= (strstr(alertBannerMessage, "Alert Received") != nullptr);
|
||||
if (lineWidths[lineCount] > maxWidth)
|
||||
maxWidth = lineWidths[lineCount];
|
||||
}
|
||||
lineCount++;
|
||||
}
|
||||
// count lines
|
||||
|
||||
uint16_t boxWidth = hPadding * 2 + maxWidth;
|
||||
if (needs_bell) {
|
||||
if (isHighResolution && boxWidth <= 150)
|
||||
@@ -141,14 +428,19 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
boxWidth += 20;
|
||||
}
|
||||
|
||||
uint16_t totalLines = lineCount + alertBannerOptions;
|
||||
uint16_t screenHeight = display->height();
|
||||
uint8_t effectiveLineHeight = FONT_HEIGHT_SMALL - 3;
|
||||
uint8_t visibleTotalLines = std::min<uint8_t>(totalLines, (screenHeight - vPadding * 2) / effectiveLineHeight);
|
||||
uint8_t visibleTotalLines = std::min<uint8_t>(lineCount, (screenHeight - vPadding * 2) / effectiveLineHeight);
|
||||
uint16_t contentHeight = visibleTotalLines * effectiveLineHeight;
|
||||
uint16_t boxHeight = contentHeight + vPadding * 2;
|
||||
if (visibleTotalLines == 1) {
|
||||
boxHeight += (isHighResolution) ? 4 : 3;
|
||||
}
|
||||
|
||||
int16_t boxLeft = (display->width() / 2) - (boxWidth / 2);
|
||||
if (totalLines > visibleTotalLines) {
|
||||
boxWidth += (isHighResolution) ? 4 : 2;
|
||||
}
|
||||
int16_t boxTop = (display->height() / 2) - (boxHeight / 2);
|
||||
|
||||
// === Draw Box ===
|
||||
@@ -169,21 +461,18 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
|
||||
// === Draw Content ===
|
||||
int16_t lineY = boxTop + vPadding;
|
||||
uint8_t linesShown = 0;
|
||||
|
||||
for (int i = 0; i < lineCount && linesShown < visibleTotalLines; i++, linesShown++) {
|
||||
strncpy(lineBuffer, lineStarts[i], 40);
|
||||
lineBuffer[lineLengths[i] > 39 ? 39 : lineLengths[i]] = '\0';
|
||||
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2;
|
||||
if (needs_bell && i == 0) {
|
||||
int bellY = lineY + (FONT_HEIGHT_SMALL - 8) / 2;
|
||||
display->drawXbm(textX - 10, bellY, 8, 8, bell_alert);
|
||||
display->drawXbm(textX + lineWidths[i] + 2, bellY, 8, 8, bell_alert);
|
||||
}
|
||||
|
||||
char lineBuffer[lineLengths[i] + 1];
|
||||
strncpy(lineBuffer, lines[i], lineLengths[i]);
|
||||
lineBuffer[lineLengths[i]] = '\0';
|
||||
// Determine if this is a pop-up or a pick list
|
||||
if (alertBannerOptions > 0) {
|
||||
if (alertBannerOptions > 0 && i == 0) {
|
||||
// Pick List
|
||||
display->setColor(WHITE);
|
||||
int background_yOffset = 1;
|
||||
@@ -199,39 +488,14 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
lineY += (effectiveLineHeight - 2 - background_yOffset);
|
||||
} else {
|
||||
// Pop-up
|
||||
display->drawString(textX, lineY - 2, lineBuffer);
|
||||
display->drawString(textX, lineY, lineBuffer);
|
||||
lineY += (effectiveLineHeight);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t firstOptionToShow = 0;
|
||||
if (alertBannerOptions > 0) {
|
||||
if (curSelected > 1 && alertBannerOptions > visibleTotalLines - lineCount)
|
||||
firstOptionToShow = curSelected - 1;
|
||||
else
|
||||
firstOptionToShow = 0;
|
||||
}
|
||||
|
||||
for (int i = firstOptionToShow; i < alertBannerOptions && linesShown < visibleTotalLines; i++, linesShown++) {
|
||||
if (i == curSelected) {
|
||||
strncpy(lineBuffer, "> ", 3);
|
||||
strncpy(lineBuffer + 2, optionsArrayPtr[i], 36);
|
||||
strncpy(lineBuffer + strlen(optionsArrayPtr[i]) + 2, " <", 3);
|
||||
lineBuffer[39] = '\0';
|
||||
} else {
|
||||
strncpy(lineBuffer, optionsArrayPtr[i], 40);
|
||||
lineBuffer[39] = '\0';
|
||||
}
|
||||
|
||||
int16_t textX = boxLeft + (boxWidth - optionWidths[i] - (i == curSelected ? arrowsWidth : 0)) / 2;
|
||||
display->drawString(textX, lineY, lineBuffer);
|
||||
lineY += effectiveLineHeight;
|
||||
}
|
||||
|
||||
// === Scroll Bar (Thicker, inside box, not over title) ===
|
||||
if (totalLines > visibleTotalLines) {
|
||||
const uint8_t scrollBarWidth = 5;
|
||||
const uint8_t scrollPadding = 2;
|
||||
|
||||
int16_t scrollBarX = boxLeft + boxWidth - scrollBarWidth - 2;
|
||||
int16_t scrollBarY = boxTop + vPadding + effectiveLineHeight; // start after title line
|
||||
@@ -239,7 +503,7 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
|
||||
float ratio = (float)visibleTotalLines / totalLines;
|
||||
uint16_t indicatorHeight = std::max((int)(scrollBarHeight * ratio), 4);
|
||||
float scrollRatio = (float)(firstOptionToShow + linesShown - visibleTotalLines) / (totalLines - visibleTotalLines);
|
||||
float scrollRatio = (float)(firstOptionToShow + lineCount - visibleTotalLines) / (totalLines - visibleTotalLines);
|
||||
uint16_t indicatorY = scrollBarY + scrollRatio * (scrollBarHeight - indicatorHeight);
|
||||
|
||||
display->drawRect(scrollBarX, scrollBarY, scrollBarWidth, scrollBarHeight);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "OLEDDisplay.h"
|
||||
#include "OLEDDisplayUi.h"
|
||||
#include "graphics/Screen.h"
|
||||
#define MAX_LINES 5
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
@@ -14,16 +16,28 @@ class NotificationRenderer
|
||||
static char alertBannerMessage[256];
|
||||
static uint32_t alertBannerUntil; // 0 is a special case meaning forever
|
||||
static const char **optionsArrayPtr;
|
||||
static const int *optionsEnumPtr;
|
||||
static uint8_t alertBannerOptions; // last x lines are seelctable options
|
||||
static std::function<void(int)> alertBannerCallback;
|
||||
static uint32_t numDigits;
|
||||
static uint32_t currentNumber;
|
||||
|
||||
static bool pauseBanner;
|
||||
|
||||
static void resetBanner();
|
||||
static void drawBannercallback(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||
static void drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||
static void drawNumberPicker(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||
static void drawNodePicker(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||
static void drawNotificationBox(OLEDDisplay *display, OLEDDisplayUiState *state, const char *lines[MAX_LINES + 1],
|
||||
uint16_t totalLines, uint8_t firstOptionToShow, uint16_t maxWidth = 0);
|
||||
|
||||
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
static bool isOverlayBannerShowing();
|
||||
|
||||
static graphics::notificationTypeEnum current_notification_type;
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
@@ -18,32 +18,6 @@
|
||||
#include <RTC.h>
|
||||
#include <cstring>
|
||||
|
||||
bool isAllowedPunctuation(char c)
|
||||
{
|
||||
const std::string allowed = ".,!?;:-_()[]{}'\"@#$/\\&+=%~^ ";
|
||||
return allowed.find(c) != std::string::npos;
|
||||
}
|
||||
|
||||
std::string sanitizeString(const std::string &input)
|
||||
{
|
||||
std::string output;
|
||||
bool inReplacement = false;
|
||||
|
||||
for (char c : input) {
|
||||
if (std::isalnum(static_cast<unsigned char>(c)) || isAllowedPunctuation(c)) {
|
||||
output += c;
|
||||
inReplacement = false;
|
||||
} else {
|
||||
if (!inReplacement) {
|
||||
output += 0xbf; // ISO-8859-1 for inverted question mark
|
||||
inReplacement = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// External variables
|
||||
extern graphics::Screen *screen;
|
||||
|
||||
@@ -443,7 +417,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
*/
|
||||
float bearing = GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(p.latitude_i), DegD(p.longitude_i));
|
||||
if (screen->ignoreCompass) {
|
||||
if (uiconfig.compass_mode == meshtastic_CompassMode_FREEZE_HEADING) {
|
||||
myHeading = 0;
|
||||
} else {
|
||||
bearing -= myHeading;
|
||||
@@ -488,7 +462,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
|
||||
const auto &op = ourNode->position;
|
||||
float myHeading = 0;
|
||||
if (!screen->ignoreCompass) {
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) {
|
||||
myHeading = screen->hasHeading() ? screen->getHeading() * PI / 180
|
||||
: screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
}
|
||||
@@ -500,7 +474,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
*/
|
||||
float bearing = GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(p.latitude_i), DegD(p.longitude_i));
|
||||
if (!screen->ignoreCompass)
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING)
|
||||
bearing -= myHeading;
|
||||
graphics::CompassRenderer::drawNodeHeading(display, compassX, compassY, compassRadius * 2, bearing);
|
||||
|
||||
@@ -600,7 +574,11 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
|
||||
int chutil_bar_width = (isHighResolution) ? 100 : 50;
|
||||
if (!config.bluetooth.enabled) {
|
||||
#if defined(USE_EINK)
|
||||
chutil_bar_width = (isHighResolution) ? 50 : 30;
|
||||
#else
|
||||
chutil_bar_width = (isHighResolution) ? 80 : 40;
|
||||
#endif
|
||||
}
|
||||
int chutil_bar_height = (isHighResolution) ? 12 : 7;
|
||||
int extraoffset = (isHighResolution) ? 6 : 3;
|
||||
@@ -933,7 +911,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
// === Determine Compass Heading ===
|
||||
float heading = 0;
|
||||
bool validHeading = false;
|
||||
if (screen->ignoreCompass) {
|
||||
if (uiconfig.compass_mode == meshtastic_CompassMode_FREEZE_HEADING) {
|
||||
validHeading = true;
|
||||
} else {
|
||||
if (screen->hasHeading()) {
|
||||
@@ -999,7 +977,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
|
||||
// "N" label
|
||||
float northAngle = 0;
|
||||
if (!config.display.compass_north_top)
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FIXED_RING)
|
||||
northAngle = -heading;
|
||||
float radius = compassRadius;
|
||||
int16_t nX = compassX + (radius - 1) * sin(northAngle);
|
||||
@@ -1042,7 +1020,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
|
||||
// "N" label
|
||||
float northAngle = 0;
|
||||
if (!config.display.compass_north_top)
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FIXED_RING)
|
||||
northAngle = -heading;
|
||||
float radius = compassRadius;
|
||||
int16_t nX = compassX + (radius - 1) * sin(northAngle);
|
||||
@@ -1066,9 +1044,16 @@ 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;
|
||||
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);
|
||||
if (isHighResolution) {
|
||||
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);
|
||||
} else {
|
||||
|
||||
display->drawXbm(x + (SCREEN_WIDTH - USERPREFS_OEM_IMAGE_WIDTH) / 2,
|
||||
y + (SCREEN_HEIGHT - USERPREFS_OEM_IMAGE_HEIGHT) / 2 + 2, USERPREFS_OEM_IMAGE_WIDTH,
|
||||
USERPREFS_OEM_IMAGE_HEIGHT, xbm);
|
||||
}
|
||||
|
||||
switch (USERPREFS_OEM_FONT_SIZE) {
|
||||
case 0:
|
||||
@@ -1084,7 +1069,9 @@ void UIRenderer::drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, O
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
const char *title = USERPREFS_OEM_TEXT;
|
||||
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
||||
if (isHighResolution) {
|
||||
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
||||
}
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
// Draw region in upper left
|
||||
|
||||
+103
-51
@@ -11,11 +11,11 @@ const Emote emotes[] = {
|
||||
{"\U0001F44E", thumbdown, thumbs_width, thumbs_height}, // 👎 Thumbs Down
|
||||
|
||||
// --- Smileys (Multiple Unicode Aliases) ---
|
||||
{"\U0001F60A", smiley, smiley_width, smiley_height}, // 😊 Smiling Face with Smiling Eyes
|
||||
{"\U0001F600", smiley, smiley_width, smiley_height}, // 😀 Grinning Face
|
||||
{"\U0001F642", smiley, smiley_width, smiley_height}, // 🙂 Slightly Smiling Face
|
||||
{"\U0001F609", smiley, smiley_width, smiley_height}, // 😉 Winking Face
|
||||
{"\U0001F601", smiley, smiley_width, smiley_height}, // 😁 Grinning Face with Smiling Eyes
|
||||
{"\U0001F60A", Smiling_Eyes, Smiling_Eyes_width, Smiling_Eyes_height}, // 😊 Smiling Eyes
|
||||
{"\U0001F600", Grinning, Grinning_width, Grinning_height}, // 😀 Grinning Face
|
||||
{"\U0001F642", Slightly_Smiling, Slightly_Smiling_width, Slightly_Smiling_height}, // 🙂 Slightly Smiling Face
|
||||
{"\U0001F609", Winking_Face, Winking_Face_width, Winking_Face_height}, // 😉 Winking Face
|
||||
{"\U0001F601", Grinning_Smiling_Eyes, Grinning_Smiling_Eyes_width, Grinning_Smiling_Eyes_height}, // 😁 Grinning Smiling Eyes
|
||||
|
||||
// --- Question/Alert ---
|
||||
{"\u2753", question, question_width, question_height}, // ❓ Question Mark
|
||||
@@ -23,10 +23,11 @@ const Emote emotes[] = {
|
||||
|
||||
// --- Laughing Faces ---
|
||||
{"\U0001F602", haha, haha_width, haha_height}, // 😂 Face with Tears of Joy
|
||||
{"\U0001F923", haha, haha_width, haha_height}, // 🤣 Rolling on the Floor Laughing
|
||||
{"\U0001F606", haha, haha_width, haha_height}, // 😆 Smiling with Open Mouth and Closed Eyes
|
||||
{"\U0001F605", haha, haha_width, haha_height}, // 😅 Smiling with Sweat
|
||||
{"\U0001F604", haha, haha_width, haha_height}, // 😄 Grinning Face with Smiling Eyes
|
||||
{"\U0001F923", ROFL, ROFL_width, ROFL_height}, // 🤣 Rolling on the Floor Laughing
|
||||
{"\U0001F606", Smiling_Closed_Eyes, Smiling_Closed_Eyes_width, Smiling_Closed_Eyes_height}, // 😆 Smiling Closed Eyes
|
||||
{"\U0001F605", haha, haha_width, haha_height}, // 😅 Smiling with Sweat
|
||||
{"\U0001F604", Grinning_SmilingEyes2, Grinning_SmilingEyes2_width,
|
||||
Grinning_SmilingEyes2_height}, // 😄 Grinning Face with Smiling Eyes
|
||||
|
||||
// --- Gestures and People ---
|
||||
{"\U0001F44B", wave_icon, wave_icon_width, wave_icon_height}, // 👋 Waving Hand
|
||||
@@ -78,13 +79,45 @@ const unsigned char thumbdown[] PROGMEM = {
|
||||
0x80, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char smiley[] PROGMEM = {
|
||||
0x00, 0xfe, 0x0f, 0x00, 0x80, 0x01, 0x30, 0x00, 0x40, 0x00, 0xc0, 0x00, 0x20, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x02,
|
||||
0x08, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x10, 0x02, 0x0e, 0x0e, 0x10, 0x02, 0x09, 0x12, 0x10,
|
||||
0x01, 0x09, 0x12, 0x20, 0x01, 0x0f, 0x1e, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20,
|
||||
0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x81, 0x00, 0x20, 0x20,
|
||||
0x82, 0x00, 0x20, 0x10, 0x02, 0x01, 0x10, 0x10, 0x04, 0x02, 0x08, 0x08, 0x04, 0xfc, 0x07, 0x08, 0x08, 0x00, 0x00, 0x04,
|
||||
0x10, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x01, 0x40, 0x00, 0xc0, 0x00, 0x80, 0x01, 0x30, 0x00, 0x00, 0xfe, 0x0f, 0x00};
|
||||
const unsigned char Smiling_Eyes[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xff, 0xff, 0xcf, 0xfc, 0xff, 0xff, 0xcf,
|
||||
0x7e, 0xf8, 0xc3, 0xdf, 0x3e, 0xf0, 0x81, 0xdf, 0xbf, 0xf7, 0xbd, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0x3f, 0xff,
|
||||
0x6f, 0xff, 0xdf, 0xfe, 0x6f, 0xff, 0xdf, 0xfe, 0x9f, 0xff, 0x3f, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0x7e, 0xff, 0xdf, 0xdf,
|
||||
0x7c, 0xff, 0xdf, 0xcf, 0xfc, 0xfe, 0xef, 0xcf, 0xf8, 0xf9, 0xf7, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x07, 0xc0};
|
||||
|
||||
const unsigned char Grinning[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf9, 0xf3, 0xcf, 0xfc, 0xf0, 0xe1, 0xcf,
|
||||
0xfe, 0xf0, 0xe1, 0xdf, 0xfe, 0xf0, 0xe1, 0xdf, 0xff, 0xf0, 0xe1, 0xff, 0xff, 0xf9, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80, 0xff, 0xbe, 0xff, 0xbf, 0xdf, 0x7e, 0x00, 0xc0, 0xdf,
|
||||
0x7c, 0x00, 0xc0, 0xcf, 0xfc, 0x00, 0xe0, 0xcf, 0xf8, 0x01, 0xf0, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
||||
|
||||
const unsigned char Slightly_Smiling[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf9, 0xf3, 0xcf, 0xfc, 0xf0, 0xe1, 0xcf,
|
||||
0xfe, 0xf0, 0xe1, 0xdf, 0xfe, 0xf0, 0xe1, 0xdf, 0xff, 0xf0, 0xe1, 0xff, 0xff, 0xf9, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0x7e, 0xff, 0xdf, 0xdf,
|
||||
0x7c, 0xff, 0xdf, 0xcf, 0xfc, 0xfe, 0xef, 0xcf, 0xf8, 0xf9, 0xf7, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
||||
|
||||
const unsigned char Winking_Face[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xf0, 0xff, 0xc3, 0x78, 0xef, 0xc3, 0xc7, 0xb8, 0xdf, 0xbd, 0xcf, 0xfc, 0xf9, 0x7f, 0xcf, 0xfc, 0xf0, 0xff, 0xcf,
|
||||
0xfe, 0xf0, 0xc3, 0xdf, 0xfe, 0xf0, 0x81, 0xdf, 0xff, 0xf0, 0xbf, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0x7e, 0xff, 0xdf, 0xdf,
|
||||
0x7c, 0xff, 0xdf, 0xcf, 0xfc, 0xfe, 0xef, 0xcf, 0xf8, 0xf9, 0xf7, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x07, 0xc0};
|
||||
|
||||
const unsigned char Grinning_Smiling_Eyes[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf8, 0xe3, 0xcf, 0x7c, 0xf7, 0xdd, 0xcf,
|
||||
0xbe, 0xef, 0xbe, 0xdf, 0xbe, 0xef, 0xbe, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x5e, 0x55, 0x55, 0xdf, 0x5e, 0x55, 0x55, 0xdf,
|
||||
0x3c, 0x00, 0x80, 0xcf, 0x7c, 0x55, 0xd5, 0xcf, 0xf8, 0x54, 0xe5, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
||||
|
||||
const unsigned char question[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0xC0, 0xFF, 0x07, 0x00, 0xE0, 0xFF, 0x07, 0x00,
|
||||
@@ -104,31 +137,52 @@ const unsigned char bang[] PROGMEM = {
|
||||
};
|
||||
|
||||
const unsigned char haha[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00,
|
||||
0x00, 0xFC, 0x0F, 0x00, 0x00, 0x1F, 0x3E, 0x00, 0x80, 0x03, 0x70, 0x00, 0xC0, 0x01, 0xE0, 0x00, 0xC0, 0x00, 0xC2, 0x00,
|
||||
0x60, 0x00, 0x03, 0x00, 0x60, 0x00, 0xC1, 0x1F, 0x60, 0x80, 0x8F, 0x31, 0x30, 0x0E, 0x80, 0x31, 0x30, 0x10, 0x30, 0x1F,
|
||||
0x30, 0x08, 0x58, 0x00, 0x30, 0x04, 0x6C, 0x03, 0x60, 0x00, 0xF3, 0x01, 0x60, 0xC0, 0xFC, 0x01, 0x80, 0x38, 0xBF, 0x01,
|
||||
0xE0, 0xC5, 0xDF, 0x00, 0xB0, 0xF9, 0xEF, 0x00, 0x30, 0xF1, 0x73, 0x00, 0xB0, 0x1D, 0x3E, 0x00, 0xF0, 0xFD, 0x0F, 0x00,
|
||||
0xE0, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0xe0, 0xf9, 0xf3, 0xc0,
|
||||
0xf0, 0xfe, 0xef, 0xc1, 0x38, 0xff, 0x9f, 0xc3, 0xd8, 0xff, 0x7f, 0xc3, 0xfc, 0xf8, 0xe3, 0xc7, 0x7c, 0xf7, 0xdd, 0xcf,
|
||||
0xbe, 0xef, 0xbe, 0xcf, 0xfe, 0xff, 0xff, 0xcf, 0xef, 0xff, 0xff, 0xde, 0xe7, 0xff, 0xff, 0xdc, 0xeb, 0xff, 0xff, 0xda,
|
||||
0xed, 0xff, 0xff, 0xd6, 0xee, 0xff, 0xff, 0xce, 0x36, 0x00, 0x80, 0xcd, 0xb8, 0xff, 0xbf, 0xc3, 0x7e, 0x00, 0xc0, 0xdf,
|
||||
0x7c, 0x00, 0xc0, 0xcf, 0xfc, 0x00, 0xe0, 0xcf, 0xf8, 0x01, 0xf0, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
||||
|
||||
const unsigned char ROFL[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0xfc, 0x07, 0xc0, 0x00, 0xff, 0x1f, 0xc0, 0x80, 0xff, 0x7f, 0xc0, 0xc0, 0xff, 0xff, 0xc0,
|
||||
0xe0, 0x9f, 0xff, 0xc1, 0xf0, 0x9f, 0xff, 0xc0, 0xf8, 0x9f, 0x7f, 0xcb, 0xf8, 0x9f, 0xbf, 0xcb, 0xfc, 0x9f, 0xdf, 0xdb,
|
||||
0xfc, 0x1f, 0x08, 0xdc, 0xfe, 0x1f, 0xf8, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0x1e, 0xf0, 0x7f, 0xfe, 0x1e, 0xf0, 0xbf, 0xfe,
|
||||
0xfe, 0xf3, 0xdf, 0xfe, 0xfe, 0xf3, 0x6f, 0xfe, 0xfe, 0xf3, 0x37, 0xfe, 0xfe, 0xeb, 0x1b, 0xfe, 0xfc, 0xef, 0x0d, 0xde,
|
||||
0xfc, 0xe7, 0x06, 0xcf, 0xf8, 0x6b, 0x83, 0xcf, 0xf8, 0x0d, 0xc0, 0xc7, 0xf0, 0xed, 0xff, 0xc7, 0xe0, 0xee, 0xff, 0xc3,
|
||||
0xc0, 0xee, 0xff, 0xc1, 0x80, 0xee, 0xff, 0xc0, 0x00, 0xe6, 0x3f, 0xc0, 0x00, 0xf0, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0xc0};
|
||||
|
||||
const unsigned char Smiling_Closed_Eyes[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0x7c, 0xfe, 0xcf, 0xcf, 0xfc, 0xfc, 0xe7, 0xcf,
|
||||
0xfe, 0xf9, 0xf3, 0xdf, 0xfe, 0xf3, 0xf9, 0xdf, 0xff, 0xf9, 0xf3, 0xff, 0xff, 0xfc, 0xe7, 0xff, 0x7f, 0xfe, 0xcf, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80, 0xff, 0xbe, 0xff, 0xbf, 0xdf, 0x7e, 0x00, 0xc0, 0xdf,
|
||||
0x7c, 0x00, 0xc0, 0xcf, 0xfc, 0x00, 0xe0, 0xcf, 0xf8, 0x01, 0xf0, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
||||
|
||||
const unsigned char Grinning_SmilingEyes2[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0xe0, 0xff, 0xff, 0xc0,
|
||||
0xf0, 0xff, 0xff, 0xc1, 0xf8, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc3, 0xfc, 0xf8, 0xe3, 0xc7, 0x7c, 0xf7, 0xdd, 0xc7,
|
||||
0xbe, 0xef, 0xbe, 0xcf, 0xfe, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf,
|
||||
0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf, 0x3f, 0x00, 0x80, 0xdf, 0xbe, 0xff, 0xbf, 0xcf, 0x7e, 0x00, 0xc0, 0xcf,
|
||||
0x7c, 0x00, 0xc0, 0xc7, 0xfc, 0x00, 0xe0, 0xc7, 0xf8, 0x01, 0xf0, 0xc3, 0xf8, 0x03, 0xf8, 0xc3, 0xf0, 0xff, 0xff, 0xc1,
|
||||
0xe0, 0xff, 0xff, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
||||
|
||||
const unsigned char wave_icon[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xC0, 0x00,
|
||||
0x00, 0x0C, 0x9C, 0x01, 0x80, 0x17, 0x20, 0x01, 0x80, 0x26, 0x46, 0x02, 0x80, 0x44, 0x88, 0x02, 0xC0, 0x89, 0x8A, 0x02,
|
||||
0x40, 0x93, 0x8B, 0x02, 0x40, 0x26, 0x13, 0x00, 0x80, 0x44, 0x16, 0x00, 0xC0, 0x89, 0x24, 0x00, 0x40, 0x93, 0x60, 0x00,
|
||||
0x40, 0x26, 0x40, 0x00, 0x80, 0x0C, 0x80, 0x00, 0x00, 0x09, 0x80, 0x00, 0x00, 0x02, 0x80, 0x00, 0x40, 0x06, 0x80, 0x00,
|
||||
0x50, 0x0C, 0x80, 0x00, 0x50, 0x08, 0x40, 0x00, 0x90, 0x10, 0x20, 0x00, 0xB0, 0x21, 0x10, 0x00, 0x20, 0x47, 0x18, 0x00,
|
||||
0x40, 0x80, 0x0F, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0xc0, 0xc1, 0x00, 0x00, 0x00, 0xc7,
|
||||
0x00, 0x00, 0x1e, 0xcc, 0x00, 0x00, 0x30, 0xc8, 0x00, 0x00, 0x60, 0xd8, 0x00, 0x08, 0xc0, 0xd0, 0x00, 0x1a, 0x81, 0xd1,
|
||||
0x00, 0x36, 0x03, 0xd3, 0x80, 0x6d, 0x06, 0xd2, 0x00, 0xdb, 0x0c, 0xc2, 0x80, 0xb6, 0x1d, 0xc0, 0x80, 0x6d, 0x1f, 0xc0,
|
||||
0x00, 0xdb, 0x3f, 0xc0, 0x00, 0xf6, 0x7f, 0xc0, 0x00, 0xfc, 0x7f, 0xc0, 0x08, 0xf8, 0x7f, 0xc0, 0x48, 0xf0, 0x7f, 0xc0,
|
||||
0x48, 0xe0, 0x7f, 0xc0, 0xc8, 0xc0, 0x3f, 0xc0, 0x98, 0x81, 0x1f, 0xc0, 0x10, 0x03, 0x00, 0xc0, 0x30, 0x0e, 0x00, 0xc0,
|
||||
0x20, 0x38, 0x00, 0xc0, 0xe0, 0x00, 0x00, 0xc0, 0x80, 0x07, 0x00, 0xc0, 0x00, 0x1e, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0};
|
||||
|
||||
const unsigned char cowboy[] PROGMEM = {
|
||||
0x00, 0xF0, 0x03, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x3C, 0xFE, 0x1F, 0x0F,
|
||||
0xFE, 0xFE, 0xDF, 0x1F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F,
|
||||
0x3E, 0xC0, 0x00, 0x1F, 0x1E, 0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x0E, 0x1C, 0x04, 0x00, 0x0E, 0x1C, 0x00,
|
||||
0x04, 0x0E, 0x1C, 0x08, 0x04, 0x0E, 0x1C, 0x08, 0x04, 0x04, 0x08, 0x08, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x08,
|
||||
0x8C, 0x07, 0x70, 0x0C, 0x88, 0xFC, 0x4F, 0x04, 0x88, 0x01, 0x40, 0x04, 0x90, 0xFF, 0x7F, 0x02, 0x30, 0x03, 0x30, 0x03,
|
||||
0x60, 0x0E, 0x9C, 0x01, 0xC0, 0xF8, 0xC7, 0x00, 0x80, 0x01, 0x60, 0x00, 0x00, 0x0E, 0x1C, 0x00, 0x00, 0xF8, 0x07, 0x00,
|
||||
};
|
||||
0x00, 0x0c, 0x0c, 0xc0, 0x00, 0x02, 0x10, 0xc0, 0x00, 0x01, 0x20, 0xc0, 0xbc, 0x00, 0x40, 0xcf, 0xc2, 0x01, 0xe0, 0xd0,
|
||||
0x01, 0x01, 0x20, 0xe0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
|
||||
0xc1, 0x3f, 0xff, 0xe0, 0xe1, 0xff, 0xff, 0xe1, 0xf2, 0xf3, 0xf3, 0xd3, 0xf4, 0xf1, 0xe3, 0xcb, 0xfc, 0xf1, 0xe3, 0xc7,
|
||||
0xf8, 0xf1, 0xe3, 0xc7, 0xf8, 0xf1, 0xe3, 0xc7, 0xf8, 0xfb, 0xf7, 0xc7, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xc7,
|
||||
0x70, 0xf8, 0x8f, 0xc3, 0x70, 0x03, 0xb0, 0xc3, 0x70, 0xfe, 0xbf, 0xc3, 0x60, 0x00, 0x80, 0xc1, 0xc0, 0x00, 0xc0, 0xc0,
|
||||
0x80, 0x01, 0x60, 0xc0, 0x00, 0x07, 0x38, 0xc0, 0x00, 0xfe, 0x1f, 0xc0, 0x00, 0xf0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0xc0};
|
||||
|
||||
const unsigned char deadmau5[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x00,
|
||||
@@ -181,13 +235,12 @@ const unsigned char fog[] PROGMEM = {
|
||||
};
|
||||
|
||||
const unsigned char devil[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x10, 0x03, 0xC0, 0x01, 0x38, 0x07, 0x7C, 0x0F, 0x38, 0x1F, 0x03, 0x30, 0x1E,
|
||||
0xFE, 0x01, 0xE0, 0x1F, 0x7E, 0x00, 0x80, 0x1F, 0x3C, 0x00, 0x00, 0x0F, 0x1C, 0x00, 0x00, 0x0E, 0x18, 0x00, 0x00, 0x06,
|
||||
0x08, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x0E, 0x1C, 0x0C,
|
||||
0x0C, 0x18, 0x06, 0x0C, 0x0C, 0x1C, 0x06, 0x0C, 0x0C, 0x1C, 0x0E, 0x0C, 0x0C, 0x1C, 0x0E, 0x0C, 0x0C, 0x0C, 0x06, 0x0C,
|
||||
0x08, 0x00, 0x00, 0x06, 0x18, 0x02, 0x10, 0x06, 0x10, 0x0C, 0x0C, 0x03, 0x30, 0xF8, 0x07, 0x03, 0x60, 0xE0, 0x80, 0x01,
|
||||
0xC0, 0x00, 0xC0, 0x00, 0x80, 0x01, 0x70, 0x00, 0x00, 0x06, 0x1C, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x0f, 0xfc, 0x0f, 0xfc,
|
||||
0x3f, 0xff, 0x3f, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0xfe, 0xff, 0xff, 0xdf, 0xfe, 0xff, 0xff, 0xdf, 0xfc, 0xff, 0xff, 0xcf,
|
||||
0xfc, 0xff, 0xff, 0xcf, 0xf8, 0xff, 0xff, 0xc7, 0xf0, 0xff, 0xff, 0xc3, 0xf0, 0xff, 0xff, 0xc3, 0xf0, 0xf1, 0xe3, 0xc3,
|
||||
0xf0, 0xe7, 0xf9, 0xc3, 0xf0, 0xe7, 0xf9, 0xc3, 0xf0, 0xe3, 0xf1, 0xc3, 0xf0, 0xe3, 0xf1, 0xc3, 0xf0, 0xe7, 0xf9, 0xc3,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xe0, 0xfd, 0xef, 0xc1, 0xe0, 0xf3, 0xf3, 0xc1, 0xc0, 0x07, 0xf8, 0xc0, 0x80, 0x1f, 0x7e, 0xc0,
|
||||
0x00, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0};
|
||||
|
||||
const unsigned char heart[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0xF0, 0x00, 0xF8, 0x0F, 0xFC, 0x07, 0xFC, 0x1F, 0x06, 0x0E, 0xFE, 0x3F, 0x03, 0x18,
|
||||
@@ -199,13 +252,12 @@ const unsigned char heart[] PROGMEM = {
|
||||
};
|
||||
|
||||
const unsigned char poo[] PROGMEM = {
|
||||
0x00, 0x1C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xEC, 0x01, 0x00, 0x00, 0x8C, 0x07, 0x00, 0x00, 0x0C, 0x06, 0x00,
|
||||
0x00, 0x24, 0x0C, 0x00, 0x00, 0x34, 0x08, 0x00, 0x00, 0x1F, 0x08, 0x00, 0xC0, 0x0F, 0x08, 0x00, 0xC0, 0x00, 0x3C, 0x00,
|
||||
0x60, 0x00, 0x7C, 0x00, 0x60, 0x00, 0xC6, 0x00, 0x20, 0x00, 0xCB, 0x00, 0xA0, 0xC7, 0xFF, 0x00, 0xE0, 0x7F, 0xF7, 0x00,
|
||||
0xF0, 0x18, 0xE3, 0x03, 0x78, 0x18, 0x41, 0x03, 0x6C, 0x9B, 0x5D, 0x06, 0x64, 0x9B, 0x5D, 0x04, 0x44, 0x1A, 0x41, 0x04,
|
||||
0x4C, 0xD8, 0x63, 0x06, 0xF8, 0xFC, 0x36, 0x06, 0xFE, 0x0F, 0x9C, 0x1F, 0x07, 0x03, 0xC0, 0x30, 0x03, 0x00, 0x78, 0x20,
|
||||
0x01, 0x00, 0x1F, 0x20, 0x03, 0xE0, 0x03, 0x20, 0x07, 0x7E, 0x04, 0x30, 0xFE, 0x0F, 0xFC, 0x1F, 0xF0, 0x00, 0xF0, 0x0F,
|
||||
};
|
||||
0x00, 0x1c, 0x00, 0xc0, 0x00, 0x7c, 0x00, 0xc0, 0x00, 0xfc, 0x00, 0xc0, 0x00, 0x7c, 0x03, 0xc0, 0x00, 0xbe, 0x03, 0xc0,
|
||||
0x00, 0xdf, 0x0f, 0xc0, 0x80, 0xcf, 0x0f, 0xc0, 0xc0, 0xf1, 0x0f, 0xc0, 0x60, 0xfc, 0x0f, 0xc0, 0x30, 0xff, 0x07, 0xc0,
|
||||
0x90, 0xff, 0x3b, 0xc0, 0xc0, 0xff, 0x7d, 0xc0, 0xf8, 0xff, 0xfc, 0xc0, 0xf8, 0x3f, 0xf0, 0xc0, 0x78, 0x88, 0xc0, 0xc0,
|
||||
0x20, 0xe3, 0x18, 0xc0, 0x98, 0xe7, 0xbc, 0xc1, 0x9c, 0x64, 0xa4, 0xc3, 0x9e, 0x64, 0xa4, 0xc7, 0xbe, 0xe4, 0xa4, 0xc7,
|
||||
0xbc, 0x27, 0xbc, 0xc7, 0x38, 0x03, 0xd9, 0xc3, 0x00, 0xf0, 0x63, 0xc0, 0xf8, 0xfc, 0x3f, 0xcf, 0xfc, 0xff, 0x87, 0xdf,
|
||||
0xfe, 0xff, 0xe0, 0xdf, 0xfc, 0x1f, 0xfe, 0xdf, 0xf8, 0x07, 0xf8, 0xcf, 0xf0, 0x03, 0xe0, 0xc7, 0x00, 0x00, 0x00, 0xc0};
|
||||
|
||||
const unsigned char bell_icon[] PROGMEM = {
|
||||
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11110000,
|
||||
|
||||
+31
-3
@@ -22,9 +22,25 @@ extern const int numEmotes;
|
||||
extern const unsigned char thumbup[] PROGMEM;
|
||||
extern const unsigned char thumbdown[] PROGMEM;
|
||||
|
||||
#define smiley_height 30
|
||||
#define smiley_width 30
|
||||
extern const unsigned char smiley[] PROGMEM;
|
||||
#define Smiling_Eyes_height 30
|
||||
#define Smiling_Eyes_width 30
|
||||
extern const unsigned char Smiling_Eyes[] PROGMEM;
|
||||
|
||||
#define Grinning_height 30
|
||||
#define Grinning_width 30
|
||||
extern const unsigned char Grinning[] PROGMEM;
|
||||
|
||||
#define Slightly_Smiling_height 30
|
||||
#define Slightly_Smiling_width 30
|
||||
extern const unsigned char Slightly_Smiling[] PROGMEM;
|
||||
|
||||
#define Winking_Face_height 30
|
||||
#define Winking_Face_width 30
|
||||
extern const unsigned char Winking_Face[] PROGMEM;
|
||||
|
||||
#define Grinning_Smiling_Eyes_height 30
|
||||
#define Grinning_Smiling_Eyes_width 30
|
||||
extern const unsigned char Grinning_Smiling_Eyes[] PROGMEM;
|
||||
|
||||
#define question_height 25
|
||||
#define question_width 25
|
||||
@@ -38,6 +54,18 @@ extern const unsigned char bang[] PROGMEM;
|
||||
#define haha_width 30
|
||||
extern const unsigned char haha[] PROGMEM;
|
||||
|
||||
#define ROFL_height 30
|
||||
#define ROFL_width 30
|
||||
extern const unsigned char ROFL[] PROGMEM;
|
||||
|
||||
#define Smiling_Closed_Eyes_height 30
|
||||
#define Smiling_Closed_Eyes_width 30
|
||||
extern const unsigned char Smiling_Closed_Eyes[] PROGMEM;
|
||||
|
||||
#define Grinning_SmilingEyes2_height 30
|
||||
#define Grinning_SmilingEyes2_width 30
|
||||
extern const unsigned char Grinning_SmilingEyes2[] PROGMEM;
|
||||
|
||||
#define wave_icon_height 30
|
||||
#define wave_icon_width 30
|
||||
extern const unsigned char wave_icon[] PROGMEM;
|
||||
|
||||
+4
-1
@@ -1363,7 +1363,7 @@ void setup()
|
||||
if (!rIf->reconfigure()) {
|
||||
LOG_WARN("Reconfigure failed, rebooting");
|
||||
if (screen) {
|
||||
screen->showOverlayBanner("Rebooting...");
|
||||
screen->showSimpleBanner("Rebooting...");
|
||||
}
|
||||
rebootAtMsec = millis() + 5000;
|
||||
}
|
||||
@@ -1436,6 +1436,9 @@ void setup()
|
||||
LOG_DEBUG("Free heap : %7d bytes", ESP.getFreeHeap());
|
||||
LOG_DEBUG("Free PSRAM : %7d bytes", ESP.getFreePsram());
|
||||
#endif
|
||||
|
||||
// We manually run this to update the NodeStatus
|
||||
nodeDB->notifyObservers(true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user