mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 22:57:50 +03:00
## Summary * This change hides the button hints from overlapping chapter titles when in landscape CW mode. Before  After  ## Additional Context * I initially considered implementing an offset fix, but with potential UI changes on the horizon, hiding the button hints appears to be the simplest solution for now. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? < Partially >
160 lines
4.9 KiB
C++
160 lines
4.9 KiB
C++
#include "XtcReaderChapterSelectionActivity.h"
|
|
|
|
#include <GfxRenderer.h>
|
|
|
|
#include "MappedInputManager.h"
|
|
#include "fontIds.h"
|
|
|
|
namespace {
|
|
constexpr int SKIP_PAGE_MS = 700;
|
|
} // namespace
|
|
|
|
int XtcReaderChapterSelectionActivity::getPageItems() const {
|
|
constexpr int startY = 60;
|
|
constexpr int lineHeight = 30;
|
|
|
|
const int screenHeight = renderer.getScreenHeight();
|
|
const int endY = screenHeight - lineHeight;
|
|
|
|
const int availableHeight = endY - startY;
|
|
int items = availableHeight / lineHeight;
|
|
if (items < 1) {
|
|
items = 1;
|
|
}
|
|
return items;
|
|
}
|
|
|
|
int XtcReaderChapterSelectionActivity::findChapterIndexForPage(uint32_t page) const {
|
|
if (!xtc) {
|
|
return 0;
|
|
}
|
|
|
|
const auto& chapters = xtc->getChapters();
|
|
for (size_t i = 0; i < chapters.size(); i++) {
|
|
if (page >= chapters[i].startPage && page <= chapters[i].endPage) {
|
|
return static_cast<int>(i);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void XtcReaderChapterSelectionActivity::taskTrampoline(void* param) {
|
|
auto* self = static_cast<XtcReaderChapterSelectionActivity*>(param);
|
|
self->displayTaskLoop();
|
|
}
|
|
|
|
void XtcReaderChapterSelectionActivity::onEnter() {
|
|
Activity::onEnter();
|
|
|
|
if (!xtc) {
|
|
return;
|
|
}
|
|
|
|
renderingMutex = xSemaphoreCreateMutex();
|
|
selectorIndex = findChapterIndexForPage(currentPage);
|
|
|
|
updateRequired = true;
|
|
xTaskCreate(&XtcReaderChapterSelectionActivity::taskTrampoline, "XtcReaderChapterSelectionActivityTask",
|
|
4096, // Stack size
|
|
this, // Parameters
|
|
1, // Priority
|
|
&displayTaskHandle // Task handle
|
|
);
|
|
}
|
|
|
|
void XtcReaderChapterSelectionActivity::onExit() {
|
|
Activity::onExit();
|
|
|
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
if (displayTaskHandle) {
|
|
vTaskDelete(displayTaskHandle);
|
|
displayTaskHandle = nullptr;
|
|
}
|
|
vSemaphoreDelete(renderingMutex);
|
|
renderingMutex = nullptr;
|
|
}
|
|
|
|
void XtcReaderChapterSelectionActivity::loop() {
|
|
const bool prevReleased = mappedInput.wasReleased(MappedInputManager::Button::Up) ||
|
|
mappedInput.wasReleased(MappedInputManager::Button::Left);
|
|
const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::Down) ||
|
|
mappedInput.wasReleased(MappedInputManager::Button::Right);
|
|
|
|
const bool skipPage = mappedInput.getHeldTime() > SKIP_PAGE_MS;
|
|
const int pageItems = getPageItems();
|
|
|
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
|
const auto& chapters = xtc->getChapters();
|
|
if (!chapters.empty() && selectorIndex >= 0 && selectorIndex < static_cast<int>(chapters.size())) {
|
|
onSelectPage(chapters[selectorIndex].startPage);
|
|
}
|
|
} else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
|
onGoBack();
|
|
} else if (prevReleased) {
|
|
const int total = static_cast<int>(xtc->getChapters().size());
|
|
if (total == 0) {
|
|
return;
|
|
}
|
|
if (skipPage) {
|
|
selectorIndex = ((selectorIndex / pageItems - 1) * pageItems + total) % total;
|
|
} else {
|
|
selectorIndex = (selectorIndex + total - 1) % total;
|
|
}
|
|
updateRequired = true;
|
|
} else if (nextReleased) {
|
|
const int total = static_cast<int>(xtc->getChapters().size());
|
|
if (total == 0) {
|
|
return;
|
|
}
|
|
if (skipPage) {
|
|
selectorIndex = ((selectorIndex / pageItems + 1) * pageItems) % total;
|
|
} else {
|
|
selectorIndex = (selectorIndex + 1) % total;
|
|
}
|
|
updateRequired = true;
|
|
}
|
|
}
|
|
|
|
void XtcReaderChapterSelectionActivity::displayTaskLoop() {
|
|
while (true) {
|
|
if (updateRequired) {
|
|
updateRequired = false;
|
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
renderScreen();
|
|
xSemaphoreGive(renderingMutex);
|
|
}
|
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
}
|
|
}
|
|
|
|
void XtcReaderChapterSelectionActivity::renderScreen() {
|
|
renderer.clearScreen();
|
|
|
|
const auto pageWidth = renderer.getScreenWidth();
|
|
const int pageItems = getPageItems();
|
|
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Select Chapter", true, EpdFontFamily::BOLD);
|
|
|
|
const auto& chapters = xtc->getChapters();
|
|
if (chapters.empty()) {
|
|
renderer.drawCenteredText(UI_10_FONT_ID, 120, "No chapters");
|
|
renderer.displayBuffer();
|
|
return;
|
|
}
|
|
|
|
const auto pageStartIndex = selectorIndex / pageItems * pageItems;
|
|
renderer.fillRect(0, 60 + (selectorIndex % pageItems) * 30 - 2, pageWidth - 1, 30);
|
|
for (int i = pageStartIndex; i < static_cast<int>(chapters.size()) && i < pageStartIndex + pageItems; i++) {
|
|
const auto& chapter = chapters[i];
|
|
const char* title = chapter.name.empty() ? "Unnamed" : chapter.name.c_str();
|
|
renderer.drawText(UI_10_FONT_ID, 20, 60 + (i % pageItems) * 30, title, i != selectorIndex);
|
|
}
|
|
|
|
// Skip button hints in landscape CW mode (they overlap content)
|
|
if (renderer.getOrientation() != GfxRenderer::LandscapeClockwise) {
|
|
const auto labels = mappedInput.mapLabels("« Back", "Select", "Up", "Down");
|
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
|
}
|
|
|
|
renderer.displayBuffer();
|
|
}
|