12035f2f39
- Migrates tactility-firmware and tactility-bluetooth from ~/.hermes/skills/ into .claude/skills/ for repo co-location - Adds AGENTS.md with local workstation context, board table, board-direct build rule, Hermes PYTHONPATH pitfall, common Tactility pitfalls, and in-repo skill index Refs: personal Gitea mirror
2.7 KiB
2.7 KiB
DisplaySettings Extension Recipe
Header: Tactility/Include/Tactility/settings/DisplaySettings.h
Impl: Tactility/Source/settings/DisplaySettings.cpp
Field Types
Struct as of 2026-07-11:
struct DisplaySettings {
Orientation orientation;
uint8_t gammaCurve;
uint8_t backlightDuty;
bool backlightTimeoutEnabled;
uint32_t backlightTimeoutMs;
ScreensaverType screensaverType = BouncingBalls;
bool disableScreensaverWhenCharging = false; // new
};
enum ScreensaverType { None, BouncingBalls, Mystify, MatrixRain, StackChan, McpScreen, Count };
Adding a New Field — 5 Places in CPP
SETTINGS_KEY_*constant:
constexpr auto* SETTINGS_KEY_DISABLE_SCREENSAVER_WHEN_CHARGING = "disableScreensaverWhenCharging";
load()— parse:
bool disable_when_charging = false;
auto e = map.find(KEY_DISABLE);
if (e != map.end()) disable_when_charging = (e->second=="1"||e->second=="true"||e->second=="True");
...
settings.disableScreensaverWhenCharging = disable_when_charging;
-
getDefault()aggregate includes field. -
save():
map[KEY_DISABLE] = settings.disableScreensaverWhenCharging ? "1":"0";
- For enums: add
toString/fromStringcases. SentinelCountis bounds check.
Persistence Details
- File:
getUserDataPath()+"/settings/display.properties"(Internal or SD depending on device.properties storage.userDataLocation) loadPropertiesFile→map<string,string>, tolerant parsingatoi/strtoulsavePropertiesFilewriteskey=valuelines. Parent dir created viafindOrCreateParentDirectory(path,0755)loadOrGetDefault()tries load, else getDefault()- Settings thread-safety: save dispatched off UI via
getMainDispatcher().dispatch([settings]{ save(settings); findService()->reloadSettings(); })
Reload into DisplayIdleService
reloadSettings() sets atomic<bool> settingsReloadRequested. Next tick() (50ms timer, Lower priority) checks exchange(false) and does cachedDisplaySettings = loadOrGetDefault() while holding LVGL lock.
Display App UI Wiring
- Members stored as
lv_obj_t*raw pointers, initialized nullptr onShow()loads settingsloadOrGetDefault(), builds wrappers column flex- Each row pattern: create wrapper, label left aligned, control right aligned (switch/dropdown/slider)
- Switch state:
lv_obj_has_state(sw, LV_STATE_CHECKED); set vialv_obj_add_state(sw, LV_STATE_CHECKED)before aligning - Dependent disabling: parent
timeoutSwitchtogglestimeoutDropdown,screensaverDropdown,disableWhenChargingWrapperviaLV_STATE_DISABLED - Event callbacks static, retrieve app via
lv_event_get_user_data(event)cast to DisplayApp* onHide()only saves ifdisplaySettingsUpdated==true, dispatches async