diff --git a/src/activities/MenuListActivity.cpp b/src/activities/MenuListActivity.cpp index 4fd19076..d3b919b5 100644 --- a/src/activities/MenuListActivity.cpp +++ b/src/activities/MenuListActivity.cpp @@ -4,6 +4,7 @@ #include "MappedInputManager.h" #include "components/UITheme.h" +#include "settings/SettingsSubmenuActivity.h" void MenuListActivity::initMenuList() { const int count = static_cast(menuItems.size()); @@ -16,6 +17,10 @@ void MenuListActivity::initMenuList() { void MenuListActivity::onEnter() { Activity::onEnter(); + if (!submenusPrepared) { + prepareSubmenus(); + submenusPrepared = true; + } initMenuList(); requestUpdate(); } @@ -37,6 +42,10 @@ void MenuListActivity::toggleCurrentItem() { if (item.isSeparator) return; if (item.type == SettingType::ACTION) { + if (item.action == SettingAction::Submenu) { + openSubmenu(item); + return; + } onActionSelected(selectedIndex); return; } @@ -55,6 +64,18 @@ void MenuListActivity::drawMenuList(const Rect& rect) { [this](int index) { return getItemValueString(index); }, true); } +void MenuListActivity::prepareSubmenus() { SettingInfo::prepareSubmenus(menuItems, submenuData); } + +void MenuListActivity::openSubmenu(const SettingInfo& submenuEntry) { + auto it = std::find_if(submenuData.begin(), submenuData.end(), + [&submenuEntry](const SettingInfo::SubmenuData& d) { return d.id == submenuEntry.nameId; }); + if (it == submenuData.end()) return; + + startActivityForResult( + std::make_unique(renderer, mappedInput, submenuEntry.nameId, it->items), + [this](const ActivityResult&) { requestUpdate(); }); +} + void MenuListActivity::loop() { if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { onBackPressed(); diff --git a/src/activities/MenuListActivity.h b/src/activities/MenuListActivity.h index f8a8fdda..719f43d8 100644 --- a/src/activities/MenuListActivity.h +++ b/src/activities/MenuListActivity.h @@ -70,12 +70,18 @@ struct Rect; class MenuListActivity : public Activity { protected: std::vector menuItems; + std::vector submenuData; int selectedIndex = 0; ButtonNavigator buttonNavigator; + bool submenusPrepared = false; // Call after building/rebuilding menuItems to wire up the selectable predicate. void initMenuList(); + // Process SettingInfo items marked with withSubmenu() into submenu placeholders. + void prepareSubmenus(); + void openSubmenu(const SettingInfo& submenuEntry); + // Handle up/down navigation via buttonNavigator. Call from loop() if overriding. void handleNavigation(); diff --git a/src/activities/reader/EpubReaderMenuActivity.cpp b/src/activities/reader/EpubReaderMenuActivity.cpp index 93e08a6f..8348f698 100644 --- a/src/activities/reader/EpubReaderMenuActivity.cpp +++ b/src/activities/reader/EpubReaderMenuActivity.cpp @@ -252,8 +252,12 @@ std::string EpubReaderMenuActivity::getItemValueString(int index) const { return currentPageStarred ? std::string(tr(STR_STATE_ON)) : std::string(tr(STR_STATE_OFF)); } - // Plain ACTION items (select chapter, screenshot, etc.) show no value - if (item.type == SettingType::ACTION) return {}; + // Plain ACTION items (select chapter, screenshot, etc.) show no value. + // Submenu placeholders should still show the standard submenu indicator. + if (item.type == SettingType::ACTION) { + if (item.action == SettingAction::Submenu) return MenuListActivity::getItemValueString(index); + return {}; + } // DynamicEnum items use the standard display return MenuListActivity::getItemValueString(index); diff --git a/src/activities/settings/SettingInfo.h b/src/activities/settings/SettingInfo.h index d0e684c0..77abbe13 100644 --- a/src/activities/settings/SettingInfo.h +++ b/src/activities/settings/SettingInfo.h @@ -1,7 +1,9 @@ #pragma once #include +#include #include +#include #include #include @@ -88,6 +90,13 @@ struct SettingInfo { stringSetter(accessorCtx, v); } + struct SubmenuData { + StrId id = StrId::STR_NONE_OPT; + std::vector items; + }; + + static void prepareSubmenus(std::vector& items, std::vector& submenuData); + SettingInfo& withObfuscated() { obfuscated = true; return *this; @@ -237,3 +246,41 @@ struct SettingInfo { // not the SettingInfo itself. void toggleValue() const; }; + +inline void SettingInfo::prepareSubmenus(std::vector& items, + std::vector& submenuData) { + if (items.empty()) return; + + std::vector preparedItems; + std::vector preparedSubmenus; + preparedItems.reserve(items.size()); + + for (auto& item : items) { + if (item.submenu == StrId::STR_NONE_OPT) { + preparedItems.push_back(std::move(item)); + continue; + } + + auto it = std::find_if(preparedSubmenus.begin(), preparedSubmenus.end(), + [&item](const SubmenuData& d) { return d.id == item.submenu; }); + if (it == preparedSubmenus.end()) { + preparedItems.push_back(SettingInfo::SubmenuEntry(item.submenu)); + preparedSubmenus.push_back({item.submenu, {}}); + it = preparedSubmenus.end() - 1; + } + it->items.push_back(std::move(item)); + } + + items.swap(preparedItems); + + for (auto& submenu : preparedSubmenus) { + auto it = std::find_if(submenuData.begin(), submenuData.end(), + [&submenu](const SubmenuData& d) { return d.id == submenu.id; }); + if (it == submenuData.end()) { + submenuData.push_back(std::move(submenu)); + } else { + it->items.insert(it->items.end(), std::make_move_iterator(submenu.items.begin()), + std::make_move_iterator(submenu.items.end())); + } + } +} diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index 789b38e2..87d606e5 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -41,33 +41,19 @@ void SettingsActivity::onEnter() { StrId lastControlsSub = StrId::STR_NONE_OPT; StrId lastSystemSub = StrId::STR_NONE_OPT; - // Shared placement logic — locates submenu target or inserts separator. - // Returns the vector the caller should push into (either `vec` or a submenu's items). - auto locateTarget = [this](std::vector& vec, StrId& lastSub, - const SettingInfo& s) -> std::vector* { - if (s.submenu != StrId::STR_NONE_OPT) { - auto it = std::find_if(submenuData.begin(), submenuData.end(), - [&s](const SubmenuData& d) { return d.id == s.submenu; }); - if (it == submenuData.end()) { - vec.push_back(SettingInfo::SubmenuEntry(s.submenu)); - submenuData.push_back({s.submenu, {}}); - it = submenuData.end() - 1; - } - return &it->items; - } + auto addTo = [](std::vector& vec, StrId& lastSub, const SettingInfo& s) { if (s.subcategory != StrId::STR_NONE_OPT && s.subcategory != lastSub) { vec.push_back(SettingInfo::Separator(s.subcategory)); lastSub = s.subcategory; } - return &vec; + vec.push_back(s); }; - - auto addTo = [&locateTarget](std::vector& vec, StrId& lastSub, const SettingInfo& s) { - locateTarget(vec, lastSub, s)->push_back(s); - }; - auto addToMoved = [&locateTarget](std::vector& vec, StrId& lastSub, SettingInfo&& s) { - auto* target = locateTarget(vec, lastSub, s); - target->push_back(std::move(s)); + auto addToMoved = [](std::vector& vec, StrId& lastSub, SettingInfo&& s) { + if (s.subcategory != StrId::STR_NONE_OPT && s.subcategory != lastSub) { + vec.push_back(SettingInfo::Separator(s.subcategory)); + lastSub = s.subcategory; + } + vec.push_back(std::move(s)); }; for (const auto& setting : getSettingsList()) { @@ -122,6 +108,11 @@ void SettingsActivity::onEnter() { std::move(SettingInfo::Action(StrId::STR_SYSTEM_INFO, SettingAction::SystemInfo) .withSubcategory(StrId::STR_MENU_SYS_SYSTEM))); + SettingInfo::prepareSubmenus(displaySettings, submenuData); + SettingInfo::prepareSubmenus(readerSettings, submenuData); + SettingInfo::prepareSubmenus(controlsSettings, submenuData); + SettingInfo::prepareSubmenus(systemSettings, submenuData); + // Reset selection to first category selectedCategoryIndex = 0; selectedSettingIndex = 0; @@ -226,7 +217,7 @@ void SettingsActivity::toggleCurrentSetting() { if (setting.action == SettingAction::Submenu) { auto it = std::find_if(submenuData.begin(), submenuData.end(), - [&setting](const SubmenuData& d) { return d.id == setting.nameId; }); + [&setting](const SettingInfo::SubmenuData& d) { return d.id == setting.nameId; }); if (it != submenuData.end()) { startActivityForResult( std::make_unique(renderer, mappedInput, setting.nameId, it->items), resultHandler); diff --git a/src/activities/settings/SettingsActivity.h b/src/activities/settings/SettingsActivity.h index 60cf75b6..a84114b9 100644 --- a/src/activities/settings/SettingsActivity.h +++ b/src/activities/settings/SettingsActivity.h @@ -24,11 +24,7 @@ class SettingsActivity final : public Activity { static constexpr int categoryCount = 4; static const StrId categoryNames[categoryCount]; - struct SubmenuData { - StrId id; - std::vector items; - }; - std::vector submenuData; + std::vector submenuData; void enterCategory(int categoryIndex); void toggleCurrentSetting(); diff --git a/src/activities/settings/SettingsSubmenuActivity.cpp b/src/activities/settings/SettingsSubmenuActivity.cpp index 5ac7ffff..d3d5262a 100644 --- a/src/activities/settings/SettingsSubmenuActivity.cpp +++ b/src/activities/settings/SettingsSubmenuActivity.cpp @@ -9,6 +9,12 @@ #include "components/UITheme.h" #include "fontIds.h" +void SettingsSubmenuActivity::onEnter() { + Activity::onEnter(); + initMenuList(); + requestUpdate(); +} + void SettingsSubmenuActivity::onActionSelected(int index) { const auto& setting = menuItems[index]; auto resultHandler = [this](const ActivityResult&) { SETTINGS.saveToFile(); }; diff --git a/src/activities/settings/SettingsSubmenuActivity.h b/src/activities/settings/SettingsSubmenuActivity.h index 6fff3691..c8288dda 100644 --- a/src/activities/settings/SettingsSubmenuActivity.h +++ b/src/activities/settings/SettingsSubmenuActivity.h @@ -12,6 +12,7 @@ class SettingsSubmenuActivity final : public MenuListActivity { StrId titleId; // MenuListActivity overrides + void onEnter() override; void onActionSelected(int index) override; void onSettingToggled(int index) override;