Themes: add 'Pride' rainbow-background preset

The theme system stores one flat background colour per element, so a rainbow
background can't be expressed as a preset alone. Add a small display hook:
when Pride is selected, displayClearBuf()/displayClearRows() paint the six
pride-flag stripes across the framebuffer instead of a flat fill (gated on a
flag only the Pride preset sets, and behind HAS_COLOURS so mono builds are
untouched). Non-selected menu rows draw text straight over the canvas, while
the title/header/notifications paint solid white boxes, so chrome stays
readable over the stripes; blue/violet are lightened slightly for black-text
contrast. Docs and changelog updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Marcus Kida 2026-07-14 14:47:45 +02:00
parent 5efd14d8b7
commit 3ec4eafbc9
6 changed files with 77 additions and 6 deletions

View file

@ -7,10 +7,15 @@ single running list until the first versioned release.
## Unreleased
- **Two new theme presets** (Display Options → "Theme"): **Red** (black-on-red
day / red-on-black night) and **Neon 80s**, an 80s-synthwave palette that maps
- **Three new theme presets** (Display Options → "Theme"): **Red** (black-on-red
day / red-on-black night); **Neon 80s**, an 80s-synthwave palette that maps
several neon colours (cyan, magenta, violet, green, yellow) across the
individual UI elements over a dark background.
individual UI elements over a dark background; and **Pride**, which paints the
background as a rainbow pride flag with black text and white menu/header boxes
kept readable over the stripes.
- **Build:** each build now prints a per-region memory-usage summary
(FLASH / RAM / CCMRAM used, size and free) so the remaining headroom is
visible after every build.
## 0.7.1

View file

@ -70,6 +70,11 @@ Pick a colour theme on the radio at **Menu → Options → Display Options → "
- **Red** — black-on-red by day, red-on-black at night.
- **Neon 80s** — an 80s-synthwave palette with several neon colours (cyan,
magenta, violet, green, yellow) across the UI over a dark background.
- **Pride** — the background is painted as a rainbow pride flag; body text is
black over the stripes, and the menu title, header and notifications use white
boxes so they stay readable. (Text drawn directly over the brightest stripes
has lower contrast than a solid-background theme — that's inherent to a
rainbow background.)
Editing colours in the CPS only affects **Custom**; the built-in presets are
fixed. Every element (S-meter, frequencies, menus) follows the selected theme.

View file

@ -279,6 +279,7 @@ typedef enum
THEME_PRESET_VERTEXIC, // amber/orange (black-on-amber day / amber-on-black night)
THEME_PRESET_RED, // red (black-on-red day / red-on-black night)
THEME_PRESET_NEON80S, // 80s synthwave: cyan/magenta/violet/green neon on dark
THEME_PRESET_PRIDE, // pride flag: black text + white chrome over a rainbow background
NUM_THEME_PRESETS
} themePreset_t;

View file

@ -67,6 +67,21 @@ static uint16_t backgroundColour = 0xFFFFU;
static uint16_t screenBufData[DISPLAY_SIZE_X * DISPLAY_SIZE_Y];
uint16_t *screenBuf = screenBufData;
#if defined(HAS_COLOURS)
// When the Pride theme is active the background canvas is painted as six
// horizontal rainbow stripes instead of a single flat colour.
static bool prideBackgroundActive = false;
static uint16_t prideStripes[6];
// Pride stripe colour for a linear screen-buffer index (row = index / width).
static inline uint16_t pridePixelColour(int index)
{
int band = ((index / DISPLAY_SIZE_X) * 6) / DISPLAY_SIZE_Y;
return prideStripes[(band < 0) ? 0 : ((band > 5) ? 5 : band)];
}
#endif
//#define DISPLAY_CHECK_BOUNDS
#ifdef DISPLAY_CHECK_BOUNDS
@ -326,6 +341,16 @@ int displayPrintCoreDoubleHeight(int16_t xPos, int16_t yPos, const char *szMsg,
void displayClearBuf(void)
{
#if defined(HAS_COLOURS)
if (prideBackgroundActive)
{
for (int i = 0; i < DISPLAY_SIZE_X * DISPLAY_SIZE_Y; i++)
{
screenBuf[i] = pridePixelColour(i);
}
return;
}
#endif
// may be able to do this using DMA
for(int i = 0; i < DISPLAY_SIZE_X * DISPLAY_SIZE_Y; i++)
{
@ -353,7 +378,11 @@ void displayClearRows(int16_t startRow, int16_t endRow, bool isInverted)
for(int i = startRow; i < endRow; i++)
{
#if defined(HAS_COLOURS)
screenBuf[i] = ((prideBackgroundActive && (isInverted == false)) ? pridePixelColour(i) : fillColour);
#else
screenBuf[i] = fillColour;
#endif
}
}
@ -1584,12 +1613,27 @@ static void themeSetNeon80s(DayTime_t daytime, uint32_t bg)
themeSetItem(daytime, THEME_ITEM_FG_BD_COLOUR, orange);
}
// Pride: the background canvas is painted as a rainbow (see pridePixelColour);
// the theme items only need black text plus white "chrome" boxes (menu title,
// header, notifications) so those stay readable over any stripe. The selected
// menu row already inverts to a black bar with white text.
static void themeSetPride(DayTime_t daytime)
{
themeSetAllItems(daytime, 0x000000, 0xFFFFFF); // black text, white chrome backgrounds
// Keep warning/error notifications colour-coded on their white box.
themeSetItem(daytime, THEME_ITEM_FG_WARNING_NOTIFICATION, 0xC07800);
themeSetItem(daytime, THEME_ITEM_FG_ERROR_NOTIFICATION, 0xC00000);
}
void themeApplyPreset(uint8_t preset)
{
// Start from the monochrome defaults, then overlay the chosen preset.
themeInitToDefaultValues(NIGHT, true);
themeInitToDefaultValues(DAY, false);
prideBackgroundActive = false; // only the Pride preset re-enables the rainbow canvas
switch (preset)
{
case THEME_PRESET_BASIC80S: // Commodore 64 BASIC: light blue on blue (day & night)
@ -1617,6 +1661,22 @@ void themeApplyPreset(uint8_t preset)
themeSetNeon80s(NIGHT, 0x08040F); // near-black purple
break;
case THEME_PRESET_PRIDE: // rainbow background canvas
{
// Classic 6-stripe pride flag; blue/violet lightened a little so
// black text stays legible over the lower stripes.
static const uint32_t prideRGB[6] = { 0xE40303, 0xFF8C00, 0xFFED00, 0x22A93F, 0x3D7DF0, 0xB05CD6 };
for (int s = 0; s < 6; s++)
{
prideStripes[s] = PLATFORM_COLOUR_FORMAT_SWAP_BYTES(RGB888_TO_PLATFORM_COLOUR_FORMAT(prideRGB[s]));
}
prideBackgroundActive = true;
themeSetPride(DAY);
themeSetPride(NIGHT);
}
break;
case THEME_PRESET_CUSTOM:
default:
// Overlay the user's Custom theme from the codeplug, if present (CPS edits

View file

@ -276,7 +276,7 @@ static void updateScreen(bool isFirstRun)
case DISPLAY_THEME_PRESET:
{
// Preset names are plain literals -> rightSideVar (voice-safe).
const char *presetNames[] = { "Custom", "BASIC 80s", "Terminal", "Vertexic", "Red", "Neon 80s" };
const char *presetNames[] = { "Custom", "BASIC 80s", "Terminal", "Vertexic", "Red", "Neon 80s", "Pride" };
uint8_t p = themeGetPreset();
leftSide = "Theme";
snprintf(rightSideVar, SCREEN_LINE_BUFFER_SIZE, "%s", presetNames[(p < NUM_THEME_PRESETS) ? p : 0]);

View file

@ -41,8 +41,8 @@ FreeTRX keeps OpenGD77's core (DMR/FM, hotspot, CPS compatibility) and adds:
incoming-message popup (see the manual for details).
- **Theme presets** — pick a colour theme on the radio: **Custom** (CPS-editable,
default), **BASIC 80s** (Commodore 64), **Terminal** (green-on-black),
**Vertexic** (amber/orange), **Red**, or **Neon 80s** (multi-colour synthwave).
CPS edits only affect Custom.
**Vertexic** (amber/orange), **Red**, **Neon 80s** (multi-colour synthwave),
or **Pride** (rainbow background). CPS edits only affect Custom.
- **On-radio channel management** — create and delete channels directly from the
Channel quick menu, no PC/CPS required (see [Managing channels](#managing-channels-on-the-radio)).
- **DMR reliability fix** — resolves a hard-fault (freeze needing a battery pull)