feat: Selection Popup (#2358)
Co-authored-by: pablohc <pablonoviello@outlook.com>
This commit is contained in:
@@ -50,6 +50,8 @@ void EpubReaderMenuActivity::onEnter() {
|
||||
void EpubReaderMenuActivity::onExit() { Activity::onExit(); }
|
||||
|
||||
void EpubReaderMenuActivity::loop() {
|
||||
if (optionPopup.handleInput(mappedInput, [this] { requestUpdate(); })) return;
|
||||
|
||||
// Handle navigation
|
||||
buttonNavigator.onNext([this] {
|
||||
selectedIndex = ButtonNavigator::nextIndex(selectedIndex, static_cast<int>(menuItems.size()));
|
||||
@@ -64,14 +66,21 @@ void EpubReaderMenuActivity::loop() {
|
||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||
const auto selectedAction = menuItems[selectedIndex].action;
|
||||
if (selectedAction == MenuAction::ROTATE_SCREEN) {
|
||||
// Cycle orientation preview locally; actual rotation happens on menu exit.
|
||||
pendingOrientation = (pendingOrientation + 1) % orientationLabels.size();
|
||||
optionPopup.show(StrId::STR_ORIENTATION, orientationLabels.data(), static_cast<int>(orientationLabels.size()),
|
||||
pendingOrientation, [this](int idx) {
|
||||
pendingOrientation = idx;
|
||||
requestUpdate();
|
||||
});
|
||||
requestUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedAction == MenuAction::AUTO_PAGE_TURN) {
|
||||
selectedPageTurnOption = (selectedPageTurnOption + 1) % pageTurnLabels.size();
|
||||
optionPopup.show(I18N.get(StrId::STR_AUTO_TURN_PAGES_PER_MIN), pageTurnLabels.data(),
|
||||
static_cast<int>(pageTurnLabels.size()), selectedPageTurnOption, [this](int idx) {
|
||||
selectedPageTurnOption = idx;
|
||||
requestUpdate();
|
||||
});
|
||||
requestUpdate();
|
||||
return;
|
||||
}
|
||||
@@ -90,6 +99,8 @@ void EpubReaderMenuActivity::loop() {
|
||||
}
|
||||
|
||||
void EpubReaderMenuActivity::render(RenderLock&&) {
|
||||
if (optionPopup.processRender(renderer, mappedInput)) return;
|
||||
|
||||
renderer.clearScreen();
|
||||
|
||||
auto metrics = UITheme::getInstance().getMetrics();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "activities/Activity.h"
|
||||
#include "components/OptionPopup.h"
|
||||
#include "util/ButtonNavigator.h"
|
||||
|
||||
class EpubReaderMenuActivity final : public Activity {
|
||||
@@ -49,6 +50,7 @@ class EpubReaderMenuActivity final : public Activity {
|
||||
int selectedIndex = 0;
|
||||
|
||||
ButtonNavigator buttonNavigator;
|
||||
OptionPopup optionPopup;
|
||||
std::string title = "Reader Menu";
|
||||
uint8_t pendingOrientation = 0;
|
||||
uint8_t selectedPageTurnOption = 0;
|
||||
|
||||
@@ -113,6 +113,8 @@ void SettingsActivity::onExit() {
|
||||
}
|
||||
|
||||
void SettingsActivity::loop() {
|
||||
if (optionPopup.handleInput(mappedInput, [this] { requestUpdate(); })) return;
|
||||
|
||||
bool hasChangedCategory = false;
|
||||
|
||||
// Handle actions with early return
|
||||
@@ -203,6 +205,18 @@ void SettingsActivity::toggleCurrentSetting() {
|
||||
SETTINGS.*(setting.valuePtr) = !currentValue;
|
||||
} else if (setting.type == SettingType::ENUM && setting.valuePtr != nullptr) {
|
||||
const uint8_t currentValue = SETTINGS.*(setting.valuePtr);
|
||||
if (setting.enumValues.size() > 2) {
|
||||
const auto valuePtr = setting.valuePtr;
|
||||
optionPopup.show(setting.nameId, setting.enumValues.data(), static_cast<int>(setting.enumValues.size()),
|
||||
currentValue, [this, valuePtr, sleepScreenChanged, quickResumeTimeoutChanged](int idx) {
|
||||
SETTINGS.*valuePtr = idx;
|
||||
syncQuickResumeTimeoutForSleepScreen(sleepScreenChanged, quickResumeTimeoutChanged);
|
||||
SETTINGS.saveToFile();
|
||||
rebuildSettingsLists();
|
||||
});
|
||||
requestUpdate();
|
||||
return;
|
||||
}
|
||||
SETTINGS.*(setting.valuePtr) = (currentValue + 1) % static_cast<uint8_t>(setting.enumValues.size());
|
||||
} else if (setting.type == SettingType::ENUM && setting.valueGetter && setting.valueSetter) {
|
||||
if (setting.nameId == StrId::STR_FONT_FAMILY) {
|
||||
@@ -218,6 +232,23 @@ void SettingsActivity::toggleCurrentSetting() {
|
||||
? static_cast<uint8_t>(setting.enumValues.size())
|
||||
: static_cast<uint8_t>(setting.enumStringValues.size());
|
||||
const uint8_t cur = setting.valueGetter();
|
||||
if (totalValues > 2) {
|
||||
const auto valueSetter = setting.valueSetter;
|
||||
auto onSelect = [this, valueSetter, sleepScreenChanged, quickResumeTimeoutChanged](int idx) {
|
||||
valueSetter(idx);
|
||||
syncQuickResumeTimeoutForSleepScreen(sleepScreenChanged, quickResumeTimeoutChanged);
|
||||
SETTINGS.saveToFile();
|
||||
rebuildSettingsLists();
|
||||
};
|
||||
if (!setting.enumStringValues.empty()) {
|
||||
optionPopup.show(setting.nameId, setting.enumStringValues, cur, std::move(onSelect));
|
||||
} else {
|
||||
optionPopup.show(setting.nameId, setting.enumValues.data(), static_cast<int>(setting.enumValues.size()), cur,
|
||||
std::move(onSelect));
|
||||
}
|
||||
requestUpdate();
|
||||
return;
|
||||
}
|
||||
setting.valueSetter((cur + 1) % totalValues);
|
||||
} else if (setting.type == SettingType::VALUE && setting.valuePtr != nullptr) {
|
||||
const int8_t currentValue = SETTINGS.*(setting.valuePtr);
|
||||
@@ -319,6 +350,8 @@ void SettingsActivity::openSleepTimeoutPicker() {
|
||||
}
|
||||
|
||||
void SettingsActivity::render(RenderLock&&) {
|
||||
if (optionPopup.processRender(renderer, mappedInput)) return;
|
||||
|
||||
renderer.clearScreen();
|
||||
|
||||
const auto pageWidth = renderer.getScreenWidth();
|
||||
@@ -386,6 +419,7 @@ void SettingsActivity::render(RenderLock&&) {
|
||||
: (selectedSettingIndex > 0 && (*currentSettings)[selectedSettingIndex - 1].nameId == StrId::STR_TIME_TO_SLEEP
|
||||
? tr(STR_SELECT)
|
||||
: tr(STR_TOGGLE));
|
||||
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), confirmLabel, tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||||
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
#include "activities/Activity.h"
|
||||
#include "components/OptionPopup.h"
|
||||
#include "util/ButtonNavigator.h"
|
||||
|
||||
enum class SettingType { TOGGLE, ENUM, ACTION, VALUE, STRING };
|
||||
@@ -159,6 +160,8 @@ class SettingsActivity final : public Activity {
|
||||
bool preserveQuickResumeTimeoutOn = false;
|
||||
bool quickResumeTimeoutAutoEnabled = false;
|
||||
|
||||
OptionPopup optionPopup;
|
||||
|
||||
static constexpr int categoryCount = 4;
|
||||
static const StrId categoryNames[categoryCount];
|
||||
|
||||
|
||||
@@ -125,6 +125,8 @@ void StatusBarSettingsActivity::onEnter() {
|
||||
void StatusBarSettingsActivity::onExit() { Activity::onExit(); }
|
||||
|
||||
void StatusBarSettingsActivity::loop() {
|
||||
if (optionPopup.handleInput(mappedInput, [this] { requestUpdate(); })) return;
|
||||
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
|
||||
finish();
|
||||
return;
|
||||
@@ -167,21 +169,35 @@ void StatusBarSettingsActivity::handleSelection() {
|
||||
SETTINGS.statusBarBookProgressPercentage = (SETTINGS.statusBarBookProgressPercentage + 1) % 2;
|
||||
break;
|
||||
case ITEM_PROGRESS_BAR:
|
||||
SETTINGS.statusBarProgressBar = (SETTINGS.statusBarProgressBar + 1) % PROGRESS_BAR_ITEMS;
|
||||
break;
|
||||
optionPopup.show(StrId::STR_PROGRESS_BAR, progressBarNames, PROGRESS_BAR_ITEMS, SETTINGS.statusBarProgressBar,
|
||||
[this](int idx) {
|
||||
SETTINGS.statusBarProgressBar = idx;
|
||||
SETTINGS.saveToFile();
|
||||
});
|
||||
return;
|
||||
case ITEM_PROGRESS_BAR_THICKNESS:
|
||||
SETTINGS.statusBarProgressBarThickness =
|
||||
(SETTINGS.statusBarProgressBarThickness + 1) % PROGRESS_BAR_THICKNESS_ITEMS;
|
||||
break;
|
||||
optionPopup.show(StrId::STR_PROGRESS_BAR_THICKNESS, progressBarThicknessNames, PROGRESS_BAR_THICKNESS_ITEMS,
|
||||
SETTINGS.statusBarProgressBarThickness, [this](int idx) {
|
||||
SETTINGS.statusBarProgressBarThickness = idx;
|
||||
SETTINGS.saveToFile();
|
||||
});
|
||||
return;
|
||||
case ITEM_TITLE:
|
||||
SETTINGS.statusBarTitle = (SETTINGS.statusBarTitle + 1) % TITLE_ITEMS;
|
||||
break;
|
||||
optionPopup.show(StrId::STR_TITLE, titleNames, TITLE_ITEMS, SETTINGS.statusBarTitle, [this](int idx) {
|
||||
SETTINGS.statusBarTitle = idx;
|
||||
SETTINGS.saveToFile();
|
||||
});
|
||||
return;
|
||||
case ITEM_BATTERY:
|
||||
SETTINGS.statusBarBattery = (SETTINGS.statusBarBattery + 1) % 2;
|
||||
break;
|
||||
case ITEM_XTC_STATUS_BAR:
|
||||
SETTINGS.xtcStatusBarMode = (SETTINGS.xtcStatusBarMode + 1) % XTC_STATUS_BAR_ITEMS;
|
||||
break;
|
||||
optionPopup.show(StrId::STR_XTC_STATUS_BAR, xtcStatusBarNames, XTC_STATUS_BAR_ITEMS, SETTINGS.xtcStatusBarMode,
|
||||
[this](int idx) {
|
||||
SETTINGS.xtcStatusBarMode = idx;
|
||||
SETTINGS.saveToFile();
|
||||
});
|
||||
return;
|
||||
case ITEM_CLOCK:
|
||||
SETTINGS.statusBarClock = (SETTINGS.statusBarClock + 1) % STATUS_BAR_CLOCK_ITEMS;
|
||||
break;
|
||||
@@ -202,6 +218,8 @@ void StatusBarSettingsActivity::handleSelection() {
|
||||
}
|
||||
|
||||
void StatusBarSettingsActivity::render(RenderLock&&) {
|
||||
if (optionPopup.processRender(renderer, mappedInput)) return;
|
||||
|
||||
renderer.clearScreen();
|
||||
|
||||
auto metrics = UITheme::getInstance().getMetrics();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <freertos/task.h>
|
||||
|
||||
#include "activities/Activity.h"
|
||||
#include "components/OptionPopup.h"
|
||||
#include "util/ButtonNavigator.h"
|
||||
|
||||
// Reader status bar configuration activity
|
||||
@@ -19,6 +20,7 @@ class StatusBarSettingsActivity final : public Activity {
|
||||
|
||||
private:
|
||||
ButtonNavigator buttonNavigator;
|
||||
OptionPopup optionPopup;
|
||||
|
||||
int selectedIndex = 0;
|
||||
// Decided in onEnter() based on halClock.isAvailable() so clock entries are hidden on X4.
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
#include <I18n.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "GfxRenderer.h"
|
||||
#include "MappedInputManager.h"
|
||||
#include "components/UITheme.h"
|
||||
|
||||
class OptionPopup {
|
||||
public:
|
||||
void show(StrId titleId, const StrId* optionIds, int optionCount, int currentIndex,
|
||||
std::function<void(int)> onSelect) {
|
||||
title = I18N.get(titleId);
|
||||
ownedStrings.resize(optionCount);
|
||||
for (int i = 0; i < optionCount; i++) {
|
||||
ownedStrings[i] = I18N.get(optionIds[i]);
|
||||
}
|
||||
selectedIndex = currentIndex;
|
||||
onSelectCallback = std::move(onSelect);
|
||||
active = true;
|
||||
}
|
||||
|
||||
void show(const char* titleStr, const char* const* options, int optionCount, int currentIndex,
|
||||
std::function<void(int)> onSelect) {
|
||||
title = titleStr;
|
||||
ownedStrings.resize(optionCount);
|
||||
for (int i = 0; i < optionCount; i++) {
|
||||
ownedStrings[i] = options[i];
|
||||
}
|
||||
selectedIndex = currentIndex;
|
||||
onSelectCallback = std::move(onSelect);
|
||||
active = true;
|
||||
}
|
||||
|
||||
void show(StrId titleId, const std::vector<std::string>& options, int currentIndex,
|
||||
std::function<void(int)> onSelect) {
|
||||
title = I18N.get(titleId);
|
||||
ownedStrings = options;
|
||||
selectedIndex = currentIndex;
|
||||
onSelectCallback = std::move(onSelect);
|
||||
active = true;
|
||||
}
|
||||
|
||||
bool handleInput(MappedInputManager& input, const std::function<void()>& requestUpdate) {
|
||||
if (!active) return false;
|
||||
|
||||
const int count = static_cast<int>(ownedStrings.size());
|
||||
if (input.wasPressed(MappedInputManager::Button::Up) || input.wasPressed(MappedInputManager::Button::Left)) {
|
||||
selectedIndex = (selectedIndex - 1 + count) % count;
|
||||
requestUpdate();
|
||||
return true;
|
||||
} else if (input.wasPressed(MappedInputManager::Button::Down) ||
|
||||
input.wasPressed(MappedInputManager::Button::Right)) {
|
||||
selectedIndex = (selectedIndex + 1) % count;
|
||||
requestUpdate();
|
||||
return true;
|
||||
} else if (input.wasPressed(MappedInputManager::Button::Confirm)) {
|
||||
active = false;
|
||||
if (onSelectCallback) onSelectCallback(selectedIndex);
|
||||
requestUpdate();
|
||||
return true;
|
||||
} else if (input.wasPressed(MappedInputManager::Button::Back)) {
|
||||
active = false;
|
||||
requestUpdate();
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool processRender(GfxRenderer& renderer, const MappedInputManager& input) const {
|
||||
if (!active) return false;
|
||||
const auto popupLabels = input.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||||
GUI.drawButtonHints(renderer, popupLabels.btn1, popupLabels.btn2, popupLabels.btn3, popupLabels.btn4);
|
||||
render(renderer);
|
||||
renderer.displayBuffer();
|
||||
return true;
|
||||
}
|
||||
|
||||
void render(const GfxRenderer& renderer) const {
|
||||
if (!active) return;
|
||||
GUI.drawOptionPopup(renderer, title.c_str(), ownedStrings, selectedIndex);
|
||||
}
|
||||
|
||||
bool isActive() const { return active; }
|
||||
|
||||
private:
|
||||
bool active = false;
|
||||
std::string title;
|
||||
std::vector<std::string> ownedStrings;
|
||||
int selectedIndex = 0;
|
||||
std::function<void(int)> onSelectCallback;
|
||||
};
|
||||
@@ -1005,3 +1005,99 @@ void BaseTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const ch
|
||||
rect.y + metrics.keyboardSecondaryLabelTopPadding, secondaryLabel, !invert);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseTheme::drawOptionPopup(const GfxRenderer& renderer, const char* title, const std::vector<std::string>& options,
|
||||
int selectedIndex) const {
|
||||
const auto& metrics = UITheme::getInstance().getMetrics();
|
||||
const auto pageWidth = renderer.getScreenWidth();
|
||||
const auto pageHeight = renderer.getScreenHeight();
|
||||
|
||||
const int optionFontId = metrics.optionPopupUseSmallFont ? UI_10_FONT_ID : UI_12_FONT_ID;
|
||||
const EpdFontFamily::Style optionStyle =
|
||||
metrics.optionPopupOptionFontBold ? EpdFontFamily::BOLD : EpdFontFamily::REGULAR;
|
||||
|
||||
const int itemSpacing = metrics.optionPopupItemSpacing;
|
||||
const int innerPadding = metrics.optionPopupInnerPadding;
|
||||
const int selectionHPadding = metrics.optionPopupSelectionHPadding;
|
||||
const int selectionVPadding = metrics.optionPopupSelectionVPadding;
|
||||
|
||||
const int optionLineHeight = renderer.getLineHeight(optionFontId);
|
||||
const int titleLineHeight = renderer.getLineHeight(UI_12_FONT_ID);
|
||||
const int rowHeight = optionLineHeight + selectionVPadding * 2;
|
||||
|
||||
int maxTextWidth = renderer.getTextWidth(UI_12_FONT_ID, title, EpdFontFamily::BOLD);
|
||||
for (const auto& opt : options) {
|
||||
int w = renderer.getTextWidth(optionFontId, opt.c_str(), optionStyle);
|
||||
if (w > maxTextWidth) maxTextWidth = w;
|
||||
}
|
||||
|
||||
const int optionCount = static_cast<int>(options.size());
|
||||
const int listHeight = rowHeight * optionCount + itemSpacing * (optionCount - 1);
|
||||
const int dialogW = std::min((maxTextWidth + innerPadding * 2 + selectionHPadding * 2) * 12 / 10,
|
||||
pageWidth - metrics.optionPopupDialogSideMargin * 2);
|
||||
const int contentHeight = titleLineHeight + metrics.optionPopupTitleGap + listHeight;
|
||||
const int dialogH = contentHeight + innerPadding * 2;
|
||||
const int dialogX = (pageWidth - dialogW) / 2;
|
||||
const int dialogY = (pageHeight - dialogH) / 2;
|
||||
|
||||
const int frameThickness = metrics.popupFrameThickness;
|
||||
const int frameRadius = metrics.popupCornerRadius;
|
||||
|
||||
if (frameRadius > 0) {
|
||||
renderer.fillRoundedRect(dialogX - frameThickness, dialogY - frameThickness, dialogW + frameThickness * 2,
|
||||
dialogH + frameThickness * 2, frameRadius + frameThickness, Color::White);
|
||||
renderer.fillRoundedRect(dialogX, dialogY, dialogW, dialogH, frameRadius, Color::Black);
|
||||
renderer.fillRoundedRect(dialogX + frameThickness, dialogY + frameThickness, dialogW - frameThickness * 2,
|
||||
dialogH - frameThickness * 2,
|
||||
frameRadius - frameThickness > 0 ? frameRadius - frameThickness : 0, Color::White);
|
||||
} else {
|
||||
renderer.fillRect(dialogX - frameThickness, dialogY - frameThickness, dialogW + frameThickness * 2,
|
||||
dialogH + frameThickness * 2, true);
|
||||
renderer.fillRect(dialogX, dialogY, dialogW, dialogH, false);
|
||||
}
|
||||
|
||||
int y = dialogY + innerPadding;
|
||||
|
||||
renderer.drawCenteredText(UI_12_FONT_ID, y, title, true, EpdFontFamily::BOLD);
|
||||
y += titleLineHeight;
|
||||
|
||||
if (metrics.optionPopupTitleSeparator) {
|
||||
const int sepY = y + metrics.optionPopupTitleGap / 2;
|
||||
renderer.drawLine(dialogX + innerPadding, sepY, dialogX + dialogW - innerPadding, sepY, true);
|
||||
}
|
||||
|
||||
y += metrics.optionPopupTitleGap;
|
||||
|
||||
const int itemRectX = dialogX + innerPadding;
|
||||
const int itemRectW = dialogW - innerPadding * 2;
|
||||
const int selectionRadius = metrics.optionPopupSelectionRadius;
|
||||
|
||||
for (int i = 0; i < optionCount; i++) {
|
||||
const int itemY = y + i * (rowHeight + itemSpacing);
|
||||
const bool selected = (i == selectedIndex);
|
||||
const char* labelText = options[i].c_str();
|
||||
|
||||
if (metrics.optionPopupDrawAllRows || selected) {
|
||||
Color rowColor;
|
||||
if (selected) {
|
||||
rowColor = metrics.optionPopupSelectionLight ? Color::LightGray : Color::Black;
|
||||
} else {
|
||||
rowColor = Color::White;
|
||||
}
|
||||
if (selectionRadius > 0) {
|
||||
renderer.fillRoundedRect(itemRectX, itemY, itemRectW, rowHeight, selectionRadius, rowColor);
|
||||
} else {
|
||||
renderer.fillRect(itemRectX, itemY, itemRectW, rowHeight, rowColor == Color::Black);
|
||||
}
|
||||
}
|
||||
|
||||
const int textW = renderer.getTextWidth(optionFontId, labelText, optionStyle);
|
||||
const int textY = itemY + (rowHeight - optionLineHeight) / 2;
|
||||
const int textX = itemRectX + (itemRectW - textW) / 2;
|
||||
// Unselected items: text is dark (invert=true means draw on white bg).
|
||||
// Selected on dark bg: text must be white (invert=false).
|
||||
// Selected on light bg: text stays dark (invert=true).
|
||||
const bool invertText = selected ? metrics.optionPopupSelectionLight : true;
|
||||
renderer.drawText(optionFontId, textX, textY, labelText, invertText, optionStyle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,19 @@ struct ThemeMetrics {
|
||||
bool popupProgressFillInverted;
|
||||
bool popupProgressOutlineInverted;
|
||||
|
||||
int optionPopupItemSpacing;
|
||||
int optionPopupInnerPadding;
|
||||
int optionPopupSelectionHPadding;
|
||||
int optionPopupSelectionVPadding;
|
||||
int optionPopupTitleGap;
|
||||
bool optionPopupUseSmallFont;
|
||||
bool optionPopupOptionFontBold;
|
||||
int optionPopupSelectionRadius;
|
||||
bool optionPopupSelectionLight;
|
||||
bool optionPopupDrawAllRows;
|
||||
int optionPopupDialogSideMargin;
|
||||
bool optionPopupTitleSeparator;
|
||||
|
||||
int textFieldHorizontalPadding;
|
||||
int textFieldNormalThickness;
|
||||
int textFieldCursorThickness;
|
||||
@@ -167,6 +180,18 @@ constexpr ThemeMetrics values = {.batteryWidth = 15,
|
||||
.popupProgressClampPercent = false,
|
||||
.popupProgressFillInverted = true,
|
||||
.popupProgressOutlineInverted = true,
|
||||
.optionPopupItemSpacing = 6,
|
||||
.optionPopupInnerPadding = 16,
|
||||
.optionPopupSelectionHPadding = 8,
|
||||
.optionPopupSelectionVPadding = 4,
|
||||
.optionPopupTitleGap = 10,
|
||||
.optionPopupUseSmallFont = true,
|
||||
.optionPopupOptionFontBold = true,
|
||||
.optionPopupSelectionRadius = 0,
|
||||
.optionPopupSelectionLight = false,
|
||||
.optionPopupDrawAllRows = false,
|
||||
.optionPopupDialogSideMargin = 20,
|
||||
.optionPopupTitleSeparator = true,
|
||||
.textFieldHorizontalPadding = 6,
|
||||
.textFieldNormalThickness = 1,
|
||||
.textFieldCursorThickness = 3,
|
||||
@@ -207,6 +232,8 @@ class BaseTheme {
|
||||
const std::function<std::string(int index)>& buttonLabel,
|
||||
const std::function<UIIcon(int index)>& rowIcon) const;
|
||||
virtual Rect drawPopup(const GfxRenderer& renderer, const char* message) const;
|
||||
virtual void drawOptionPopup(const GfxRenderer& renderer, const char* title, const std::vector<std::string>& options,
|
||||
int selectedIndex) const;
|
||||
virtual void fillPopupProgress(const GfxRenderer& renderer, const Rect& layout, const int progress) const;
|
||||
void drawStatusBar(GfxRenderer& renderer, const float bookProgress, const int currentPage, const int pageCount,
|
||||
std::string title, const int paddingBottom = 0, const int textYOffset = 0,
|
||||
|
||||
@@ -65,6 +65,18 @@ constexpr ThemeMetrics values = {.batteryWidth = 16,
|
||||
.popupProgressClampPercent = false,
|
||||
.popupProgressFillInverted = false,
|
||||
.popupProgressOutlineInverted = false,
|
||||
.optionPopupItemSpacing = 8,
|
||||
.optionPopupInnerPadding = 20,
|
||||
.optionPopupSelectionHPadding = 16,
|
||||
.optionPopupSelectionVPadding = 12,
|
||||
.optionPopupTitleGap = 16,
|
||||
.optionPopupUseSmallFont = true,
|
||||
.optionPopupOptionFontBold = false,
|
||||
.optionPopupSelectionRadius = 6,
|
||||
.optionPopupSelectionLight = true,
|
||||
.optionPopupDrawAllRows = false,
|
||||
.optionPopupDialogSideMargin = 20,
|
||||
.optionPopupTitleSeparator = true,
|
||||
.textFieldHorizontalPadding = 6,
|
||||
.textFieldNormalThickness = 1,
|
||||
.textFieldCursorThickness = 3,
|
||||
|
||||
@@ -65,6 +65,18 @@ constexpr ThemeMetrics values = {.batteryWidth = 15,
|
||||
.popupProgressClampPercent = true,
|
||||
.popupProgressFillInverted = false,
|
||||
.popupProgressOutlineInverted = false,
|
||||
.optionPopupItemSpacing = 6,
|
||||
.optionPopupInnerPadding = 24,
|
||||
.optionPopupSelectionHPadding = 20,
|
||||
.optionPopupSelectionVPadding = 10,
|
||||
.optionPopupTitleGap = 16,
|
||||
.optionPopupUseSmallFont = false,
|
||||
.optionPopupOptionFontBold = true,
|
||||
.optionPopupSelectionRadius = 30,
|
||||
.optionPopupSelectionLight = false,
|
||||
.optionPopupDrawAllRows = true,
|
||||
.optionPopupDialogSideMargin = 20,
|
||||
.optionPopupTitleSeparator = true,
|
||||
.textFieldHorizontalPadding = 8,
|
||||
.textFieldNormalThickness = 2,
|
||||
.textFieldCursorThickness = 3,
|
||||
|
||||
Reference in New Issue
Block a user