From fe9b8d4e1040f34d80c790f3e84fb538b117f321 Mon Sep 17 00:00:00 2001 From: Marcus Kida Date: Mon, 6 Jul 2026 14:41:43 +0200 Subject: [PATCH] add menu icons --- .../include/user_interface/menuSystem.h | 3 + .../user_interface/menuDisplayMenuList.c | 3 + .../source/user_interface/menuSystem.c | 59 ++++++++++++++++++- 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/MDUV380_firmware/application/include/user_interface/menuSystem.h b/MDUV380_firmware/application/include/user_interface/menuSystem.h index 06e7792..be5fe5d 100644 --- a/MDUV380_firmware/application/include/user_interface/menuSystem.h +++ b/MDUV380_firmware/application/include/user_interface/menuSystem.h @@ -172,6 +172,9 @@ typedef struct void menuDisplayTitle(const char *title); void menuDisplayEntry(int loopOffset, int focusedItem, const char *entryText, int32_t optStart, themeItem_t fgItem, themeItem_t fgOptItem, themeItem_t bgItem); +#if defined(HAS_COLOURS) +void menuSetNextEntryIconByMenuNum(int menuNum); // sets the icon the next menuDisplayEntry() will draw (0/none for menus without an icon) +#endif // menuGetMenuOffset() return values #define MENU_OFFSET_BEFORE_FIRST_ENTRY -1 diff --git a/MDUV380_firmware/application/source/user_interface/menuDisplayMenuList.c b/MDUV380_firmware/application/source/user_interface/menuDisplayMenuList.c index 03d0dbe..5bc2fb4 100644 --- a/MDUV380_firmware/application/source/user_interface/menuDisplayMenuList.c +++ b/MDUV380_firmware/application/source/user_interface/menuDisplayMenuList.c @@ -121,6 +121,9 @@ static void updateScreen(bool isFirstRun) if (menuDataGlobal.currentMenuList[mNum].stringOffset >= 0) { const char *menuName = (currentLanguage->LANGUAGE_NAME + (menuDataGlobal.currentMenuList[mNum].stringOffset * LANGUAGE_TEXTS_LENGTH)); +#if defined(HAS_COLOURS) + menuSetNextEntryIconByMenuNum(menuDataGlobal.currentMenuList[mNum].menuNum); +#endif menuDisplayEntry(i, mNum, menuName, 0, THEME_ITEM_FG_MENU_ITEM, THEME_ITEM_COLOUR_NONE, THEME_ITEM_BG); if (i == 0) diff --git a/MDUV380_firmware/application/source/user_interface/menuSystem.c b/MDUV380_firmware/application/source/user_interface/menuSystem.c index f3b13ac..380208c 100644 --- a/MDUV380_firmware/application/source/user_interface/menuSystem.c +++ b/MDUV380_firmware/application/source/user_interface/menuSystem.c @@ -725,9 +725,53 @@ void menuDisplayTitle(const char *title) // optStart: // - if less than 0, entryText will use fgOptItem colour // - if equal to 0, no coloured option will be handled +#if defined(HAS_COLOURS) +// 16x16 1-bit main-menu icons (row-major, MSB-first) for displayDrawBitmap. +static const uint8_t menuIcon_zone[32] = { 0x00, 0x00, 0x3F, 0xFC, 0x20, 0x04, 0x2F, 0xF4, 0x20, 0x04, 0x2F, 0xF4, 0x20, 0x04, 0x2F, 0xF4, 0x20, 0x04, 0x2F, 0xF4, 0x20, 0x04, 0x3F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t menuIcon_contacts[32] = { 0x00, 0x00, 0x03, 0xC0, 0x07, 0xE0, 0x05, 0xA0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x0F, 0xF0, 0x1F, 0xF8, 0x3F, 0xFC, 0x30, 0x0C, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t menuIcon_channel[32] = { 0x00, 0x00, 0x00, 0x00, 0x21, 0x08, 0x21, 0x08, 0x71, 0x1C, 0x51, 0x14, 0x73, 0x9C, 0x22, 0x88, 0x23, 0x88, 0x21, 0x08, 0x21, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t menuIcon_rssi[32] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x66, 0x00, 0x66, 0x00, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t menuIcon_info[32] = { 0x00, 0x00, 0x07, 0xE0, 0x18, 0x18, 0x21, 0x84, 0x21, 0x84, 0x40, 0x08, 0x43, 0xC2, 0x40, 0xC2, 0x40, 0xC2, 0x40, 0xC2, 0x21, 0xE2, 0x20, 0x04, 0x18, 0x18, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t menuIcon_options[32] = { 0x00, 0x00, 0x03, 0xC0, 0x13, 0xC8, 0x1B, 0xD8, 0x3F, 0xFC, 0x38, 0x1C, 0x7B, 0xDE, 0x7B, 0xDE, 0x7B, 0xDE, 0x38, 0x1C, 0x3F, 0xFC, 0x1B, 0xD8, 0x13, 0xC8, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t menuIcon_lastheard[32] = { 0x00, 0x00, 0x3F, 0xF8, 0x40, 0x04, 0x4C, 0x62, 0x40, 0x04, 0x4C, 0x62, 0x40, 0x04, 0x4C, 0x62, 0x40, 0x04, 0x3C, 0x7C, 0x04, 0x40, 0x02, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t menuIcon_radio[32] = { 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x1F, 0xC0, 0x10, 0x40, 0x17, 0x40, 0x17, 0x40, 0x10, 0x40, 0x15, 0x40, 0x15, 0x40, 0x15, 0x40, 0x10, 0x40, 0x1F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t menuIcon_satellite[32] = { 0x00, 0x00, 0x30, 0x00, 0x28, 0x10, 0x24, 0x28, 0x02, 0x44, 0x01, 0x94, 0x00, 0xA4, 0x01, 0x38, 0x02, 0x00, 0x0D, 0x00, 0x11, 0x00, 0x11, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t menuIcon_gps[32] = { 0x00, 0x00, 0x07, 0xE0, 0x18, 0x18, 0x20, 0x04, 0x43, 0xC2, 0x44, 0x22, 0x44, 0x22, 0x44, 0x22, 0x43, 0xC2, 0x20, 0x04, 0x10, 0x08, 0x08, 0x10, 0x04, 0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x00 }; + +static const uint8_t *menuIconForMenuNumber(int menuNum) +{ + switch (menuNum) + { + case MENU_ZONE_LIST: return menuIcon_zone; + case MENU_CONTACTS_MENU: return menuIcon_contacts; + case MENU_CHANNEL_DETAILS: return menuIcon_channel; + case MENU_RSSI_SCREEN: return menuIcon_rssi; + case MENU_FIRMWARE_INFO: return menuIcon_info; + case MENU_OPTIONS: return menuIcon_options; + case MENU_LAST_HEARD: return menuIcon_lastheard; + case MENU_RADIO_INFOS: return menuIcon_radio; + case MENU_SATELLITE: return menuIcon_satellite; + case MENU_GPS: return menuIcon_gps; + default: return NULL; + } +} + +// One-shot: the next menuDisplayEntry() draws this icon and shifts its text right. +static const uint8_t *nextMenuEntryIcon = NULL; +void menuSetNextEntryIconByMenuNum(int menuNum) +{ + nextMenuEntryIcon = menuIconForMenuNumber(menuNum); +} +#endif // HAS_COLOURS + void menuDisplayEntry(int loopOffset, int focusedItem, const char *entryText, int32_t optStart, themeItem_t fgItem, themeItem_t fgOptItem, themeItem_t bgItem) { bool focused = (focusedItem == menuDataGlobal.currentItemIndex); + int16_t textXPos = DISPLAY_X_POS_MENU_TEXT_OFFSET; +#if defined(HAS_COLOURS) + const uint8_t *entryIcon = nextMenuEntryIcon; + nextMenuEntryIcon = NULL; // consume it (one-shot) +#endif if (focused) { @@ -741,6 +785,15 @@ void menuDisplayEntry(int loopOffset, int focusedItem, const char *entryText, in displayThemeApply(fgItem, bgItem); +#if defined(HAS_COLOURS) + if (entryIcon != NULL) + { + int16_t iconY = DISPLAY_Y_POS_MENU_ENTRY_HIGHLIGHT + (loopOffset * MENU_ENTRY_HEIGHT); + displayDrawBitmap((DISPLAY_X_POS_MENU_OFFSET + 2), iconY, (uint8_t *)entryIcon, 16, 16, focused); + textXPos = (DISPLAY_X_POS_MENU_OFFSET + 2 + 16 + 3); // icon width + gap + } +#endif + if ((focused == false) && ((optStart < 0) || (optStart > 0))) { char buffer[SCREEN_LINE_BUFFER_SIZE]; @@ -752,17 +805,17 @@ void menuDisplayEntry(int loopOffset, int focusedItem, const char *entryText, in displayThemeApply(fgOptItem, bgItem); } - displayPrintCore(DISPLAY_X_POS_MENU_TEXT_OFFSET, DISPLAY_Y_POS_MENU_ENTRY_HIGHLIGHT + (loopOffset * MENU_ENTRY_HEIGHT), buffer, FONT_SIZE_3, TEXT_ALIGN_LEFT, focused); + displayPrintCore(textXPos, DISPLAY_Y_POS_MENU_ENTRY_HIGHLIGHT + (loopOffset * MENU_ENTRY_HEIGHT), buffer, FONT_SIZE_3, TEXT_ALIGN_LEFT, focused); if (optStart > 0) { displayThemeApply(fgOptItem, bgItem); - displayPrintCore(DISPLAY_X_POS_MENU_TEXT_OFFSET + (optStart * 8), DISPLAY_Y_POS_MENU_ENTRY_HIGHLIGHT + (loopOffset * MENU_ENTRY_HEIGHT), (entryText + optStart), FONT_SIZE_3, TEXT_ALIGN_LEFT, focused); + displayPrintCore(textXPos + (optStart * 8), DISPLAY_Y_POS_MENU_ENTRY_HIGHLIGHT + (loopOffset * MENU_ENTRY_HEIGHT), (entryText + optStart), FONT_SIZE_3, TEXT_ALIGN_LEFT, focused); } } else { - displayPrintCore(DISPLAY_X_POS_MENU_TEXT_OFFSET, DISPLAY_Y_POS_MENU_ENTRY_HIGHLIGHT + (loopOffset * MENU_ENTRY_HEIGHT), entryText, FONT_SIZE_3, TEXT_ALIGN_LEFT, focused); + displayPrintCore(textXPos, DISPLAY_Y_POS_MENU_ENTRY_HIGHLIGHT + (loopOffset * MENU_ENTRY_HEIGHT), entryText, FONT_SIZE_3, TEXT_ALIGN_LEFT, focused); } displayThemeResetToDefault();