#include "UITheme.h" #include #include #include #include #include "MappedInputManager.h" #include "RecentBooksStore.h" #include "components/themes/BaseTheme.h" #include "components/themes/lyra/Lyra3CoversTheme.h" #include "components/themes/lyra/LyraTheme.h" #include "components/themes/roundedraff/RoundedRaffTheme.h" UITheme UITheme::instance; UITheme::UITheme() { auto themeType = static_cast(SETTINGS.uiTheme); setTheme(themeType); } void UITheme::reload() { auto themeType = static_cast(SETTINGS.uiTheme); setTheme(themeType); } void UITheme::setTheme(CrossPointSettings::UI_THEME type) { switch (type) { case CrossPointSettings::UI_THEME::CLASSIC: LOG_DBG("UI", "Using Classic theme"); currentTheme = std::make_unique(); currentMetrics = &BaseMetrics::values; break; case CrossPointSettings::UI_THEME::LYRA: LOG_DBG("UI", "Using Lyra theme"); currentTheme = std::make_unique(); currentMetrics = &LyraMetrics::values; break; case CrossPointSettings::UI_THEME::ROUNDEDRAFF: LOG_DBG("UI", "Using RoundedRaff theme"); currentTheme = std::make_unique(); currentMetrics = &RoundedRaffMetrics::values; break; case CrossPointSettings::UI_THEME::LYRA_3_COVERS: LOG_DBG("UI", "Using Lyra 3 Covers theme"); currentTheme = std::make_unique(); currentMetrics = &Lyra3CoversMetrics::values; break; } } int UITheme::getNumberOfItemsPerPage(const GfxRenderer& renderer, bool hasHeader, bool hasTabBar, bool hasButtonHints, bool hasSubtitle, int extraReservedHeight) { const ThemeMetrics& metrics = UITheme::getInstance().getMetrics(); auto orientation = renderer.getOrientation(); int reservedHeight = metrics.topPadding; if (hasHeader) { reservedHeight += metrics.headerHeight + metrics.verticalSpacing; } if (hasTabBar) { reservedHeight += metrics.tabBarHeight; } if (hasButtonHints && orientation != GfxRenderer::Orientation::LandscapeClockwise && orientation != GfxRenderer::Orientation::LandscapeCounterClockwise) { reservedHeight += metrics.verticalSpacing + metrics.buttonHintsHeight; } const int availableHeight = renderer.getScreenHeight() - reservedHeight - extraReservedHeight; int rowHeight = hasSubtitle ? metrics.listWithSubtitleRowHeight : metrics.listRowHeight; return availableHeight / rowHeight; } // Screen area excluding the button hints Rect UITheme::getScreenSafeArea(const GfxRenderer& renderer, bool hasFrontButtonHints, bool hasSideButtonHints) { auto orientation = renderer.getOrientation(); const int screenWidth = renderer.getScreenWidth(); const int screenHeight = renderer.getScreenHeight(); Rect safeArea = Rect{0, 0, screenWidth, screenHeight}; switch (orientation) { case GfxRenderer::Orientation::Portrait: if (hasFrontButtonHints) { safeArea.height -= currentMetrics->buttonHintsHeight; } break; case GfxRenderer::Orientation::LandscapeClockwise: if (hasFrontButtonHints) { safeArea.x += currentMetrics->buttonHintsHeight; safeArea.width -= currentMetrics->buttonHintsHeight; } break; case GfxRenderer::Orientation::PortraitInverted: if (hasFrontButtonHints) { safeArea.y += currentMetrics->buttonHintsHeight; safeArea.height -= currentMetrics->buttonHintsHeight; } break; case GfxRenderer::Orientation::LandscapeCounterClockwise: if (hasFrontButtonHints) { safeArea.width -= currentMetrics->buttonHintsHeight; } break; } return safeArea; } std::string UITheme::getCoverThumbPath(std::string coverBmpPath, int coverHeight) { size_t pos = coverBmpPath.find("[HEIGHT]", 0); if (pos != std::string::npos) { coverBmpPath.replace(pos, 8, std::to_string(coverHeight)); } return coverBmpPath; } UIIcon UITheme::getFileIcon(const std::string& filename) { if (filename.back() == '/') { return Folder; } if (FsHelpers::hasEpubExtension(filename) || FsHelpers::hasXtcExtension(filename)) { return Book; } if (FsHelpers::hasTxtExtension(filename) || FsHelpers::hasMarkdownExtension(filename)) { return Text; } if (FsHelpers::hasBmpExtension(filename)) { return Image; } return File; } int UITheme::getStatusBarHeight() { const ThemeMetrics& metrics = UITheme::getInstance().getMetrics(); // Add status bar margin const bool showStatusBar = SETTINGS.statusBarChapterPageCount || SETTINGS.statusBarBookProgressPercentage || SETTINGS.statusBarTitle != CrossPointSettings::STATUS_BAR_TITLE::HIDE_TITLE || SETTINGS.statusBarBattery || SETTINGS.statusBarClock != CrossPointSettings::STATUS_BAR_CLOCK_MODE::STATUS_BAR_CLOCK_HIDE; const bool showProgressBar = SETTINGS.statusBarProgressBar != CrossPointSettings::STATUS_BAR_PROGRESS_BAR::HIDE_PROGRESS; return (showStatusBar ? (metrics.statusBarVerticalMargin) : 0) + (showProgressBar ? (((SETTINGS.statusBarProgressBarThickness + 1) * 2) + metrics.progressBarMarginTop) : 0); } int UITheme::getProgressBarHeight() { const ThemeMetrics& metrics = UITheme::getInstance().getMetrics(); const bool showProgressBar = SETTINGS.statusBarProgressBar != CrossPointSettings::STATUS_BAR_PROGRESS_BAR::HIDE_PROGRESS; return (showProgressBar ? (((SETTINGS.statusBarProgressBarThickness + 1) * 2) + metrics.progressBarMarginTop) : 0); } // Centered text implementation that takes the safe area into account void UITheme::drawCenteredText(const GfxRenderer& renderer, Rect screen, int fontId, int y, const char* text, bool black, EpdFontFamily::Style style) { const int x = screen.x + (screen.width - renderer.getTextWidth(fontId, text, style)) / 2; renderer.drawText(fontId, x, y, text, black, style); }