diff --git a/src/activities/home/HomeActivity.cpp b/src/activities/home/HomeActivity.cpp index 11107fdc..898452f4 100644 --- a/src/activities/home/HomeActivity.cpp +++ b/src/activities/home/HomeActivity.cpp @@ -134,8 +134,8 @@ void HomeActivity::render() const { const auto pageWidth = renderer.getScreenWidth(); const auto pageHeight = renderer.getScreenHeight(); - constexpr int margin = 20; - constexpr int bottomMargin = 60; + constexpr int margin = 16; + constexpr int bottomMargin = 56; // --- Top "book" card for the current title (selectorIndex == 0) --- const int bookWidth = pageWidth / 2; @@ -279,8 +279,8 @@ void HomeActivity::render() const { // --- Bottom menu tiles (indices 1-3) --- const int menuTileWidth = pageWidth - 2 * margin; - constexpr int menuTileHeight = 50; - constexpr int menuSpacing = 10; + constexpr int menuTileHeight = 44; + constexpr int menuSpacing = 8; constexpr int totalMenuHeight = 3 * menuTileHeight + 2 * menuSpacing; int menuStartY = bookY + bookHeight + 20; @@ -316,7 +316,7 @@ void HomeActivity::render() const { const auto labels = mappedInput.mapLabels("", "Confirm", "Up", "Down"); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); - ScreenComponents::drawBattery(renderer, 20, pageHeight - 70); + ScreenComponents::drawBattery(renderer, margin, pageHeight - 68); renderer.displayBuffer(); } diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index fae5d241..e665721c 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -18,7 +18,13 @@ constexpr unsigned long skipChapterMs = 700; constexpr unsigned long goHomeMs = 1000; constexpr int topPadding = 5; constexpr int horizontalPadding = 5; -constexpr int statusBarMargin = 19; +// Footer layout: total height reserved for footer area +// contentGap = space between last line of book text and delimiter line +// lineToText = space between delimiter line and footer text +// footerTextHeight ~= 12px for small font +constexpr int footerHeight = 34; // total footer area height (includes bottom margin) +constexpr int contentGap = 6; // gap above delimiter line +constexpr int lineToText = 6; // gap below delimiter line to text } // namespace void EpubReaderActivity::taskTrampoline(void* param) { @@ -256,7 +262,7 @@ void EpubReaderActivity::renderScreen() { orientedMarginTop += topPadding; orientedMarginLeft += horizontalPadding; orientedMarginRight += horizontalPadding; - orientedMarginBottom += statusBarMargin; + orientedMarginBottom += footerHeight + contentGap; if (!section) { const auto filepath = epub->getSpineItem(currentSpineIndex).href; @@ -419,9 +425,20 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in const bool showChapterTitle = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS || SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL; - // Position status bar near the bottom of the logical screen, regardless of orientation + // Footer layout calculation: + // Screen bottom -> viewable margin -> footer text -> lineToText -> line -> contentGap -> book content + // orientedMarginBottom already includes (footerHeight + contentGap) + // So book content ends at: screenHeight - orientedMarginBottom + // Line should be at: screenHeight - orientedMarginBottom + contentGap (just below content) + // Footer text at: lineY + lineToText + some offset for text baseline + const auto screenHeight = renderer.getScreenHeight(); - const auto textY = screenHeight - orientedMarginBottom - 4; + const int contentBottom = screenHeight - orientedMarginBottom; + const int lineY = contentBottom + contentGap; + const int textY = lineY + lineToText; + + renderer.drawLine(orientedMarginLeft, lineY, renderer.getScreenWidth() - orientedMarginRight, lineY); + int progressTextWidth = 0; if (showProgress) { diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp index 63f1e5a7..0048e08b 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp @@ -8,16 +8,17 @@ namespace { // Time threshold for treating a long press as a page-up/page-down constexpr int SKIP_PAGE_MS = 700; +constexpr int headerY = 16; +constexpr int separatorY = 42; +constexpr int listStartY = 54; +constexpr int rowHeight = 28; +constexpr int horizontalMargin = 16; } // namespace int EpubReaderChapterSelectionActivity::getPageItems() const { - // Layout constants used in renderScreen - constexpr int startY = 60; - constexpr int lineHeight = 30; - const int screenHeight = renderer.getScreenHeight(); - const int availableHeight = screenHeight - startY; - int items = availableHeight / lineHeight; + const int availableHeight = screenHeight - listStartY; + int items = availableHeight / rowHeight; // Ensure we always have at least one item per page to avoid division by zero if (items < 1) { @@ -121,17 +122,25 @@ void EpubReaderChapterSelectionActivity::renderScreen() { const auto pageWidth = renderer.getScreenWidth(); const int pageItems = getPageItems(); + // Draw header with book title const std::string title = - renderer.truncatedText(UI_12_FONT_ID, epub->getTitle().c_str(), pageWidth - 40, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_12_FONT_ID, 15, title.c_str(), true, EpdFontFamily::BOLD); + renderer.truncatedText(UI_12_FONT_ID, epub->getTitle().c_str(), pageWidth - horizontalMargin * 2, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_12_FONT_ID, headerY, title.c_str(), true, EpdFontFamily::BOLD); + // Subtle separator line under header + renderer.drawLine(horizontalMargin, separatorY, pageWidth - horizontalMargin, separatorY); + + // Draw selection highlight const auto pageStartIndex = selectorIndex / pageItems * pageItems; - renderer.fillRect(0, 60 + (selectorIndex % pageItems) * 30 - 2, pageWidth - 1, 30); + renderer.fillRect(0, listStartY + (selectorIndex % pageItems) * rowHeight - 2, pageWidth - 1, rowHeight); + + // Draw chapter list for (int tocIndex = pageStartIndex; tocIndex < epub->getTocItemsCount() && tocIndex < pageStartIndex + pageItems; tocIndex++) { auto item = epub->getTocItem(tocIndex); - renderer.drawText(UI_10_FONT_ID, 20 + (item.level - 1) * 15, 60 + (tocIndex % pageItems) * 30, item.title.c_str(), - tocIndex != selectorIndex); + const int indentPx = (item.level - 1) * 12; + renderer.drawText(UI_10_FONT_ID, horizontalMargin + 4 + indentPx, listStartY + (tocIndex % pageItems) * rowHeight, + item.title.c_str(), tocIndex != selectorIndex); } renderer.displayBuffer(); diff --git a/src/activities/reader/FileSelectionActivity.cpp b/src/activities/reader/FileSelectionActivity.cpp index f87cc97c..951cabb8 100644 --- a/src/activities/reader/FileSelectionActivity.cpp +++ b/src/activities/reader/FileSelectionActivity.cpp @@ -7,9 +7,14 @@ #include "fontIds.h" namespace { -constexpr int PAGE_ITEMS = 23; +constexpr int PAGE_ITEMS = 20; constexpr int SKIP_PAGE_MS = 700; constexpr unsigned long GO_HOME_MS = 1000; +constexpr int headerY = 16; +constexpr int separatorY = 42; +constexpr int listStartY = 54; +constexpr int rowHeight = 28; +constexpr int horizontalMargin = 16; } // namespace void sortFileList(std::vector& strs) { @@ -173,23 +178,28 @@ void FileSelectionActivity::render() const { renderer.clearScreen(); const auto pageWidth = renderer.getScreenWidth(); - renderer.drawCenteredText(UI_12_FONT_ID, 15, "Books", true, EpdFontFamily::BOLD); + + // Draw header + renderer.drawCenteredText(UI_12_FONT_ID, headerY, "Books", true, EpdFontFamily::BOLD); + + // Subtle separator line under header + renderer.drawLine(horizontalMargin, separatorY, pageWidth - horizontalMargin, separatorY); // Help text const auto labels = mappedInput.mapLabels("« Home", "Open", "", ""); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); if (files.empty()) { - renderer.drawText(UI_10_FONT_ID, 20, 60, "No books found"); + renderer.drawText(UI_10_FONT_ID, horizontalMargin + 4, listStartY, "No books found"); renderer.displayBuffer(); return; } const auto pageStartIndex = selectorIndex / PAGE_ITEMS * PAGE_ITEMS; - renderer.fillRect(0, 60 + (selectorIndex % PAGE_ITEMS) * 30 - 2, pageWidth - 1, 30); + renderer.fillRect(0, listStartY + (selectorIndex % PAGE_ITEMS) * rowHeight - 2, pageWidth - 1, rowHeight); for (int i = pageStartIndex; i < files.size() && i < pageStartIndex + PAGE_ITEMS; i++) { - auto item = renderer.truncatedText(UI_10_FONT_ID, files[i].c_str(), renderer.getScreenWidth() - 40); - renderer.drawText(UI_10_FONT_ID, 20, 60 + (i % PAGE_ITEMS) * 30, item.c_str(), i != selectorIndex); + auto item = renderer.truncatedText(UI_10_FONT_ID, files[i].c_str(), pageWidth - horizontalMargin * 2 - 8); + renderer.drawText(UI_10_FONT_ID, horizontalMargin + 4, listStartY + (i % PAGE_ITEMS) * rowHeight, item.c_str(), i != selectorIndex); } renderer.displayBuffer();