refactor(ui): tag SettingsScreen ifdefs with semantic FEAT_* macros

Extends Features.h with preprocessor flags (FEAT_BRIGHTNESS_SETTING,
FEAT_CLOCK_SECONDS_SETTING, FEAT_DISPLAY_ROTATION_SETTING,
FEAT_JOYSTICK_ROTATION_SETTING, FEAT_FULL_REFRESH_SETTING) since
constexpr can't gate enum members or class fields. SettingsScreen.h
now uses #if FEAT_X instead of #if defined(EINK_DISPLAY_MODEL) — grep
on the feature name finds the toggle and every use site, and the
condition names *what* the gate controls.

Driver headers (DisplayDriver.h, GxEPDDisplay.h) keep raw
EINK_DISPLAY_MODEL — they're below the companion_radio layer and the
ifdef there gates on the build's panel type, not a UI feature.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-05-24 22:20:42 +02:00
parent 7c81ea0f52
commit 900f2d59e9
2 changed files with 47 additions and 23 deletions

View File

@@ -1,11 +1,33 @@
#pragma once #pragma once
// Build-time feature flags derived from board defines. // Build-time feature flags derived from board defines. Two flavours:
// Use these instead of `#ifdef EINK_DISPLAY_MODEL` for runtime-shape decisions //
// (booleans, timings, defaults). Compiler dead-branch-eliminates on the // FEAT_* preprocessor macros — for conditional compilation of struct
// constexpr, so cost is identical to a preprocessor branch but the code // members, enum entries, and class fields where the preprocessor must
// remains readable and reachable to tooling. Conditional struct members // run. Use `#if FEAT_X` instead of `#ifdef EINK_DISPLAY_MODEL`; the
// (enum entries, NodePrefs fields) still need a real `#if defined(...)`. // name documents *what* the flag toggles rather than *why* it's bound
// to e-ink.
//
// Features::* constexpr values — for runtime-shape decisions (booleans,
// timings, defaults). Compiler dead-branch-eliminates on the constexpr,
// so cost is identical to a preprocessor branch but the code stays
// reachable to tooling.
#if defined(EINK_DISPLAY_MODEL)
// E-ink build: slow refresh, rotatable panel, no per-second redraws
#define FEAT_BRIGHTNESS_SETTING 0
#define FEAT_CLOCK_SECONDS_SETTING 0
#define FEAT_DISPLAY_ROTATION_SETTING 1
#define FEAT_JOYSTICK_ROTATION_SETTING 1
#define FEAT_FULL_REFRESH_SETTING 1
#else
// OLED build: fast refresh, fixed orientation
#define FEAT_BRIGHTNESS_SETTING 1
#define FEAT_CLOCK_SECONDS_SETTING 1
#define FEAT_DISPLAY_ROTATION_SETTING 0
#define FEAT_JOYSTICK_ROTATION_SETTING 0
#define FEAT_FULL_REFRESH_SETTING 0
#endif
namespace Features { namespace Features {

View File

@@ -2,13 +2,15 @@
// Custom screen — not part of upstream UITask.cpp // Custom screen — not part of upstream UITask.cpp
// Included by UITask.cpp after SensorPlaceholders.h is defined. // Included by UITask.cpp after SensorPlaceholders.h is defined.
#include "../Features.h"
class SettingsScreen : public UIScreen { class SettingsScreen : public UIScreen {
UITask* _task; UITask* _task;
enum SettingItem { enum SettingItem {
// Display section // Display section
SECTION_DISPLAY, SECTION_DISPLAY,
#if !defined(EINK_DISPLAY_MODEL) #if FEAT_BRIGHTNESS_SETTING
BRIGHTNESS, BRIGHTNESS,
#endif #endif
#if AUTO_OFF_MILLIS > 0 #if AUTO_OFF_MILLIS > 0
@@ -16,18 +18,18 @@ class SettingsScreen : public UIScreen {
#endif #endif
AUTO_LOCK, AUTO_LOCK,
BATT_DISPLAY, BATT_DISPLAY,
#if !defined(EINK_DISPLAY_MODEL) #if FEAT_CLOCK_SECONDS_SETTING
CLOCK_SECONDS, CLOCK_SECONDS,
#endif #endif
CLOCK_FORMAT, CLOCK_FORMAT,
FONT, FONT,
#if defined(EINK_DISPLAY_MODEL) #if FEAT_DISPLAY_ROTATION_SETTING
ROTATION, ROTATION,
#endif #endif
#if defined(EINK_DISPLAY_MODEL) #if FEAT_JOYSTICK_ROTATION_SETTING
JOY_ROTATION, JOY_ROTATION,
#endif #endif
#if defined(EINK_DISPLAY_MODEL) #if FEAT_FULL_REFRESH_SETTING
EINK_FULL_REFRESH, EINK_FULL_REFRESH,
#endif #endif
// Sound section // Sound section
@@ -88,7 +90,7 @@ class SettingsScreen : public UIScreen {
static const int LOW_BAT_COUNT = 7; static const int LOW_BAT_COUNT = 7;
static const char* BATT_DISPLAY_LABELS[3]; static const char* BATT_DISPLAY_LABELS[3];
static const int BATT_DISPLAY_COUNT = 3; static const int BATT_DISPLAY_COUNT = 3;
#if defined(EINK_DISPLAY_MODEL) #if FEAT_FULL_REFRESH_SETTING
static const char* EINK_FULL_REFRESH_LABELS[5]; static const char* EINK_FULL_REFRESH_LABELS[5];
static const int EINK_FULL_REFRESH_COUNT = 5; static const int EINK_FULL_REFRESH_COUNT = 5;
#endif #endif
@@ -322,7 +324,7 @@ class SettingsScreen : public UIScreen {
display.print(sel ? ">" : " "); display.print(sel ? ">" : " ");
display.setCursor(display.getCharWidth() + 2, y); display.setCursor(display.getCharWidth() + 2, y);
#if !defined(EINK_DISPLAY_MODEL) #if FEAT_BRIGHTNESS_SETTING
if (item == BRIGHTNESS) { if (item == BRIGHTNESS) {
display.print("Bright"); display.print("Bright");
renderBar(display, display.valCol(), y, (p ? p->display_brightness : 2) + 1, 5); renderBar(display, display.valCol(), y, (p ? p->display_brightness : 2) + 1, 5);
@@ -410,7 +412,7 @@ class SettingsScreen : public UIScreen {
display.setCursor(display.valCol(), y); display.setCursor(display.valCol(), y);
uint8_t mode = p ? p->batt_display_mode : 0; uint8_t mode = p ? p->batt_display_mode : 0;
display.print(BATT_DISPLAY_LABELS[mode < BATT_DISPLAY_COUNT ? mode : 0]); display.print(BATT_DISPLAY_LABELS[mode < BATT_DISPLAY_COUNT ? mode : 0]);
#if !defined(EINK_DISPLAY_MODEL) #if FEAT_CLOCK_SECONDS_SETTING
} else if (item == CLOCK_SECONDS) { } else if (item == CLOCK_SECONDS) {
display.print("Seconds"); display.print("Seconds");
display.setCursor(display.valCol(), y); display.setCursor(display.valCol(), y);
@@ -424,7 +426,7 @@ class SettingsScreen : public UIScreen {
display.print("Font"); display.print("Font");
display.setCursor(display.valCol(), y); display.setCursor(display.valCol(), y);
display.print((p && p->use_lemon_font) ? "Lemon" : "Default"); display.print((p && p->use_lemon_font) ? "Lemon" : "Default");
#if defined(EINK_DISPLAY_MODEL) #if FEAT_DISPLAY_ROTATION_SETTING
} else if (item == ROTATION) { } else if (item == ROTATION) {
display.print("Rotation"); display.print("Rotation");
display.setCursor(display.valCol(), y); display.setCursor(display.valCol(), y);
@@ -432,7 +434,7 @@ class SettingsScreen : public UIScreen {
uint8_t r = p ? (p->display_rotation & 3) : 0; uint8_t r = p ? (p->display_rotation & 3) : 0;
display.print(ROT_LABELS[r]); } display.print(ROT_LABELS[r]); }
#endif #endif
#if defined(EINK_DISPLAY_MODEL) #if FEAT_JOYSTICK_ROTATION_SETTING
} else if (item == JOY_ROTATION) { } else if (item == JOY_ROTATION) {
display.print("Joystick"); display.print("Joystick");
display.setCursor(display.valCol(), y); display.setCursor(display.valCol(), y);
@@ -440,7 +442,7 @@ class SettingsScreen : public UIScreen {
uint8_t r = p ? (p->joystick_rotation & 3) : 0; uint8_t r = p ? (p->joystick_rotation & 3) : 0;
display.print(ROT_LABELS[r]); } display.print(ROT_LABELS[r]); }
#endif #endif
#if defined(EINK_DISPLAY_MODEL) #if FEAT_FULL_REFRESH_SETTING
} else if (item == EINK_FULL_REFRESH) { } else if (item == EINK_FULL_REFRESH) {
display.print("Full rfsh"); display.print("Full rfsh");
display.setCursor(display.valCol(), y); display.setCursor(display.valCol(), y);
@@ -557,7 +559,7 @@ public:
bool left = (c == KEY_LEFT || c == KEY_PREV); bool left = (c == KEY_LEFT || c == KEY_PREV);
bool enter = (c == KEY_ENTER); bool enter = (c == KEY_ENTER);
#if !defined(EINK_DISPLAY_MODEL) #if FEAT_BRIGHTNESS_SETTING
if (_selected == BRIGHTNESS) { if (_selected == BRIGHTNESS) {
uint8_t lvl = _task->getBrightnessLevel(); uint8_t lvl = _task->getBrightnessLevel();
if (right && lvl < 4) { _task->setBrightnessLevel(lvl + 1); _dirty = true; return true; } if (right && lvl < 4) { _task->setBrightnessLevel(lvl + 1); _dirty = true; return true; }
@@ -646,7 +648,7 @@ public:
if (left) idx = (idx + BATT_DISPLAY_COUNT - 1) % BATT_DISPLAY_COUNT; if (left) idx = (idx + BATT_DISPLAY_COUNT - 1) % BATT_DISPLAY_COUNT;
if (left || right) { p->batt_display_mode = idx; _dirty = true; return true; } if (left || right) { p->batt_display_mode = idx; _dirty = true; return true; }
} }
#if !defined(EINK_DISPLAY_MODEL) #if FEAT_CLOCK_SECONDS_SETTING
if (_selected == CLOCK_SECONDS && p && (left || right || enter)) { if (_selected == CLOCK_SECONDS && p && (left || right || enter)) {
p->clock_hide_seconds ^= 1; p->clock_hide_seconds ^= 1;
_dirty = true; _dirty = true;
@@ -664,7 +666,7 @@ public:
_dirty = true; _dirty = true;
return true; return true;
} }
#if defined(EINK_DISPLAY_MODEL) #if FEAT_DISPLAY_ROTATION_SETTING
if (_selected == ROTATION && p && (left || right || enter)) { if (_selected == ROTATION && p && (left || right || enter)) {
p->display_rotation = (p->display_rotation + (left ? 3 : 1)) & 3; p->display_rotation = (p->display_rotation + (left ? 3 : 1)) & 3;
_task->applyRotation(); _task->applyRotation();
@@ -672,14 +674,14 @@ public:
return true; return true;
} }
#endif #endif
#if defined(EINK_DISPLAY_MODEL) #if FEAT_JOYSTICK_ROTATION_SETTING
if (_selected == JOY_ROTATION && p && (left || right || enter)) { if (_selected == JOY_ROTATION && p && (left || right || enter)) {
p->joystick_rotation = (p->joystick_rotation + (left ? 3 : 1)) & 3; p->joystick_rotation = (p->joystick_rotation + (left ? 3 : 1)) & 3;
_dirty = true; _dirty = true;
return true; return true;
} }
#endif #endif
#if defined(EINK_DISPLAY_MODEL) #if FEAT_FULL_REFRESH_SETTING
if (_selected == EINK_FULL_REFRESH && p && (left || right || enter)) { if (_selected == EINK_FULL_REFRESH && p && (left || right || enter)) {
int idx = p->eink_full_refresh_every; int idx = p->eink_full_refresh_every;
if (idx >= EINK_FULL_REFRESH_COUNT) idx = 0; if (idx >= EINK_FULL_REFRESH_COUNT) idx = 0;
@@ -722,6 +724,6 @@ const char* SettingsScreen::GPS_INTERVAL_LABELS[6] = { "off", "30s", "1min",
const uint16_t SettingsScreen::LOW_BAT_OPTS[7] = { 0, 3000, 3100, 3200, 3300, 3400, 3500 }; const uint16_t SettingsScreen::LOW_BAT_OPTS[7] = { 0, 3000, 3100, 3200, 3300, 3400, 3500 };
const char* SettingsScreen::LOW_BAT_LABELS[7] = { "off", "3.0V", "3.1V", "3.2V", "3.3V", "3.4V", "3.5V" }; const char* SettingsScreen::LOW_BAT_LABELS[7] = { "off", "3.0V", "3.1V", "3.2V", "3.3V", "3.4V", "3.5V" };
const char* SettingsScreen::BATT_DISPLAY_LABELS[3] = { "icon", "%", "V" }; const char* SettingsScreen::BATT_DISPLAY_LABELS[3] = { "icon", "%", "V" };
#if defined(EINK_DISPLAY_MODEL) #if FEAT_FULL_REFRESH_SETTING
const char* SettingsScreen::EINK_FULL_REFRESH_LABELS[5] = { "off", "5", "10", "20", "30" }; const char* SettingsScreen::EINK_FULL_REFRESH_LABELS[5] = { "off", "5", "10", "20", "30" };
#endif #endif