mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-08 14:12:05 +00:00
New Icons for navigation bar - Submitted by JasonP
This commit is contained in:
parent
75c5080fd9
commit
66a06230c4
@ -135,6 +135,20 @@ static bool heartbeat = false;
|
||||
#include "graphics/ScreenFonts.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)
|
||||
|
||||
// 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 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)
|
||||
{
|
||||
int currentFrame = state->currentFrame;
|
||||
@ -3151,37 +3167,61 @@ void drawCustomFrameIcons(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
}
|
||||
|
||||
// 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 int spacing = 2;
|
||||
size_t totalIcons = screen->indicatorIcons.size();
|
||||
if (totalIcons == 0) return;
|
||||
const bool useBigIcons = (SCREEN_WIDTH > 128);
|
||||
const int iconSize = useBigIcons ? 16 : 8;
|
||||
const int spacing = useBigIcons ? 8 : 4;
|
||||
const int bigOffset = useBigIcons ? 1 : 0;
|
||||
|
||||
int totalWidth = totalIcons * iconSize + (totalIcons - 1) * spacing;
|
||||
int xStart = (SCREEN_WIDTH - totalWidth) / 2;
|
||||
int y = SCREEN_HEIGHT - iconSize - 1;
|
||||
const size_t totalIcons = screen->indicatorIcons.size();
|
||||
if (totalIcons == 0)
|
||||
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->fillRect(xStart - 1, y - 2, totalWidth + 2, iconSize + 4);
|
||||
display->fillRect(rectX + 1, y - 2, rectWidth - 2, rectHeight - 2);
|
||||
display->setColor(WHITE);
|
||||
display->drawRect(rectX, y - 2, rectWidth, rectHeight);
|
||||
|
||||
// Icon drawing loop
|
||||
for (size_t i = 0; i < totalIcons; ++i) {
|
||||
const uint8_t* icon = screen->indicatorIcons[i];
|
||||
int x = xStart + i * (iconSize + spacing);
|
||||
const uint8_t *icon = screen->indicatorIcons[i];
|
||||
const int x = xStart + i * (iconSize + spacing);
|
||||
const bool isActive = (i == static_cast<size_t>(currentFrame));
|
||||
|
||||
if (i == static_cast<size_t>(currentFrame)) {
|
||||
// Draw white box and invert icon for visibility
|
||||
if (isActive) {
|
||||
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->drawXbm(x, y, iconSize, iconSize, icon);
|
||||
display->setColor(WHITE);
|
||||
}
|
||||
|
||||
if (useBigIcons) {
|
||||
drawScaledXBitmap16x16(x, y, 8, 8, icon, display);
|
||||
} else {
|
||||
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()
|
||||
@ -3209,17 +3249,17 @@ void Screen::setup()
|
||||
displayWidth = dispdev->width();
|
||||
displayHeight = dispdev->height();
|
||||
|
||||
ui->setTimePerTransition(0); // Disable animation delays
|
||||
ui->setIndicatorPosition(BOTTOM); // Not used (indicators disabled below)
|
||||
ui->setIndicatorDirection(LEFT_RIGHT); // Not used (indicators disabled below)
|
||||
ui->setFrameAnimation(SLIDE_LEFT); // Used only when indicators are active
|
||||
ui->disableAllIndicators(); // Disable page indicator dots
|
||||
ui->getUiState()->userData = this; // Allow static callbacks to access Screen instance
|
||||
ui->setTimePerTransition(0); // Disable animation delays
|
||||
ui->setIndicatorPosition(BOTTOM); // Not used (indicators disabled below)
|
||||
ui->setIndicatorDirection(LEFT_RIGHT); // Not used (indicators disabled below)
|
||||
ui->setFrameAnimation(SLIDE_LEFT); // Used only when indicators are active
|
||||
ui->disableAllIndicators(); // Disable page indicator dots
|
||||
ui->getUiState()->userData = this; // Allow static callbacks to access Screen instance
|
||||
|
||||
// === Set custom overlay callbacks ===
|
||||
static OverlayCallback overlays[] = {
|
||||
drawFunctionOverlay, // For mute/buzzer modifiers etc.
|
||||
drawCustomFrameIcons // Custom indicator icons for each frame
|
||||
drawFunctionOverlay, // For mute/buzzer modifiers etc.
|
||||
drawCustomFrameIcons // Custom indicator icons for each frame
|
||||
};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
|
||||
@ -3254,14 +3294,14 @@ void Screen::setup()
|
||||
dispdev->mirrorScreen();
|
||||
#else
|
||||
if (!config.display.flip_screen) {
|
||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
|
||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS)
|
||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
|
||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS)
|
||||
static_cast<TFTDisplay *>(dispdev)->flipScreenVertically();
|
||||
#elif defined(USE_ST7789)
|
||||
#elif defined(USE_ST7789)
|
||||
static_cast<ST7789Spi *>(dispdev)->flipScreenVertically();
|
||||
#else
|
||||
#else
|
||||
dispdev->flipScreenVertically();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -3271,7 +3311,7 @@ void Screen::setup()
|
||||
snprintf(ourId, sizeof(ourId), "%02x%02x", dmac[4], dmac[5]);
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
handleSetOn(false); // Ensure proper init for Arduino targets
|
||||
handleSetOn(false); // Ensure proper init for Arduino targets
|
||||
#endif
|
||||
|
||||
// === Turn on display and trigger first draw ===
|
||||
@ -3285,17 +3325,13 @@ void Screen::setup()
|
||||
// === Optional touchscreen support ===
|
||||
#if ARCH_PORTDUINO && !HAS_TFT
|
||||
if (settingsMap[touchscreenModule]) {
|
||||
touchScreenImpl1 = new TouchScreenImpl1(
|
||||
dispdev->getWidth(), dispdev->getHeight(),
|
||||
static_cast<TFTDisplay *>(dispdev)->getTouch
|
||||
);
|
||||
touchScreenImpl1 =
|
||||
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
|
||||
touchScreenImpl1->init();
|
||||
}
|
||||
#elif HAS_TOUCHSCREEN
|
||||
touchScreenImpl1 = new TouchScreenImpl1(
|
||||
dispdev->getWidth(), dispdev->getHeight(),
|
||||
static_cast<TFTDisplay *>(dispdev)->getTouch
|
||||
);
|
||||
touchScreenImpl1 =
|
||||
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
|
||||
touchScreenImpl1->init();
|
||||
#endif
|
||||
|
||||
@ -3728,7 +3764,7 @@ void Screen::setFrames(FrameFocus focus)
|
||||
}
|
||||
#endif
|
||||
|
||||
fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE
|
||||
fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE
|
||||
this->frameCount = numframes; // ✅ Save frame count for use in custom overlay
|
||||
LOG_DEBUG("Finished build frames. numframes: %d", numframes);
|
||||
|
||||
@ -3736,10 +3772,7 @@ void Screen::setFrames(FrameFocus focus)
|
||||
ui->disableAllIndicators();
|
||||
|
||||
// Add function overlay here. This can show when notifications muted, modifier key is active etc
|
||||
static OverlayCallback overlays[] = {
|
||||
drawFunctionOverlay,
|
||||
drawCustomFrameIcons
|
||||
};
|
||||
static OverlayCallback overlays[] = {drawFunctionOverlay, drawCustomFrameIcons};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
|
||||
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
|
||||
|
@ -258,85 +258,76 @@ static const unsigned char mail[] PROGMEM = {
|
||||
|
||||
// 📬 Mail / Message
|
||||
const uint8_t icon_mail[] PROGMEM = {
|
||||
0b00000000, // (padding)
|
||||
0b11111111, // ████████ top border
|
||||
0b10000001, // █ █ sides
|
||||
0b11000011, // ██ ██ diagonal
|
||||
0b10100101, // █ █ █ █ inner M
|
||||
0b10011001, // █ ██ █ inner M
|
||||
0b10000001, // █ █ sides
|
||||
0b11111111, // ████████ bottom
|
||||
0b00000000 // (padding)
|
||||
0b11111111 // ████████ bottom
|
||||
};
|
||||
|
||||
// 📍 GPS Screen / Location Pin
|
||||
const uint8_t icon_compass[] PROGMEM = {
|
||||
0b00011000, // ██
|
||||
0b00111100, // ████
|
||||
0b01100110, // ██ ██
|
||||
0b01000010, // █ █
|
||||
0b01000010, // █ █
|
||||
0b00111100, // ████
|
||||
0b00011000, // ██
|
||||
0b00010000 // █
|
||||
const unsigned char icon_compass[] PROGMEM = {
|
||||
0x3C, // Row 0: ..####..
|
||||
0x52, // Row 1: .#..#.#.
|
||||
0x91, // Row 2: #...#..#
|
||||
0x91, // Row 3: #...#..#
|
||||
0x91, // Row 4: #...#..#
|
||||
0x81, // Row 5: #......#
|
||||
0x42, // Row 6: .#....#.
|
||||
0x3C // Row 7: ..####..
|
||||
};
|
||||
|
||||
const uint8_t icon_radio[] PROGMEM = {
|
||||
0b00111000, // ░███░
|
||||
0b01000100, // █░░░█
|
||||
0b10000010, // █░░░░█
|
||||
0b00010000, // ░░█░
|
||||
0b00010000, // ░░█░
|
||||
0b00111000, // ░███░
|
||||
0b01111100, // █████
|
||||
0b00000000 // ░░░░░
|
||||
0x0F, // Row 0: ####....
|
||||
0x10, // Row 1: ....#...
|
||||
0x27, // Row 2: ###..#..
|
||||
0x48, // Row 3: ...#..#.
|
||||
0x93, // Row 4: ##..#..#
|
||||
0xA4, // Row 5: ..#..#.#
|
||||
0xA8, // Row 6: ...#.#.#
|
||||
0xA9 // Row 7: #..#.#.#
|
||||
};
|
||||
|
||||
// 🪙 Memory Drum Icon (Barrel shape with cuts on the sides)
|
||||
// 🪙 Memory Icon
|
||||
const uint8_t icon_memory[] PROGMEM = {
|
||||
0b00111100, // ░░████░░
|
||||
0b01111110, // ░██████░
|
||||
0b11100111, // ███░░███
|
||||
0b11100111, // ███░░███
|
||||
0b11100111, // ███░░███
|
||||
0b11100111, // ███░░███
|
||||
0b01111110, // ░██████░
|
||||
0b00111100 // ░░████░░
|
||||
0x24, // Row 0: ..#..#..
|
||||
0x3C, // Row 1: ..####..
|
||||
0xC3, // Row 2: ##....##
|
||||
0x5A, // Row 3: .#.##.#.
|
||||
0x5A, // Row 4: .#.##.#.
|
||||
0xC3, // Row 5: ##....##
|
||||
0x3C, // Row 6: ..####..
|
||||
0x24 // Row 7: ..#..#..
|
||||
};
|
||||
|
||||
// 🌐 Wi-Fi
|
||||
const uint8_t icon_wifi[] PROGMEM = {
|
||||
0b00000000,
|
||||
0b00011000,
|
||||
0b00111100,
|
||||
0b01111110,
|
||||
0b11011011,
|
||||
0b00011000,
|
||||
0b00011000,
|
||||
0b00000000
|
||||
};
|
||||
const uint8_t icon_wifi[] PROGMEM = {0b00000000, 0b00011000, 0b00111100, 0b01111110,
|
||||
0b11011011, 0b00011000, 0b00011000, 0b00000000};
|
||||
|
||||
// 📄 Paper/List Icon (for DynamicNodeListScreen)
|
||||
const uint8_t icon_nodes[] PROGMEM = {
|
||||
0b11111111, // Top edge of paper
|
||||
0b10000001, // Left & right margin
|
||||
0b10101001, // ••• line
|
||||
0b10000001, //
|
||||
0b10101001, // ••• line
|
||||
0b10000001, //
|
||||
0b11111111, // Bottom edge
|
||||
0b00000000 //
|
||||
0xF9, // Row 0 #..#######
|
||||
0x00, // Row 1
|
||||
0xF9, // Row 2 #..#######
|
||||
0x00, // Row 3
|
||||
0xF9, // Row 4 #..#######
|
||||
0x00, // Row 5
|
||||
0xF9, // Row 6 #..#######
|
||||
0x00 // Row 7
|
||||
};
|
||||
|
||||
// ➤ Chevron Triangle Arrow Icon (8x8)
|
||||
const uint8_t icon_list[] PROGMEM = {
|
||||
0b00011000, // ░░██░░
|
||||
0b00011100, // ░░███░
|
||||
0b00011110, // ░░████
|
||||
0b11111111, // ██████
|
||||
0b00011110, // ░░████
|
||||
0b00011100, // ░░███░
|
||||
0b00011000, // ░░██░░
|
||||
0b00000000 // ░░░░░░
|
||||
0x10, // Row 0: ...#....
|
||||
0x10, // Row 1: ...#....
|
||||
0x38, // Row 2: ..###...
|
||||
0x38, // Row 3: ..###...
|
||||
0x7C, // Row 4: .#####..
|
||||
0x6C, // Row 5: .##.##..
|
||||
0xC6, // Row 6: ##...##.
|
||||
0x82 // Row 7: #.....#.
|
||||
};
|
||||
|
||||
// 📶 Signal Bars Icon (left to right, small to large with spacing)
|
||||
@ -377,14 +368,14 @@ const uint8_t icon_error[] PROGMEM = {
|
||||
|
||||
// 🏠 Optimized Home Icon (8x8)
|
||||
const uint8_t icon_home[] PROGMEM = {
|
||||
0b00011000, // ██
|
||||
0b00111100, // ████
|
||||
0b01111110, // ██████
|
||||
0b11111111, // ███████
|
||||
0b11000011, // ██ ██
|
||||
0b11011011, // ██ ██ ██
|
||||
0b11011011, // ██ ██ ██
|
||||
0b11111111 // ███████
|
||||
0b00011000, // ██
|
||||
0b00111100, // ████
|
||||
0b01111110, // ██████
|
||||
0b11111111, // ███████
|
||||
0b11000011, // ██ ██
|
||||
0b11011011, // ██ ██ ██
|
||||
0b11011011, // ██ ██ ██
|
||||
0b11111111 // ███████
|
||||
};
|
||||
|
||||
// 🔧 Generic module (gear-like shape)
|
||||
|
Loading…
Reference in New Issue
Block a user