Movable status bar and dual-edge progress bars

This commit is contained in:
jpirnay
2026-05-06 23:09:26 +02:00
parent 464846fd75
commit 4f140afd10
14 changed files with 475 additions and 168 deletions
+64 -36
View File
@@ -52,6 +52,21 @@ void drawBatteryIcon(const GfxRenderer& renderer, int x, int y, int battWidth, i
BaseTheme::drawBatteryLightningBolt(renderer, x + 4, y + 2);
}
}
int progressBarPixelHeight(const uint8_t progressBar, const uint8_t thickness, const ThemeMetrics& metrics) {
const int reservedHeight = UITheme::getProgressBarHeight(progressBar, thickness);
return std::max(0, reservedHeight - metrics.progressBarMarginTop);
}
int statusBarProgressPercent(const uint8_t progressBar, const float bookProgress, const int currentPage,
const int pageCount) {
if (progressBar == CrossPointSettings::STATUS_BAR_PROGRESS_BAR::BOOK_PROGRESS) {
return std::clamp(static_cast<int>(bookProgress), 0, 100);
}
const int chapterProgress =
(pageCount > 0) ? static_cast<int>((static_cast<float>(currentPage) / pageCount) * 100) : 0;
return std::clamp(chapterProgress, 0, 100);
}
} // namespace
void BaseTheme::drawBatteryOutline(const GfxRenderer& renderer, int x, int y, int battWidth, int rectHeight) {
@@ -748,19 +763,56 @@ void BaseTheme::fillPopupProgress(const GfxRenderer& renderer, const Rect& layou
}
void BaseTheme::drawStatusBar(GfxRenderer& renderer, const float bookProgress, const int currentPage,
const int pageCount, std::string title, const int paddingBottom, const int textYOffset,
const int pageCount, std::string title, const int paddingBottom,
const bool isStarred) const {
auto metrics = UITheme::getInstance().getMetrics();
int orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft;
renderer.getOrientedViewableTRBL(&orientedMarginTop, &orientedMarginRight, &orientedMarginBottom,
&orientedMarginLeft);
// Draw Progress Text
const auto screenHeight = renderer.getScreenHeight();
auto textY = screenHeight - UITheme::getInstance().getStatusBarHeight() - orientedMarginBottom - paddingBottom - 4;
const auto screenWidth = renderer.getScreenWidth();
const int progressBarMaxWidth = screenWidth - orientedMarginLeft - orientedMarginRight;
auto drawEdgeProgressBar = [&](const uint8_t progressBar, const uint8_t thickness, const bool topEdge) {
const int barHeight = progressBarPixelHeight(progressBar, thickness, metrics);
if (barHeight <= 0) {
return;
}
const int progress = statusBarProgressPercent(progressBar, bookProgress, currentPage, pageCount);
const int barWidth = progressBarMaxWidth * progress / 100;
const int y =
topEdge ? orientedMarginTop + paddingBottom : screenHeight - orientedMarginBottom - paddingBottom - barHeight;
renderer.fillRect(orientedMarginLeft, y, barWidth, barHeight, true);
};
// Draw progress bars first; status items are then placed inside the reserved band for their selected edge.
drawEdgeProgressBar(SETTINGS.statusBarUpperProgressBar, SETTINGS.statusBarUpperProgressBarThickness, true);
drawEdgeProgressBar(SETTINGS.statusBarLowerProgressBar, SETTINGS.statusBarLowerProgressBarThickness, false);
const bool hasProgressText = SETTINGS.statusBarBookProgressPercentage || SETTINGS.statusBarChapterPageCount;
const bool hasStatusItems = hasProgressText || SETTINGS.statusBarBattery || !title.empty() ||
SETTINGS.statusBarTitle != CrossPointSettings::STATUS_BAR_TITLE::HIDE_TITLE ||
(SETTINGS.useClock && SETTINGS.statusBarClock);
if (!hasStatusItems) {
return;
}
const bool statusItemsAtTop =
SETTINGS.statusBarItemsPosition == CrossPointSettings::STATUS_BAR_ITEMS_POSITION::STATUS_BAR_ITEMS_TOP;
const int adjacentProgressHeight = statusItemsAtTop
? UITheme::getProgressBarHeight(SETTINGS.statusBarUpperProgressBar,
SETTINGS.statusBarUpperProgressBarThickness)
: UITheme::getProgressBarHeight(SETTINGS.statusBarLowerProgressBar,
SETTINGS.statusBarLowerProgressBarThickness);
const int statusItemsHeight = UITheme::getStatusBarItemsHeight();
const int textY = statusItemsAtTop ? orientedMarginTop + paddingBottom + adjacentProgressHeight + 4
: screenHeight - orientedMarginBottom - paddingBottom - adjacentProgressHeight -
statusItemsHeight + 4;
int progressTextWidth = 0;
if (SETTINGS.statusBarBookProgressPercentage || SETTINGS.statusBarChapterPageCount) {
if (hasProgressText) {
// Right aligned text for progress counter
char progressStr[32];
@@ -773,27 +825,9 @@ void BaseTheme::drawStatusBar(GfxRenderer& renderer, const float bookProgress, c
}
progressTextWidth = renderer.getTextWidth(SMALL_FONT_ID, progressStr);
renderer.drawText(
SMALL_FONT_ID,
renderer.getScreenWidth() - metrics.statusBarHorizontalMargin - orientedMarginRight - progressTextWidth, textY,
progressStr);
}
// Draw Progress Bar
if (SETTINGS.statusBarProgressBar != CrossPointSettings::STATUS_BAR_PROGRESS_BAR::HIDE_PROGRESS) {
const int progressBarMaxWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight;
const int progressBarY = renderer.getScreenHeight() - orientedMarginBottom -
((SETTINGS.statusBarProgressBarThickness + 1) * 2) - paddingBottom;
size_t progress;
if (SETTINGS.statusBarProgressBar == CrossPointSettings::STATUS_BAR_PROGRESS_BAR::BOOK_PROGRESS) {
progress = static_cast<size_t>(bookProgress);
} else {
// Chapter progress
progress = (pageCount > 0) ? (static_cast<float>(currentPage) / pageCount) * 100 : 0;
}
const int barWidth = progressBarMaxWidth * progress / 100;
renderer.fillRect(orientedMarginLeft, progressBarY, barWidth, ((SETTINGS.statusBarProgressBarThickness + 1) * 2),
true);
renderer.drawText(SMALL_FONT_ID,
screenWidth - metrics.statusBarHorizontalMargin - orientedMarginRight - progressTextWidth, textY,
progressStr);
}
// Draw Battery
@@ -819,11 +853,8 @@ void BaseTheme::drawStatusBar(GfxRenderer& renderer, const float bookProgress, c
// Draw Title
if (!title.empty()) {
textY -= textYOffset;
// Centered chapter title text
// Page width minus existing content with 30px padding on each side
const int rendererableScreenWidth =
renderer.getScreenWidth() - (metrics.statusBarHorizontalMargin * 2) - orientedMarginLeft - orientedMarginRight;
screenWidth - (metrics.statusBarHorizontalMargin * 2) - orientedMarginLeft - orientedMarginRight;
const int batterySize = SETTINGS.statusBarBattery ? (showBatteryPercentage ? 50 : 20) : 0;
const int starReserve = isStarred ? (renderer.getTextWidth(SMALL_FONT_ID, "*") + 6) : 0;
@@ -836,8 +867,7 @@ void BaseTheme::drawStatusBar(GfxRenderer& renderer, const float bookProgress, c
int titleMarginLeftAdjusted = std::max(titleMarginLeft, titleMarginRight);
int availableTitleSpace = rendererableScreenWidth - 2 * titleMarginLeftAdjusted;
int titleWidth;
titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str());
int titleWidth = renderer.getTextWidth(SMALL_FONT_ID, title.c_str());
if (titleWidth > availableTitleSpace) {
// Not enough space to center on the screen, center it within the remaining space instead
availableTitleSpace = rendererableScreenWidth - titleMarginLeft - titleMarginRight;
@@ -860,14 +890,12 @@ void BaseTheme::drawStatusBar(GfxRenderer& renderer, const float bookProgress, c
int starX;
if (progressTextWidth > 0) {
// Place star just left of the progress text with a small gap
starX = renderer.getScreenWidth() - metrics.statusBarHorizontalMargin - orientedMarginRight - progressTextWidth -
starWidth - 6;
starX = screenWidth - metrics.statusBarHorizontalMargin - orientedMarginRight - progressTextWidth - starWidth - 6;
} else {
// No progress text, place star at right edge
starX = renderer.getScreenWidth() - metrics.statusBarHorizontalMargin - orientedMarginRight - starWidth;
starX = screenWidth - metrics.statusBarHorizontalMargin - orientedMarginRight - starWidth;
}
const int starY = title.empty() ? textY : (textY + textYOffset);
renderer.drawText(SMALL_FONT_ID, starX, starY, "*");
renderer.drawText(SMALL_FONT_ID, starX, textY, "*");
}
}