Frequency display: 7-segment "LED" font with dimmed inactive segments

Render the VFO/Channel frequency (and the SK1-held frequency view, which share
uiUtilityDisplayFrequency) as 7-segment "LED" digits instead of the normal font,
on colour displays.

- HX8353E_display.c: displayDrawFrequencySevenSeg() draws each digit's 7 segments
  as filled rectangles; lit segments use the theme frequency colour, inactive
  segments a dimmed (~3/8 intensity, same hue) version, giving the classic LED
  look with faintly-visible "off" segments. The decimal point takes half a cell.
- Digits are 12 px wide (wider than the 8 px font) to fill the space toward the
  "MHz" label; height follows the existing single/double-height frequency layout.
- Monochrome displays keep the normal font.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marcus Kida 2026-07-06 13:34:35 +02:00
parent ad52422031
commit 70089d370f
3 changed files with 83 additions and 0 deletions

View file

@ -263,6 +263,11 @@ uint16_t displayConvertRGB888ToNative(uint32_t RGB888);
void displaySetForegroundAndBackgroundColours(uint16_t fgColour, uint16_t bgColour); void displaySetForegroundAndBackgroundColours(uint16_t fgColour, uint16_t bgColour);
void displayGetForegroundAndBackgroundColours(uint16_t *fgColour, uint16_t *bgColour); void displayGetForegroundAndBackgroundColours(uint16_t *fgColour, uint16_t *bgColour);
#if defined(HAS_COLOURS)
// Render a numeric string as 7-segment "LED" digits with dimmed inactive segments.
void displayDrawFrequencySevenSeg(int16_t x, int16_t y, int16_t cellW, int16_t cellH, const char *str, themeItem_t fgItem);
#endif
#if defined(HAS_COLOURS) #if defined(HAS_COLOURS)
void themeInitToDefaultValues(DayTime_t daytime, bool invert); void themeInitToDefaultValues(DayTime_t daytime, bool invert);
void themeInit(bool SPIFlashAvailable); void themeInit(bool SPIFlashAvailable);

View file

@ -1063,6 +1063,77 @@ void displayFillRect(int16_t x, int16_t y, int16_t width, int16_t height, bool i
} }
} }
#if defined(HAS_COLOURS)
// --- 7-segment ("LED") number rendering ------------------------------------
// Segment bitmask per digit 0-9. Bits: a=0x01 b=0x02 c=0x04 d=0x08 e=0x10 f=0x20 g=0x40
//
// aaa
// f b
// f b
// ggg
// e c
// e c
// ddd
static const uint8_t sevenSegDigits[10] =
{
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F
};
// Draw one digit's 7 segments inside a w x h cell. Lit segments use litColour,
// the rest use dimColour, giving the "inactive segments faintly visible" look.
static void displayDrawSevenSegDigit(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t seg, uint16_t litColour, uint16_t dimColour, uint16_t bgColour)
{
int16_t t = (h > 20) ? 3 : 2; // segment thickness
int16_t midY = y + (h / 2);
int16_t vLen = (h / 2) - t; // vertical segment length
#define SEG_COL(bit) displaySetForegroundAndBackgroundColours((((seg) & (bit)) ? litColour : dimColour), bgColour)
SEG_COL(0x01); displayFillRect(x + t, y, w - (2 * t), t, false); // a top
SEG_COL(0x02); displayFillRect(x + w - t, y + t, t, vLen, false); // b top-right
SEG_COL(0x04); displayFillRect(x + w - t, midY, t, vLen, false); // c bottom-right
SEG_COL(0x08); displayFillRect(x + t, y + h - t, w - (2 * t), t, false); // d bottom
SEG_COL(0x10); displayFillRect(x, midY, t, vLen, false); // e bottom-left
SEG_COL(0x20); displayFillRect(x, y + t, t, vLen, false); // f top-left
SEG_COL(0x40); displayFillRect(x + t, midY - (t / 2), w - (2 * t), t, false); // g middle
#undef SEG_COL
}
// Render a numeric string (digits, '.', spaces) as 7-segment "LED" characters,
// one cellW-wide cell per character, using the given theme foreground colour lit
// and a dimmed version of it for the inactive segments.
void displayDrawFrequencySevenSeg(int16_t x, int16_t y, int16_t cellW, int16_t cellH, const char *str, themeItem_t fgItem)
{
uint16_t litColour = themeItems[DAYTIME_CURRENT][fgItem];
uint16_t bgColour = themeItems[DAYTIME_CURRENT][THEME_ITEM_BG];
// dimColour: same hue at ~3/8 intensity (round-trip through RGB888) so the
// inactive segments stay clearly visible without washing out the lit ones.
uint32_t rgb = PLATFORM_COLOUR_FORMAT_TO_RGB888(__builtin_bswap16(litColour));
uint32_t dimRgb = (((((rgb >> 16) & 0xFF) * 3) / 8) << 16) | (((((rgb >> 8) & 0xFF) * 3) / 8) << 8) | ((((rgb) & 0xFF) * 3) / 8);
uint16_t dimColour = __builtin_bswap16(RGB888_TO_PLATFORM_COLOUR_FORMAT(dimRgb));
for (const char *p = str; *p != '\0'; p++)
{
if ((*p >= '0') && (*p <= '9'))
{
displayDrawSevenSegDigit(x, y, (cellW - 1), cellH, sevenSegDigits[*p - '0'], litColour, dimColour, bgColour);
x += cellW;
}
else if (*p == '.')
{
// The decimal point takes half a cell so the wide digits still fit.
displaySetForegroundAndBackgroundColours(litColour, bgColour);
displayFillRect((x + 1), (y + cellH - 3), 3, 3, false);
x += (cellW / 2);
}
else
{
x += cellW;
}
}
}
#endif // HAS_COLOURS
/* /*
* *
*/ */

View file

@ -2504,7 +2504,14 @@ void uiUtilityDisplayFrequency(uint8_t y, bool isTX, bool hasFocus, uint32_t fre
// Frequency // Frequency
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%d.%05d", val_before_dp, val_after_dp); snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%d.%05d", val_before_dp, val_after_dp);
#if defined(HAS_COLOURS)
// 7-segment "LED" style with faint inactive segments. Digits are wider than the
// normal font (12 px cells) to fill the space up to the "MHz" label.
displayDrawFrequencySevenSeg(FREQUENCY_X_POS, yFont3, 12, (displayFocusAndDblHeight ? (FONT_SIZE_3_HEIGHT * 2) : FONT_SIZE_3_HEIGHT),
buffer, (isTX ? THEME_ITEM_FG_TX_FREQ : THEME_ITEM_FG_RX_FREQ));
#else
displayPrintAtDoubleHeight(FREQUENCY_X_POS, yFont3, buffer, FONT_SIZE_3, displayFocusAndDblHeight); displayPrintAtDoubleHeight(FREQUENCY_X_POS, yFont3, buffer, FONT_SIZE_3, displayFocusAndDblHeight);
#endif
displayPrintAtDoubleHeight(DISPLAY_SIZE_X - (3 * 8), yFont3, "MHz", FONT_SIZE_3, displayFocusAndDblHeight); displayPrintAtDoubleHeight(DISPLAY_SIZE_X - (3 * 8), yFont3, "MHz", FONT_SIZE_3, displayFocusAndDblHeight);
displayThemeResetToDefault(); displayThemeResetToDefault();