New Icons for navigation bar - Submitted by JasonP

This commit is contained in:
HarukiToreda 2025-05-05 20:10:00 -04:00
parent 75c5080fd9
commit 66a06230c4
2 changed files with 132 additions and 108 deletions

View File

@ -135,6 +135,20 @@ static bool heartbeat = false;
#include "graphics/ScreenFonts.h" #include "graphics/ScreenFonts.h"
#include <Throttle.h> #include <Throttle.h>
void drawScaledXBitmap16x16(int x, int y, int width, int height, const uint8_t *bitmapXBM, OLEDDisplay *display)
{
for (int row = 0; row < height; row++) {
uint8_t rowMask = (1 << row);
for (int col = 0; col < width; col++) {
uint8_t colData = pgm_read_byte(&bitmapXBM[col]);
if (colData & rowMask) {
// Note: rows become X, columns become Y after transpose
display->fillRect(x + row * 2, y + col * 2, 2, 2);
}
}
}
}
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2) #define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
// Check if the display can render a string (detect special chars; emoji) // Check if the display can render a string (detect special chars; emoji)
@ -3138,8 +3152,10 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
} }
static int8_t lastFrameIndex = -1; static int8_t lastFrameIndex = -1;
static uint32_t lastFrameChangeTime = 0; static uint32_t lastFrameChangeTime = 0;
constexpr uint32_t ICON_DISPLAY_DURATION_MS = 1000; // constexpr uint32_t ICON_DISPLAY_DURATION_MS = 1250;
constexpr uint32_t ICON_DISPLAY_DURATION_MS = 10250;
// Bottom navigation icons
void drawCustomFrameIcons(OLEDDisplay *display, OLEDDisplayUiState *state) void drawCustomFrameIcons(OLEDDisplay *display, OLEDDisplayUiState *state)
{ {
int currentFrame = state->currentFrame; int currentFrame = state->currentFrame;
@ -3151,39 +3167,63 @@ void drawCustomFrameIcons(OLEDDisplay *display, OLEDDisplayUiState *state)
} }
// Only show bar briefly after switching frames // Only show bar briefly after switching frames
if (millis() - lastFrameChangeTime > ICON_DISPLAY_DURATION_MS) return; if (millis() - lastFrameChangeTime > ICON_DISPLAY_DURATION_MS)
return;
const int iconSize = 8; const bool useBigIcons = (SCREEN_WIDTH > 128);
const int spacing = 2; const int iconSize = useBigIcons ? 16 : 8;
size_t totalIcons = screen->indicatorIcons.size(); const int spacing = useBigIcons ? 8 : 4;
if (totalIcons == 0) return; const int bigOffset = useBigIcons ? 1 : 0;
int totalWidth = totalIcons * iconSize + (totalIcons - 1) * spacing; const size_t totalIcons = screen->indicatorIcons.size();
int xStart = (SCREEN_WIDTH - totalWidth) / 2; if (totalIcons == 0)
int y = SCREEN_HEIGHT - iconSize - 1; return;
// Clear background under icon bar to avoid overlaps const int totalWidth = totalIcons * iconSize + (totalIcons - 1) * spacing;
const int xStart = (SCREEN_WIDTH - totalWidth) / 2;
const int y = SCREEN_HEIGHT - iconSize - 1;
// Pre-calculate bounding rect
const int rectX = xStart - 2 - bigOffset;
const int rectWidth = totalWidth + 4 + (bigOffset * 2);
const int rectHeight = iconSize + 6;
// Clear background and draw border
display->setColor(BLACK); display->setColor(BLACK);
display->fillRect(xStart - 1, y - 2, totalWidth + 2, iconSize + 4); display->fillRect(rectX + 1, y - 2, rectWidth - 2, rectHeight - 2);
display->setColor(WHITE); display->setColor(WHITE);
display->drawRect(rectX, y - 2, rectWidth, rectHeight);
// Icon drawing loop
for (size_t i = 0; i < totalIcons; ++i) { for (size_t i = 0; i < totalIcons; ++i) {
const uint8_t *icon = screen->indicatorIcons[i]; const uint8_t *icon = screen->indicatorIcons[i];
int x = xStart + i * (iconSize + spacing); const int x = xStart + i * (iconSize + spacing);
const bool isActive = (i == static_cast<size_t>(currentFrame));
if (i == static_cast<size_t>(currentFrame)) { if (isActive) {
// Draw white box and invert icon for visibility
display->setColor(WHITE); display->setColor(WHITE);
display->fillRect(x - 1, y - 1, iconSize + 2, iconSize + 2); display->fillRect(x - 2, y - 2, iconSize + 4, iconSize + 4);
display->setColor(BLACK); display->setColor(BLACK);
display->drawXbm(x, y, iconSize, iconSize, icon); }
display->setColor(WHITE);
if (useBigIcons) {
drawScaledXBitmap16x16(x, y, 8, 8, icon, display);
} else { } else {
display->drawXbm(x, y, iconSize, iconSize, icon); display->drawXbm(x, y, iconSize, iconSize, icon);
} }
if (isActive) {
display->setColor(WHITE);
} }
} }
// Knock the corners off the square
display->setColor(BLACK);
display->drawRect(rectX, y - 2, 1, 1);
display->drawRect(rectX + rectWidth - 1, y - 2, 1, 1);
display->setColor(WHITE);
}
void Screen::setup() void Screen::setup()
{ {
// === Enable display rendering === // === Enable display rendering ===
@ -3285,17 +3325,13 @@ void Screen::setup()
// === Optional touchscreen support === // === Optional touchscreen support ===
#if ARCH_PORTDUINO && !HAS_TFT #if ARCH_PORTDUINO && !HAS_TFT
if (settingsMap[touchscreenModule]) { if (settingsMap[touchscreenModule]) {
touchScreenImpl1 = new TouchScreenImpl1( touchScreenImpl1 =
dispdev->getWidth(), dispdev->getHeight(), new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
static_cast<TFTDisplay *>(dispdev)->getTouch
);
touchScreenImpl1->init(); touchScreenImpl1->init();
} }
#elif HAS_TOUCHSCREEN #elif HAS_TOUCHSCREEN
touchScreenImpl1 = new TouchScreenImpl1( touchScreenImpl1 =
dispdev->getWidth(), dispdev->getHeight(), new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
static_cast<TFTDisplay *>(dispdev)->getTouch
);
touchScreenImpl1->init(); touchScreenImpl1->init();
#endif #endif
@ -3736,10 +3772,7 @@ void Screen::setFrames(FrameFocus focus)
ui->disableAllIndicators(); ui->disableAllIndicators();
// Add function overlay here. This can show when notifications muted, modifier key is active etc // Add function overlay here. This can show when notifications muted, modifier key is active etc
static OverlayCallback overlays[] = { static OverlayCallback overlays[] = {drawFunctionOverlay, drawCustomFrameIcons};
drawFunctionOverlay,
drawCustomFrameIcons
};
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0])); ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list

View File

@ -258,85 +258,76 @@ static const unsigned char mail[] PROGMEM = {
// 📬 Mail / Message // 📬 Mail / Message
const uint8_t icon_mail[] PROGMEM = { const uint8_t icon_mail[] PROGMEM = {
0b00000000, // (padding)
0b11111111, // ████████ top border 0b11111111, // ████████ top border
0b10000001, // █ █ sides 0b10000001, // █ █ sides
0b11000011, // ██ ██ diagonal 0b11000011, // ██ ██ diagonal
0b10100101, // █ █ █ █ inner M 0b10100101, // █ █ █ █ inner M
0b10011001, // █ ██ █ inner M 0b10011001, // █ ██ █ inner M
0b10000001, // █ █ sides 0b10000001, // █ █ sides
0b11111111, // ████████ bottom 0b11111111 // ████████ bottom
0b00000000 // (padding)
}; };
// 📍 GPS Screen / Location Pin // 📍 GPS Screen / Location Pin
const uint8_t icon_compass[] PROGMEM = { const unsigned char icon_compass[] PROGMEM = {
0b00011000, // ██ 0x3C, // Row 0: ..####..
0b00111100, // ████ 0x52, // Row 1: .#..#.#.
0b01100110, // ██ ██ 0x91, // Row 2: #...#..#
0b01000010, // █ █ 0x91, // Row 3: #...#..#
0b01000010, // █ █ 0x91, // Row 4: #...#..#
0b00111100, // ████ 0x81, // Row 5: #......#
0b00011000, // ██ 0x42, // Row 6: .#....#.
0b00010000 // █ 0x3C // Row 7: ..####..
}; };
const uint8_t icon_radio[] PROGMEM = { const uint8_t icon_radio[] PROGMEM = {
0b00111000, // ░███░ 0x0F, // Row 0: ####....
0b01000100, // █░░░█ 0x10, // Row 1: ....#...
0b10000010, // █░░░░█ 0x27, // Row 2: ###..#..
0b00010000, // ░░█░ 0x48, // Row 3: ...#..#.
0b00010000, // ░░█░ 0x93, // Row 4: ##..#..#
0b00111000, // ░███░ 0xA4, // Row 5: ..#..#.#
0b01111100, // █████ 0xA8, // Row 6: ...#.#.#
0b00000000 // ░░░░░ 0xA9 // Row 7: #..#.#.#
}; };
// 🪙 Memory Drum Icon (Barrel shape with cuts on the sides) // 🪙 Memory Icon
const uint8_t icon_memory[] PROGMEM = { const uint8_t icon_memory[] PROGMEM = {
0b00111100, // ░░████░░ 0x24, // Row 0: ..#..#..
0b01111110, // ░██████░ 0x3C, // Row 1: ..####..
0b11100111, // ███░░███ 0xC3, // Row 2: ##....##
0b11100111, // ███░░███ 0x5A, // Row 3: .#.##.#.
0b11100111, // ███░░███ 0x5A, // Row 4: .#.##.#.
0b11100111, // ███░░███ 0xC3, // Row 5: ##....##
0b01111110, // ░██████░ 0x3C, // Row 6: ..####..
0b00111100 // ░░████░░ 0x24 // Row 7: ..#..#..
}; };
// 🌐 Wi-Fi // 🌐 Wi-Fi
const uint8_t icon_wifi[] PROGMEM = { const uint8_t icon_wifi[] PROGMEM = {0b00000000, 0b00011000, 0b00111100, 0b01111110,
0b00000000, 0b11011011, 0b00011000, 0b00011000, 0b00000000};
0b00011000,
0b00111100,
0b01111110,
0b11011011,
0b00011000,
0b00011000,
0b00000000
};
// 📄 Paper/List Icon (for DynamicNodeListScreen)
const uint8_t icon_nodes[] PROGMEM = { const uint8_t icon_nodes[] PROGMEM = {
0b11111111, // Top edge of paper 0xF9, // Row 0 #..#######
0b10000001, // Left & right margin 0x00, // Row 1
0b10101001, // ••• line 0xF9, // Row 2 #..#######
0b10000001, // 0x00, // Row 3
0b10101001, // ••• line 0xF9, // Row 4 #..#######
0b10000001, // 0x00, // Row 5
0b11111111, // Bottom edge 0xF9, // Row 6 #..#######
0b00000000 // 0x00 // Row 7
}; };
// ➤ Chevron Triangle Arrow Icon (8x8) // ➤ Chevron Triangle Arrow Icon (8x8)
const uint8_t icon_list[] PROGMEM = { const uint8_t icon_list[] PROGMEM = {
0b00011000, // ░░██░░ 0x10, // Row 0: ...#....
0b00011100, // ░░███░ 0x10, // Row 1: ...#....
0b00011110, // ░░████ 0x38, // Row 2: ..###...
0b11111111, // ██████ 0x38, // Row 3: ..###...
0b00011110, // ░░████ 0x7C, // Row 4: .#####..
0b00011100, // ░░███░ 0x6C, // Row 5: .##.##..
0b00011000, // ░░██░░ 0xC6, // Row 6: ##...##.
0b00000000 // ░░░░░░ 0x82 // Row 7: #.....#.
}; };
// 📶 Signal Bars Icon (left to right, small to large with spacing) // 📶 Signal Bars Icon (left to right, small to large with spacing)