смена темы дисплея в рантайме: страница THEME, образцы цветов, сохранение в prefs
Build and deploy Docs site to GitHub Pages / github-pages (push) Canceled after 0s
Run Unit Tests / test (push) Canceled after 0s
PR Build Check / build (Heltec_v3_companion_radio_ble) (push) Canceled after 0s
PR Build Check / build (Heltec_v3_repeater) (push) Canceled after 0s
PR Build Check / build (Heltec_v3_room_server) (push) Canceled after 0s
PR Build Check / build (LilyGo_Tlora_C6_repeater_) (push) Canceled after 0s
PR Build Check / build (PicoW_repeater) (push) Canceled after 0s
PR Build Check / build (RAK_4631_companion_radio_ble) (push) Canceled after 0s
PR Build Check / build (RAK_4631_companion_radio_ethernet) (push) Canceled after 0s
PR Build Check / build (RAK_4631_repeater) (push) Canceled after 0s
PR Build Check / build (RAK_4631_repeater_ethernet) (push) Canceled after 0s
PR Build Check / build (RAK_4631_room_server) (push) Canceled after 0s
PR Build Check / build (RAK_4631_room_server_ethernet) (push) Canceled after 0s
PR Build Check / build (Tbeam_SX1276_repeater) (push) Canceled after 0s
PR Build Check / build (wio-e5-mini_repeater) (push) Canceled after 0s
PR Build Check / build (wio_wm1110_repeater) (push) Canceled after 0s

This commit is contained in:
shade committed 2026-10-08 20:00:56 +03:00
1 parent 3c10296b90
commit 76e754f7ad
6 files changed
+280 -81

No files matched your search

+27
View File
@@ -172,4 +172,31 @@ public:
}
virtual void endFrame() = 0;
// Темы (палитры). По умолчанию тем нет — так у монохромных панелей
// (SSD1306 / SH1106 / e-ink), где все цвета и так белые.
virtual uint8_t getThemeCount() { return 0; }
virtual const char* getThemeName(uint8_t i) { (void)i; return ""; }
virtual uint8_t getTheme() { return 0; }
virtual void setTheme(uint8_t i) { (void)i; }
// Роли цветов темы — для образцов в меню выбора темы
enum ThemeColorRole {
THEME_COLOR_WINDOW = 0, // фон
THEME_COLOR_TITLE, // полоса заголовка
THEME_COLOR_POPUP, // заливка попапа
THEME_COLOR_ACCENT, // акцент (предупреждения)
THEME_COLOR_TEXT, // основной текст
};
virtual ColorVal getThemeColor(uint8_t theme, uint8_t role) { (void)theme; (void)role; return 0; }
// Поиск темы по имени (имена хранятся в prefs — устойчиво к перестановке тем в таблице).
// Возвращает 0xFF, если имени нет.
uint8_t findTheme(const char* name) {
if (name == NULL || name[0] == 0) return 0xFF;
for (uint8_t i = 0; i < getThemeCount(); i++) {
if (strcmp(getThemeName(i), name) == 0) return i;
}
return 0xFF;
}
};
+91 -76
View File
@@ -422,97 +422,112 @@ bool ST7735Display::i2c_probe(TwoWire& wire, uint8_t addr) {
// Color scheme
//
// Палитры вынесены в таблицу, поэтому тема переключается в рантайме (UIColor::* —
// обычные статические переменные, не const). Выбранная тема хранится в prefs по имени
// и применяется при старте; в меню ui-new есть страница THEME с живым предпросмотром.
//
// Тема по умолчанию зависит от платы:
// - Heltec T096 — AMBER (графит + янтарь);
// - остальные платы на этом драйвере (heltec_t1 / tracker / tracker_v2) —
// официальная схема MeshCore, её же можно включить явно: ST7735_THEME_CLASSIC.
// Любую тему можно включить на любой плате флагом ST7735_THEME_* в platformio.ini
// варианта (см. variants/heltec_t096).
// официальная схема MeshCore (CLASSIC).
// Флаг ST7735_THEME_* в platformio.ini варианта переопределяет этот дефолт.
//
// Тема CLASSIC взята из upstream: github.com/meshcore-dev/MeshCore, ветка main,
// src/helpers/ui/ST7735Display.cpp. Это светлая схема: белый фон, чёрный текст.
// CLASSIC взята из upstream: github.com/meshcore-dev/MeshCore, ветка main,
// src/helpers/ui/ST7735Display.cpp — светлая схема (белый фон, чёрный текст).
// В форке она была перекрашена в тёмную вручную, здесь восстановлен оригинал.
#if (defined(ST7735_THEME_CLASSIC) + defined(ST7735_THEME_AMBER) + defined(ST7735_THEME_TEAL) + defined(ST7735_THEME_SIGNAL) + defined(ST7735_THEME_NEON)) > 1
#error "ST7735Display: выбрана более чем одна тема ST7735_THEME_*"
#endif
#define MC_CLASSIC_WINDOW_BKG ST77XX_WHITE
#define MC_CLASSIC_TITLE_BKG ST77XX_BLUE
#define MC_CLASSIC_TITLE_TXT ST77XX_WHITE
#define MC_CLASSIC_PRIMARY_TXT ST77XX_BLACK
#define MC_CLASSIC_SECONDARY_TXT ((18 << 11) | (36 << 5) | 18) // mid-gray
#define MC_CLASSIC_WARNING_TXT ST77XX_ORANGE
#define MC_CLASSIC_POPUP_BKG ST77XX_CYAN
#define MC_CLASSIC_POPUP_TXT ST77XX_BLACK
#define MC_CLASSIC_CORP_BLUE 0x001A
#if defined(ST7735_THEME_CLASSIC) // официальная схема MeshCore (светлая)
ColorVal UIColor::window_bkg = MC_CLASSIC_WINDOW_BKG;
ColorVal UIColor::title_bkg = MC_CLASSIC_TITLE_BKG;
ColorVal UIColor::title_txt = MC_CLASSIC_TITLE_TXT;
ColorVal UIColor::primary_txt = MC_CLASSIC_PRIMARY_TXT;
ColorVal UIColor::secondary_txt = MC_CLASSIC_SECONDARY_TXT;
ColorVal UIColor::warning_txt = MC_CLASSIC_WARNING_TXT;
ColorVal UIColor::popup_bkg = MC_CLASSIC_POPUP_BKG;
ColorVal UIColor::popup_txt = MC_CLASSIC_POPUP_TXT;
ColorVal UIColor::corp_blue = MC_CLASSIC_CORP_BLUE;
struct ColorTheme {
const char* name;
ColorVal window_bkg, title_bkg, title_txt, primary_txt,
secondary_txt, warning_txt, popup_bkg, popup_txt, corp_blue;
};
#elif defined(ST7735_THEME_TEAL) // B. ночная бирюза
ColorVal UIColor::window_bkg = 0x0883; // #081018
ColorVal UIColor::title_bkg = 0x1187; // #103038
ColorVal UIColor::title_txt = 0xEFDF; // #E8F8F8
ColorVal UIColor::primary_txt = 0xF7DF; // #F0F8F8
ColorVal UIColor::secondary_txt = 0x8515; // #80A0A8
ColorVal UIColor::warning_txt = 0xFE4A; // #FFC850
ColorVal UIColor::popup_bkg = 0x1696; // #10D0B0
ColorVal UIColor::popup_txt = 0x0881; // #081008
ColorVal UIColor::corp_blue = 0x45DF; // #40B8F8
// Порядок в таблице = порядок в меню выбора темы.
// constexpr — чтобы палитра инициализировалась статически (иначе значения уехали бы
// в .bss и заполнялись динамической инициализацией C++).
static constexpr ColorTheme THEMES[] = {
{ "amber", 0x1082, 0x2146, 0xF79E, 0xFFDF, 0x9493, 0xFD84, 0xFD84, 0x10A3, 0x551F }, // #101010 / #202830 / #FFB020
{ "teal", 0x0883, 0x1187, 0xEFDF, 0xF7DF, 0x8515, 0xFE4A, 0x1696, 0x0881, 0x45DF }, // #081018 / #103038 / #10D0B0
{ "signal", 0x0000, 0xEB07, 0x1082, 0xFFDF, 0x9D15, 0xFE8C, 0xFB46, 0x1082, 0x5D5F }, // #000000 / #E86038 / #FF6830
{ "neon", 0x0000, 0x0000, 0xEF5D, 0xFFFF, 0x8C52, 0xFEA0, 0x18C3, 0xFEA0, 0x555F }, // #000000 / #000000 / #FFD400
{ "classic", ST77XX_WHITE, ST77XX_BLUE, ST77XX_WHITE, ST77XX_BLACK, MC_CLASSIC_SECONDARY_TXT,
ST77XX_ORANGE, ST77XX_CYAN, ST77XX_BLACK, 0x001A }, // официальная светлая
};
#define THEME_COUNT ((uint8_t)(sizeof(THEMES) / sizeof(THEMES[0])))
#elif defined(ST7735_THEME_SIGNAL) // C. чёрный + оранжевый сигнал
ColorVal UIColor::window_bkg = 0x0000; // #000000
ColorVal UIColor::title_bkg = 0xEB07; // #E86038
ColorVal UIColor::title_txt = 0x1082; // #101010
ColorVal UIColor::primary_txt = 0xFFDF; // #F8F8F8
ColorVal UIColor::secondary_txt = 0x9D15; // #98A0A8
ColorVal UIColor::warning_txt = 0xFE8C; // #FFD060
ColorVal UIColor::popup_bkg = 0xFB46; // #FF6830
ColorVal UIColor::popup_txt = 0x1082; // #101010
ColorVal UIColor::corp_blue = 0x5D5F; // #58A8FF
#elif defined(ST7735_THEME_NEON) // D. неон на чёрном
ColorVal UIColor::window_bkg = 0x0000; // #000000
ColorVal UIColor::title_bkg = 0x0000; // #000000 (полоса слита с фоном)
ColorVal UIColor::title_txt = 0xEF5D; // #E8E8E8
ColorVal UIColor::primary_txt = 0xFFFF; // #FFFFFF
ColorVal UIColor::secondary_txt = 0x8C52; // #888890
ColorVal UIColor::warning_txt = 0xFEA0; // #FFD400
ColorVal UIColor::popup_bkg = 0x18C3; // #181818
ColorVal UIColor::popup_txt = 0xFEA0; // #FFD400 (рамка и текст)
ColorVal UIColor::corp_blue = 0x555F; // #50A8FF
#elif defined(ST7735_THEME_AMBER) || defined(HELTEC_T096) // A. графит + янтарь (по умолчанию для T096)
ColorVal UIColor::window_bkg = 0x1082; // #101010
ColorVal UIColor::title_bkg = 0x2146; // #202830
ColorVal UIColor::title_txt = 0xF79E; // #F0F0F0
ColorVal UIColor::primary_txt = 0xFFDF; // #F8F8F8
ColorVal UIColor::secondary_txt = 0x9493; // #909098
ColorVal UIColor::warning_txt = 0xFD84; // #FFB020
ColorVal UIColor::popup_bkg = 0xFD84; // #FFB020
ColorVal UIColor::popup_txt = 0x10A3; // #101418
ColorVal UIColor::corp_blue = 0x551F; // #50A0FF
#else // остальные платы: официальная схема MeshCore
ColorVal UIColor::window_bkg = MC_CLASSIC_WINDOW_BKG;
ColorVal UIColor::title_bkg = MC_CLASSIC_TITLE_BKG;
ColorVal UIColor::title_txt = MC_CLASSIC_TITLE_TXT;
ColorVal UIColor::primary_txt = MC_CLASSIC_PRIMARY_TXT;
ColorVal UIColor::secondary_txt = MC_CLASSIC_SECONDARY_TXT;
ColorVal UIColor::warning_txt = MC_CLASSIC_WARNING_TXT;
ColorVal UIColor::popup_bkg = MC_CLASSIC_POPUP_BKG;
ColorVal UIColor::popup_txt = MC_CLASSIC_POPUP_TXT;
ColorVal UIColor::corp_blue = MC_CLASSIC_CORP_BLUE;
static constexpr uint8_t default_theme_index() {
#if defined(ST7735_THEME_CLASSIC)
return 4;
#elif defined(ST7735_THEME_TEAL)
return 1;
#elif defined(ST7735_THEME_SIGNAL)
return 2;
#elif defined(ST7735_THEME_NEON)
return 3;
#elif defined(ST7735_THEME_AMBER) || defined(HELTEC_T096)
return 0;
#else
return 4; // остальные платы: официальная схема MeshCore
#endif
}
static constexpr uint8_t DEFAULT_THEME = default_theme_index();
static uint8_t active_theme = DEFAULT_THEME;
ColorVal UIColor::window_bkg = THEMES[DEFAULT_THEME].window_bkg;
ColorVal UIColor::title_bkg = THEMES[DEFAULT_THEME].title_bkg;
ColorVal UIColor::title_txt = THEMES[DEFAULT_THEME].title_txt;
ColorVal UIColor::primary_txt = THEMES[DEFAULT_THEME].primary_txt;
ColorVal UIColor::secondary_txt = THEMES[DEFAULT_THEME].secondary_txt;
ColorVal UIColor::warning_txt = THEMES[DEFAULT_THEME].warning_txt;
ColorVal UIColor::popup_bkg = THEMES[DEFAULT_THEME].popup_bkg;
ColorVal UIColor::popup_txt = THEMES[DEFAULT_THEME].popup_txt;
ColorVal UIColor::corp_blue = THEMES[DEFAULT_THEME].corp_blue;
uint8_t ST7735Display::getThemeCount() {
return THEME_COUNT;
}
const char* ST7735Display::getThemeName(uint8_t i) {
return i < THEME_COUNT ? THEMES[i].name : "";
}
uint8_t ST7735Display::getTheme() {
return active_theme;
}
void ST7735Display::setTheme(uint8_t i) {
if (i >= THEME_COUNT) return;
const ColorTheme* t = &THEMES[i];
UIColor::window_bkg = t->window_bkg;
UIColor::title_bkg = t->title_bkg;
UIColor::title_txt = t->title_txt;
UIColor::primary_txt = t->primary_txt;
UIColor::secondary_txt = t->secondary_txt;
UIColor::warning_txt = t->warning_txt;
UIColor::popup_bkg = t->popup_bkg;
UIColor::popup_txt = t->popup_txt;
UIColor::corp_blue = t->corp_blue;
active_theme = i;
}
ColorVal ST7735Display::getThemeColor(uint8_t theme, uint8_t role) {
if (theme >= THEME_COUNT) return 0;
const ColorTheme* t = &THEMES[theme];
switch (role) {
case THEME_COLOR_WINDOW: return t->window_bkg;
case THEME_COLOR_TITLE: return t->title_bkg;
case THEME_COLOR_POPUP: return t->popup_bkg;
case THEME_COLOR_ACCENT: return t->warning_txt;
default: return t->primary_txt;
}
}
bool ST7735Display::begin() {
if (!sprite) {
+7
View File
@@ -56,6 +56,13 @@ public:
uint16_t getTextWidth(const char* str) override;
void endFrame() override;
// Темы (палитры заданы в таблице THEMES в ST7735Display.cpp)
uint8_t getThemeCount() override;
const char* getThemeName(uint8_t i) override;
uint8_t getTheme() override;
void setTheme(uint8_t i) override;
ColorVal getThemeColor(uint8_t theme, uint8_t role) override;
protected:
void _resetAndInit();
};