feat: Status bar for XTC files (#1849)
## Summary Add ability to show a status bar for 1-bit XTC files (closes #1848) Overlays a status bar (similar style to that for epubs) over the image. Defaults to hidden, users can set to show and either top or bottom of the screen within "Customize Status Bar" reader settings. I've leaned toward a simple overlay approach rather than trying anything clever e.g. resizing the original image or allowing for shifting the image around. I think it's more straight forward for the user to create a buffer zone when generating the XTC files. For 2-bit image files, it'd require more work to handle the multiple render passes so I'm holding off on that. Sample from a Japanese text XTC <img width="400" height="600" alt="image" src="https://github.com/user-attachments/assets/03ac67cf-acec-4b49-969f-73e3656760ce" /> ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**< YES | PARTIALLY | NO >**_ YES - Codex --------- Co-authored-by: Zach Nelson <zach@zdnelson.com>
This commit is contained in:
co-authored by
Zach Nelson
parent
b463966045
commit
29fd29f537
@@ -12,6 +12,8 @@
|
||||
#include <HalStorage.h>
|
||||
#include <I18n.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
#include "CrossPointState.h"
|
||||
#include "MappedInputManager.h"
|
||||
@@ -131,6 +133,76 @@ void XtcReaderActivity::render(RenderLock&&) {
|
||||
saveProgress();
|
||||
}
|
||||
|
||||
XtcReaderActivity::StatusBarInfo XtcReaderActivity::getStatusBarInfo() const {
|
||||
const int bookPageCount = static_cast<int>(xtc->getPageCount());
|
||||
const int bookPage = static_cast<int>(currentPage) + 1;
|
||||
std::string title =
|
||||
SETTINGS.statusBarTitle == CrossPointSettings::STATUS_BAR_TITLE::BOOK_TITLE ? xtc->getTitle() : "";
|
||||
|
||||
if (!xtc->hasChapters()) {
|
||||
return StatusBarInfo{bookPage, bookPageCount, std::move(title)};
|
||||
}
|
||||
|
||||
const auto& chapters = xtc->getChapters();
|
||||
const auto chapterIt = std::find_if(chapters.begin(), chapters.end(), [this](const xtc::ChapterInfo& chapter) {
|
||||
return currentPage >= chapter.startPage && currentPage <= chapter.endPage;
|
||||
});
|
||||
|
||||
if (chapterIt == chapters.end() || chapterIt->endPage < chapterIt->startPage) {
|
||||
return StatusBarInfo{bookPage, bookPageCount, std::move(title)};
|
||||
}
|
||||
|
||||
if (SETTINGS.statusBarTitle == CrossPointSettings::STATUS_BAR_TITLE::CHAPTER_TITLE) {
|
||||
title = chapterIt->name.empty() ? tr(STR_UNNAMED) : chapterIt->name;
|
||||
}
|
||||
|
||||
return StatusBarInfo{static_cast<int>(currentPage - chapterIt->startPage) + 1,
|
||||
static_cast<int>(chapterIt->endPage - chapterIt->startPage) + 1, std::move(title)};
|
||||
}
|
||||
|
||||
void XtcReaderActivity::renderStatusBarOverlay(const StatusBarOverlayPosition position) const {
|
||||
const bool drawBottom = SETTINGS.xtcStatusBarMode == CrossPointSettings::XTC_STATUS_BAR_MODE::XTC_STATUS_BAR_BOTTOM &&
|
||||
position == StatusBarOverlayPosition::Bottom;
|
||||
const bool drawTop = SETTINGS.xtcStatusBarMode == CrossPointSettings::XTC_STATUS_BAR_MODE::XTC_STATUS_BAR_TOP &&
|
||||
position == StatusBarOverlayPosition::Top;
|
||||
if (!drawBottom && !drawTop) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int statusBarHeight = UITheme::getInstance().getStatusBarHeight();
|
||||
if (statusBarHeight <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft;
|
||||
renderer.getOrientedViewableTRBL(&orientedMarginTop, &orientedMarginRight, &orientedMarginBottom,
|
||||
&orientedMarginLeft);
|
||||
|
||||
int clearY;
|
||||
int paddingBottom = 0;
|
||||
if (position == StatusBarOverlayPosition::Bottom) {
|
||||
clearY = renderer.getScreenHeight() - orientedMarginBottom - statusBarHeight - 4;
|
||||
if (clearY < 0) {
|
||||
clearY = 0;
|
||||
}
|
||||
} else {
|
||||
clearY = orientedMarginTop;
|
||||
paddingBottom = renderer.getScreenHeight() - statusBarHeight - orientedMarginBottom - orientedMarginTop - 4;
|
||||
}
|
||||
const int clearHeight = position == StatusBarOverlayPosition::Bottom
|
||||
? renderer.getScreenHeight() - orientedMarginBottom - clearY
|
||||
: statusBarHeight + 4;
|
||||
if (clearHeight > 0) {
|
||||
renderer.fillRect(0, clearY, renderer.getScreenWidth(), clearHeight, false);
|
||||
}
|
||||
|
||||
const int pageCount = static_cast<int>(xtc->getPageCount());
|
||||
const int displayPage = static_cast<int>(currentPage) + 1;
|
||||
const float progress = pageCount > 0 ? (static_cast<float>(displayPage) * 100.0f) / pageCount : 0.0f;
|
||||
const auto pageInfo = getStatusBarInfo();
|
||||
GUI.drawStatusBar(renderer, progress, pageInfo.currentPage, pageInfo.pageCount, pageInfo.title, paddingBottom);
|
||||
}
|
||||
|
||||
void XtcReaderActivity::renderPage() {
|
||||
const uint16_t pageWidth = xtc->getPageWidth();
|
||||
const uint16_t pageHeight = xtc->getPageHeight();
|
||||
@@ -291,7 +363,11 @@ void XtcReaderActivity::renderPage() {
|
||||
|
||||
free(pageBuffer);
|
||||
|
||||
// XTC pages already have status bar pre-rendered, no need to add our own
|
||||
if (SETTINGS.xtcStatusBarMode == CrossPointSettings::XTC_STATUS_BAR_MODE::XTC_STATUS_BAR_TOP) {
|
||||
renderStatusBarOverlay(StatusBarOverlayPosition::Top);
|
||||
} else {
|
||||
renderStatusBarOverlay(StatusBarOverlayPosition::Bottom);
|
||||
}
|
||||
|
||||
ReaderUtils::displayWithRefreshCycle(renderer, pagesUntilFullRefresh);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user