#include "EpubReaderFootnotesActivity.h" #include #include #include #include "MappedInputManager.h" #include "components/UITheme.h" #include "fontIds.h" void EpubReaderFootnotesActivity::onEnter() { Activity::onEnter(); selectedIndex = 0; requestUpdate(); } void EpubReaderFootnotesActivity::onExit() { Activity::onExit(); } void EpubReaderFootnotesActivity::loop() { ButtonEventManager::ButtonEvent ev; while (buttonEvents.consumeEvent(ev)) { if (ev.button == MappedInputManager::Button::Back && ev.type == ButtonEventManager::PressType::Short) { ActivityResult result; result.isCancelled = true; setResult(std::move(result)); finish(); return; } if (ev.button == MappedInputManager::Button::Confirm && ev.type == ButtonEventManager::PressType::Short) { if (selectedIndex >= 0 && selectedIndex < static_cast(footnotes.size())) { setResult(FootnoteResult{footnotes[selectedIndex].href}); finish(); } return; } if ((ev.button == MappedInputManager::Button::PageBack || ev.button == MappedInputManager::Button::Left) && ev.type == ButtonEventManager::PressType::Short) { advanceSelection(-1); return; } if ((ev.button == MappedInputManager::Button::PageForward || ev.button == MappedInputManager::Button::Right) && ev.type == ButtonEventManager::PressType::Short) { advanceSelection(1); return; } } buttonNavigator.onNextRelease([this] { advanceSelection(1); }); buttonNavigator.onPreviousRelease([this] { advanceSelection(-1); }); buttonNavigator.onNextContinuous([this] { advanceSelection(1); }); buttonNavigator.onPreviousContinuous([this] { advanceSelection(-1); }); } void EpubReaderFootnotesActivity::advanceSelection(int delta) { if (footnotes.empty()) { return; } const int n = static_cast(footnotes.size()); selectedIndex = ((selectedIndex + delta) % n + n) % n; requestUpdate(); } void EpubReaderFootnotesActivity::render(RenderLock&&) { renderer.clearScreen(); renderer.drawCenteredText(UI_12_FONT_ID, 15, tr(STR_FOOTNOTES), true, EpdFontFamily::BOLD); if (footnotes.empty()) { renderer.drawCenteredText(UI_10_FONT_ID, 90, tr(STR_NO_FOOTNOTES)); const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", ""); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); renderer.displayBuffer(); return; } constexpr int startY = 50; constexpr int lineHeight = 36; const Rect contentRect = UITheme::getContentRect(renderer, true, false); constexpr int marginLeft = 20; const int visibleCount = std::max(1, (contentRect.height - startY) / lineHeight); if (selectedIndex < scrollOffset) scrollOffset = selectedIndex; if (selectedIndex >= scrollOffset + visibleCount) scrollOffset = selectedIndex - visibleCount + 1; for (int i = scrollOffset; i < static_cast(footnotes.size()) && i < scrollOffset + visibleCount; i++) { const int y = contentRect.y + startY + (i - scrollOffset) * lineHeight; const bool isSelected = (i == selectedIndex); if (isSelected) { renderer.fillRect(contentRect.x, y, contentRect.width, lineHeight, true); } // Show footnote number and abbreviated href std::string label = footnotes[i].number; if (label.empty()) { label = tr(STR_LINK); } renderer.drawText(UI_10_FONT_ID, contentRect.x + marginLeft, y + 4, label.c_str(), !isSelected); } const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), "", ""); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); renderer.displayBuffer(); }