Add font foverrides to reader menu
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -518,6 +518,7 @@ STR_IMAGE_DISPLAY_GRAYSCALE: ">> Gray"
|
||||
STR_WEATHER_MOON_INFO: "Moon"
|
||||
STR_WEATHER_SUN_INFO: "Sun"
|
||||
STR_READER_BOOKMARKS: "Bookmarks & Footnotes"
|
||||
STR_READER_OVERRIDES: "Book-specific overrides"
|
||||
STR_READER_UTILS: "Helper"
|
||||
STR_READER_TOOLS: "Tools"
|
||||
STR_READER_NAVIGATION: "Navigation"
|
||||
|
||||
@@ -394,6 +394,8 @@ bool JsonSettingsIO::saveRecentBooks(const RecentBooksStore& store, const char*
|
||||
obj["coverBmpPath"] = book.coverBmpPath;
|
||||
obj["embeddedStyleOverride"] = book.embeddedStyleOverride;
|
||||
obj["imageRenderingOverride"] = book.imageRenderingOverride;
|
||||
obj["fontFamilyOverride"] = book.fontFamilyOverride;
|
||||
obj["fontSizeOverride"] = book.fontSizeOverride;
|
||||
}
|
||||
|
||||
String json;
|
||||
@@ -428,6 +430,9 @@ bool JsonSettingsIO::loadRecentBooks(RecentBooksStore& store, const char* json)
|
||||
book.coverBmpPath = obj["coverBmpPath"] | std::string("");
|
||||
book.embeddedStyleOverride = clampInt8(obj["embeddedStyleOverride"] | -1, -1, 1, -1);
|
||||
book.imageRenderingOverride = clampInt8(obj["imageRenderingOverride"] | -1, -1, 2, -1);
|
||||
book.fontFamilyOverride =
|
||||
clampInt8(obj["fontFamilyOverride"] | -1, -1, CrossPointSettings::FONT_FAMILY_COUNT - 1, -1);
|
||||
book.fontSizeOverride = clampInt8(obj["fontSizeOverride"] | -1, -1, CrossPointSettings::FONT_SIZE_COUNT - 1, -1);
|
||||
store.recentBooks.push_back(book);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ void RecentBooksStore::addBook(const std::string& path, const std::string& title
|
||||
const std::string& series, const std::string& coverBmpPath) {
|
||||
int8_t embeddedStyleOverride = -1;
|
||||
int8_t imageRenderingOverride = -1;
|
||||
int8_t fontFamilyOverride = -1;
|
||||
int8_t fontSizeOverride = -1;
|
||||
|
||||
// Remove existing entry if present
|
||||
auto it =
|
||||
@@ -31,12 +33,14 @@ void RecentBooksStore::addBook(const std::string& path, const std::string& title
|
||||
if (it != recentBooks.end()) {
|
||||
embeddedStyleOverride = it->embeddedStyleOverride;
|
||||
imageRenderingOverride = it->imageRenderingOverride;
|
||||
fontFamilyOverride = it->fontFamilyOverride;
|
||||
fontSizeOverride = it->fontSizeOverride;
|
||||
recentBooks.erase(it);
|
||||
}
|
||||
|
||||
// Add to front
|
||||
recentBooks.insert(recentBooks.begin(),
|
||||
{path, title, author, series, coverBmpPath, embeddedStyleOverride, imageRenderingOverride});
|
||||
recentBooks.insert(recentBooks.begin(), {path, title, author, series, coverBmpPath, embeddedStyleOverride,
|
||||
imageRenderingOverride, fontFamilyOverride, fontSizeOverride});
|
||||
|
||||
// Trim to max size
|
||||
if (recentBooks.size() > MAX_RECENT_BOOKS) {
|
||||
@@ -80,6 +84,12 @@ RecentBook RecentBooksStore::getBookByPath(const std::string& path) const {
|
||||
|
||||
bool RecentBooksStore::setReaderOverrides(const std::string& path, const int8_t embeddedStyleOverride,
|
||||
const int8_t imageRenderingOverride) {
|
||||
return setReaderOverrides(path, embeddedStyleOverride, imageRenderingOverride, -1, -1);
|
||||
}
|
||||
|
||||
bool RecentBooksStore::setReaderOverrides(const std::string& path, const int8_t embeddedStyleOverride,
|
||||
const int8_t imageRenderingOverride, const int8_t fontFamilyOverride,
|
||||
const int8_t fontSizeOverride) {
|
||||
auto it =
|
||||
std::find_if(recentBooks.begin(), recentBooks.end(), [&](const RecentBook& book) { return book.path == path; });
|
||||
if (it == recentBooks.end()) {
|
||||
@@ -88,6 +98,8 @@ bool RecentBooksStore::setReaderOverrides(const std::string& path, const int8_t
|
||||
|
||||
it->embeddedStyleOverride = embeddedStyleOverride;
|
||||
it->imageRenderingOverride = imageRenderingOverride;
|
||||
it->fontFamilyOverride = fontFamilyOverride;
|
||||
it->fontSizeOverride = fontSizeOverride;
|
||||
return saveToFile();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@ struct RecentBook {
|
||||
int8_t embeddedStyleOverride = -1;
|
||||
// -1 = use global setting, otherwise CrossPointSettings::IMAGE_RENDERING value.
|
||||
int8_t imageRenderingOverride = -1;
|
||||
// -1 = use global setting, otherwise CrossPointSettings::FONT_FAMILY value.
|
||||
int8_t fontFamilyOverride = -1;
|
||||
// -1 = use global setting, otherwise CrossPointSettings::FONT_SIZE value.
|
||||
int8_t fontSizeOverride = -1;
|
||||
|
||||
bool operator==(const RecentBook& other) const { return path == other.path; }
|
||||
};
|
||||
@@ -58,6 +62,8 @@ class RecentBooksStore {
|
||||
RecentBook getDataFromBook(std::string path) const;
|
||||
RecentBook getBookByPath(const std::string& path) const;
|
||||
bool setReaderOverrides(const std::string& path, int8_t embeddedStyleOverride, int8_t imageRenderingOverride);
|
||||
bool setReaderOverrides(const std::string& path, int8_t embeddedStyleOverride, int8_t imageRenderingOverride,
|
||||
int8_t fontFamilyOverride, int8_t fontSizeOverride);
|
||||
|
||||
private:
|
||||
bool loadFromBinaryFile();
|
||||
|
||||
@@ -24,6 +24,8 @@ struct MenuResult {
|
||||
uint8_t pageTurnOption = 0;
|
||||
int8_t embeddedStyleOverride = -1;
|
||||
int8_t imageRenderingOverride = -1;
|
||||
int8_t fontFamilyOverride = -1;
|
||||
int8_t fontSizeOverride = -1;
|
||||
uint8_t textDarkness = 1;
|
||||
};
|
||||
|
||||
|
||||
@@ -148,6 +148,8 @@ void EpubReaderActivity::onEnter() {
|
||||
const RecentBook currentBook = RECENT_BOOKS.getBookByPath(epub->getPath());
|
||||
bookEmbeddedStyleOverride = currentBook.embeddedStyleOverride;
|
||||
bookImageRenderingOverride = currentBook.imageRenderingOverride;
|
||||
bookFontFamilyOverride = currentBook.fontFamilyOverride;
|
||||
bookFontSizeOverride = currentBook.fontSizeOverride;
|
||||
logReaderMemSnapshot("onEnter_after_recent_books");
|
||||
|
||||
// Trigger first update
|
||||
@@ -239,22 +241,23 @@ void EpubReaderActivity::loop() {
|
||||
const bool isCurrentPageStarred = section && bookmarkStore.has(static_cast<uint16_t>(currentSpineIndex),
|
||||
static_cast<uint16_t>(section->currentPage));
|
||||
ReaderUtils::enforceExitFullRefresh(renderer);
|
||||
startActivityForResult(
|
||||
std::make_unique<EpubReaderMenuActivity>(
|
||||
renderer, mappedInput, epub->getTitle(), currentPage, totalPages, bookProgressPercent, SETTINGS.orientation,
|
||||
!currentPageFootnotes.empty(), bookEmbeddedStyleOverride, bookImageRenderingOverride, SETTINGS.textDarkness,
|
||||
!bookmarkStore.isEmpty(), isCurrentPageStarred),
|
||||
[this](const ActivityResult& result) {
|
||||
// Always apply orientation/darkness change even if the menu was cancelled
|
||||
const auto& menu = std::get<MenuResult>(result.data);
|
||||
applyOrientation(menu.orientation);
|
||||
applyTextDarkness(menu.textDarkness);
|
||||
toggleAutoPageTurn(menu.pageTurnOption);
|
||||
applyBookReaderOverrides(menu.embeddedStyleOverride, menu.imageRenderingOverride);
|
||||
if (!result.isCancelled) {
|
||||
onReaderMenuConfirm(static_cast<EpubReaderMenuActivity::MenuAction>(menu.action));
|
||||
}
|
||||
});
|
||||
startActivityForResult(std::make_unique<EpubReaderMenuActivity>(
|
||||
renderer, mappedInput, epub->getTitle(), currentPage, totalPages, bookProgressPercent,
|
||||
SETTINGS.orientation, !currentPageFootnotes.empty(), bookEmbeddedStyleOverride,
|
||||
bookImageRenderingOverride, bookFontFamilyOverride, bookFontSizeOverride,
|
||||
SETTINGS.textDarkness, !bookmarkStore.isEmpty(), isCurrentPageStarred),
|
||||
[this](const ActivityResult& result) {
|
||||
// Always apply orientation/darkness change even if the menu was cancelled
|
||||
const auto& menu = std::get<MenuResult>(result.data);
|
||||
applyOrientation(menu.orientation);
|
||||
applyTextDarkness(menu.textDarkness);
|
||||
toggleAutoPageTurn(menu.pageTurnOption);
|
||||
applyBookReaderOverrides(menu.embeddedStyleOverride, menu.imageRenderingOverride,
|
||||
menu.fontFamilyOverride, menu.fontSizeOverride);
|
||||
if (!result.isCancelled) {
|
||||
onReaderMenuConfirm(static_cast<EpubReaderMenuActivity::MenuAction>(menu.action));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Long press BACK (1s+) goes to home screen
|
||||
@@ -814,18 +817,23 @@ void EpubReaderActivity::toggleAutoPageTurn(const uint8_t selectedPageTurnOption
|
||||
}
|
||||
|
||||
void EpubReaderActivity::applyBookReaderOverrides(const int8_t embeddedStyleOverride,
|
||||
const int8_t imageRenderingOverride) {
|
||||
const int8_t imageRenderingOverride, const int8_t fontFamilyOverride,
|
||||
const int8_t fontSizeOverride) {
|
||||
if (!epub) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bookEmbeddedStyleOverride == embeddedStyleOverride && bookImageRenderingOverride == imageRenderingOverride) {
|
||||
if (bookEmbeddedStyleOverride == embeddedStyleOverride && bookImageRenderingOverride == imageRenderingOverride &&
|
||||
bookFontFamilyOverride == fontFamilyOverride && bookFontSizeOverride == fontSizeOverride) {
|
||||
return;
|
||||
}
|
||||
|
||||
bookEmbeddedStyleOverride = embeddedStyleOverride;
|
||||
bookImageRenderingOverride = imageRenderingOverride;
|
||||
RECENT_BOOKS.setReaderOverrides(epub->getPath(), bookEmbeddedStyleOverride, bookImageRenderingOverride);
|
||||
bookFontFamilyOverride = fontFamilyOverride;
|
||||
bookFontSizeOverride = fontSizeOverride;
|
||||
RECENT_BOOKS.setReaderOverrides(epub->getPath(), bookEmbeddedStyleOverride, bookImageRenderingOverride,
|
||||
bookFontFamilyOverride, bookFontSizeOverride);
|
||||
|
||||
RenderLock lock(*this);
|
||||
if (section) {
|
||||
@@ -850,6 +858,51 @@ uint8_t EpubReaderActivity::getEffectiveImageRendering() const {
|
||||
return SETTINGS.imageRendering;
|
||||
}
|
||||
|
||||
int EpubReaderActivity::getEffectiveReaderFontId() const {
|
||||
const uint8_t fontFamily =
|
||||
(bookFontFamilyOverride >= 0) ? static_cast<uint8_t>(bookFontFamilyOverride) : SETTINGS.fontFamily;
|
||||
const uint8_t fontSize = (bookFontSizeOverride >= 0) ? static_cast<uint8_t>(bookFontSizeOverride) : SETTINGS.fontSize;
|
||||
switch (fontFamily) {
|
||||
case CrossPointSettings::NOTOSANS:
|
||||
switch (fontSize) {
|
||||
case CrossPointSettings::SMALL:
|
||||
return NOTOSANS_12_FONT_ID;
|
||||
case CrossPointSettings::MEDIUM:
|
||||
default:
|
||||
return NOTOSANS_14_FONT_ID;
|
||||
case CrossPointSettings::LARGE:
|
||||
return NOTOSANS_16_FONT_ID;
|
||||
case CrossPointSettings::EXTRA_LARGE:
|
||||
return NOTOSANS_18_FONT_ID;
|
||||
}
|
||||
case CrossPointSettings::OPENDYSLEXIC:
|
||||
switch (fontSize) {
|
||||
case CrossPointSettings::SMALL:
|
||||
return OPENDYSLEXIC_8_FONT_ID;
|
||||
case CrossPointSettings::MEDIUM:
|
||||
default:
|
||||
return OPENDYSLEXIC_10_FONT_ID;
|
||||
case CrossPointSettings::LARGE:
|
||||
return OPENDYSLEXIC_12_FONT_ID;
|
||||
case CrossPointSettings::EXTRA_LARGE:
|
||||
return OPENDYSLEXIC_14_FONT_ID;
|
||||
}
|
||||
case CrossPointSettings::BOOKERLY:
|
||||
default:
|
||||
switch (fontSize) {
|
||||
case CrossPointSettings::SMALL:
|
||||
return BOOKERLY_12_FONT_ID;
|
||||
case CrossPointSettings::MEDIUM:
|
||||
default:
|
||||
return BOOKERLY_14_FONT_ID;
|
||||
case CrossPointSettings::LARGE:
|
||||
return BOOKERLY_16_FONT_ID;
|
||||
case CrossPointSettings::EXTRA_LARGE:
|
||||
return BOOKERLY_18_FONT_ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EpubReaderActivity::pageTurn(bool isForwardTurn) {
|
||||
if (isForwardTurn) {
|
||||
if (section->currentPage < section->pageCount - 1) {
|
||||
@@ -934,7 +987,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
LOG_DBG("ERS", "Loading file: %s, index: %d", filepath.c_str(), currentSpineIndex);
|
||||
section = std::make_unique<Section>(epub, currentSpineIndex, renderer);
|
||||
|
||||
if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
if (!section->loadSectionFile(getEffectiveReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, embeddedStyle, imageRendering)) {
|
||||
LOG_DBG("ERS", "Cache not found, building...");
|
||||
@@ -947,7 +1000,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
GUI.fillPopupProgress(renderer, popupRect, progress);
|
||||
};
|
||||
|
||||
if (!section->createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
if (!section->createSectionFile(getEffectiveReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, embeddedStyle, imageRendering,
|
||||
progressFn)) {
|
||||
@@ -1090,14 +1143,14 @@ void EpubReaderActivity::silentIndexNextChapterIfNeeded(const uint16_t viewportW
|
||||
const uint8_t imageRendering = getEffectiveImageRendering();
|
||||
|
||||
Section nextSection(epub, nextSpineIndex, renderer);
|
||||
if (nextSection.loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
if (nextSection.loadSectionFile(getEffectiveReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, embeddedStyle, imageRendering)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DBG("ERS", "Silently indexing next chapter: %d", nextSpineIndex);
|
||||
if (!nextSection.createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
if (!nextSection.createSectionFile(getEffectiveReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, embeddedStyle, imageRendering)) {
|
||||
LOG_ERR("ERS", "Failed silent indexing for chapter: %d", nextSpineIndex);
|
||||
@@ -1133,7 +1186,7 @@ void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int or
|
||||
// Font prewarm: scan pass accumulates text, then prewarm, then real render
|
||||
const uint32_t heapBefore = esp_get_free_heap_size();
|
||||
auto scope = fcm->createPrewarmScope();
|
||||
page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop); // scan pass
|
||||
page->render(renderer, getEffectiveReaderFontId(), orientedMarginLeft, orientedMarginTop); // scan pass
|
||||
scope.endScanAndPrewarm();
|
||||
const uint32_t heapAfter = esp_get_free_heap_size();
|
||||
fcm->logStats("prewarm");
|
||||
@@ -1149,7 +1202,7 @@ void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int or
|
||||
pendingHalfRefreshAfterImagePage = false;
|
||||
|
||||
logReaderMemSnapshot("before_bw_render");
|
||||
page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop);
|
||||
page->render(renderer, getEffectiveReaderFontId(), orientedMarginLeft, orientedMarginTop);
|
||||
renderStatusBar();
|
||||
fcm->logStats("bw_render");
|
||||
const auto tBwRender = millis();
|
||||
@@ -1168,7 +1221,7 @@ void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int or
|
||||
|
||||
// Re-render page content to restore images into the blanked area
|
||||
// Status bar is not re-rendered here to avoid reading stale dynamic values (e.g. battery %)
|
||||
page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop);
|
||||
page->render(renderer, getEffectiveReaderFontId(), orientedMarginLeft, orientedMarginTop);
|
||||
renderer.displayBuffer(HalDisplay::FAST_REFRESH);
|
||||
} else {
|
||||
renderer.displayBuffer(HalDisplay::HALF_REFRESH);
|
||||
@@ -1201,7 +1254,7 @@ void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int or
|
||||
logReaderMemSnapshot("gray_lsb_begin");
|
||||
renderer.clearScreen(0x00);
|
||||
renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
|
||||
page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop);
|
||||
page->render(renderer, getEffectiveReaderFontId(), orientedMarginLeft, orientedMarginTop);
|
||||
renderer.copyGrayscaleLsbBuffers();
|
||||
const auto tGrayLsb = millis();
|
||||
logReaderMemSnapshot("gray_lsb_end");
|
||||
@@ -1210,7 +1263,7 @@ void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int or
|
||||
logReaderMemSnapshot("gray_msb_begin");
|
||||
renderer.clearScreen(0x00);
|
||||
renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
|
||||
page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop);
|
||||
page->render(renderer, getEffectiveReaderFontId(), orientedMarginLeft, orientedMarginTop);
|
||||
renderer.copyGrayscaleMsbBuffers();
|
||||
const auto tGrayMsb = millis();
|
||||
logReaderMemSnapshot("gray_msb_end");
|
||||
@@ -1385,16 +1438,63 @@ bool EpubReaderActivity::drawCurrentPageToBuffer(const std::string& filePath, Gf
|
||||
|
||||
// Load or rebuild the section cache. Rebuilding is needed when the cache is missing or stale
|
||||
// (e.g. after a firmware update). A no-op popup callback avoids any UI during sleep preparation.
|
||||
const RecentBook currentBook = RECENT_BOOKS.getBookByPath(filePath);
|
||||
const uint8_t effectiveFontFamily =
|
||||
currentBook.fontFamilyOverride >= 0 ? static_cast<uint8_t>(currentBook.fontFamilyOverride) : SETTINGS.fontFamily;
|
||||
const uint8_t effectiveFontSize =
|
||||
currentBook.fontSizeOverride >= 0 ? static_cast<uint8_t>(currentBook.fontSizeOverride) : SETTINGS.fontSize;
|
||||
auto getEffectiveFontId = [&](uint8_t family, uint8_t size) {
|
||||
switch (family) {
|
||||
case CrossPointSettings::NOTOSANS:
|
||||
switch (size) {
|
||||
case CrossPointSettings::SMALL:
|
||||
return NOTOSANS_12_FONT_ID;
|
||||
case CrossPointSettings::LARGE:
|
||||
return NOTOSANS_16_FONT_ID;
|
||||
case CrossPointSettings::EXTRA_LARGE:
|
||||
return NOTOSANS_18_FONT_ID;
|
||||
case CrossPointSettings::MEDIUM:
|
||||
default:
|
||||
return NOTOSANS_14_FONT_ID;
|
||||
}
|
||||
case CrossPointSettings::OPENDYSLEXIC:
|
||||
switch (size) {
|
||||
case CrossPointSettings::SMALL:
|
||||
return OPENDYSLEXIC_8_FONT_ID;
|
||||
case CrossPointSettings::LARGE:
|
||||
return OPENDYSLEXIC_12_FONT_ID;
|
||||
case CrossPointSettings::EXTRA_LARGE:
|
||||
return OPENDYSLEXIC_14_FONT_ID;
|
||||
case CrossPointSettings::MEDIUM:
|
||||
default:
|
||||
return OPENDYSLEXIC_10_FONT_ID;
|
||||
}
|
||||
case CrossPointSettings::BOOKERLY:
|
||||
default:
|
||||
switch (size) {
|
||||
case CrossPointSettings::SMALL:
|
||||
return BOOKERLY_12_FONT_ID;
|
||||
case CrossPointSettings::LARGE:
|
||||
return BOOKERLY_16_FONT_ID;
|
||||
case CrossPointSettings::EXTRA_LARGE:
|
||||
return BOOKERLY_18_FONT_ID;
|
||||
case CrossPointSettings::MEDIUM:
|
||||
default:
|
||||
return BOOKERLY_14_FONT_ID;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto section = std::make_unique<Section>(epub, spineIndex, renderer);
|
||||
if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle,
|
||||
SETTINGS.imageRendering)) {
|
||||
if (!section->loadSectionFile(getEffectiveFontId(effectiveFontFamily, effectiveFontSize),
|
||||
SETTINGS.getReaderLineCompression(), SETTINGS.extraParagraphSpacing,
|
||||
SETTINGS.paragraphAlignment, viewportWidth, viewportHeight, SETTINGS.hyphenationEnabled,
|
||||
SETTINGS.embeddedStyle, SETTINGS.imageRendering)) {
|
||||
LOG_DBG("SLP", "EPUB: section cache not found for spine %d, rebuilding", spineIndex);
|
||||
if (!section->createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle,
|
||||
SETTINGS.imageRendering)) {
|
||||
if (!section->createSectionFile(getEffectiveFontId(effectiveFontFamily, effectiveFontSize),
|
||||
SETTINGS.getReaderLineCompression(), SETTINGS.extraParagraphSpacing,
|
||||
SETTINGS.paragraphAlignment, viewportWidth, viewportHeight,
|
||||
SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, SETTINGS.imageRendering)) {
|
||||
LOG_ERR("SLP", "EPUB: failed to rebuild section cache for spine %d", spineIndex);
|
||||
return false;
|
||||
}
|
||||
@@ -1410,7 +1510,7 @@ bool EpubReaderActivity::drawCurrentPageToBuffer(const std::string& filePath, Gf
|
||||
}
|
||||
|
||||
renderer.clearScreen();
|
||||
page->render(renderer, SETTINGS.getReaderFontId(), marginLeft, marginTop);
|
||||
page->render(renderer, getEffectiveFontId(effectiveFontFamily, effectiveFontSize), marginLeft, marginTop);
|
||||
// No displayBuffer call — caller (SleepActivity) handles that after compositing the overlay
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ class EpubReaderActivity final : public Activity {
|
||||
// -1 means use global SETTINGS value.
|
||||
int8_t bookEmbeddedStyleOverride = -1;
|
||||
int8_t bookImageRenderingOverride = -1;
|
||||
int8_t bookFontFamilyOverride = -1;
|
||||
int8_t bookFontSizeOverride = -1;
|
||||
|
||||
// Bookmarks (starred pages)
|
||||
BookmarkStore bookmarkStore;
|
||||
@@ -88,9 +90,11 @@ class EpubReaderActivity final : public Activity {
|
||||
void applyOrientation(uint8_t orientation);
|
||||
void applyTextDarkness(uint8_t textDarkness);
|
||||
void toggleAutoPageTurn(uint8_t selectedPageTurnOption);
|
||||
void applyBookReaderOverrides(int8_t embeddedStyleOverride, int8_t imageRenderingOverride);
|
||||
void applyBookReaderOverrides(int8_t embeddedStyleOverride, int8_t imageRenderingOverride, int8_t fontFamilyOverride,
|
||||
int8_t fontSizeOverride);
|
||||
bool getEffectiveEmbeddedStyle() const;
|
||||
uint8_t getEffectiveImageRendering() const;
|
||||
int getEffectiveReaderFontId() const;
|
||||
void pageTurn(bool isForwardTurn);
|
||||
|
||||
// Footnote navigation
|
||||
|
||||
@@ -13,13 +13,16 @@ EpubReaderMenuActivity::EpubReaderMenuActivity(GfxRenderer& renderer, MappedInpu
|
||||
const int bookProgressPercent, const uint8_t currentOrientation,
|
||||
const bool hasFootnotes, const int8_t initialEmbeddedStyleOverride,
|
||||
const int8_t initialImageRenderingOverride,
|
||||
const uint8_t initialTextDarkness, const bool hasStarredPages,
|
||||
const bool isCurrentPageStarred)
|
||||
const int8_t initialFontFamilyOverride,
|
||||
const int8_t initialFontSizeOverride, const uint8_t initialTextDarkness,
|
||||
const bool hasStarredPages, const bool isCurrentPageStarred)
|
||||
: MenuListActivity("EpubReaderMenu", renderer, mappedInput),
|
||||
currentPageStarred(isCurrentPageStarred),
|
||||
pendingOrientation(currentOrientation),
|
||||
pendingEmbeddedStyleOverride(initialEmbeddedStyleOverride),
|
||||
pendingImageRenderingOverride(initialImageRenderingOverride),
|
||||
pendingFontFamilyOverride(initialFontFamilyOverride),
|
||||
pendingFontSizeOverride(initialFontSizeOverride),
|
||||
pendingTextDarkness(initialTextDarkness),
|
||||
title(title),
|
||||
currentPage(currentPage),
|
||||
@@ -51,50 +54,6 @@ void EpubReaderMenuActivity::buildMenuItems(bool hasFootnotes, bool hasStarredPa
|
||||
menuItems.push_back(SettingInfo::Separator(StrId::STR_READER_APPEARANCE));
|
||||
|
||||
auto* self = this;
|
||||
|
||||
// Embedded style: cycles default(-1) -> ON(1) -> OFF(0) via DynamicEnum indices 0/1/2
|
||||
menuItems.push_back(SettingInfo::DynamicEnumCtx(
|
||||
StrId::STR_EMBEDDED_STYLE, {StrId::STR_DEFAULT_VALUE, StrId::STR_STATE_ON, StrId::STR_STATE_OFF}, self,
|
||||
[](const void* ctx) -> uint8_t {
|
||||
const auto* s = static_cast<const EpubReaderMenuActivity*>(ctx);
|
||||
if (s->pendingEmbeddedStyleOverride < 0) return 0;
|
||||
if (s->pendingEmbeddedStyleOverride > 0) return 1;
|
||||
return 2;
|
||||
},
|
||||
[](void* ctx, uint8_t v) {
|
||||
auto* s = static_cast<EpubReaderMenuActivity*>(ctx);
|
||||
if (v == 0)
|
||||
s->pendingEmbeddedStyleOverride = -1;
|
||||
else if (v == 1)
|
||||
s->pendingEmbeddedStyleOverride = 1;
|
||||
else
|
||||
s->pendingEmbeddedStyleOverride = 0;
|
||||
}));
|
||||
|
||||
// Image rendering: cycles default(-1) -> display(0) -> placeholder(1) -> suppress(2)
|
||||
menuItems.push_back(SettingInfo::DynamicEnumCtx(
|
||||
StrId::STR_IMAGES,
|
||||
{StrId::STR_DEFAULT_VALUE, StrId::STR_IMAGES_DISPLAY, StrId::STR_IMAGES_PLACEHOLDER, StrId::STR_IMAGES_SUPPRESS},
|
||||
self,
|
||||
[](const void* ctx) -> uint8_t {
|
||||
const auto* s = static_cast<const EpubReaderMenuActivity*>(ctx);
|
||||
return (s->pendingImageRenderingOverride < 0) ? 0 : (s->pendingImageRenderingOverride + 1);
|
||||
},
|
||||
[](void* ctx, uint8_t v) {
|
||||
auto* s = static_cast<EpubReaderMenuActivity*>(ctx);
|
||||
s->pendingImageRenderingOverride = (v == 0) ? -1 : static_cast<int8_t>(v - 1);
|
||||
}));
|
||||
|
||||
// Text darkness: straightforward 0-3 cycle
|
||||
menuItems.push_back(SettingInfo::DynamicEnumCtx(
|
||||
StrId::STR_TEXT_DARKNESS, {StrId::STR_NORMAL, StrId::STR_DARK, StrId::STR_EXTRA_DARK, StrId::STR_MAX_DARK}, self,
|
||||
[](const void* ctx) -> uint8_t { return static_cast<const EpubReaderMenuActivity*>(ctx)->pendingTextDarkness; },
|
||||
[](void* ctx, uint8_t v) { static_cast<EpubReaderMenuActivity*>(ctx)->pendingTextDarkness = v; }));
|
||||
|
||||
// Helper functions, reading ruler, auto page turn, orientation
|
||||
menuItems.push_back(SettingInfo::Separator(StrId::STR_READER_UTILS));
|
||||
// Auto page turn: ACTION type with custom cycling in onActionSelected
|
||||
menuItems.push_back(SettingInfo::Action(StrId::STR_AUTO_TURN_PAGES_PER_MIN, SettingAction::None));
|
||||
// Orientation: straightforward 0-3 cycle
|
||||
menuItems.push_back(SettingInfo::DynamicEnumCtx(
|
||||
StrId::STR_ORIENTATION,
|
||||
@@ -102,6 +61,89 @@ void EpubReaderMenuActivity::buildMenuItems(bool hasFootnotes, bool hasStarredPa
|
||||
[](const void* ctx) -> uint8_t { return static_cast<const EpubReaderMenuActivity*>(ctx)->pendingOrientation; },
|
||||
[](void* ctx, uint8_t v) { static_cast<EpubReaderMenuActivity*>(ctx)->pendingOrientation = v; }));
|
||||
|
||||
// Embedded style: cycles default(-1) -> ON(1) -> OFF(0) via DynamicEnum indices 0/1/2
|
||||
menuItems.push_back(SettingInfo::DynamicEnumCtx(
|
||||
StrId::STR_EMBEDDED_STYLE,
|
||||
{StrId::STR_DEFAULT_VALUE, StrId::STR_STATE_ON, StrId::STR_STATE_OFF}, self,
|
||||
[](const void* ctx) -> uint8_t {
|
||||
const auto* s = static_cast<const EpubReaderMenuActivity*>(ctx);
|
||||
if (s->pendingEmbeddedStyleOverride < 0) return 0;
|
||||
if (s->pendingEmbeddedStyleOverride > 0) return 1;
|
||||
return 2;
|
||||
},
|
||||
[](void* ctx, uint8_t v) {
|
||||
auto* s = static_cast<EpubReaderMenuActivity*>(ctx);
|
||||
if (v == 0)
|
||||
s->pendingEmbeddedStyleOverride = -1;
|
||||
else if (v == 1)
|
||||
s->pendingEmbeddedStyleOverride = 1;
|
||||
else
|
||||
s->pendingEmbeddedStyleOverride = 0;
|
||||
})
|
||||
.withSubmenu(StrId::STR_READER_OVERRIDES));
|
||||
|
||||
// Image rendering: cycles default(-1) -> display(0) -> placeholder(1) -> suppress(2)
|
||||
menuItems.push_back(SettingInfo::DynamicEnumCtx(
|
||||
StrId::STR_IMAGES,
|
||||
{StrId::STR_DEFAULT_VALUE, StrId::STR_IMAGES_DISPLAY, StrId::STR_IMAGES_PLACEHOLDER,
|
||||
StrId::STR_IMAGES_SUPPRESS},
|
||||
self,
|
||||
[](const void* ctx) -> uint8_t {
|
||||
const auto* s = static_cast<const EpubReaderMenuActivity*>(ctx);
|
||||
return (s->pendingImageRenderingOverride < 0) ? 0 : (s->pendingImageRenderingOverride + 1);
|
||||
},
|
||||
[](void* ctx, uint8_t v) {
|
||||
auto* s = static_cast<EpubReaderMenuActivity*>(ctx);
|
||||
s->pendingImageRenderingOverride = (v == 0) ? -1 : static_cast<int8_t>(v - 1);
|
||||
})
|
||||
.withSubmenu(StrId::STR_READER_OVERRIDES));
|
||||
|
||||
// Reader font family: cycles default(-1) -> Bookerly(0) -> Noto Sans(1) -> Open Dyslexic(2)
|
||||
menuItems.push_back(
|
||||
SettingInfo::DynamicEnumCtx(
|
||||
StrId::STR_FONT_FAMILY,
|
||||
{StrId::STR_DEFAULT_VALUE, StrId::STR_BOOKERLY, StrId::STR_NOTO_SANS, StrId::STR_OPEN_DYSLEXIC}, self,
|
||||
[](const void* ctx) -> uint8_t {
|
||||
const auto* s = static_cast<const EpubReaderMenuActivity*>(ctx);
|
||||
return (s->pendingFontFamilyOverride < 0) ? 0 : static_cast<uint8_t>(s->pendingFontFamilyOverride + 1);
|
||||
},
|
||||
[](void* ctx, uint8_t v) {
|
||||
auto* s = static_cast<EpubReaderMenuActivity*>(ctx);
|
||||
s->pendingFontFamilyOverride = (v == 0) ? -1 : static_cast<int8_t>(v - 1);
|
||||
})
|
||||
.withSubmenu(StrId::STR_READER_OVERRIDES));
|
||||
|
||||
// Reader font size: cycles default(-1) -> Small(0) -> Medium(1) -> Large(2) -> X Large(3)
|
||||
menuItems.push_back(
|
||||
SettingInfo::DynamicEnumCtx(
|
||||
StrId::STR_FONT_SIZE,
|
||||
{StrId::STR_DEFAULT_VALUE, StrId::STR_SMALL, StrId::STR_MEDIUM, StrId::STR_LARGE, StrId::STR_X_LARGE}, self,
|
||||
[](const void* ctx) -> uint8_t {
|
||||
const auto* s = static_cast<const EpubReaderMenuActivity*>(ctx);
|
||||
return (s->pendingFontSizeOverride < 0) ? 0 : static_cast<uint8_t>(s->pendingFontSizeOverride + 1);
|
||||
},
|
||||
[](void* ctx, uint8_t v) {
|
||||
auto* s = static_cast<EpubReaderMenuActivity*>(ctx);
|
||||
s->pendingFontSizeOverride = (v == 0) ? -1 : static_cast<int8_t>(v - 1);
|
||||
})
|
||||
.withSubmenu(StrId::STR_READER_OVERRIDES));
|
||||
|
||||
// Text darkness: straightforward 0-3 cycle
|
||||
menuItems.push_back(
|
||||
SettingInfo::DynamicEnumCtx(
|
||||
StrId::STR_TEXT_DARKNESS, {StrId::STR_NORMAL, StrId::STR_DARK, StrId::STR_EXTRA_DARK, StrId::STR_MAX_DARK},
|
||||
self,
|
||||
[](const void* ctx) -> uint8_t {
|
||||
return static_cast<const EpubReaderMenuActivity*>(ctx)->pendingTextDarkness;
|
||||
},
|
||||
[](void* ctx, uint8_t v) { static_cast<EpubReaderMenuActivity*>(ctx)->pendingTextDarkness = v; })
|
||||
.withSubmenu(StrId::STR_READER_OVERRIDES));
|
||||
|
||||
// Helper functions, reading ruler, auto page turn, orientation
|
||||
menuItems.push_back(SettingInfo::Separator(StrId::STR_READER_UTILS));
|
||||
// Auto page turn: ACTION type with custom cycling in onActionSelected
|
||||
menuItems.push_back(SettingInfo::Action(StrId::STR_AUTO_TURN_PAGES_PER_MIN, SettingAction::None));
|
||||
|
||||
// --- Synchronisation (only if credentials are set) ---
|
||||
if (KOREADER_STORE.hasCredentials()) {
|
||||
menuItems.push_back(SettingInfo::Separator(StrId::STR_KOREADER_SYNC));
|
||||
@@ -158,7 +200,8 @@ EpubReaderMenuActivity::MenuAction EpubReaderMenuActivity::actionForNameId(StrId
|
||||
|
||||
void EpubReaderMenuActivity::finishWithAction(MenuAction action) {
|
||||
setResult(MenuResult{static_cast<int>(action), pendingOrientation, selectedPageTurnOption,
|
||||
pendingEmbeddedStyleOverride, pendingImageRenderingOverride, pendingTextDarkness});
|
||||
pendingEmbeddedStyleOverride, pendingImageRenderingOverride, pendingFontFamilyOverride,
|
||||
pendingFontSizeOverride, pendingTextDarkness});
|
||||
finish();
|
||||
}
|
||||
|
||||
@@ -188,6 +231,8 @@ void EpubReaderMenuActivity::onBackPressed() {
|
||||
selectedPageTurnOption,
|
||||
pendingEmbeddedStyleOverride,
|
||||
pendingImageRenderingOverride,
|
||||
pendingFontFamilyOverride,
|
||||
pendingFontSizeOverride,
|
||||
pendingTextDarkness};
|
||||
setResult(std::move(result));
|
||||
finish();
|
||||
|
||||
@@ -35,6 +35,7 @@ class EpubReaderMenuActivity final : public MenuListActivity {
|
||||
const int currentPage, const int totalPages, const int bookProgressPercent,
|
||||
const uint8_t currentOrientation, const bool hasFootnotes,
|
||||
const int8_t initialEmbeddedStyleOverride, const int8_t initialImageRenderingOverride,
|
||||
const int8_t initialFontFamilyOverride, const int8_t initialFontSizeOverride,
|
||||
const uint8_t initialTextDarkness, const bool hasStarredPages,
|
||||
const bool isCurrentPageStarred);
|
||||
|
||||
@@ -61,6 +62,8 @@ class EpubReaderMenuActivity final : public MenuListActivity {
|
||||
uint8_t selectedPageTurnOption = 0;
|
||||
int8_t pendingEmbeddedStyleOverride = -1;
|
||||
int8_t pendingImageRenderingOverride = -1;
|
||||
int8_t pendingFontFamilyOverride = -1;
|
||||
int8_t pendingFontSizeOverride = -1;
|
||||
uint8_t pendingTextDarkness = 1;
|
||||
|
||||
static constexpr const char* pageTurnLabels[] = {"", "1", "3", "6", "12"};
|
||||
|
||||
Reference in New Issue
Block a user