diff --git a/src/CrossPointSettings.h b/src/CrossPointSettings.h index 066d906..a364cec 100644 --- a/src/CrossPointSettings.h +++ b/src/CrossPointSettings.h @@ -20,7 +20,7 @@ class CrossPointSettings { enum SLEEP_SCREEN_COVER_MODE { FIT = 0, CROP = 1, ACTUAL = 2 }; // Status bar display type enum - enum STATUS_BAR_MODE { NONE = 0, NO_PROGRESS = 1, FULL = 2 }; + enum STATUS_BAR_MODE { NONE = 0, NO_PROGRESS = 1, FULL = 2, FULL_WITH_PROGRESS_BAR = 3, ONLY_PROGRESS_BAR = 4 }; enum ORIENTATION { PORTRAIT = 0, // 480x800 logical coordinates (current default) diff --git a/src/ScreenComponents.cpp b/src/ScreenComponents.cpp index 29da701..b5fa96e 100644 --- a/src/ScreenComponents.cpp +++ b/src/ScreenComponents.cpp @@ -77,6 +77,17 @@ void ScreenComponents::drawBatteryLarge(const GfxRenderer& renderer, const int l renderer.fillRect(x + 2, y + 2, filledWidth, batteryHeight - 4); } +void ScreenComponents::drawBookProgressBar(const GfxRenderer& renderer, const size_t bookProgress) { + int vieweableMarginTop, vieweableMarginRight, vieweableMarginBottom, vieweableMarginLeft; + renderer.getOrientedViewableTRBL(&vieweableMarginTop, &vieweableMarginRight, &vieweableMarginBottom, + &vieweableMarginLeft); + + const int progressBarMaxWidth = renderer.getScreenWidth() - vieweableMarginLeft - vieweableMarginRight; + const int progressBarY = renderer.getScreenHeight() - vieweableMarginBottom - BOOK_PROGRESS_BAR_HEIGHT; + const int barWidth = progressBarMaxWidth * bookProgress / 100; + renderer.fillRect(vieweableMarginLeft, progressBarY, barWidth, BOOK_PROGRESS_BAR_HEIGHT, true); +} + int ScreenComponents::drawTabBar(const GfxRenderer& renderer, const int y, const std::vector& tabs) { constexpr int tabPadding = 20; // Horizontal padding between tabs constexpr int leftMargin = 20; // Left margin for first tab diff --git a/src/ScreenComponents.h b/src/ScreenComponents.h index c03adac..9857811 100644 --- a/src/ScreenComponents.h +++ b/src/ScreenComponents.h @@ -13,7 +13,10 @@ struct TabInfo { class ScreenComponents { public: + static const int BOOK_PROGRESS_BAR_HEIGHT = 4; + static void drawBattery(const GfxRenderer& renderer, int left, int top, bool showPercentage = true); + static void drawBookProgressBar(const GfxRenderer& renderer, size_t bookProgress); // Draw a larger battery icon suitable for bottom button hint area static void drawBatteryLarge(const GfxRenderer& renderer, int left, int top, bool showPercentage = true); diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index c96358c..b997fe2 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -24,6 +24,7 @@ namespace { constexpr unsigned long skipChapterMs = 700; constexpr unsigned long goHomeMs = 1000; constexpr int statusBarMargin = 19; +constexpr int progressBarMarginTop = 1; // Progress file version for content offset tracking // Version 1: Added content offset for position restoration after re-indexing @@ -467,7 +468,16 @@ void EpubReaderActivity::renderScreen() { orientedMarginTop += SETTINGS.screenMargin; orientedMarginLeft += SETTINGS.screenMargin; orientedMarginRight += SETTINGS.screenMargin; - orientedMarginBottom += statusBarMargin; + orientedMarginBottom += SETTINGS.screenMargin; + + // Add status bar margin + if (SETTINGS.statusBar != CrossPointSettings::STATUS_BAR_MODE::NONE) { + // Add additional margin for status bar if progress bar is shown + const bool showProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR || + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_PROGRESS_BAR; + orientedMarginBottom += statusBarMargin - SETTINGS.screenMargin + + (showProgressBar ? (ScreenComponents::BOOK_PROGRESS_BAR_HEIGHT + progressBarMarginTop) : 0); + } if (!section) { const auto filepath = epub->getSpineItem(currentSpineIndex).href; @@ -657,11 +667,17 @@ void EpubReaderActivity::renderContents(std::unique_ptr page, const int or void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const int orientedMarginBottom, const int orientedMarginLeft) const { // determine visible status bar elements - const bool showProgress = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL; + const bool showProgressPercentage = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL; + const bool showProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR || + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_PROGRESS_BAR; + const bool showProgressText = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL || + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR; const bool showBattery = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL; + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL || + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR; const bool showChapterTitle = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL; + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL || + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR; const bool showBatteryPercentage = SETTINGS.hideBatteryPercentage == CrossPointSettings::HIDE_BATTERY_PERCENTAGE::HIDE_NEVER; @@ -670,19 +686,30 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in const auto textY = screenHeight - orientedMarginBottom - 4; int progressTextWidth = 0; - if (showProgress) { - // Calculate progress in book - const float sectionChapterProg = static_cast(section->currentPage) / section->pageCount; - const float bookProgress = epub->calculateProgress(currentSpineIndex, sectionChapterProg) * 100; + // Calculate progress in book + const float sectionChapterProg = static_cast(section->currentPage) / section->pageCount; + const float bookProgress = epub->calculateProgress(currentSpineIndex, sectionChapterProg) * 100; + if (showProgressText || showProgressPercentage) { // Right aligned text for progress counter char progressStr[32]; - snprintf(progressStr, sizeof(progressStr), "%d/%d %.1f%%", section->currentPage + 1, section->pageCount, - bookProgress); - const std::string progress = progressStr; - progressTextWidth = renderer.getTextWidth(SMALL_FONT_ID, progress.c_str()); + + // Hide percentage when progress bar is shown to reduce clutter + if (showProgressPercentage) { + snprintf(progressStr, sizeof(progressStr), "%d/%d %.1f%%", section->currentPage + 1, section->pageCount, + bookProgress); + } else { + snprintf(progressStr, sizeof(progressStr), "%d/%d", section->currentPage + 1, section->pageCount); + } + + progressTextWidth = renderer.getTextWidth(SMALL_FONT_ID, progressStr); renderer.drawText(SMALL_FONT_ID, renderer.getScreenWidth() - orientedMarginRight - progressTextWidth, textY, - progress.c_str()); + progressStr); + } + + if (showProgressBar) { + // Draw progress bar at the very bottom of the screen, from edge to edge of viewable area + ScreenComponents::drawBookProgressBar(renderer, static_cast(bookProgress)); } if (showBattery) { diff --git a/src/activities/reader/TxtReaderActivity.cpp b/src/activities/reader/TxtReaderActivity.cpp index 631f960..aa1175a 100644 --- a/src/activities/reader/TxtReaderActivity.cpp +++ b/src/activities/reader/TxtReaderActivity.cpp @@ -17,6 +17,7 @@ namespace { constexpr unsigned long goHomeMs = 1000; constexpr int statusBarMargin = 25; +constexpr int progressBarMarginTop = 1; constexpr size_t CHUNK_SIZE = 8 * 1024; // 8KB chunk for reading // Cache file magic and version @@ -235,7 +236,16 @@ void TxtReaderActivity::initializeReader() { orientedMarginTop += cachedScreenMargin; orientedMarginLeft += cachedScreenMargin; orientedMarginRight += cachedScreenMargin; - orientedMarginBottom += statusBarMargin; + orientedMarginBottom += cachedScreenMargin; + + // Add status bar margin + if (SETTINGS.statusBar != CrossPointSettings::STATUS_BAR_MODE::NONE) { + // Add additional margin for status bar if progress bar is shown + const bool showProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR || + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_PROGRESS_BAR; + orientedMarginBottom += statusBarMargin - cachedScreenMargin + + (showProgressBar ? (ScreenComponents::BOOK_PROGRESS_BAR_HEIGHT + progressBarMarginTop) : 0); + } viewportWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight; const int viewportHeight = renderer.getScreenHeight() - orientedMarginTop - orientedMarginBottom; @@ -580,27 +590,46 @@ void TxtReaderActivity::renderPage() { void TxtReaderActivity::renderStatusBar(const int orientedMarginRight, const int orientedMarginBottom, const int orientedMarginLeft) const { - const bool showProgress = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL; + const bool showProgressPercentage = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL; + const bool showProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR || + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_PROGRESS_BAR; + const bool showProgressText = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL || + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR; const bool showBattery = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL; + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL || + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR; const bool showTitle = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS || - SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL; + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL || + SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR; + const bool showBatteryPercentage = + SETTINGS.hideBatteryPercentage == CrossPointSettings::HIDE_BATTERY_PERCENTAGE::HIDE_NEVER; const auto screenHeight = renderer.getScreenHeight(); const auto textY = screenHeight - orientedMarginBottom - 4; int progressTextWidth = 0; - if (showProgress) { - const int progress = totalPages > 0 ? (currentPage + 1) * 100 / totalPages : 0; - const std::string progressStr = - std::to_string(currentPage + 1) + "/" + std::to_string(totalPages) + " " + std::to_string(progress) + "%"; - progressTextWidth = renderer.getTextWidth(SMALL_FONT_ID, progressStr.c_str()); + const float progress = totalPages > 0 ? (currentPage + 1) * 100.0f / totalPages : 0; + + if (showProgressText || showProgressPercentage) { + char progressStr[32]; + if (showProgressPercentage) { + snprintf(progressStr, sizeof(progressStr), "%d/%d %.1f%%", currentPage + 1, totalPages, progress); + } else { + snprintf(progressStr, sizeof(progressStr), "%d/%d", currentPage + 1, totalPages); + } + + progressTextWidth = renderer.getTextWidth(SMALL_FONT_ID, progressStr); renderer.drawText(SMALL_FONT_ID, renderer.getScreenWidth() - orientedMarginRight - progressTextWidth, textY, - progressStr.c_str()); + progressStr); + } + + if (showProgressBar) { + // Draw progress bar at the very bottom of the screen, from edge to edge of viewable area + ScreenComponents::drawBookProgressBar(renderer, static_cast(progress)); } if (showBattery) { - ScreenComponents::drawBattery(renderer, orientedMarginLeft, textY); + ScreenComponents::drawBattery(renderer, orientedMarginLeft, textY, showBatteryPercentage); } if (showTitle) { diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index 9f3ff5a..2bf2e63 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -17,7 +17,8 @@ const SettingInfo displaySettings[displaySettingsCount] = { // Should match with SLEEP_SCREEN_MODE SettingInfo::Enum("Sleep Screen", &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover", "None"}), SettingInfo::Enum("Sleep Screen Cover Mode", &CrossPointSettings::sleepScreenCoverMode, {"Fit", "Crop", "Actual"}), - SettingInfo::Enum("Status Bar", &CrossPointSettings::statusBar, {"None", "No Progress", "Full"}), + SettingInfo::Enum("Status Bar", &CrossPointSettings::statusBar, + {"None", "No Progress", "Full w/ Percentage", "Full w/ Progress Bar", "Progress Bar"}), SettingInfo::Enum("Hide Battery %", &CrossPointSettings::hideBatteryPercentage, {"Never", "In Reader", "Always"}), SettingInfo::Enum("Refresh Frequency", &CrossPointSettings::refreshFrequency, {"1 page", "5 pages", "10 pages", "15 pages", "30 pages"})};