Add submenus

This commit is contained in:
jpirnay
2026-04-12 14:21:48 +02:00
parent 1f1777385c
commit df3fec574d
5 changed files with 192 additions and 157 deletions
+5
View File
@@ -481,3 +481,8 @@ STR_MENU_SYS_TOOLS: "Tools"
STR_MENU_DISP_SLEEP: "Sleepscreen"
STR_MENU_DISP_BATTERY: "Battery symbol"
STR_MENU_DISP_REFRESH: "Screen refresh"
STR_MENU_READER_FONT: "Reader Font"
STR_MENU_READER_FONT_SETTINGS: "Font Settings"
STR_MENU_READER_LAYOUT: "Layout Settings"
STR_MENU_READER_TWEAKS: "Reader Tweaks"
STR_MENU_READER_SPACING: "Spacing"
+52 -30
View File
@@ -27,8 +27,14 @@
//
// ACTION-type entries and entries without a key are device-only and are added directly
// in SettingsActivity::onEnter(), not here.
inline const std::vector<SettingInfo>& getSettingsList() {
static const std::vector<SettingInfo> list = {
//
// Implementation note: the list is a namespace-level static (not a function-local static) so
// it is initialised during the global-static phase before setup() runs. A function-local
// static would trigger __cxa_guard_acquire on the first call, which creates a FreeRTOS mutex
// deep inside the heap allocator chain — enough stack to overflow the 8 KB loop task stack
// when called from inside SETTINGS.loadFromFile() at boot time.
namespace SettingsListDetail {
inline const std::vector<SettingInfo> list = {
// --- Display ---
SettingInfo::Enum(StrId::STR_TIME_TO_SLEEP, &CrossPointSettings::sleepTimeout,
{StrId::STR_MIN_1, StrId::STR_MIN_5, StrId::STR_MIN_10, StrId::STR_MIN_15, StrId::STR_MIN_30},
@@ -41,8 +47,8 @@ inline const std::vector<SettingInfo>& getSettingsList() {
SettingInfo::Enum(StrId::STR_SLEEP_COVER_MODE, &CrossPointSettings::sleepScreenCoverMode,
{StrId::STR_FIT, StrId::STR_CROP}, "sleepScreenCoverMode", StrId::STR_CAT_DISPLAY),
SettingInfo::Enum(StrId::STR_SLEEP_COVER_FILTER, &CrossPointSettings::sleepScreenCoverFilter,
{StrId::STR_NONE_OPT, StrId::STR_FILTER_CONTRAST, StrId::STR_INVERTED},
"sleepScreenCoverFilter", StrId::STR_CAT_DISPLAY),
{StrId::STR_NONE_OPT, StrId::STR_FILTER_CONTRAST, StrId::STR_INVERTED}, "sleepScreenCoverFilter",
StrId::STR_CAT_DISPLAY),
SettingInfo::Enum(
StrId::STR_SLEEP_COVER_OVERLAY, &CrossPointSettings::sleepCoverOverlay,
{StrId::STR_OVERLAY_OFF, StrId::STR_OVERLAY_WHITE, StrId::STR_OVERLAY_GRAY, StrId::STR_OVERLAY_BLACK},
@@ -65,39 +71,54 @@ inline const std::vector<SettingInfo>& getSettingsList() {
StrId::STR_CAT_DISPLAY),
// --- Reader ---
// General reader settings
SettingInfo::Enum(StrId::STR_ORIENTATION, &CrossPointSettings::orientation,
{StrId::STR_PORTRAIT, StrId::STR_LANDSCAPE_CW, StrId::STR_INVERTED, StrId::STR_LANDSCAPE_CCW},
"orientation", StrId::STR_CAT_READER),
// Font
SettingInfo::Enum(StrId::STR_FONT_FAMILY, &CrossPointSettings::fontFamily,
{StrId::STR_BOOKERLY, StrId::STR_NOTO_SANS, StrId::STR_OPEN_DYSLEXIC}, "fontFamily",
StrId::STR_CAT_READER),
StrId::STR_CAT_READER)
.withSubcategory(StrId::STR_FONT_FAMILY),
SettingInfo::Enum(StrId::STR_FONT_SIZE, &CrossPointSettings::fontSize,
{StrId::STR_SMALL, StrId::STR_MEDIUM, StrId::STR_LARGE, StrId::STR_X_LARGE}, "fontSize",
StrId::STR_CAT_READER),
SettingInfo::Enum(StrId::STR_LINE_SPACING, &CrossPointSettings::lineSpacing,
{StrId::STR_TIGHT, StrId::STR_NORMAL, StrId::STR_WIDE}, "lineSpacing", StrId::STR_CAT_READER),
SettingInfo::Value(StrId::STR_SCREEN_MARGIN, &CrossPointSettings::screenMargin, {5, 40, 5}, "screenMargin",
StrId::STR_CAT_READER),
SettingInfo::Enum(StrId::STR_PARA_ALIGNMENT, &CrossPointSettings::paragraphAlignment,
{StrId::STR_JUSTIFY, StrId::STR_ALIGN_LEFT, StrId::STR_CENTER, StrId::STR_ALIGN_RIGHT,
StrId::STR_BOOK_S_STYLE},
"paragraphAlignment", StrId::STR_CAT_READER),
StrId::STR_CAT_READER)
.withSubmenu(StrId::STR_MENU_READER_FONT),
SettingInfo::Toggle(StrId::STR_TEXT_AA, &CrossPointSettings::textAntiAliasing, "textAntiAliasing",
StrId::STR_CAT_READER)
.withSubmenu(StrId::STR_MENU_READER_FONT),
SettingInfo::Enum(StrId::STR_TEXT_DARKNESS, &CrossPointSettings::textDarkness,
{StrId::STR_NORMAL, StrId::STR_DARK, StrId::STR_EXTRA_DARK, StrId::STR_MAX_DARK}, "textDarkness",
StrId::STR_CAT_READER)
.withSubmenu(StrId::STR_MENU_READER_FONT),
// Formatting settings
SettingInfo::Enum(
StrId::STR_PARA_ALIGNMENT, &CrossPointSettings::paragraphAlignment,
{StrId::STR_JUSTIFY, StrId::STR_ALIGN_LEFT, StrId::STR_CENTER, StrId::STR_ALIGN_RIGHT, StrId::STR_BOOK_S_STYLE},
"paragraphAlignment", StrId::STR_CAT_READER)
.withSubcategory(StrId::STR_MENU_READER_LAYOUT),
SettingInfo::Toggle(StrId::STR_EMBEDDED_STYLE, &CrossPointSettings::embeddedStyle, "embeddedStyle",
StrId::STR_CAT_READER),
SettingInfo::Toggle(StrId::STR_HYPHENATION, &CrossPointSettings::hyphenationEnabled, "hyphenationEnabled",
StrId::STR_CAT_READER),
SettingInfo::Enum(StrId::STR_ORIENTATION, &CrossPointSettings::orientation,
{StrId::STR_PORTRAIT, StrId::STR_LANDSCAPE_CW, StrId::STR_INVERTED, StrId::STR_LANDSCAPE_CCW},
"orientation", StrId::STR_CAT_READER),
SettingInfo::Toggle(StrId::STR_EXTRA_SPACING, &CrossPointSettings::extraParagraphSpacing, "extraParagraphSpacing",
StrId::STR_CAT_READER),
SettingInfo::Toggle(StrId::STR_TEXT_AA, &CrossPointSettings::textAntiAliasing, "textAntiAliasing",
StrId::STR_CAT_READER),
SettingInfo::Enum(StrId::STR_TEXT_DARKNESS, &CrossPointSettings::textDarkness,
{StrId::STR_NORMAL, StrId::STR_DARK, StrId::STR_EXTRA_DARK, StrId::STR_MAX_DARK},
"textDarkness", StrId::STR_CAT_READER),
SettingInfo::Enum(StrId::STR_IMAGES, &CrossPointSettings::imageRendering,
{StrId::STR_IMAGES_DISPLAY, StrId::STR_IMAGES_PLACEHOLDER, StrId::STR_IMAGES_SUPPRESS},
"imageRendering", StrId::STR_CAT_READER),
SettingInfo::Value(StrId::STR_SCREEN_MARGIN, &CrossPointSettings::screenMargin, {5, 40, 5}, "screenMargin",
StrId::STR_CAT_READER)
.withSubmenu(StrId::STR_MENU_READER_SPACING),
SettingInfo::Enum(StrId::STR_LINE_SPACING, &CrossPointSettings::lineSpacing,
{StrId::STR_TIGHT, StrId::STR_NORMAL, StrId::STR_WIDE}, "lineSpacing", StrId::STR_CAT_READER)
.withSubmenu(StrId::STR_MENU_READER_SPACING),
SettingInfo::Toggle(StrId::STR_EXTRA_SPACING, &CrossPointSettings::extraParagraphSpacing, "extraParagraphSpacing",
StrId::STR_CAT_READER)
.withSubmenu(StrId::STR_MENU_READER_SPACING),
// Generic reader settings
SettingInfo::Toggle(StrId::STR_CREATE_FALLBACK_FOR_INVALID_TOC, &CrossPointSettings::syntheticTocFallback,
"syntheticTocFallback", StrId::STR_CAT_READER),
"syntheticTocFallback", StrId::STR_CAT_READER)
.withSubcategory(StrId::STR_MENU_READER_TWEAKS),
// --- Controls ---
SettingInfo::Enum(StrId::STR_SIDE_BTN_LAYOUT, &CrossPointSettings::sideButtonLayout,
{StrId::STR_PREV_NEXT, StrId::STR_NEXT_PREV}, "sideButtonLayout", StrId::STR_CAT_CONTROLS),
@@ -110,8 +131,8 @@ inline const std::vector<SettingInfo>& getSettingsList() {
// --- System ---
SettingInfo::Toggle(StrId::STR_SHOW_HIDDEN_FILES, &CrossPointSettings::showHiddenFiles, "showHiddenFiles",
StrId::STR_CAT_SYSTEM),
SettingInfo::Toggle(StrId::STR_SHOW_FILE_EXTENSIONS, &CrossPointSettings::showFileExtensions,
"showFileExtensions", StrId::STR_CAT_SYSTEM),
SettingInfo::Toggle(StrId::STR_SHOW_FILE_EXTENSIONS, &CrossPointSettings::showFileExtensions, "showFileExtensions",
StrId::STR_CAT_SYSTEM),
SettingInfo::Enum(StrId::STR_CLOCK_FORMAT, &CrossPointSettings::clockFormat12h, {StrId::STR_24H, StrId::STR_12H},
"clockFormat12h", StrId::STR_CAT_SYSTEM),
SettingInfo::Enum(StrId::STR_TIMEZONE, &CrossPointSettings::timeZone,
@@ -179,6 +200,7 @@ inline const std::vector<SettingInfo>& getSettingsList() {
StrId::STR_CUSTOMISE_STATUS_BAR),
SettingInfo::Toggle(StrId::STR_CLOCK, &CrossPointSettings::statusBarClock, "statusBarClock",
StrId::STR_CUSTOMISE_STATUS_BAR),
};
return list;
}
};
} // namespace SettingsListDetail
inline const std::vector<SettingInfo>& getSettingsList() { return SettingsListDetail::list; }
+12 -8
View File
@@ -333,17 +333,21 @@ void SettingsActivity::render(RenderLock&&) {
nullptr,
[&settings](int i) {
const auto& setting = settings[i];
std::string valueText = "";
if (setting.type == SettingType::TOGGLE && setting.valuePtr != nullptr) {
const bool value = SETTINGS.*(setting.valuePtr);
valueText = value ? tr(STR_STATE_ON) : tr(STR_STATE_OFF);
} else if (setting.type == SettingType::ENUM && setting.valuePtr != nullptr) {
const uint8_t value = SETTINGS.*(setting.valuePtr);
valueText = I18N.get(setting.enumValues[value]);
} else if (setting.type == SettingType::VALUE && setting.valuePtr != nullptr) {
valueText = std::to_string(SETTINGS.*(setting.valuePtr));
return std::string(value ? tr(STR_STATE_ON) : tr(STR_STATE_OFF));
}
return valueText;
if (setting.type == SettingType::ENUM && setting.valuePtr != nullptr) {
const uint8_t value = SETTINGS.*(setting.valuePtr);
return std::string(I18N.get(setting.enumValues[value]));
}
if (setting.type == SettingType::VALUE && setting.valuePtr != nullptr) {
return std::to_string(SETTINGS.*(setting.valuePtr));
}
if (setting.type == SettingType::ACTION && !setting.isSeparator) {
return std::string(">>");
}
return std::string();
},
true);
@@ -22,8 +22,7 @@
void SettingsSubmenuActivity::onEnter() {
Activity::onEnter();
itemCount = static_cast<int>(items.size());
const auto pred = UITheme::makeSelectablePredicate(itemCount,
[this](int i) { return items[i].getTitle(); });
const auto pred = UITheme::makeSelectablePredicate(itemCount, [this](int i) { return items[i].getTitle(); });
buttonNavigator.setSelectablePredicate(pred, itemCount);
if (!pred(selectedIndex)) {
selectedIndex = buttonNavigator.nextIndex(selectedIndex);
@@ -151,6 +150,9 @@ void SettingsSubmenuActivity::render(RenderLock&&) {
if (setting.type == SettingType::VALUE && setting.valuePtr != nullptr) {
return std::to_string(SETTINGS.*(setting.valuePtr));
}
if (setting.type == SettingType::ACTION && !setting.isSeparator) {
return std::string(">>");
}
return std::string();
},
true);
+3 -1
View File
@@ -204,10 +204,12 @@ void setup() {
HalSystem::checkPanic();
HalSystem::clearPanic(); // TODO: move this to an activity when we have one to display the panic info
LOG_DBG("MAIN", "System initialized, now setting up environment, millis=%lu", millis());
SETTINGS.loadFromFile();
LOG_DBG("MAIN", "Settings loaded, now setting up clock and localization, millis=%lu", millis());
HalClock::applyTimezone(SETTINGS.timeZone);
I18N.loadSettings();
LOG_DBG("MAIN", "Localization loaded, now setting up theme and button navigation, millis=%lu", millis());
KOREADER_STORE.loadFromFile();
WEATHER_SETTINGS.loadFromFile();
UITheme::getInstance().reload();