mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 06:37:38 +03:00
feat: implement screen rotation feature in Epub reader menu
This commit is contained in:
parent
465cc029ff
commit
a85ec57018
@ -20,22 +20,8 @@ constexpr unsigned long goHomeMs = 1000;
|
||||
constexpr int statusBarMargin = 19;
|
||||
constexpr int progressBarMarginTop = 1;
|
||||
|
||||
} // namespace
|
||||
|
||||
void EpubReaderActivity::taskTrampoline(void* param) {
|
||||
auto* self = static_cast<EpubReaderActivity*>(param);
|
||||
self->displayTaskLoop();
|
||||
}
|
||||
|
||||
void EpubReaderActivity::onEnter() {
|
||||
ActivityWithSubactivity::onEnter();
|
||||
|
||||
if (!epub) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Configure screen orientation based on settings
|
||||
switch (SETTINGS.orientation) {
|
||||
void applyReaderOrientation(GfxRenderer& renderer, const uint8_t orientation) {
|
||||
switch (orientation) {
|
||||
case CrossPointSettings::ORIENTATION::PORTRAIT:
|
||||
renderer.setOrientation(GfxRenderer::Orientation::Portrait);
|
||||
break;
|
||||
@ -51,6 +37,24 @@ void EpubReaderActivity::onEnter() {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void EpubReaderActivity::taskTrampoline(void* param) {
|
||||
auto* self = static_cast<EpubReaderActivity*>(param);
|
||||
self->displayTaskLoop();
|
||||
}
|
||||
|
||||
void EpubReaderActivity::onEnter() {
|
||||
ActivityWithSubactivity::onEnter();
|
||||
|
||||
if (!epub) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Configure screen orientation based on settings
|
||||
applyReaderOrientation(renderer, SETTINGS.orientation);
|
||||
|
||||
renderingMutex = xSemaphoreCreateMutex();
|
||||
|
||||
@ -127,11 +131,10 @@ void EpubReaderActivity::loop() {
|
||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||
// Don't start activity transition while rendering
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
const int currentPage = section ? section->currentPage : 0;
|
||||
const int totalPages = section ? section->pageCount : 0;
|
||||
exitActivity();
|
||||
enterNewActivity(new EpubReaderMenuActivity(
|
||||
this->renderer, this->mappedInput, epub->getTitle(), [this]() { onReaderMenuBack(); },
|
||||
this->renderer, this->mappedInput, epub->getTitle(), SETTINGS.orientation,
|
||||
[this](const uint8_t orientation) { onReaderMenuBack(orientation); },
|
||||
[this](EpubReaderMenuActivity::MenuAction action) { onReaderMenuConfirm(action); }));
|
||||
xSemaphoreGive(renderingMutex);
|
||||
}
|
||||
@ -220,8 +223,9 @@ void EpubReaderActivity::loop() {
|
||||
}
|
||||
}
|
||||
|
||||
void EpubReaderActivity::onReaderMenuBack() {
|
||||
void EpubReaderActivity::onReaderMenuBack(const uint8_t orientation) {
|
||||
exitActivity();
|
||||
applyOrientation(orientation);
|
||||
updateRequired = true;
|
||||
}
|
||||
|
||||
@ -268,40 +272,6 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction
|
||||
xSemaphoreGive(renderingMutex);
|
||||
break;
|
||||
}
|
||||
case EpubReaderMenuActivity::MenuAction::ROTATE_SCREEN: {
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
if (section) {
|
||||
cachedSpineIndex = currentSpineIndex;
|
||||
cachedChapterTotalPageCount = section->pageCount;
|
||||
nextPageNumber = section->currentPage;
|
||||
}
|
||||
|
||||
SETTINGS.orientation = (SETTINGS.orientation + 1) % CrossPointSettings::ORIENTATION_COUNT;
|
||||
SETTINGS.saveToFile();
|
||||
|
||||
switch (SETTINGS.orientation) {
|
||||
case CrossPointSettings::ORIENTATION::PORTRAIT:
|
||||
renderer.setOrientation(GfxRenderer::Orientation::Portrait);
|
||||
break;
|
||||
case CrossPointSettings::ORIENTATION::LANDSCAPE_CW:
|
||||
renderer.setOrientation(GfxRenderer::Orientation::LandscapeClockwise);
|
||||
break;
|
||||
case CrossPointSettings::ORIENTATION::INVERTED:
|
||||
renderer.setOrientation(GfxRenderer::Orientation::PortraitInverted);
|
||||
break;
|
||||
case CrossPointSettings::ORIENTATION::LANDSCAPE_CCW:
|
||||
renderer.setOrientation(GfxRenderer::Orientation::LandscapeCounterClockwise);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
section.reset();
|
||||
exitActivity();
|
||||
updateRequired = true;
|
||||
xSemaphoreGive(renderingMutex);
|
||||
break;
|
||||
}
|
||||
case EpubReaderMenuActivity::MenuAction::GO_HOME: {
|
||||
// 2. Trigger the reader's "Go Home" callback
|
||||
if (onGoHome) {
|
||||
@ -337,6 +307,27 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction
|
||||
}
|
||||
}
|
||||
|
||||
void EpubReaderActivity::applyOrientation(const uint8_t orientation) {
|
||||
if (SETTINGS.orientation == orientation) {
|
||||
return;
|
||||
}
|
||||
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
if (section) {
|
||||
cachedSpineIndex = currentSpineIndex;
|
||||
cachedChapterTotalPageCount = section->pageCount;
|
||||
nextPageNumber = section->currentPage;
|
||||
}
|
||||
|
||||
SETTINGS.orientation = orientation;
|
||||
SETTINGS.saveToFile();
|
||||
|
||||
applyReaderOrientation(renderer, SETTINGS.orientation);
|
||||
|
||||
section.reset();
|
||||
xSemaphoreGive(renderingMutex);
|
||||
}
|
||||
|
||||
void EpubReaderActivity::displayTaskLoop() {
|
||||
while (true) {
|
||||
if (updateRequired) {
|
||||
|
||||
@ -29,8 +29,9 @@ class EpubReaderActivity final : public ActivityWithSubactivity {
|
||||
int orientedMarginBottom, int orientedMarginLeft);
|
||||
void renderStatusBar(int orientedMarginRight, int orientedMarginBottom, int orientedMarginLeft) const;
|
||||
void saveProgress(int spineIndex, int currentPage, int pageCount);
|
||||
void onReaderMenuBack();
|
||||
void onReaderMenuBack(uint8_t orientation);
|
||||
void onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction action);
|
||||
void applyOrientation(uint8_t orientation);
|
||||
|
||||
public:
|
||||
explicit EpubReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::unique_ptr<Epub> epub,
|
||||
|
||||
@ -56,9 +56,15 @@ void EpubReaderMenuActivity::loop() {
|
||||
selectedIndex = (selectedIndex + 1) % menuItems.size();
|
||||
updateRequired = true;
|
||||
} else if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||
const auto selectedAction = menuItems[selectedIndex].action;
|
||||
if (selectedAction == MenuAction::ROTATE_SCREEN) {
|
||||
pendingOrientation = (pendingOrientation + 1) % orientationLabels.size();
|
||||
updateRequired = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Capture the callback and action locally
|
||||
auto actionCallback = onAction;
|
||||
auto selectedAction = menuItems[selectedIndex].action;
|
||||
|
||||
// 2. Execute the callback
|
||||
actionCallback(selectedAction);
|
||||
@ -66,7 +72,7 @@ void EpubReaderMenuActivity::loop() {
|
||||
// 3. CRITICAL: Return immediately. 'this' is likely deleted now.
|
||||
return;
|
||||
} else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
||||
onBack();
|
||||
onBack(pendingOrientation);
|
||||
return; // Also return here just in case
|
||||
}
|
||||
}
|
||||
@ -93,6 +99,12 @@ void EpubReaderMenuActivity::renderScreen() {
|
||||
}
|
||||
|
||||
renderer.drawText(UI_10_FONT_ID, 20, displayY, menuItems[i].label.c_str(), !isSelected);
|
||||
|
||||
if (menuItems[i].action == MenuAction::ROTATE_SCREEN) {
|
||||
const auto value = orientationLabels[pendingOrientation];
|
||||
const auto width = renderer.getTextWidth(UI_10_FONT_ID, value);
|
||||
renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, displayY, value, !isSelected);
|
||||
}
|
||||
}
|
||||
|
||||
// Footer / Hints
|
||||
|
||||
@ -16,9 +16,12 @@ class EpubReaderMenuActivity final : public ActivityWithSubactivity {
|
||||
enum class MenuAction { SELECT_CHAPTER, ROTATE_SCREEN, GO_HOME, DELETE_CACHE };
|
||||
|
||||
explicit EpubReaderMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, const std::string& title,
|
||||
const std::function<void()>& onBack, const std::function<void(MenuAction)>& onAction)
|
||||
const uint8_t currentOrientation,
|
||||
const std::function<void(uint8_t)>& onBack,
|
||||
const std::function<void(MenuAction)>& onAction)
|
||||
: ActivityWithSubactivity("EpubReaderMenu", renderer, mappedInput),
|
||||
title(title),
|
||||
pendingOrientation(currentOrientation),
|
||||
onBack(onBack),
|
||||
onAction(onAction) {}
|
||||
|
||||
@ -33,7 +36,7 @@ class EpubReaderMenuActivity final : public ActivityWithSubactivity {
|
||||
};
|
||||
|
||||
const std::vector<MenuItem> menuItems = {{MenuAction::SELECT_CHAPTER, "Go to Chapter"},
|
||||
{MenuAction::ROTATE_SCREEN, "Rotate Screen"},
|
||||
{MenuAction::ROTATE_SCREEN, "Reading Orientation"},
|
||||
{MenuAction::GO_HOME, "Go Home"},
|
||||
{MenuAction::DELETE_CACHE, "Delete Book Cache"}};
|
||||
|
||||
@ -42,8 +45,10 @@ class EpubReaderMenuActivity final : public ActivityWithSubactivity {
|
||||
TaskHandle_t displayTaskHandle = nullptr;
|
||||
SemaphoreHandle_t renderingMutex = nullptr;
|
||||
std::string title = "Reader Menu";
|
||||
uint8_t pendingOrientation = 0;
|
||||
const std::vector<const char*> orientationLabels = {"Portrait", "Landscape CW", "Inverted", "Landscape CCW"};
|
||||
|
||||
const std::function<void()> onBack;
|
||||
const std::function<void(uint8_t)> onBack;
|
||||
const std::function<void(MenuAction)> onAction;
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user