More reshaping
This commit is contained in:
@@ -60,6 +60,7 @@ STR_CALIBRE_INSTRUCTION_4: "\"Keep this screen open while sending\""
|
|||||||
STR_CAT_DISPLAY: "Display"
|
STR_CAT_DISPLAY: "Display"
|
||||||
STR_CAT_READER: "Reader"
|
STR_CAT_READER: "Reader"
|
||||||
STR_CAT_CONTROLS: "Controls"
|
STR_CAT_CONTROLS: "Controls"
|
||||||
|
STR_CAT_NETWORK: "Network"
|
||||||
STR_CAT_SYSTEM: "System"
|
STR_CAT_SYSTEM: "System"
|
||||||
STR_SLEEP_SCREEN: "Sleep Screen"
|
STR_SLEEP_SCREEN: "Sleep Screen"
|
||||||
STR_SLEEP_COVER_MODE: "Sleep Screen Cover Mode"
|
STR_SLEEP_COVER_MODE: "Sleep Screen Cover Mode"
|
||||||
@@ -468,4 +469,10 @@ STR_WEATHER_MOON_INFO: "Moon"
|
|||||||
STR_WEATHER_SUN_INFO: "Sun"
|
STR_WEATHER_SUN_INFO: "Sun"
|
||||||
STR_READER_TOOLS: "Tools"
|
STR_READER_TOOLS: "Tools"
|
||||||
STR_READER_NAVIGATION: "Navigation"
|
STR_READER_NAVIGATION: "Navigation"
|
||||||
STR_READER_APPEARANCE: "Appearance"
|
STR_READER_APPEARANCE: "Appearance"
|
||||||
|
STR_SETTINGS_MENU_SYSTEM: "System"
|
||||||
|
STR_SETTINGS_MENU_TOOLS: "Tools"
|
||||||
|
STR_SETTINGS_MENU_NETWORK: "Network"
|
||||||
|
STR_SETTINGS_MENU_SETTINGS: "Behaviour"
|
||||||
|
STR_SETTINGS_MENU_SOURCES: "Online Sources"
|
||||||
|
STR_SETTINGS_MENU_SYNC: "Synchronisation"
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "MappedInputManager.h"
|
#include "MappedInputManager.h"
|
||||||
#include "components/UITheme.h"
|
#include "components/UITheme.h"
|
||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
#include "util/MenuItemHelpers.h"
|
||||||
|
|
||||||
EpubReaderMenuActivity::EpubReaderMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
EpubReaderMenuActivity::EpubReaderMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||||
const std::string& title, const int currentPage, const int totalPages,
|
const std::string& title, const int currentPage, const int totalPages,
|
||||||
@@ -29,7 +30,7 @@ std::vector<EpubReaderMenuActivity::MenuItem> EpubReaderMenuActivity::buildMenuI
|
|||||||
std::vector<MenuItem> items;
|
std::vector<MenuItem> items;
|
||||||
items.reserve(18);
|
items.reserve(18);
|
||||||
// Navigation
|
// Navigation
|
||||||
items.push_back({MenuAction::NONE, StrId::STR_READER_NAVIGATION, true});
|
items.push_back(makeSeparatorMenuItem<MenuItem>(StrId::STR_READER_NAVIGATION));
|
||||||
items.push_back({MenuAction::SELECT_CHAPTER, StrId::STR_SELECT_CHAPTER});
|
items.push_back({MenuAction::SELECT_CHAPTER, StrId::STR_SELECT_CHAPTER});
|
||||||
items.push_back({MenuAction::GO_TO_PERCENT, StrId::STR_GO_TO_PERCENT});
|
items.push_back({MenuAction::GO_TO_PERCENT, StrId::STR_GO_TO_PERCENT});
|
||||||
if (hasFootnotes) {
|
if (hasFootnotes) {
|
||||||
@@ -38,7 +39,7 @@ std::vector<EpubReaderMenuActivity::MenuItem> EpubReaderMenuActivity::buildMenuI
|
|||||||
items.push_back({MenuAction::AUTO_PAGE_TURN, StrId::STR_AUTO_TURN_PAGES_PER_MIN});
|
items.push_back({MenuAction::AUTO_PAGE_TURN, StrId::STR_AUTO_TURN_PAGES_PER_MIN});
|
||||||
|
|
||||||
// Appearance
|
// Appearance
|
||||||
items.push_back({MenuAction::NONE, StrId::STR_READER_APPEARANCE, true});
|
items.push_back(makeSeparatorMenuItem<MenuItem>(StrId::STR_READER_APPEARANCE));
|
||||||
items.push_back({MenuAction::EMBEDDED_STYLE, StrId::STR_EMBEDDED_STYLE});
|
items.push_back({MenuAction::EMBEDDED_STYLE, StrId::STR_EMBEDDED_STYLE});
|
||||||
items.push_back({MenuAction::IMAGE_RENDERING, StrId::STR_IMAGES});
|
items.push_back({MenuAction::IMAGE_RENDERING, StrId::STR_IMAGES});
|
||||||
items.push_back({MenuAction::TEXT_DARKNESS, StrId::STR_TEXT_DARKNESS});
|
items.push_back({MenuAction::TEXT_DARKNESS, StrId::STR_TEXT_DARKNESS});
|
||||||
@@ -46,13 +47,13 @@ std::vector<EpubReaderMenuActivity::MenuItem> EpubReaderMenuActivity::buildMenuI
|
|||||||
|
|
||||||
// Synchronisation (only if credentials are set, to avoid confusion)
|
// Synchronisation (only if credentials are set, to avoid confusion)
|
||||||
if (KOREADER_STORE.hasCredentials()) {
|
if (KOREADER_STORE.hasCredentials()) {
|
||||||
items.push_back({MenuAction::NONE, StrId::STR_KOREADER_SYNC, true});
|
items.push_back(makeSeparatorMenuItem<MenuItem>(StrId::STR_KOREADER_SYNC));
|
||||||
items.push_back({MenuAction::PULL_REMOTE, StrId::STR_PULL_PROGRESS_FROM_OTHER_DEVICES});
|
items.push_back({MenuAction::PULL_REMOTE, StrId::STR_PULL_PROGRESS_FROM_OTHER_DEVICES});
|
||||||
items.push_back({MenuAction::PUSH_LOCAL, StrId::STR_PUSH_PROGRESS_FROM_THIS_DEVICE});
|
items.push_back({MenuAction::PUSH_LOCAL, StrId::STR_PUSH_PROGRESS_FROM_THIS_DEVICE});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tools
|
// Tools
|
||||||
items.push_back({MenuAction::NONE, StrId::STR_READER_TOOLS, true});
|
items.push_back(makeSeparatorMenuItem<MenuItem>(StrId::STR_READER_TOOLS));
|
||||||
items.push_back({MenuAction::SCREENSHOT, StrId::STR_SCREENSHOT_BUTTON});
|
items.push_back({MenuAction::SCREENSHOT, StrId::STR_SCREENSHOT_BUTTON});
|
||||||
items.push_back({MenuAction::DISPLAY_QR, StrId::STR_DISPLAY_QR});
|
items.push_back({MenuAction::DISPLAY_QR, StrId::STR_DISPLAY_QR});
|
||||||
items.push_back({MenuAction::DELETE_CACHE, StrId::STR_DELETE_CACHE});
|
items.push_back({MenuAction::DELETE_CACHE, StrId::STR_DELETE_CACHE});
|
||||||
@@ -61,9 +62,7 @@ std::vector<EpubReaderMenuActivity::MenuItem> EpubReaderMenuActivity::buildMenuI
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::function<bool(int)> EpubReaderMenuActivity::buildSelectablePredicate() const {
|
std::function<bool(int)> EpubReaderMenuActivity::buildSelectablePredicate() const {
|
||||||
return [this](int index) {
|
return makeSelectablePredicate(menuItems);
|
||||||
return index >= 0 && index < static_cast<int>(menuItems.size()) && !menuItems[index].isSeparator;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EpubReaderMenuActivity::onEnter() {
|
void EpubReaderMenuActivity::onEnter() {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <Epub.h>
|
#include <Epub.h>
|
||||||
#include <I18n.h>
|
#include <I18n.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -29,6 +30,12 @@ class EpubReaderMenuActivity final : public Activity {
|
|||||||
DELETE_CACHE
|
DELETE_CACHE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MenuItem {
|
||||||
|
MenuAction action;
|
||||||
|
StrId labelId;
|
||||||
|
bool isSeparator = false;
|
||||||
|
};
|
||||||
|
|
||||||
explicit EpubReaderMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, const std::string& title,
|
explicit EpubReaderMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, const std::string& title,
|
||||||
const int currentPage, const int totalPages, const int bookProgressPercent,
|
const int currentPage, const int totalPages, const int bookProgressPercent,
|
||||||
const uint8_t currentOrientation, const bool hasFootnotes,
|
const uint8_t currentOrientation, const bool hasFootnotes,
|
||||||
@@ -40,17 +47,10 @@ class EpubReaderMenuActivity final : public Activity {
|
|||||||
void loop() override;
|
void loop() override;
|
||||||
void render(RenderLock&&) override;
|
void render(RenderLock&&) override;
|
||||||
|
|
||||||
private:
|
|
||||||
struct MenuItem {
|
|
||||||
MenuAction action;
|
|
||||||
StrId labelId;
|
|
||||||
bool isSeparator = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::vector<MenuItem> buildMenuItems(bool hasFootnotes);
|
static std::vector<MenuItem> buildMenuItems(bool hasFootnotes);
|
||||||
|
|
||||||
std::function<bool(int)> buildSelectablePredicate() const;
|
std::function<bool(int)> buildSelectablePredicate() const;
|
||||||
|
|
||||||
|
private:
|
||||||
// Fixed menu layout
|
// Fixed menu layout
|
||||||
const std::vector<MenuItem> menuItems;
|
const std::vector<MenuItem> menuItems;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "SyncTimeActivity.h"
|
#include "SyncTimeActivity.h"
|
||||||
#include "components/UITheme.h"
|
#include "components/UITheme.h"
|
||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
#include "util/MenuItemHelpers.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const StrId timeZoneNames[CrossPointSettings::TIMEZONE_COUNT] = {
|
const StrId timeZoneNames[CrossPointSettings::TIMEZONE_COUNT] = {
|
||||||
@@ -23,22 +24,20 @@ std::vector<ClockSettingsActivity::MenuItem> ClockSettingsActivity::buildMenuIte
|
|||||||
std::vector<MenuItem> items;
|
std::vector<MenuItem> items;
|
||||||
items.reserve(7);
|
items.reserve(7);
|
||||||
// Settings
|
// Settings
|
||||||
items.push_back({Action::NONE, StrId::STR_SETTINGS_TITLE, true});
|
items.push_back(makeSeparatorMenuItem<MenuItem>(StrId::STR_SETTINGS_TITLE));
|
||||||
items.push_back({Action::USE_CLOCK, StrId::STR_USE_CLOCK});
|
items.push_back({Action::USE_CLOCK, StrId::STR_USE_CLOCK});
|
||||||
items.push_back({Action::CLOCK_FORMAT, StrId::STR_CLOCK_FORMAT});
|
items.push_back({Action::CLOCK_FORMAT, StrId::STR_CLOCK_FORMAT});
|
||||||
items.push_back({Action::TIMEZONE, StrId::STR_TIMEZONE});
|
items.push_back({Action::TIMEZONE, StrId::STR_TIMEZONE});
|
||||||
|
|
||||||
// Tools
|
// Tools
|
||||||
items.push_back({Action::NONE, StrId::STR_READER_TOOLS, true});
|
items.push_back(makeSeparatorMenuItem<MenuItem>(StrId::STR_READER_TOOLS));
|
||||||
items.push_back({Action::DETECT_TIMEZONE, StrId::STR_DETECT_TIMEZONE});
|
items.push_back({Action::DETECT_TIMEZONE, StrId::STR_DETECT_TIMEZONE});
|
||||||
items.push_back({Action::SYNC_TIME, StrId::STR_SYNC_TIME});
|
items.push_back({Action::SYNC_TIME, StrId::STR_SYNC_TIME});
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<bool(int)> ClockSettingsActivity::buildSelectablePredicate() const {
|
std::function<bool(int)> ClockSettingsActivity::buildSelectablePredicate() const {
|
||||||
return [this](int index) {
|
return makeSelectablePredicate(menuItems);
|
||||||
return index >= 0 && index < static_cast<int>(menuItems.size()) && !menuItems[index].isSeparator;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClockSettingsActivity::onEnter() {
|
void ClockSettingsActivity::onEnter() {
|
||||||
@@ -124,8 +123,7 @@ void ClockSettingsActivity::render(RenderLock&&) {
|
|||||||
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing * 2;
|
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing * 2;
|
||||||
|
|
||||||
GUI.drawList(
|
GUI.drawList(
|
||||||
renderer, Rect{0, contentTop, pageWidth, contentHeight}, static_cast<int>(menuItems.size()),
|
renderer, Rect{0, contentTop, pageWidth, contentHeight}, static_cast<int>(menuItems.size()), selectedIndex,
|
||||||
selectedIndex,
|
|
||||||
[this](int index) {
|
[this](int index) {
|
||||||
const auto title = I18N.get(menuItems[index].labelId);
|
const auto title = I18N.get(menuItems[index].labelId);
|
||||||
return menuItems[index].isSeparator ? UITheme::makeSeparatorTitle(title) : title;
|
return menuItems[index].isSeparator ? UITheme::makeSeparatorTitle(title) : title;
|
||||||
|
|||||||
@@ -1,21 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <I18n.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <I18n.h>
|
|
||||||
|
|
||||||
#include "activities/Activity.h"
|
#include "activities/Activity.h"
|
||||||
#include "util/ButtonNavigator.h"
|
#include "util/ButtonNavigator.h"
|
||||||
|
|
||||||
class ClockSettingsActivity final : public Activity {
|
class ClockSettingsActivity final : public Activity {
|
||||||
enum class Action {
|
enum class Action { USE_CLOCK, CLOCK_FORMAT, TIMEZONE, SYNC_TIME, DETECT_TIMEZONE, NONE };
|
||||||
USE_CLOCK,
|
|
||||||
CLOCK_FORMAT,
|
|
||||||
TIMEZONE,
|
|
||||||
SYNC_TIME,
|
|
||||||
DETECT_TIMEZONE,
|
|
||||||
NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MenuItem {
|
struct MenuItem {
|
||||||
Action action;
|
Action action;
|
||||||
|
|||||||
@@ -22,9 +22,11 @@
|
|||||||
#include "activities/weather/WeatherSettingsActivity.h"
|
#include "activities/weather/WeatherSettingsActivity.h"
|
||||||
#include "components/UITheme.h"
|
#include "components/UITheme.h"
|
||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
#include "util/MenuItemHelpers.h"
|
||||||
|
|
||||||
const StrId SettingsActivity::categoryNames[categoryCount] = {StrId::STR_CAT_DISPLAY, StrId::STR_CAT_READER,
|
const StrId SettingsActivity::categoryNames[categoryCount] = {StrId::STR_CAT_DISPLAY, StrId::STR_CAT_READER,
|
||||||
StrId::STR_CAT_CONTROLS, StrId::STR_CAT_SYSTEM};
|
StrId::STR_CAT_CONTROLS, StrId::STR_CAT_NETWORK,
|
||||||
|
StrId::STR_CAT_SYSTEM};
|
||||||
|
|
||||||
void SettingsActivity::onEnter() {
|
void SettingsActivity::onEnter() {
|
||||||
Activity::onEnter();
|
Activity::onEnter();
|
||||||
@@ -33,7 +35,9 @@ void SettingsActivity::onEnter() {
|
|||||||
displaySettings.clear();
|
displaySettings.clear();
|
||||||
readerSettings.clear();
|
readerSettings.clear();
|
||||||
controlsSettings.clear();
|
controlsSettings.clear();
|
||||||
|
networkSettings.clear();
|
||||||
systemSettings.clear();
|
systemSettings.clear();
|
||||||
|
systemSettings.push_back(SettingInfo::Separator(StrId::STR_SETTINGS_MENU_SETTINGS));
|
||||||
|
|
||||||
for (const auto& setting : getSettingsList()) {
|
for (const auto& setting : getSettingsList()) {
|
||||||
if (setting.category == StrId::STR_NONE_OPT) continue;
|
if (setting.category == StrId::STR_NONE_OPT) continue;
|
||||||
@@ -50,6 +54,8 @@ void SettingsActivity::onEnter() {
|
|||||||
controlsSettings.push_back(setting);
|
controlsSettings.push_back(setting);
|
||||||
} else if (setting.category == StrId::STR_CAT_SYSTEM) {
|
} else if (setting.category == StrId::STR_CAT_SYSTEM) {
|
||||||
systemSettings.push_back(setting);
|
systemSettings.push_back(setting);
|
||||||
|
} else if (setting.category == StrId::STR_CAT_NETWORK) {
|
||||||
|
networkSettings.push_back(setting);
|
||||||
}
|
}
|
||||||
// Web-only categories (KOReader Sync, OPDS Browser) are skipped for device UI
|
// Web-only categories (KOReader Sync, OPDS Browser) are skipped for device UI
|
||||||
}
|
}
|
||||||
@@ -57,15 +63,26 @@ void SettingsActivity::onEnter() {
|
|||||||
// Append device-only ACTION items
|
// Append device-only ACTION items
|
||||||
controlsSettings.insert(controlsSettings.begin(),
|
controlsSettings.insert(controlsSettings.begin(),
|
||||||
SettingInfo::Action(StrId::STR_REMAP_FRONT_BUTTONS, SettingAction::RemapFrontButtons));
|
SettingInfo::Action(StrId::STR_REMAP_FRONT_BUTTONS, SettingAction::RemapFrontButtons));
|
||||||
|
|
||||||
|
networkSettings.push_back(SettingInfo::Separator(StrId::STR_SETTINGS_MENU_NETWORK));
|
||||||
|
networkSettings.push_back(SettingInfo::Action(StrId::STR_WIFI_NETWORKS, SettingAction::Network));
|
||||||
|
networkSettings.push_back(SettingInfo::Separator(StrId::STR_SETTINGS_MENU_SOURCES));
|
||||||
|
networkSettings.push_back(SettingInfo::Action(StrId::STR_OPDS_BROWSER, SettingAction::OPDSBrowser));
|
||||||
|
networkSettings.push_back(SettingInfo::Separator(StrId::STR_SETTINGS_MENU_SYNC));
|
||||||
|
networkSettings.push_back(SettingInfo::Action(StrId::STR_KOREADER_SYNC, SettingAction::KOReaderSync));
|
||||||
|
|
||||||
|
// System settings with actions
|
||||||
|
systemSettings.push_back(SettingInfo::Action(StrId::STR_LANGUAGE, SettingAction::Language));
|
||||||
|
|
||||||
|
systemSettings.push_back(SettingInfo::Separator(StrId::STR_SETTINGS_MENU_TOOLS));
|
||||||
systemSettings.push_back(SettingInfo::Action(StrId::STR_CLOCK_SETTINGS, SettingAction::ClockSettings));
|
systemSettings.push_back(SettingInfo::Action(StrId::STR_CLOCK_SETTINGS, SettingAction::ClockSettings));
|
||||||
systemSettings.push_back(SettingInfo::Action(StrId::STR_WIFI_NETWORKS, SettingAction::Network));
|
systemSettings.push_back(SettingInfo::Action(StrId::STR_WEATHER_SETTINGS, SettingAction::Weather));
|
||||||
systemSettings.push_back(SettingInfo::Action(StrId::STR_KOREADER_SYNC, SettingAction::KOReaderSync));
|
|
||||||
systemSettings.push_back(SettingInfo::Action(StrId::STR_OPDS_BROWSER, SettingAction::OPDSBrowser));
|
systemSettings.push_back(SettingInfo::Separator(StrId::STR_SETTINGS_MENU_SYSTEM));
|
||||||
systemSettings.push_back(SettingInfo::Action(StrId::STR_CLEAR_READING_CACHE, SettingAction::ClearCache));
|
systemSettings.push_back(SettingInfo::Action(StrId::STR_CLEAR_READING_CACHE, SettingAction::ClearCache));
|
||||||
systemSettings.push_back(SettingInfo::Action(StrId::STR_CHECK_UPDATES, SettingAction::CheckForUpdates));
|
systemSettings.push_back(SettingInfo::Action(StrId::STR_CHECK_UPDATES, SettingAction::CheckForUpdates));
|
||||||
systemSettings.push_back(SettingInfo::Action(StrId::STR_LANGUAGE, SettingAction::Language));
|
|
||||||
systemSettings.push_back(SettingInfo::Action(StrId::STR_SYSTEM_INFO, SettingAction::SystemInfo));
|
systemSettings.push_back(SettingInfo::Action(StrId::STR_SYSTEM_INFO, SettingAction::SystemInfo));
|
||||||
systemSettings.push_back(SettingInfo::Action(StrId::STR_WEATHER_SETTINGS, SettingAction::Weather));
|
|
||||||
readerSettings.push_back(SettingInfo::Action(StrId::STR_CUSTOMISE_STATUS_BAR, SettingAction::CustomiseStatusBar));
|
readerSettings.push_back(SettingInfo::Action(StrId::STR_CUSTOMISE_STATUS_BAR, SettingAction::CustomiseStatusBar));
|
||||||
|
|
||||||
// Reset selection to first category
|
// Reset selection to first category
|
||||||
@@ -75,11 +92,16 @@ void SettingsActivity::onEnter() {
|
|||||||
// Initialize with first category (Display)
|
// Initialize with first category (Display)
|
||||||
currentSettings = &displaySettings;
|
currentSettings = &displaySettings;
|
||||||
settingsCount = static_cast<int>(displaySettings.size());
|
settingsCount = static_cast<int>(displaySettings.size());
|
||||||
|
buttonNavigator.setSelectablePredicate(makeSelectablePredicate(*currentSettings, 1, true), settingsCount + 1);
|
||||||
|
|
||||||
// Trigger first update
|
// Trigger first update
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::function<bool(int)> SettingsActivity::buildSelectablePredicate() const {
|
||||||
|
return makeSelectablePredicate(*currentSettings, 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsActivity::onExit() {
|
void SettingsActivity::onExit() {
|
||||||
Activity::onExit();
|
Activity::onExit();
|
||||||
|
|
||||||
@@ -115,12 +137,12 @@ void SettingsActivity::loop() {
|
|||||||
|
|
||||||
// Handle navigation
|
// Handle navigation
|
||||||
buttonNavigator.onNextRelease([this] {
|
buttonNavigator.onNextRelease([this] {
|
||||||
selectedSettingIndex = ButtonNavigator::nextIndex(selectedSettingIndex, settingsCount + 1);
|
selectedSettingIndex = buttonNavigator.nextIndex(selectedSettingIndex);
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonNavigator.onPreviousRelease([this] {
|
buttonNavigator.onPreviousRelease([this] {
|
||||||
selectedSettingIndex = ButtonNavigator::previousIndex(selectedSettingIndex, settingsCount + 1);
|
selectedSettingIndex = buttonNavigator.previousIndex(selectedSettingIndex);
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -149,10 +171,14 @@ void SettingsActivity::loop() {
|
|||||||
currentSettings = &controlsSettings;
|
currentSettings = &controlsSettings;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
|
currentSettings = &networkSettings;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
currentSettings = &systemSettings;
|
currentSettings = &systemSettings;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
settingsCount = static_cast<int>(currentSettings->size());
|
settingsCount = static_cast<int>(currentSettings->size());
|
||||||
|
buttonNavigator.setSelectablePredicate(makeSelectablePredicate(*currentSettings, 1, true), settingsCount + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,6 +189,9 @@ void SettingsActivity::toggleCurrentSetting() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto& setting = (*currentSettings)[selectedSetting];
|
const auto& setting = (*currentSettings)[selectedSetting];
|
||||||
|
if (setting.isSeparator) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (setting.type == SettingType::TOGGLE && setting.valuePtr != nullptr) {
|
if (setting.type == SettingType::TOGGLE && setting.valuePtr != nullptr) {
|
||||||
// Toggle the boolean value using the member pointer
|
// Toggle the boolean value using the member pointer
|
||||||
@@ -259,7 +288,11 @@ void SettingsActivity::render(RenderLock&&) {
|
|||||||
contentRect.height -
|
contentRect.height -
|
||||||
(metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing * 2)},
|
(metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing * 2)},
|
||||||
settingsCount, selectedSettingIndex - 1,
|
settingsCount, selectedSettingIndex - 1,
|
||||||
[&settings](int index) { return std::string(I18N.get(settings[index].nameId)); }, nullptr, nullptr,
|
[&settings](int index) {
|
||||||
|
const auto title = I18N.get(settings[index].nameId);
|
||||||
|
return settings[index].isSeparator ? UITheme::makeSeparatorTitle(title) : title;
|
||||||
|
},
|
||||||
|
nullptr, nullptr,
|
||||||
[&settings](int i) {
|
[&settings](int i) {
|
||||||
const auto& setting = settings[i];
|
const auto& setting = settings[i];
|
||||||
std::string valueText = "";
|
std::string valueText = "";
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ enum class SettingAction {
|
|||||||
|
|
||||||
struct SettingInfo {
|
struct SettingInfo {
|
||||||
StrId nameId;
|
StrId nameId;
|
||||||
|
bool isSeparator = false;
|
||||||
SettingType type;
|
SettingType type;
|
||||||
uint8_t CrossPointSettings::* valuePtr = nullptr;
|
uint8_t CrossPointSettings::* valuePtr = nullptr;
|
||||||
std::vector<StrId> enumValues;
|
std::vector<StrId> enumValues;
|
||||||
@@ -84,11 +85,21 @@ struct SettingInfo {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SettingInfo Action(StrId nameId, SettingAction action) {
|
static SettingInfo Action(StrId nameId, SettingAction action, bool isSeparator = false) {
|
||||||
SettingInfo s;
|
SettingInfo s;
|
||||||
s.nameId = nameId;
|
s.nameId = nameId;
|
||||||
s.type = SettingType::ACTION;
|
s.type = SettingType::ACTION;
|
||||||
s.action = action;
|
s.action = action;
|
||||||
|
s.isSeparator = isSeparator;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SettingInfo Separator(StrId nameId) {
|
||||||
|
SettingInfo s;
|
||||||
|
s.nameId = nameId;
|
||||||
|
s.type = SettingType::ACTION;
|
||||||
|
s.action = SettingAction::None;
|
||||||
|
s.isSeparator = true;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,14 +166,16 @@ class SettingsActivity final : public Activity {
|
|||||||
std::vector<SettingInfo> displaySettings;
|
std::vector<SettingInfo> displaySettings;
|
||||||
std::vector<SettingInfo> readerSettings;
|
std::vector<SettingInfo> readerSettings;
|
||||||
std::vector<SettingInfo> controlsSettings;
|
std::vector<SettingInfo> controlsSettings;
|
||||||
|
std::vector<SettingInfo> networkSettings;
|
||||||
std::vector<SettingInfo> systemSettings;
|
std::vector<SettingInfo> systemSettings;
|
||||||
const std::vector<SettingInfo>* currentSettings = nullptr;
|
const std::vector<SettingInfo>* currentSettings = nullptr;
|
||||||
|
|
||||||
static constexpr int categoryCount = 4;
|
static constexpr int categoryCount = 5;
|
||||||
static const StrId categoryNames[categoryCount];
|
static const StrId categoryNames[categoryCount];
|
||||||
|
|
||||||
void enterCategory(int categoryIndex);
|
void enterCategory(int categoryIndex);
|
||||||
void toggleCurrentSetting();
|
void toggleCurrentSetting();
|
||||||
|
std::function<bool(int)> buildSelectablePredicate() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SettingsActivity(GfxRenderer& renderer, MappedInputManager& mappedInput)
|
explicit SettingsActivity(GfxRenderer& renderer, MappedInputManager& mappedInput)
|
||||||
|
|||||||
@@ -98,17 +98,11 @@ Rect UITheme::getContentRect(const GfxRenderer& renderer, bool hasBottomHints, b
|
|||||||
return Rect{left, top, w - left - right, h - top - bottom};
|
return Rect{left, top, w - left - right, h - top - bottom};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string UITheme::makeSeparatorTitle(const std::string& title) {
|
std::string UITheme::makeSeparatorTitle(const std::string& title) { return std::string("__") + title; }
|
||||||
return std::string("__") + title;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string UITheme::makeSeparatorTitle(StrId labelId) {
|
std::string UITheme::makeSeparatorTitle(StrId labelId) { return std::string("__") + I18N.get(labelId); }
|
||||||
return std::string("__") + I18N.get(labelId);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UITheme::isSeparatorTitle(const std::string& title) {
|
bool UITheme::isSeparatorTitle(const std::string& title) { return title.rfind("__", 0) == 0; }
|
||||||
return title.rfind("__", 0) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string UITheme::stripSeparatorTitle(const std::string& title) {
|
std::string UITheme::stripSeparatorTitle(const std::string& title) {
|
||||||
return isSeparatorTitle(title) ? title.substr(2) : title;
|
return isSeparatorTitle(title) ? title.substr(2) : title;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <I18n.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <I18n.h>
|
|
||||||
|
|
||||||
#include "CrossPointSettings.h"
|
#include "CrossPointSettings.h"
|
||||||
#include "components/themes/BaseTheme.h"
|
#include "components/themes/BaseTheme.h"
|
||||||
|
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ class ButtonNavigator final {
|
|||||||
[[nodiscard]] static int nextIndex(int currentIndex, const std::vector<bool>& selectable);
|
[[nodiscard]] static int nextIndex(int currentIndex, const std::vector<bool>& selectable);
|
||||||
[[nodiscard]] static int previousIndex(int currentIndex, const std::vector<bool>& selectable);
|
[[nodiscard]] static int previousIndex(int currentIndex, const std::vector<bool>& selectable);
|
||||||
[[nodiscard]] static int nextIndex(int currentIndex, int totalItems,
|
[[nodiscard]] static int nextIndex(int currentIndex, int totalItems,
|
||||||
const std::function<bool(int index)>& isSelectable);
|
const std::function<bool(int index)>& isSelectable);
|
||||||
[[nodiscard]] static int previousIndex(int currentIndex, int totalItems,
|
[[nodiscard]] static int previousIndex(int currentIndex, int totalItems,
|
||||||
const std::function<bool(int index)>& isSelectable);
|
const std::function<bool(int index)>& isSelectable);
|
||||||
|
|
||||||
[[nodiscard]] int nextIndex(int currentIndex) const;
|
[[nodiscard]] int nextIndex(int currentIndex) const;
|
||||||
[[nodiscard]] int previousIndex(int currentIndex) const;
|
[[nodiscard]] int previousIndex(int currentIndex) const;
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <I18n.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Generic helper for constructing separator rows in menu item vectors.
|
||||||
|
// The item type must have an `action`, an `isSeparator`, and either a `labelId` or `nameId` member.
|
||||||
|
template <typename ItemType>
|
||||||
|
inline ItemType makeSeparatorMenuItem(StrId labelId) {
|
||||||
|
ItemType item{};
|
||||||
|
if constexpr (std::is_member_object_pointer_v<decltype(&ItemType::action)>) {
|
||||||
|
item.action = static_cast<decltype(item.action)>(0);
|
||||||
|
}
|
||||||
|
if constexpr (std::is_member_object_pointer_v<decltype(&ItemType::labelId)>) {
|
||||||
|
item.labelId = labelId;
|
||||||
|
} else if constexpr (std::is_member_object_pointer_v<decltype(&ItemType::nameId)>) {
|
||||||
|
item.nameId = labelId;
|
||||||
|
} else {
|
||||||
|
static_assert(sizeof(ItemType) == 0,
|
||||||
|
"makeSeparatorMenuItem requires ItemType with labelId or nameId member");
|
||||||
|
}
|
||||||
|
item.isSeparator = true;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic helper for creating a selectable predicate for menu lists.
|
||||||
|
// The item type must have an `isSeparator` member.
|
||||||
|
template <typename ItemType>
|
||||||
|
inline std::function<bool(int)> makeSelectablePredicate(const std::vector<ItemType>& items) {
|
||||||
|
return
|
||||||
|
[&items](int index) { return index >= 0 && index < static_cast<int>(items.size()) && !items[index].isSeparator; };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ItemType>
|
||||||
|
inline std::function<bool(int)> makeSelectablePredicate(const std::vector<ItemType>& items, int indexOffset,
|
||||||
|
bool firstIndexSelectable) {
|
||||||
|
return [&items, indexOffset, firstIndexSelectable](int index) {
|
||||||
|
if (firstIndexSelectable && index == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int itemIndex = index - indexOffset;
|
||||||
|
return itemIndex >= 0 && itemIndex < static_cast<int>(items.size()) && !items[itemIndex].isSeparator;
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user