diff --git a/lib/GfxRenderer/GfxRenderer.cpp b/lib/GfxRenderer/GfxRenderer.cpp index b5aa7710..06a0ac70 100644 --- a/lib/GfxRenderer/GfxRenderer.cpp +++ b/lib/GfxRenderer/GfxRenderer.cpp @@ -494,11 +494,11 @@ void GfxRenderer::drawButtonHints(const int fontId, const char* btn1, const char setOrientation(Orientation::Portrait); const int pageHeight = getScreenHeight(); - constexpr int buttonWidth = 106; + constexpr int buttonWidth = 94; constexpr int buttonHeight = 40; constexpr int buttonY = 40; // Distance from bottom constexpr int textYOffset = 7; // Distance from top of button to text baseline - constexpr int buttonPositions[] = {25, 130, 245, 350}; + constexpr int buttonPositions[] = {50, 143, 247, 340}; const char* labels[] = {btn1, btn2, btn3, btn4}; for (int i = 0; i < 4; i++) { @@ -516,7 +516,10 @@ void GfxRenderer::drawButtonHints(const int fontId, const char* btn1, const char setOrientation(orig_orientation); } -void GfxRenderer::drawSideButtonHints(const int fontId, const char* topBtn, const char* bottomBtn) const { +void GfxRenderer::drawSideButtonHints(const int fontId, const char* topBtn, const char* bottomBtn) { + const Orientation orig_orientation = getOrientation(); + setOrientation(Orientation::Portrait); + const int screenWidth = getScreenWidth(); constexpr int buttonWidth = 40; // Width on screen (height when rotated) constexpr int buttonHeight = 80; // Height on screen (width when rotated) @@ -565,6 +568,8 @@ void GfxRenderer::drawSideButtonHints(const int fontId, const char* topBtn, cons drawTextRotated90CW(fontId, textX, textY, labels[i]); } } + + setOrientation(orig_orientation); } int GfxRenderer::getTextHeight(const int fontId) const { diff --git a/lib/GfxRenderer/GfxRenderer.h b/lib/GfxRenderer/GfxRenderer.h index 86ddc8fc..02ec29df 100644 --- a/lib/GfxRenderer/GfxRenderer.h +++ b/lib/GfxRenderer/GfxRenderer.h @@ -85,7 +85,7 @@ class GfxRenderer { // UI Components void drawButtonHints(int fontId, const char* btn1, const char* btn2, const char* btn3, const char* btn4); - void drawSideButtonHints(int fontId, const char* topBtn, const char* bottomBtn) const; + void drawSideButtonHints(int fontId, const char* topBtn, const char* bottomBtn); private: // Helper for drawing rotated text (90 degrees clockwise, for side buttons) diff --git a/src/activities/Activity.cpp b/src/activities/Activity.cpp new file mode 100644 index 00000000..e4d9f81b --- /dev/null +++ b/src/activities/Activity.cpp @@ -0,0 +1,78 @@ +#include "Activity.h" + +#include + +#include "CrossPointSettings.h" + +void Activity::onEnter() { + Serial.printf("[%lu] [ACT] Entering activity: %s\n", millis(), name.c_str()); + updateMargins(); +} + +void Activity::onExit() { Serial.printf("[%lu] [ACT] Exiting activity: %s\n", millis(), name.c_str()); } + +void Activity::updateMargins() { + switch (SETTINGS.orientation) { + case CrossPointSettings::ORIENTATION::PORTRAIT: + marginTop = 15; + marginBottom = 50; + marginLeft = marginRight = 20; + break; + case CrossPointSettings::ORIENTATION::LANDSCAPE_CW: + marginTop = 15; + marginLeft = 50; + marginRight = marginBottom = 20; + break; + case CrossPointSettings::ORIENTATION::INVERTED: + marginTop = 50; + marginBottom = 15; + marginLeft = marginRight = 20; + break; + case CrossPointSettings::ORIENTATION::LANDSCAPE_CCW: + marginTop = 15; + marginRight = 50; + marginLeft = marginBottom = 20; + break; + default: + break; + } + contentStartY = marginTop + 45; +} + +void Activity::updateRendererOrientation() { + 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; + } + updateMargins(); +} + +// Number of items that fit on a page, derived from logical screen height. +// This adapts automatically when switching between portrait and landscape. +int Activity::getPageItems() const { + // Layout constants used in renderScreen + const int startY = contentStartY; + constexpr int lineHeight = LINE_HEIGHT; + + const int screenHeight = renderer.getScreenHeight(); + const int endY = screenHeight - lineHeight; + + const int availableHeight = endY - startY; + int items = availableHeight / lineHeight; + + // Ensure we always have at least one item per page to avoid division by zero + if (items < 1) { + items = 1; + } + return items; +} diff --git a/src/activities/Activity.h b/src/activities/Activity.h index 4a60607b..b6c1fa55 100644 --- a/src/activities/Activity.h +++ b/src/activities/Activity.h @@ -8,19 +8,31 @@ class MappedInputManager; class GfxRenderer; +constexpr int LINE_HEIGHT = 30; + class Activity { protected: std::string name; GfxRenderer& renderer; MappedInputManager& mappedInput; + int marginTop = 15; + int marginBottom = 50; + int marginLeft = 20; + int marginRight = 20; + int contentStartY = 60; public: explicit Activity(std::string name, GfxRenderer& renderer, MappedInputManager& mappedInput) : name(std::move(name)), renderer(renderer), mappedInput(mappedInput) {} virtual ~Activity() = default; - virtual void onEnter() { Serial.printf("[%lu] [ACT] Entering activity: %s\n", millis(), name.c_str()); } - virtual void onExit() { Serial.printf("[%lu] [ACT] Exiting activity: %s\n", millis(), name.c_str()); } + virtual void onEnter(); + virtual void onExit(); virtual void loop() {} virtual bool skipLoopDelay() { return false; } virtual bool preventAutoSleep() { return false; } + + void updateMargins(); + void updateRendererOrientation(); + + int getPageItems() const; }; diff --git a/src/activities/boot_sleep/BootActivity.cpp b/src/activities/boot_sleep/BootActivity.cpp index b741c3e3..8f9232c2 100644 --- a/src/activities/boot_sleep/BootActivity.cpp +++ b/src/activities/boot_sleep/BootActivity.cpp @@ -7,6 +7,7 @@ void BootActivity::onEnter() { Activity::onEnter(); + updateRendererOrientation(); const auto pageWidth = renderer.getScreenWidth(); const auto pageHeight = renderer.getScreenHeight(); diff --git a/src/activities/boot_sleep/SleepActivity.cpp b/src/activities/boot_sleep/SleepActivity.cpp index 7ffc5851..80442899 100644 --- a/src/activities/boot_sleep/SleepActivity.cpp +++ b/src/activities/boot_sleep/SleepActivity.cpp @@ -126,6 +126,7 @@ void SleepActivity::renderDefaultSleepScreen() const { void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const { int x, y; + renderer.setOrientation(GfxRenderer::Orientation::Portrait); const auto pageWidth = renderer.getScreenWidth(); const auto pageHeight = renderer.getScreenHeight(); float cropX = 0, cropY = 0; diff --git a/src/activities/browser/OpdsBookBrowserActivity.cpp b/src/activities/browser/OpdsBookBrowserActivity.cpp index 2bde74de..64c8d2c1 100644 --- a/src/activities/browser/OpdsBookBrowserActivity.cpp +++ b/src/activities/browser/OpdsBookBrowserActivity.cpp @@ -228,7 +228,7 @@ void OpdsBookBrowserActivity::render() const { } const auto pageStartIndex = selectorIndex / PAGE_ITEMS * PAGE_ITEMS; - renderer.fillRect(0, 60 + (selectorIndex % PAGE_ITEMS) * 30 - 2, pageWidth - 1, 30); + renderer.fillRect(0, contentStartY + (selectorIndex % PAGE_ITEMS) * LINE_HEIGHT - 2, pageWidth - 1, LINE_HEIGHT); for (size_t i = pageStartIndex; i < entries.size() && i < static_cast(pageStartIndex + PAGE_ITEMS); i++) { const auto& entry = entries[i]; @@ -246,7 +246,7 @@ void OpdsBookBrowserActivity::render() const { } auto item = renderer.truncatedText(UI_10_FONT_ID, displayText.c_str(), renderer.getScreenWidth() - 40); - renderer.drawText(UI_10_FONT_ID, 20, 60 + (i % PAGE_ITEMS) * 30, item.c_str(), + renderer.drawText(UI_10_FONT_ID, 20, contentStartY + (i % PAGE_ITEMS) * LINE_HEIGHT, item.c_str(), i != static_cast(selectorIndex)); } diff --git a/src/activities/home/HomeActivity.cpp b/src/activities/home/HomeActivity.cpp index 678af7cb..befeb05f 100644 --- a/src/activities/home/HomeActivity.cpp +++ b/src/activities/home/HomeActivity.cpp @@ -220,14 +220,29 @@ void HomeActivity::render() { const auto pageWidth = renderer.getScreenWidth(); const auto pageHeight = renderer.getScreenHeight(); - constexpr int margin = 20; - constexpr int bottomMargin = 60; + // --- Bottom menu tiles --- + // Build menu items dynamically + std::vector menuItems = {"My Library", "File Transfer", "Settings"}; + if (hasOpdsUrl) { + // Insert OPDS Browser after My Library + menuItems.insert(menuItems.begin() + 1, "OPDS Browser"); + } + + const int menuTileWidth = pageWidth - marginLeft - marginRight; + constexpr int menuTileHeight = 45; + constexpr int menuSpacing = 8; + const int totalMenuHeight = + static_cast(menuItems.size()) * menuTileHeight + (static_cast(menuItems.size()) - 1) * menuSpacing; // --- Top "book" card for the current title (selectorIndex == 0) --- + // if we're in inverted portrait, battery and hints can overlap + GfxRenderer::Orientation orientation = renderer.getOrientation(); + const int batteryHeight = (orientation == GfxRenderer::Orientation::PortraitInverted ? 0 : 20); const int bookWidth = pageWidth / 2; - const int bookHeight = pageHeight / 2; - const int bookX = (pageWidth - bookWidth) / 2; - constexpr int bookY = 30; + const int maxBookHeight = pageHeight - marginTop - marginBottom - totalMenuHeight - batteryHeight; + const int bookHeight = std::min(pageHeight / 2, maxBookHeight); + const int bookX = marginLeft + (pageWidth - marginLeft - marginRight - bookWidth) / 2; + const int bookY = marginTop + batteryHeight; const bool bookSelected = hasContinueReading && selectorIndex == 0; // Bookmark dimensions (used in multiple places) @@ -443,7 +458,7 @@ void HomeActivity::render() { const int boxWidth = maxTextWidth + boxPadding * 2; const int boxHeight = totalTextHeight + boxPadding * 2; - const int boxX = (pageWidth - boxWidth) / 2; + const int boxX = bookX + (bookWidth - boxWidth) / 2; const int boxY = titleYStart - boxPadding; // Draw box (inverted when selected: black box instead of white) @@ -453,7 +468,8 @@ void HomeActivity::render() { } for (const auto& line : lines) { - renderer.drawCenteredText(UI_12_FONT_ID, titleYStart, line.c_str(), !bookSelected); + renderer.drawText(UI_12_FONT_ID, bookX + (bookWidth - renderer.getTextWidth(UI_12_FONT_ID, line.c_str())) / 2, + titleYStart, line.c_str(), !bookSelected); titleYStart += renderer.getLineHeight(UI_12_FONT_ID); } @@ -474,26 +490,27 @@ void HomeActivity::render() { } trimmedAuthor.append("..."); } - renderer.drawCenteredText(UI_10_FONT_ID, titleYStart, trimmedAuthor.c_str(), !bookSelected); + renderer.drawText(UI_10_FONT_ID, + bookX + (bookWidth - renderer.getTextWidth(UI_10_FONT_ID, trimmedAuthor.c_str())) / 2, + titleYStart, trimmedAuthor.c_str(), !bookSelected); } // "Continue Reading" label at the bottom const int continueY = bookY + bookHeight - renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2; + const char* continueText = "Continue Reading"; + const int continueTextWidth = renderer.getTextWidth(UI_10_FONT_ID, continueText); if (coverRendered) { // Draw box behind "Continue Reading" text (inverted when selected: black box instead of white) - const char* continueText = "Continue Reading"; - const int continueTextWidth = renderer.getTextWidth(UI_10_FONT_ID, continueText); constexpr int continuePadding = 6; const int continueBoxWidth = continueTextWidth + continuePadding * 2; const int continueBoxHeight = renderer.getLineHeight(UI_10_FONT_ID) + continuePadding; - const int continueBoxX = (pageWidth - continueBoxWidth) / 2; + const int continueBoxX = bookX + (bookWidth - continueBoxWidth) / 2; const int continueBoxY = continueY - continuePadding / 2; renderer.fillRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, bookSelected); renderer.drawRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, !bookSelected); - renderer.drawCenteredText(UI_10_FONT_ID, continueY, continueText, !bookSelected); - } else { - renderer.drawCenteredText(UI_10_FONT_ID, continueY, "Continue Reading", !bookSelected); } + renderer.drawText(UI_10_FONT_ID, bookX + (bookWidth - continueTextWidth) / 2, continueY, continueText, + !bookSelected); } else { // No book to continue reading const int y = @@ -502,30 +519,11 @@ void HomeActivity::render() { renderer.drawCenteredText(UI_10_FONT_ID, y + renderer.getLineHeight(UI_12_FONT_ID), "Start reading below"); } - // --- Bottom menu tiles --- - // Build menu items dynamically - std::vector menuItems = {"My Library", "File Transfer", "Settings"}; - if (hasOpdsUrl) { - // Insert OPDS Browser after My Library - menuItems.insert(menuItems.begin() + 1, "OPDS Browser"); - } - - const int menuTileWidth = pageWidth - 2 * margin; - constexpr int menuTileHeight = 45; - constexpr int menuSpacing = 8; - const int totalMenuHeight = - static_cast(menuItems.size()) * menuTileHeight + (static_cast(menuItems.size()) - 1) * menuSpacing; - - int menuStartY = bookY + bookHeight + 15; - // Ensure we don't collide with the bottom button legend - const int maxMenuStartY = pageHeight - bottomMargin - totalMenuHeight - margin; - if (menuStartY > maxMenuStartY) { - menuStartY = maxMenuStartY; - } + int menuStartY = bookY + bookHeight + menuSpacing; for (size_t i = 0; i < menuItems.size(); ++i) { const int overallIndex = static_cast(i) + (hasContinueReading ? 1 : 0); - constexpr int tileX = margin; + const int tileX = marginLeft; const int tileY = menuStartY + static_cast(i) * (menuTileHeight + menuSpacing); const bool selected = selectorIndex == overallIndex; @@ -553,7 +551,7 @@ void HomeActivity::render() { // get percentage so we can align text properly const uint16_t percentage = battery.readPercentage(); const auto percentageText = showBatteryPercentage ? std::to_string(percentage) + "%" : ""; - const auto batteryX = pageWidth - 25 - renderer.getTextWidth(SMALL_FONT_ID, percentageText.c_str()); + const auto batteryX = pageWidth - 30 - renderer.getTextWidth(SMALL_FONT_ID, percentageText.c_str()); ScreenComponents::drawBattery(renderer, batteryX, 10, showBatteryPercentage); renderer.displayBuffer(); diff --git a/src/activities/home/MyLibraryActivity.cpp b/src/activities/home/MyLibraryActivity.cpp index 29c6ea73..66c38876 100644 --- a/src/activities/home/MyLibraryActivity.cpp +++ b/src/activities/home/MyLibraryActivity.cpp @@ -13,12 +13,8 @@ namespace { // Layout constants -constexpr int TAB_BAR_Y = 15; -constexpr int CONTENT_START_Y = 60; -constexpr int LINE_HEIGHT = 30; constexpr int RECENTS_LINE_HEIGHT = 65; // Increased for two-line items -constexpr int LEFT_MARGIN = 20; -constexpr int RIGHT_MARGIN = 40; // Extra space for scroll indicator +constexpr int scrollIndicatorWidth = 20; // Timing thresholds constexpr int SKIP_PAGE_MS = 700; @@ -35,17 +31,6 @@ void sortFileList(std::vector& strs) { } } // namespace -int MyLibraryActivity::getPageItems() const { - const int screenHeight = renderer.getScreenHeight(); - const int bottomBarHeight = 60; // Space for button hints - const int availableHeight = screenHeight - CONTENT_START_Y - bottomBarHeight; - int items = availableHeight / LINE_HEIGHT; - if (items < 1) { - items = 1; - } - return items; -} - int MyLibraryActivity::getCurrentItemCount() const { if (currentTab == Tab::Recent) { return static_cast(recentBooks.size()); @@ -286,7 +271,7 @@ void MyLibraryActivity::render() const { // Draw tab bar std::vector tabs = {{"Recent", currentTab == Tab::Recent}, {"Files", currentTab == Tab::Files}}; - ScreenComponents::drawTabBar(renderer, TAB_BAR_Y, tabs); + ScreenComponents::drawTabBar(renderer, marginTop, tabs); // Draw content based on current tab if (currentTab == Tab::Recent) { @@ -297,8 +282,8 @@ void MyLibraryActivity::render() const { // Draw scroll indicator const int screenHeight = renderer.getScreenHeight(); - const int contentHeight = screenHeight - CONTENT_START_Y - 60; // 60 for bottom bar - ScreenComponents::drawScrollIndicator(renderer, getCurrentPage(), getTotalPages(), CONTENT_START_Y, contentHeight); + const int contentHeight = screenHeight - contentStartY - marginBottom; + ScreenComponents::drawScrollIndicator(renderer, getCurrentPage(), getTotalPages(), contentStartY, contentHeight); // Draw side button hints (up/down navigation on right side) // Note: text is rotated 90° CW, so ">" appears as "^" and "<" appears as "v" @@ -317,20 +302,20 @@ void MyLibraryActivity::renderRecentTab() const { const int bookCount = static_cast(recentBooks.size()); if (bookCount == 0) { - renderer.drawText(UI_10_FONT_ID, LEFT_MARGIN, CONTENT_START_Y, "No recent books"); + renderer.drawText(UI_10_FONT_ID, marginLeft, contentStartY, "No recent books"); return; } const auto pageStartIndex = selectorIndex / pageItems * pageItems; // Draw selection highlight - renderer.fillRect(0, CONTENT_START_Y + (selectorIndex % pageItems) * RECENTS_LINE_HEIGHT - 2, - pageWidth - RIGHT_MARGIN, RECENTS_LINE_HEIGHT); + renderer.fillRect(0, contentStartY + (selectorIndex % pageItems) * RECENTS_LINE_HEIGHT - 2, + pageWidth - marginRight - scrollIndicatorWidth, RECENTS_LINE_HEIGHT); // Draw items for (int i = pageStartIndex; i < bookCount && i < pageStartIndex + pageItems; i++) { const auto& book = recentBooks[i]; - const int y = CONTENT_START_Y + (i % pageItems) * RECENTS_LINE_HEIGHT; + const int y = contentStartY + (i % pageItems) * RECENTS_LINE_HEIGHT; // Line 1: Title std::string title = book.title; @@ -346,14 +331,15 @@ void MyLibraryActivity::renderRecentTab() const { title.resize(dot); } } - auto truncatedTitle = renderer.truncatedText(UI_12_FONT_ID, title.c_str(), pageWidth - LEFT_MARGIN - RIGHT_MARGIN); - renderer.drawText(UI_12_FONT_ID, LEFT_MARGIN, y + 2, truncatedTitle.c_str(), i != selectorIndex); + auto truncatedTitle = renderer.truncatedText(UI_12_FONT_ID, title.c_str(), + pageWidth - marginLeft - marginRight - scrollIndicatorWidth); + renderer.drawText(UI_12_FONT_ID, marginLeft, y + 2, truncatedTitle.c_str(), i != selectorIndex); // Line 2: Author if (!book.author.empty()) { - auto truncatedAuthor = - renderer.truncatedText(UI_10_FONT_ID, book.author.c_str(), pageWidth - LEFT_MARGIN - RIGHT_MARGIN); - renderer.drawText(UI_10_FONT_ID, LEFT_MARGIN, y + 32, truncatedAuthor.c_str(), i != selectorIndex); + auto truncatedAuthor = renderer.truncatedText(UI_10_FONT_ID, book.author.c_str(), + pageWidth - marginLeft - marginRight - scrollIndicatorWidth); + renderer.drawText(UI_10_FONT_ID, marginLeft, y + 32, truncatedAuthor.c_str(), i != selectorIndex); } } } @@ -364,20 +350,21 @@ void MyLibraryActivity::renderFilesTab() const { const int fileCount = static_cast(files.size()); if (fileCount == 0) { - renderer.drawText(UI_10_FONT_ID, LEFT_MARGIN, CONTENT_START_Y, "No books found"); + renderer.drawText(UI_10_FONT_ID, marginLeft, contentStartY, "No books found"); return; } const auto pageStartIndex = selectorIndex / pageItems * pageItems; // Draw selection highlight - renderer.fillRect(0, CONTENT_START_Y + (selectorIndex % pageItems) * LINE_HEIGHT - 2, pageWidth - RIGHT_MARGIN, - LINE_HEIGHT); + renderer.fillRect(0, contentStartY + (selectorIndex % pageItems) * LINE_HEIGHT - 2, + pageWidth - marginRight - scrollIndicatorWidth, LINE_HEIGHT); // Draw items for (int i = pageStartIndex; i < fileCount && i < pageStartIndex + pageItems; i++) { - auto item = renderer.truncatedText(UI_10_FONT_ID, files[i].c_str(), pageWidth - LEFT_MARGIN - RIGHT_MARGIN); - renderer.drawText(UI_10_FONT_ID, LEFT_MARGIN, CONTENT_START_Y + (i % pageItems) * LINE_HEIGHT, item.c_str(), + auto item = renderer.truncatedText(UI_10_FONT_ID, files[i].c_str(), + pageWidth - marginLeft - marginRight - scrollIndicatorWidth); + renderer.drawText(UI_10_FONT_ID, marginLeft, contentStartY + (i % pageItems) * LINE_HEIGHT, item.c_str(), i != selectorIndex); } } diff --git a/src/activities/home/MyLibraryActivity.h b/src/activities/home/MyLibraryActivity.h index 39a27ed7..e0f1110f 100644 --- a/src/activities/home/MyLibraryActivity.h +++ b/src/activities/home/MyLibraryActivity.h @@ -34,7 +34,6 @@ class MyLibraryActivity final : public Activity { const std::function onSelectBook; // Number of items that fit on a page - int getPageItems() const; int getCurrentItemCount() const; int getTotalPages() const; int getCurrentPage() const; diff --git a/src/activities/network/CrossPointWebServerActivity.cpp b/src/activities/network/CrossPointWebServerActivity.cpp index c6af1497..448f5f03 100644 --- a/src/activities/network/CrossPointWebServerActivity.cpp +++ b/src/activities/network/CrossPointWebServerActivity.cpp @@ -417,12 +417,13 @@ void drawQRCode(const GfxRenderer& renderer, const int x, const int y, const std void CrossPointWebServerActivity::renderServerRunning() const { // Use consistent line spacing constexpr int LINE_SPACING = 28; // Space between lines + const int screenWidth = renderer.getScreenWidth(); - renderer.drawCenteredText(UI_12_FONT_ID, 15, "File Transfer", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, marginTop, "File Transfer", true, EpdFontFamily::BOLD); if (isApMode) { // AP mode display - center the content block - int startY = 55; + int startY = marginTop + 35; renderer.drawCenteredText(UI_10_FONT_ID, startY, "Hotspot Mode", true, EpdFontFamily::BOLD); @@ -435,7 +436,7 @@ void CrossPointWebServerActivity::renderServerRunning() const { "or scan QR code with your phone to connect to Wifi."); // Show QR code for URL const std::string wifiConfig = std::string("WIFI:S:") + connectedSSID + ";;"; - drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 4, wifiConfig); + drawQRCode(renderer, (screenWidth - 6 * 33) / 2, startY + LINE_SPACING * 4, wifiConfig); startY += 6 * 29 + 3 * LINE_SPACING; // Show primary URL (hostname) @@ -449,10 +450,10 @@ void CrossPointWebServerActivity::renderServerRunning() const { // Show QR code for URL renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 6, "or scan QR code with your phone:"); - drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 7, hostnameUrl); + drawQRCode(renderer, (screenWidth - 6 * 33) / 2, startY + LINE_SPACING * 7, hostnameUrl); } else { // STA mode display (original behavior) - const int startY = 65; + const int startY = marginTop + 50; std::string ssidInfo = "Network: " + connectedSSID; if (ssidInfo.length() > 28) { @@ -474,7 +475,7 @@ void CrossPointWebServerActivity::renderServerRunning() const { renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 4, "Open this URL in your browser"); // Show QR code for URL - drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 6, webInfo); + drawQRCode(renderer, (screenWidth - 6 * 33) / 2, startY + LINE_SPACING * 6, webInfo); renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 5, "or scan QR code with your phone:"); } diff --git a/src/activities/network/NetworkModeSelectionActivity.cpp b/src/activities/network/NetworkModeSelectionActivity.cpp index 50767084..f157fc2d 100644 --- a/src/activities/network/NetworkModeSelectionActivity.cpp +++ b/src/activities/network/NetworkModeSelectionActivity.cpp @@ -105,10 +105,10 @@ void NetworkModeSelectionActivity::render() const { const auto pageHeight = renderer.getScreenHeight(); // Draw header - renderer.drawCenteredText(UI_12_FONT_ID, 15, "File Transfer", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, marginTop, "File Transfer", true, EpdFontFamily::BOLD); // Draw subtitle - renderer.drawCenteredText(UI_10_FONT_ID, 50, "How would you like to connect?"); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 35, "How would you like to connect?"); // Draw menu items centered on screen constexpr int itemHeight = 50; // Height for each menu item (including description) @@ -120,13 +120,13 @@ void NetworkModeSelectionActivity::render() const { // Draw selection highlight (black fill) for selected item if (isSelected) { - renderer.fillRect(20, itemY - 2, pageWidth - 40, itemHeight - 6); + renderer.fillRect(marginLeft, itemY - 2, pageWidth - marginLeft - marginRight, itemHeight - 6); } // Draw text: black=false (white text) when selected (on black background) // black=true (black text) when not selected (on white background) - renderer.drawText(UI_10_FONT_ID, 30, itemY, MENU_ITEMS[i], /*black=*/!isSelected); - renderer.drawText(SMALL_FONT_ID, 30, itemY + 22, MENU_DESCRIPTIONS[i], /*black=*/!isSelected); + renderer.drawText(UI_10_FONT_ID, marginLeft + 10, itemY, MENU_ITEMS[i], /*black=*/!isSelected); + renderer.drawText(SMALL_FONT_ID, marginLeft + 10, itemY + 22, MENU_DESCRIPTIONS[i], /*black=*/!isSelected); } // Draw help text at bottom diff --git a/src/activities/network/WifiSelectionActivity.cpp b/src/activities/network/WifiSelectionActivity.cpp index becd41a3..94d00986 100644 --- a/src/activities/network/WifiSelectionActivity.cpp +++ b/src/activities/network/WifiSelectionActivity.cpp @@ -513,7 +513,7 @@ void WifiSelectionActivity::renderNetworkList() const { const auto pageHeight = renderer.getScreenHeight(); // Draw header - renderer.drawCenteredText(UI_12_FONT_ID, 15, "WiFi Networks", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, marginTop, "WiFi Networks", true, EpdFontFamily::BOLD); if (networks.empty()) { // No networks found or scan failed @@ -523,8 +523,8 @@ void WifiSelectionActivity::renderNetworkList() const { renderer.drawCenteredText(SMALL_FONT_ID, top + height + 10, "Press OK to scan again"); } else { // Calculate how many networks we can display - constexpr int startY = 60; - constexpr int lineHeight = 25; + const int startY = contentStartY; + constexpr int lineHeight = 25; // tighter spacing than normal menus const int maxVisibleNetworks = (pageHeight - startY - 40) / lineHeight; // Calculate scroll offset to keep selected item visible @@ -541,7 +541,7 @@ void WifiSelectionActivity::renderNetworkList() const { // Draw selection indicator if (static_cast(i) == selectedNetworkIndex) { - renderer.drawText(UI_10_FONT_ID, 5, networkY, ">"); + renderer.drawText(UI_10_FONT_ID, marginLeft - 15, networkY, ">"); } // Draw network name (truncate if too long) @@ -549,42 +549,47 @@ void WifiSelectionActivity::renderNetworkList() const { if (displayName.length() > 33) { displayName.replace(30, displayName.length() - 30, "..."); } - renderer.drawText(UI_10_FONT_ID, 20, networkY, displayName.c_str()); + renderer.drawText(UI_10_FONT_ID, marginLeft, networkY, displayName.c_str()); // Draw signal strength indicator std::string signalStr = getSignalStrengthIndicator(network.rssi); - renderer.drawText(UI_10_FONT_ID, pageWidth - 90, networkY, signalStr.c_str()); + renderer.drawText(UI_10_FONT_ID, pageWidth - marginRight - 90, networkY, signalStr.c_str()); // Draw saved indicator (checkmark) for networks with saved passwords if (network.hasSavedPassword) { - renderer.drawText(UI_10_FONT_ID, pageWidth - 50, networkY, "+"); + renderer.drawText(UI_10_FONT_ID, pageWidth - marginRight - 50, networkY, "+"); } // Draw lock icon for encrypted networks if (network.isEncrypted) { - renderer.drawText(UI_10_FONT_ID, pageWidth - 30, networkY, "*"); + renderer.drawText(UI_10_FONT_ID, pageWidth - marginRight - 30, networkY, "*"); } } // Draw scroll indicators if needed if (scrollOffset > 0) { - renderer.drawText(SMALL_FONT_ID, pageWidth - 15, startY - 10, "^"); + renderer.drawText(SMALL_FONT_ID, pageWidth - marginRight - 15, startY - 10, "^"); } if (scrollOffset + maxVisibleNetworks < static_cast(networks.size())) { - renderer.drawText(SMALL_FONT_ID, pageWidth - 15, startY + maxVisibleNetworks * lineHeight, "v"); + renderer.drawText(SMALL_FONT_ID, pageWidth - marginRight - 15, startY + maxVisibleNetworks * lineHeight, "v"); } // Show network count char countStr[32]; snprintf(countStr, sizeof(countStr), "%zu networks found", networks.size()); - renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 90, countStr); + renderer.drawText(SMALL_FONT_ID, pageWidth - marginRight - renderer.getTextWidth(SMALL_FONT_ID, countStr) - 95, + pageHeight - 90, countStr); } // Show MAC address above the network count and legend - renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 105, cachedMacAddress.c_str()); + renderer.drawText(SMALL_FONT_ID, + pageWidth - marginRight - renderer.getTextWidth(SMALL_FONT_ID, cachedMacAddress.c_str()) - 95, + pageHeight - 105, cachedMacAddress.c_str()); // Draw help text - renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 75, "* = Encrypted | + = Saved"); + const char helpLabel[] = "* = Encrypted | + = Saved"; + renderer.drawText(SMALL_FONT_ID, pageWidth - marginRight - renderer.getTextWidth(SMALL_FONT_ID, helpLabel) - 95, + pageHeight - 75, helpLabel); const auto labels = mappedInput.mapLabels("« Back", "Connect", "", ""); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); } diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 5ccfb4fe..a78fb36a 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -34,24 +34,6 @@ void EpubReaderActivity::onEnter() { return; } - // Configure screen orientation based on settings - 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; - } - renderingMutex = xSemaphoreCreateMutex(); epub->setupCacheDir(); @@ -101,9 +83,6 @@ void EpubReaderActivity::onEnter() { void EpubReaderActivity::onExit() { ActivityWithSubactivity::onExit(); - // Reset orientation back to portrait for the rest of the UI - renderer.setOrientation(GfxRenderer::Orientation::Portrait); - // Wait until not rendering to delete task to avoid killing mid-instruction to EPD xSemaphoreTake(renderingMutex, portMAX_DELAY); if (displayTaskHandle) { diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp index a77b37d0..6d644846 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp @@ -32,24 +32,6 @@ int EpubReaderChapterSelectionActivity::tocIndexFromItemIndex(int itemIndex) con return itemIndex - offset; } -int EpubReaderChapterSelectionActivity::getPageItems() const { - // Layout constants used in renderScreen - 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; - - // Ensure we always have at least one item per page to avoid division by zero - if (items < 1) { - items = 1; - } - return items; -} - void EpubReaderChapterSelectionActivity::taskTrampoline(void* param) { auto* self = static_cast(param); self->displayTaskLoop(); @@ -184,21 +166,21 @@ void EpubReaderChapterSelectionActivity::renderScreen() { renderer.drawCenteredText(UI_12_FONT_ID, 15, "Go to Chapter", true, EpdFontFamily::BOLD); const auto pageStartIndex = selectorIndex / pageItems * pageItems; - renderer.fillRect(0, 60 + (selectorIndex % pageItems) * 30 - 2, pageWidth - 1, 30); + renderer.fillRect(0, contentStartY + (selectorIndex % pageItems) * LINE_HEIGHT - 2, pageWidth - 1, LINE_HEIGHT); for (int i = 0; i < pageItems; i++) { int itemIndex = pageStartIndex + i; if (itemIndex >= totalItems) break; - const int displayY = 60 + i * 30; + const int displayY = contentStartY + (itemIndex % pageItems) * LINE_HEIGHT; const bool isSelected = (itemIndex == selectorIndex); if (isSyncItem(itemIndex)) { - renderer.drawText(UI_10_FONT_ID, 20, displayY, ">> Sync Progress", !isSelected); + renderer.drawText(UI_10_FONT_ID, marginLeft, displayY, ">> Sync Progress", !isSelected); } else { const int tocIndex = tocIndexFromItemIndex(itemIndex); auto item = epub->getTocItem(tocIndex); - const int indentSize = 20 + (item.level - 1) * 15; + const int indentSize = marginLeft + (item.level - 1) * 15; const std::string chapterName = renderer.truncatedText(UI_10_FONT_ID, item.title.c_str(), pageWidth - 40 - indentSize); @@ -206,11 +188,8 @@ void EpubReaderChapterSelectionActivity::renderScreen() { } } - // 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); - } + 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(); } diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.h b/src/activities/reader/EpubReaderChapterSelectionActivity.h index 255f0cea..70944f34 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.h +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.h @@ -22,10 +22,6 @@ class EpubReaderChapterSelectionActivity final : public ActivityWithSubactivity const std::function onSelectSpineIndex; const std::function onSyncPosition; - // Number of items that fit on a page, derived from logical screen height. - // This adapts automatically when switching between portrait and landscape. - int getPageItems() const; - // Total items including sync options (top and bottom) int getTotalItems() const; diff --git a/src/activities/reader/KOReaderSyncActivity.cpp b/src/activities/reader/KOReaderSyncActivity.cpp index 4a85f23d..74911d6c 100644 --- a/src/activities/reader/KOReaderSyncActivity.cpp +++ b/src/activities/reader/KOReaderSyncActivity.cpp @@ -259,11 +259,11 @@ void KOReaderSyncActivity::render() { const auto pageWidth = renderer.getScreenWidth(); renderer.clearScreen(); - renderer.drawCenteredText(UI_12_FONT_ID, 15, "KOReader Sync", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, marginTop, "KOReader Sync", true, EpdFontFamily::BOLD); if (state == NO_CREDENTIALS) { - renderer.drawCenteredText(UI_10_FONT_ID, 280, "No credentials configured", true, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_10_FONT_ID, 320, "Set up KOReader account in Settings"); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 265, "No credentials configured", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 305, "Set up KOReader account in Settings"); const auto labels = mappedInput.mapLabels("Back", "", "", ""); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); @@ -272,14 +272,14 @@ void KOReaderSyncActivity::render() { } if (state == SYNCING || state == UPLOADING) { - renderer.drawCenteredText(UI_10_FONT_ID, 300, statusMessage.c_str(), true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 285, statusMessage.c_str(), true, EpdFontFamily::BOLD); renderer.displayBuffer(); return; } if (state == SHOWING_RESULT) { // Show comparison - renderer.drawCenteredText(UI_10_FONT_ID, 120, "Progress found!", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 105, "Progress found!", true, EpdFontFamily::BOLD); // Get chapter names from TOC const int remoteTocIndex = epub->getTocIndexForSpineIndex(remotePosition.spineIndex); @@ -291,52 +291,52 @@ void KOReaderSyncActivity::render() { : ("Section " + std::to_string(currentSpineIndex + 1)); // Remote progress - chapter and page - renderer.drawText(UI_10_FONT_ID, 20, 160, "Remote:", true); + renderer.drawText(UI_10_FONT_ID, marginLeft, marginTop + 145, "Remote:", true); char remoteChapterStr[128]; snprintf(remoteChapterStr, sizeof(remoteChapterStr), " %s", remoteChapter.c_str()); - renderer.drawText(UI_10_FONT_ID, 20, 185, remoteChapterStr); + renderer.drawText(UI_10_FONT_ID, marginLeft, marginTop + 170, remoteChapterStr); char remotePageStr[64]; snprintf(remotePageStr, sizeof(remotePageStr), " Page %d, %.2f%% overall", remotePosition.pageNumber + 1, remoteProgress.percentage * 100); - renderer.drawText(UI_10_FONT_ID, 20, 210, remotePageStr); + renderer.drawText(UI_10_FONT_ID, marginLeft, marginTop + 195, remotePageStr); if (!remoteProgress.device.empty()) { char deviceStr[64]; snprintf(deviceStr, sizeof(deviceStr), " From: %s", remoteProgress.device.c_str()); - renderer.drawText(UI_10_FONT_ID, 20, 235, deviceStr); + renderer.drawText(UI_10_FONT_ID, marginLeft, marginTop + 220, deviceStr); } // Local progress - chapter and page - renderer.drawText(UI_10_FONT_ID, 20, 270, "Local:", true); + renderer.drawText(UI_10_FONT_ID, marginLeft, marginTop + 255, "Local:", true); char localChapterStr[128]; snprintf(localChapterStr, sizeof(localChapterStr), " %s", localChapter.c_str()); - renderer.drawText(UI_10_FONT_ID, 20, 295, localChapterStr); + renderer.drawText(UI_10_FONT_ID, marginLeft, marginTop + 280, localChapterStr); char localPageStr[64]; snprintf(localPageStr, sizeof(localPageStr), " Page %d/%d, %.2f%% overall", currentPage + 1, totalPagesInSpine, localProgress.percentage * 100); - renderer.drawText(UI_10_FONT_ID, 20, 320, localPageStr); + renderer.drawText(UI_10_FONT_ID, marginLeft, marginTop + 305, localPageStr); // Options - const int optionY = 350; + const int optionY = marginTop + 335; const int optionHeight = 30; // Apply option if (selectedOption == 0) { renderer.fillRect(0, optionY - 2, pageWidth - 1, optionHeight); } - renderer.drawText(UI_10_FONT_ID, 20, optionY, "Apply remote progress", selectedOption != 0); + renderer.drawText(UI_10_FONT_ID, marginLeft, optionY, "Apply remote progress", selectedOption != 0); // Upload option if (selectedOption == 1) { renderer.fillRect(0, optionY + optionHeight - 2, pageWidth - 1, optionHeight); } - renderer.drawText(UI_10_FONT_ID, 20, optionY + optionHeight, "Upload local progress", selectedOption != 1); + renderer.drawText(UI_10_FONT_ID, marginLeft, optionY + optionHeight, "Upload local progress", selectedOption != 1); // Cancel option if (selectedOption == 2) { renderer.fillRect(0, optionY + optionHeight * 2 - 2, pageWidth - 1, optionHeight); } - renderer.drawText(UI_10_FONT_ID, 20, optionY + optionHeight * 2, "Cancel", selectedOption != 2); + renderer.drawText(UI_10_FONT_ID, marginLeft, optionY + optionHeight * 2, "Cancel", selectedOption != 2); const auto labels = mappedInput.mapLabels("", "Select", "", ""); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); @@ -345,8 +345,8 @@ void KOReaderSyncActivity::render() { } if (state == NO_REMOTE_PROGRESS) { - renderer.drawCenteredText(UI_10_FONT_ID, 280, "No remote progress found", true, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_10_FONT_ID, 320, "Upload current position?"); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 265, "No remote progress found", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 305, "Upload current position?"); const auto labels = mappedInput.mapLabels("Cancel", "Upload", "", ""); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); @@ -355,7 +355,7 @@ void KOReaderSyncActivity::render() { } if (state == UPLOAD_COMPLETE) { - renderer.drawCenteredText(UI_10_FONT_ID, 300, "Progress uploaded!", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 285, "Progress uploaded!", true, EpdFontFamily::BOLD); const auto labels = mappedInput.mapLabels("Back", "", "", ""); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); @@ -364,8 +364,8 @@ void KOReaderSyncActivity::render() { } if (state == SYNC_FAILED) { - renderer.drawCenteredText(UI_10_FONT_ID, 280, "Sync failed", true, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_10_FONT_ID, 320, statusMessage.c_str()); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 265, "Sync failed", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 305, statusMessage.c_str()); const auto labels = mappedInput.mapLabels("Back", "", "", ""); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); diff --git a/src/activities/reader/TxtReaderActivity.cpp b/src/activities/reader/TxtReaderActivity.cpp index eb1a9eef..f0092e3f 100644 --- a/src/activities/reader/TxtReaderActivity.cpp +++ b/src/activities/reader/TxtReaderActivity.cpp @@ -35,24 +35,6 @@ void TxtReaderActivity::onEnter() { return; } - // Configure screen orientation based on settings - 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; - } - renderingMutex = xSemaphoreCreateMutex(); txt->setupCacheDir(); @@ -76,9 +58,6 @@ void TxtReaderActivity::onEnter() { void TxtReaderActivity::onExit() { ActivityWithSubactivity::onExit(); - // Reset orientation back to portrait for the rest of the UI - renderer.setOrientation(GfxRenderer::Orientation::Portrait); - // Wait until not rendering to delete task xSemaphoreTake(renderingMutex, portMAX_DELAY); if (displayTaskHandle) { diff --git a/src/activities/reader/XtcReaderActivity.cpp b/src/activities/reader/XtcReaderActivity.cpp index f579abcd..8a128cbb 100644 --- a/src/activities/reader/XtcReaderActivity.cpp +++ b/src/activities/reader/XtcReaderActivity.cpp @@ -30,6 +30,7 @@ void XtcReaderActivity::taskTrampoline(void* param) { void XtcReaderActivity::onEnter() { ActivityWithSubactivity::onEnter(); + renderer.setOrientation(GfxRenderer::Orientation::Portrait); if (!xtc) { return; @@ -60,6 +61,7 @@ void XtcReaderActivity::onEnter() { void XtcReaderActivity::onExit() { ActivityWithSubactivity::onExit(); + updateRendererOrientation(); // Wait until not rendering to delete task xSemaphoreTake(renderingMutex, portMAX_DELAY); @@ -84,6 +86,7 @@ void XtcReaderActivity::loop() { if (xtc && xtc->hasChapters() && !xtc->getChapters().empty()) { xSemaphoreTake(renderingMutex, portMAX_DELAY); exitActivity(); + updateRendererOrientation(); enterNewActivity(new XtcReaderChapterSelectionActivity( this->renderer, this->mappedInput, xtc, currentPage, [this] { @@ -93,6 +96,7 @@ void XtcReaderActivity::loop() { [this](const uint32_t newPage) { currentPage = newPage; exitActivity(); + renderer.setOrientation(GfxRenderer::Orientation::Portrait); updateRequired = true; })); xSemaphoreGive(renderingMutex); diff --git a/src/activities/reader/XtcReaderChapterSelectionActivity.cpp b/src/activities/reader/XtcReaderChapterSelectionActivity.cpp index ad806a30..48836566 100644 --- a/src/activities/reader/XtcReaderChapterSelectionActivity.cpp +++ b/src/activities/reader/XtcReaderChapterSelectionActivity.cpp @@ -9,21 +9,6 @@ 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; @@ -132,28 +117,26 @@ void XtcReaderChapterSelectionActivity::renderScreen() { const auto pageWidth = renderer.getScreenWidth(); const int pageItems = getPageItems(); - renderer.drawCenteredText(UI_12_FONT_ID, 15, "Select Chapter", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, marginTop, "Select Chapter", true, EpdFontFamily::BOLD); const auto& chapters = xtc->getChapters(); if (chapters.empty()) { - renderer.drawCenteredText(UI_10_FONT_ID, 120, "No chapters"); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 105, "No chapters"); renderer.displayBuffer(); return; } const auto pageStartIndex = selectorIndex / pageItems * pageItems; - renderer.fillRect(0, 60 + (selectorIndex % pageItems) * 30 - 2, pageWidth - 1, 30); + renderer.fillRect(0, contentStartY + (selectorIndex % pageItems) * LINE_HEIGHT - 2, pageWidth - 1, LINE_HEIGHT); for (int i = pageStartIndex; i < static_cast(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); + renderer.drawText(UI_10_FONT_ID, marginLeft, contentStartY + (i % pageItems) * LINE_HEIGHT, 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); - } + 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(); } diff --git a/src/activities/reader/XtcReaderChapterSelectionActivity.h b/src/activities/reader/XtcReaderChapterSelectionActivity.h index f0fe06bb..b51d8173 100644 --- a/src/activities/reader/XtcReaderChapterSelectionActivity.h +++ b/src/activities/reader/XtcReaderChapterSelectionActivity.h @@ -18,7 +18,6 @@ class XtcReaderChapterSelectionActivity final : public Activity { const std::function onGoBack; const std::function onSelectPage; - int getPageItems() const; int findChapterIndexForPage(uint32_t page) const; static void taskTrampoline(void* param); diff --git a/src/activities/settings/CalibreSettingsActivity.cpp b/src/activities/settings/CalibreSettingsActivity.cpp index d1df9d0e..f2c3e364 100644 --- a/src/activities/settings/CalibreSettingsActivity.cpp +++ b/src/activities/settings/CalibreSettingsActivity.cpp @@ -80,7 +80,7 @@ void CalibreSettingsActivity::handleSelection() { // OPDS Server URL exitActivity(); enterNewActivity(new KeyboardEntryActivity( - renderer, mappedInput, "OPDS Server URL", SETTINGS.opdsServerUrl, 10, + renderer, mappedInput, "OPDS Server URL", SETTINGS.opdsServerUrl, 50, 127, // maxLength false, // not password [this](const std::string& url) { @@ -98,7 +98,7 @@ void CalibreSettingsActivity::handleSelection() { // Username exitActivity(); enterNewActivity(new KeyboardEntryActivity( - renderer, mappedInput, "Username", SETTINGS.opdsUsername, 10, + renderer, mappedInput, "Username", SETTINGS.opdsUsername, 50, 63, // maxLength false, // not password [this](const std::string& username) { @@ -116,7 +116,7 @@ void CalibreSettingsActivity::handleSelection() { // Password exitActivity(); enterNewActivity(new KeyboardEntryActivity( - renderer, mappedInput, "Password", SETTINGS.opdsPassword, 10, + renderer, mappedInput, "Password", SETTINGS.opdsPassword, 50, 63, // maxLength false, // not password mode [this](const std::string& password) { @@ -153,20 +153,20 @@ void CalibreSettingsActivity::render() { const auto pageWidth = renderer.getScreenWidth(); // Draw header - renderer.drawCenteredText(UI_12_FONT_ID, 15, "OPDS Browser", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, marginTop, "OPDS Browser", true, EpdFontFamily::BOLD); // Draw info text about Calibre - renderer.drawCenteredText(UI_10_FONT_ID, 40, "For Calibre, add /opds to your URL"); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 25, "For Calibre, add /opds to your URL"); // Draw selection highlight - renderer.fillRect(0, 70 + selectedIndex * 30 - 2, pageWidth - 1, 30); + renderer.fillRect(0, contentStartY + 10 + selectedIndex * LINE_HEIGHT - 2, pageWidth - 1, LINE_HEIGHT); // Draw menu items for (int i = 0; i < MENU_ITEMS; i++) { - const int settingY = 70 + i * 30; + const int settingY = contentStartY + 10 + i * LINE_HEIGHT; const bool isSelected = (i == selectedIndex); - renderer.drawText(UI_10_FONT_ID, 20, settingY, menuNames[i], !isSelected); + renderer.drawText(UI_10_FONT_ID, marginLeft, settingY, menuNames[i], !isSelected); // Draw status for each setting const char* status = "[Not Set]"; @@ -178,7 +178,7 @@ void CalibreSettingsActivity::render() { status = (strlen(SETTINGS.opdsPassword) > 0) ? "[Set]" : "[Not Set]"; } const auto width = renderer.getTextWidth(UI_10_FONT_ID, status); - renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, status, !isSelected); + renderer.drawText(UI_10_FONT_ID, pageWidth - marginRight - width, settingY, status, !isSelected); } // Draw button hints diff --git a/src/activities/settings/CategorySettingsActivity.cpp b/src/activities/settings/CategorySettingsActivity.cpp index 7fd5ef5f..4ab4a44b 100644 --- a/src/activities/settings/CategorySettingsActivity.cpp +++ b/src/activities/settings/CategorySettingsActivity.cpp @@ -87,6 +87,9 @@ void CategorySettingsActivity::toggleCurrentSetting() { } else if (setting.type == SettingType::ENUM && setting.valuePtr != nullptr) { const uint8_t currentValue = SETTINGS.*(setting.valuePtr); SETTINGS.*(setting.valuePtr) = (currentValue + 1) % static_cast(setting.enumValues.size()); + if (strcmp(setting.name, "Orientation") == 0) { + updateRendererOrientation(); + } } else if (setting.type == SettingType::VALUE && setting.valuePtr != nullptr) { const int8_t currentValue = SETTINGS.*(setting.valuePtr); if (currentValue + setting.valueRange.step > setting.valueRange.max) { @@ -151,20 +154,22 @@ void CategorySettingsActivity::render() const { renderer.clearScreen(); const auto pageWidth = renderer.getScreenWidth(); - const auto pageHeight = renderer.getScreenHeight(); + const int pageItems = getPageItems(); - renderer.drawCenteredText(UI_12_FONT_ID, 15, categoryName, true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, marginTop, categoryName, true, EpdFontFamily::BOLD); // Draw selection highlight - renderer.fillRect(0, 60 + selectedSettingIndex * 30 - 2, pageWidth - 1, 30); + renderer.fillRect(0, contentStartY + (selectedSettingIndex % pageItems) * LINE_HEIGHT - 2, pageWidth - 1, + LINE_HEIGHT); // Draw all settings - for (int i = 0; i < settingsCount; i++) { - const int settingY = 60 + i * 30; // 30 pixels between settings + const auto pageStartIndex = selectedSettingIndex / pageItems * pageItems; + for (int i = pageStartIndex; i < settingsCount && i < pageStartIndex + pageItems; i++) { + const int settingY = contentStartY + (i % pageItems) * LINE_HEIGHT; const bool isSelected = (i == selectedSettingIndex); // Draw setting name - renderer.drawText(UI_10_FONT_ID, 20, settingY, settingsList[i].name, !isSelected); + renderer.drawText(UI_10_FONT_ID, marginLeft, settingY, settingsList[i].name, !isSelected); // Draw value based on setting type std::string valueText; @@ -179,12 +184,12 @@ void CategorySettingsActivity::render() const { } if (!valueText.empty()) { const auto width = renderer.getTextWidth(UI_10_FONT_ID, valueText.c_str()); - renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, valueText.c_str(), !isSelected); + renderer.drawText(UI_10_FONT_ID, pageWidth - marginRight - width, settingY, valueText.c_str(), !isSelected); } } - renderer.drawText(SMALL_FONT_ID, pageWidth - 20 - renderer.getTextWidth(SMALL_FONT_ID, CROSSPOINT_VERSION), - pageHeight - 60, CROSSPOINT_VERSION); + renderer.drawText(SMALL_FONT_ID, pageWidth - marginRight - renderer.getTextWidth(SMALL_FONT_ID, CROSSPOINT_VERSION), + marginTop + 5, CROSSPOINT_VERSION); const auto labels = mappedInput.mapLabels("« Back", "Toggle", "", ""); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); diff --git a/src/activities/settings/ClearCacheActivity.cpp b/src/activities/settings/ClearCacheActivity.cpp index 1e10c14b..8e280bb4 100644 --- a/src/activities/settings/ClearCacheActivity.cpp +++ b/src/activities/settings/ClearCacheActivity.cpp @@ -56,7 +56,7 @@ void ClearCacheActivity::render() { const auto pageHeight = renderer.getScreenHeight(); renderer.clearScreen(); - renderer.drawCenteredText(UI_12_FONT_ID, 15, "Clear Cache", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, marginTop, "Clear Cache", true, EpdFontFamily::BOLD); if (state == WARNING) { renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 60, "This will clear all cached book data.", true); diff --git a/src/activities/settings/KOReaderAuthActivity.cpp b/src/activities/settings/KOReaderAuthActivity.cpp index 8681812f..628c69a7 100644 --- a/src/activities/settings/KOReaderAuthActivity.cpp +++ b/src/activities/settings/KOReaderAuthActivity.cpp @@ -123,17 +123,17 @@ void KOReaderAuthActivity::render() { } renderer.clearScreen(); - renderer.drawCenteredText(UI_12_FONT_ID, 15, "KOReader Auth", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, marginTop, "KOReader Auth", true, EpdFontFamily::BOLD); if (state == AUTHENTICATING) { - renderer.drawCenteredText(UI_10_FONT_ID, 300, statusMessage.c_str(), true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 285, statusMessage.c_str(), true, EpdFontFamily::BOLD); renderer.displayBuffer(); return; } if (state == SUCCESS) { - renderer.drawCenteredText(UI_10_FONT_ID, 280, "Success!", true, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_10_FONT_ID, 320, "KOReader sync is ready to use"); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 265, "Success!", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 305, "KOReader sync is ready to use"); const auto labels = mappedInput.mapLabels("Done", "", "", ""); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); @@ -142,8 +142,8 @@ void KOReaderAuthActivity::render() { } if (state == FAILED) { - renderer.drawCenteredText(UI_10_FONT_ID, 280, "Authentication Failed", true, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_10_FONT_ID, 320, errorMessage.c_str()); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 265, "Authentication Failed", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 305, errorMessage.c_str()); const auto labels = mappedInput.mapLabels("Back", "", "", ""); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); diff --git a/src/activities/settings/KOReaderSettingsActivity.cpp b/src/activities/settings/KOReaderSettingsActivity.cpp index 71003433..342f5e11 100644 --- a/src/activities/settings/KOReaderSettingsActivity.cpp +++ b/src/activities/settings/KOReaderSettingsActivity.cpp @@ -81,7 +81,7 @@ void KOReaderSettingsActivity::handleSelection() { // Username exitActivity(); enterNewActivity(new KeyboardEntryActivity( - renderer, mappedInput, "KOReader Username", KOREADER_STORE.getUsername(), 10, + renderer, mappedInput, "KOReader Username", KOREADER_STORE.getUsername(), 50, 64, // maxLength false, // not password [this](const std::string& username) { @@ -98,7 +98,7 @@ void KOReaderSettingsActivity::handleSelection() { // Password exitActivity(); enterNewActivity(new KeyboardEntryActivity( - renderer, mappedInput, "KOReader Password", KOREADER_STORE.getPassword(), 10, + renderer, mappedInput, "KOReader Password", KOREADER_STORE.getPassword(), 50, 64, // maxLength false, // show characters [this](const std::string& password) { @@ -117,7 +117,7 @@ void KOReaderSettingsActivity::handleSelection() { const std::string prefillUrl = currentUrl.empty() ? "https://" : currentUrl; exitActivity(); enterNewActivity(new KeyboardEntryActivity( - renderer, mappedInput, "Sync Server URL", prefillUrl, 10, + renderer, mappedInput, "Sync Server URL", prefillUrl, 50, 128, // maxLength - URLs can be long false, // not password [this](const std::string& url) { @@ -175,17 +175,17 @@ void KOReaderSettingsActivity::render() { const auto pageWidth = renderer.getScreenWidth(); // Draw header - renderer.drawCenteredText(UI_12_FONT_ID, 15, "KOReader Sync", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, marginTop, "KOReader Sync", true, EpdFontFamily::BOLD); // Draw selection highlight - renderer.fillRect(0, 60 + selectedIndex * 30 - 2, pageWidth - 1, 30); + renderer.fillRect(0, contentStartY + selectedIndex * LINE_HEIGHT - 2, pageWidth - 1, LINE_HEIGHT); // Draw menu items for (int i = 0; i < MENU_ITEMS; i++) { - const int settingY = 60 + i * 30; + const int settingY = contentStartY + i * LINE_HEIGHT; const bool isSelected = (i == selectedIndex); - renderer.drawText(UI_10_FONT_ID, 20, settingY, menuNames[i], !isSelected); + renderer.drawText(UI_10_FONT_ID, marginLeft, settingY, menuNames[i], !isSelected); // Draw status for each item const char* status = ""; @@ -202,7 +202,7 @@ void KOReaderSettingsActivity::render() { } const auto width = renderer.getTextWidth(UI_10_FONT_ID, status); - renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, status, !isSelected); + renderer.drawText(UI_10_FONT_ID, pageWidth - marginRight - width, settingY, status, !isSelected); } // Draw button hints diff --git a/src/activities/settings/OtaUpdateActivity.cpp b/src/activities/settings/OtaUpdateActivity.cpp index 86dcf2ac..b6f63875 100644 --- a/src/activities/settings/OtaUpdateActivity.cpp +++ b/src/activities/settings/OtaUpdateActivity.cpp @@ -128,18 +128,19 @@ void OtaUpdateActivity::render() { const auto pageWidth = renderer.getScreenWidth(); renderer.clearScreen(); - renderer.drawCenteredText(UI_12_FONT_ID, 15, "Update", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, marginTop, "Update", true, EpdFontFamily::BOLD); if (state == CHECKING_FOR_UPDATE) { - renderer.drawCenteredText(UI_10_FONT_ID, 300, "Checking for update...", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 285, "Checking for update...", true, EpdFontFamily::BOLD); renderer.displayBuffer(); return; } if (state == WAITING_CONFIRMATION) { - renderer.drawCenteredText(UI_10_FONT_ID, 200, "New update available!", true, EpdFontFamily::BOLD); - renderer.drawText(UI_10_FONT_ID, 20, 250, "Current Version: " CROSSPOINT_VERSION); - renderer.drawText(UI_10_FONT_ID, 20, 270, ("New Version: " + updater.getLatestVersion()).c_str()); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 185, "New update available!", true, EpdFontFamily::BOLD); + renderer.drawText(UI_10_FONT_ID, marginLeft, marginTop + 235, "Current Version: " CROSSPOINT_VERSION); + renderer.drawText(UI_10_FONT_ID, marginLeft, marginTop + 255, + ("New Version: " + updater.getLatestVersion()).c_str()); const auto labels = mappedInput.mapLabels("Cancel", "Update", "", ""); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); @@ -148,33 +149,34 @@ void OtaUpdateActivity::render() { } if (state == UPDATE_IN_PROGRESS) { - renderer.drawCenteredText(UI_10_FONT_ID, 310, "Updating...", true, EpdFontFamily::BOLD); - renderer.drawRect(20, 350, pageWidth - 40, 50); - renderer.fillRect(24, 354, static_cast(updaterProgress * static_cast(pageWidth - 44)), 42); - renderer.drawCenteredText(UI_10_FONT_ID, 420, + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 295, "Updating...", true, EpdFontFamily::BOLD); + renderer.drawRect(marginLeft, marginTop + 335, pageWidth - 40, 50); + renderer.fillRect(marginLeft + 4, marginTop + 339, + static_cast(updaterProgress * static_cast(pageWidth - 44)), 42); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 405, (std::to_string(static_cast(updaterProgress * 100)) + "%").c_str()); renderer.drawCenteredText( - UI_10_FONT_ID, 440, + UI_10_FONT_ID, marginTop + 425, (std::to_string(updater.getProcessedSize()) + " / " + std::to_string(updater.getTotalSize())).c_str()); renderer.displayBuffer(); return; } if (state == NO_UPDATE) { - renderer.drawCenteredText(UI_10_FONT_ID, 300, "No update available", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 285, "No update available", true, EpdFontFamily::BOLD); renderer.displayBuffer(); return; } if (state == FAILED) { - renderer.drawCenteredText(UI_10_FONT_ID, 300, "Update failed", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 285, "Update failed", true, EpdFontFamily::BOLD); renderer.displayBuffer(); return; } if (state == FINISHED) { - renderer.drawCenteredText(UI_10_FONT_ID, 300, "Update complete", true, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_10_FONT_ID, 350, "Press and hold power button to turn back on"); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 285, "Update complete", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, marginTop + 335, "Press and hold power button to turn back on"); renderer.displayBuffer(); state = SHUTTING_DOWN; return; diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index 7316db05..458641c1 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -11,9 +11,11 @@ const char* SettingsActivity::categoryNames[categoryCount] = {"Display", "Reader", "Controls", "System"}; namespace { -constexpr int displaySettingsCount = 6; +constexpr int displaySettingsCount = 7; const SettingInfo displaySettings[displaySettingsCount] = { // Should match with SLEEP_SCREEN_MODE + SettingInfo::Enum("Orientation", &CrossPointSettings::orientation, + {"Portrait", "Landscape CW", "Inverted", "Landscape CCW"}), SettingInfo::Enum("Sleep Screen", &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover", "None"}), SettingInfo::Enum("Sleep Screen Cover Mode", &CrossPointSettings::sleepScreenCoverMode, {"Fit", "Crop"}), SettingInfo::Enum("Sleep Screen Cover Filter", &CrossPointSettings::sleepScreenCoverFilter, @@ -24,7 +26,7 @@ const SettingInfo displaySettings[displaySettingsCount] = { SettingInfo::Enum("Refresh Frequency", &CrossPointSettings::refreshFrequency, {"1 page", "5 pages", "10 pages", "15 pages", "30 pages"})}; -constexpr int readerSettingsCount = 9; +constexpr int readerSettingsCount = 8; const SettingInfo readerSettings[readerSettingsCount] = { SettingInfo::Enum("Font Family", &CrossPointSettings::fontFamily, {"Bookerly", "Noto Sans", "Open Dyslexic"}), SettingInfo::Enum("Font Size", &CrossPointSettings::fontSize, {"Small", "Medium", "Large", "X Large"}), @@ -33,8 +35,6 @@ const SettingInfo readerSettings[readerSettingsCount] = { SettingInfo::Enum("Paragraph Alignment", &CrossPointSettings::paragraphAlignment, {"Justify", "Left", "Center", "Right"}), SettingInfo::Toggle("Hyphenation", &CrossPointSettings::hyphenationEnabled), - SettingInfo::Enum("Reading Orientation", &CrossPointSettings::orientation, - {"Portrait", "Landscape CW", "Inverted", "Landscape CCW"}), SettingInfo::Toggle("Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing), SettingInfo::Toggle("Text Anti-Aliasing", &CrossPointSettings::textAntiAliasing)}; @@ -157,6 +157,7 @@ void SettingsActivity::enterCategory(int categoryIndex) { enterNewActivity(new CategorySettingsActivity(renderer, mappedInput, categoryNames[categoryIndex], settingsList, settingsCount, [this] { exitActivity(); + updateMargins(); // we may have changed orientation updateRequired = true; })); xSemaphoreGive(renderingMutex); @@ -178,25 +179,24 @@ void SettingsActivity::render() const { renderer.clearScreen(); const auto pageWidth = renderer.getScreenWidth(); - const auto pageHeight = renderer.getScreenHeight(); // Draw header - renderer.drawCenteredText(UI_12_FONT_ID, 15, "Settings", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, marginTop, "Settings", true, EpdFontFamily::BOLD); // Draw selection - renderer.fillRect(0, 60 + selectedCategoryIndex * 30 - 2, pageWidth - 1, 30); + renderer.fillRect(0, contentStartY + selectedCategoryIndex * LINE_HEIGHT - 2, pageWidth - 1, LINE_HEIGHT); // Draw all categories for (int i = 0; i < categoryCount; i++) { - const int categoryY = 60 + i * 30; // 30 pixels between categories + const int categoryY = contentStartY + i * LINE_HEIGHT; // Draw category name - renderer.drawText(UI_10_FONT_ID, 20, categoryY, categoryNames[i], i != selectedCategoryIndex); + renderer.drawText(UI_10_FONT_ID, marginLeft, categoryY, categoryNames[i], i != selectedCategoryIndex); } - // Draw version text above button hints - renderer.drawText(SMALL_FONT_ID, pageWidth - 20 - renderer.getTextWidth(SMALL_FONT_ID, CROSSPOINT_VERSION), - pageHeight - 60, CROSSPOINT_VERSION); + // Draw version text in corner of header + renderer.drawText(SMALL_FONT_ID, pageWidth - marginRight - renderer.getTextWidth(SMALL_FONT_ID, CROSSPOINT_VERSION), + marginTop + 5, CROSSPOINT_VERSION); // Draw help text const auto labels = mappedInput.mapLabels("« Back", "Select", "", "");