198 lines
8.2 KiB
C++
198 lines
8.2 KiB
C++
#include "EpubReaderMenuActivity.h"
|
|
|
|
#include <GfxRenderer.h>
|
|
#include <I18n.h>
|
|
|
|
#include "MappedInputManager.h"
|
|
#include "components/UITheme.h"
|
|
#include "fontIds.h"
|
|
|
|
EpubReaderMenuActivity::EpubReaderMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
|
const std::string& title, const int currentPage, const int totalPages,
|
|
const int bookProgressPercent, const uint8_t currentOrientation,
|
|
const bool hasFootnotes, const int8_t initialEmbeddedStyleOverride,
|
|
const int8_t initialImageRenderingOverride)
|
|
: Activity("EpubReaderMenu", renderer, mappedInput),
|
|
menuItems(buildMenuItems(hasFootnotes)),
|
|
title(title),
|
|
pendingOrientation(currentOrientation),
|
|
pendingEmbeddedStyleOverride(initialEmbeddedStyleOverride),
|
|
pendingImageRenderingOverride(initialImageRenderingOverride),
|
|
currentPage(currentPage),
|
|
totalPages(totalPages),
|
|
bookProgressPercent(bookProgressPercent) {}
|
|
|
|
std::vector<EpubReaderMenuActivity::MenuItem> EpubReaderMenuActivity::buildMenuItems(bool hasFootnotes) {
|
|
std::vector<MenuItem> items;
|
|
items.reserve(10);
|
|
items.push_back({MenuAction::SELECT_CHAPTER, StrId::STR_SELECT_CHAPTER});
|
|
if (hasFootnotes) {
|
|
items.push_back({MenuAction::FOOTNOTES, StrId::STR_FOOTNOTES});
|
|
}
|
|
items.push_back({MenuAction::EMBEDDED_STYLE, StrId::STR_EMBEDDED_STYLE});
|
|
items.push_back({MenuAction::IMAGE_RENDERING, StrId::STR_IMAGES});
|
|
items.push_back({MenuAction::ROTATE_SCREEN, StrId::STR_ORIENTATION});
|
|
items.push_back({MenuAction::AUTO_PAGE_TURN, StrId::STR_AUTO_TURN_PAGES_PER_MIN});
|
|
items.push_back({MenuAction::GO_TO_PERCENT, StrId::STR_GO_TO_PERCENT});
|
|
items.push_back({MenuAction::SCREENSHOT, StrId::STR_SCREENSHOT_BUTTON});
|
|
items.push_back({MenuAction::DISPLAY_QR, StrId::STR_DISPLAY_QR});
|
|
items.push_back({MenuAction::GO_HOME, StrId::STR_GO_HOME_BUTTON});
|
|
items.push_back({MenuAction::SYNC, StrId::STR_SYNC_PROGRESS});
|
|
items.push_back({MenuAction::DELETE_CACHE, StrId::STR_DELETE_CACHE});
|
|
return items;
|
|
}
|
|
|
|
void EpubReaderMenuActivity::onEnter() {
|
|
Activity::onEnter();
|
|
requestUpdate();
|
|
}
|
|
|
|
void EpubReaderMenuActivity::onExit() { Activity::onExit(); }
|
|
|
|
void EpubReaderMenuActivity::loop() {
|
|
// Handle navigation
|
|
buttonNavigator.onNext([this] {
|
|
selectedIndex = ButtonNavigator::nextIndex(selectedIndex, static_cast<int>(menuItems.size()));
|
|
requestUpdate();
|
|
});
|
|
|
|
buttonNavigator.onPrevious([this] {
|
|
selectedIndex = ButtonNavigator::previousIndex(selectedIndex, static_cast<int>(menuItems.size()));
|
|
requestUpdate();
|
|
});
|
|
|
|
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();
|
|
requestUpdate();
|
|
return;
|
|
}
|
|
|
|
if (selectedAction == MenuAction::AUTO_PAGE_TURN) {
|
|
selectedPageTurnOption = (selectedPageTurnOption + 1) % pageTurnLabels.size();
|
|
requestUpdate();
|
|
return;
|
|
}
|
|
|
|
if (selectedAction == MenuAction::EMBEDDED_STYLE) {
|
|
// Cycle per-book override: default -> ON -> OFF -> default.
|
|
if (pendingEmbeddedStyleOverride < 0) {
|
|
pendingEmbeddedStyleOverride = 1;
|
|
} else if (pendingEmbeddedStyleOverride > 0) {
|
|
pendingEmbeddedStyleOverride = 0;
|
|
} else {
|
|
pendingEmbeddedStyleOverride = -1;
|
|
}
|
|
requestUpdate();
|
|
return;
|
|
}
|
|
|
|
if (selectedAction == MenuAction::IMAGE_RENDERING) {
|
|
// Cycle per-book override: default -> display -> placeholder -> suppress -> default.
|
|
if (pendingImageRenderingOverride < 0) {
|
|
pendingImageRenderingOverride = 0;
|
|
} else if (pendingImageRenderingOverride >= 2) {
|
|
pendingImageRenderingOverride = -1;
|
|
} else {
|
|
pendingImageRenderingOverride++;
|
|
}
|
|
requestUpdate();
|
|
return;
|
|
}
|
|
|
|
setResult(MenuResult{static_cast<int>(selectedAction), pendingOrientation, selectedPageTurnOption,
|
|
pendingEmbeddedStyleOverride, pendingImageRenderingOverride});
|
|
finish();
|
|
return;
|
|
} else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
|
ActivityResult result;
|
|
result.isCancelled = true;
|
|
result.data = MenuResult{-1, pendingOrientation, selectedPageTurnOption, pendingEmbeddedStyleOverride,
|
|
pendingImageRenderingOverride};
|
|
setResult(std::move(result));
|
|
finish();
|
|
return;
|
|
}
|
|
}
|
|
|
|
void EpubReaderMenuActivity::render(RenderLock&&) {
|
|
renderer.clearScreen();
|
|
const Rect contentRect = UITheme::getContentRect(renderer, true, false);
|
|
|
|
// Title
|
|
const std::string truncTitle =
|
|
renderer.truncatedText(UI_12_FONT_ID, title.c_str(), contentRect.width - 40, EpdFontFamily::BOLD);
|
|
// Manual centering so we can respect the content gutter.
|
|
const int titleX =
|
|
contentRect.x +
|
|
(contentRect.width - renderer.getTextWidth(UI_12_FONT_ID, truncTitle.c_str(), EpdFontFamily::BOLD)) / 2;
|
|
renderer.drawText(UI_12_FONT_ID, titleX, 15 + contentRect.y, truncTitle.c_str(), true, EpdFontFamily::BOLD);
|
|
|
|
// Progress summary
|
|
std::string progressLine;
|
|
if (totalPages > 0) {
|
|
progressLine = std::string(tr(STR_CHAPTER_PREFIX)) + std::to_string(currentPage) + "/" +
|
|
std::to_string(totalPages) + std::string(tr(STR_PAGES_SEPARATOR));
|
|
}
|
|
progressLine += std::string(tr(STR_BOOK_PREFIX)) + std::to_string(bookProgressPercent) + "%";
|
|
renderer.drawCenteredText(UI_10_FONT_ID, 45, progressLine.c_str());
|
|
|
|
// Menu Items
|
|
const int startY = 75 + contentRect.y;
|
|
constexpr int lineHeight = 30;
|
|
|
|
for (size_t i = 0; i < menuItems.size(); ++i) {
|
|
const int displayY = startY + (i * lineHeight);
|
|
const bool isSelected = (static_cast<int>(i) == selectedIndex);
|
|
|
|
if (isSelected) {
|
|
// Highlight only the content area so we don't paint over hint gutters.
|
|
renderer.fillRect(contentRect.x, displayY, contentRect.width - 1, lineHeight, true);
|
|
}
|
|
|
|
renderer.drawText(UI_10_FONT_ID, contentRect.x + 20, displayY, I18N.get(menuItems[i].labelId), !isSelected);
|
|
|
|
if (menuItems[i].action == MenuAction::ROTATE_SCREEN) {
|
|
// Render current orientation value on the right edge of the content area.
|
|
const char* value = I18N.get(orientationLabels[pendingOrientation]);
|
|
const auto width = renderer.getTextWidth(UI_10_FONT_ID, value);
|
|
renderer.drawText(UI_10_FONT_ID, contentRect.x + contentRect.width - 20 - width, displayY, value, !isSelected);
|
|
}
|
|
|
|
if (menuItems[i].action == MenuAction::AUTO_PAGE_TURN) {
|
|
// Render current page turn value on the right edge of the content area.
|
|
const auto value = pageTurnLabels[selectedPageTurnOption];
|
|
const auto width = renderer.getTextWidth(UI_10_FONT_ID, value);
|
|
renderer.drawText(UI_10_FONT_ID, contentRect.x + contentRect.width - 20 - width, displayY, value, !isSelected);
|
|
}
|
|
|
|
if (menuItems[i].action == MenuAction::EMBEDDED_STYLE) {
|
|
const char* value = tr(STR_DEFAULT_VALUE);
|
|
if (pendingEmbeddedStyleOverride == 1) {
|
|
value = tr(STR_STATE_ON);
|
|
} else if (pendingEmbeddedStyleOverride == 0) {
|
|
value = tr(STR_STATE_OFF);
|
|
}
|
|
const auto width = renderer.getTextWidth(UI_10_FONT_ID, value);
|
|
renderer.drawText(UI_10_FONT_ID, contentX + contentWidth - 20 - width, displayY, value, !isSelected);
|
|
}
|
|
|
|
if (menuItems[i].action == MenuAction::IMAGE_RENDERING) {
|
|
const char* value = tr(STR_DEFAULT_VALUE);
|
|
if (pendingImageRenderingOverride >= 0 && pendingImageRenderingOverride < imageRenderingLabels.size()) {
|
|
value = I18N.get(imageRenderingLabels[pendingImageRenderingOverride]);
|
|
}
|
|
const auto width = renderer.getTextWidth(UI_10_FONT_ID, value);
|
|
renderer.drawText(UI_10_FONT_ID, contentX + contentWidth - 20 - width, displayY, value, !isSelected);
|
|
}
|
|
}
|
|
|
|
// Footer / Hints
|
|
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
|
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
|
|
|
renderer.displayBuffer();
|
|
}
|