mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2025-12-19 15:47:40 +03:00
clang-format-fix
This commit is contained in:
parent
dcf2b257f4
commit
c4430793e7
@ -337,9 +337,7 @@ void Epub::markAsFootnotePage(const std::string& href) {
|
|||||||
|
|
||||||
// Extract filename from href (remove #anchor if present)
|
// Extract filename from href (remove #anchor if present)
|
||||||
size_t hashPos = href.find('#');
|
size_t hashPos = href.find('#');
|
||||||
std::string filename = (hashPos != std::string::npos)
|
std::string filename = (hashPos != std::string::npos) ? href.substr(0, hashPos) : href;
|
||||||
? href.substr(0, hashPos)
|
|
||||||
: href;
|
|
||||||
|
|
||||||
// Extract just the filename without path
|
// Extract just the filename without path
|
||||||
size_t lastSlash = filename.find_last_of('/');
|
size_t lastSlash = filename.find_last_of('/');
|
||||||
@ -356,7 +354,6 @@ bool Epub::isFootnotePage(const std::string& filename) const {
|
|||||||
return footnotePages->find(filename) != footnotePages->end();
|
return footnotePages->find(filename) != footnotePages->end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Epub::shouldHideFromToc(int spineIndex) const {
|
bool Epub::shouldHideFromToc(int spineIndex) const {
|
||||||
// Always hide virtual spine items
|
// Always hide virtual spine items
|
||||||
if (isVirtualSpineItem(spineIndex)) {
|
if (isVirtualSpineItem(spineIndex)) {
|
||||||
@ -371,9 +368,7 @@ bool Epub::shouldHideFromToc(int spineIndex) const {
|
|||||||
|
|
||||||
// Extract filename from spine item
|
// Extract filename from spine item
|
||||||
size_t lastSlash = spineItem.find_last_of('/');
|
size_t lastSlash = spineItem.find_last_of('/');
|
||||||
std::string filename = (lastSlash != std::string::npos)
|
std::string filename = (lastSlash != std::string::npos) ? spineItem.substr(lastSlash + 1) : spineItem;
|
||||||
? spineItem.substr(lastSlash + 1)
|
|
||||||
: spineItem;
|
|
||||||
|
|
||||||
return isFootnotePage(filename);
|
return isFootnotePage(filename);
|
||||||
}
|
}
|
||||||
@ -387,14 +382,11 @@ int Epub::addVirtualSpineItem(const std::string& path) {
|
|||||||
|
|
||||||
virtualSpineItems->push_back(path);
|
virtualSpineItems->push_back(path);
|
||||||
int newIndex = spine.size() + virtualSpineItems->size() - 1;
|
int newIndex = spine.size() + virtualSpineItems->size() - 1;
|
||||||
Serial.printf("[%lu] [EPUB] Added virtual spine item: %s (index %d)\n",
|
Serial.printf("[%lu] [EPUB] Added virtual spine item: %s (index %d)\n", millis(), path.c_str(), newIndex);
|
||||||
millis(), path.c_str(), newIndex);
|
|
||||||
return newIndex;
|
return newIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Epub::isVirtualSpineItem(int spineIndex) const {
|
bool Epub::isVirtualSpineItem(int spineIndex) const { return spineIndex >= static_cast<int>(spine.size()); }
|
||||||
return spineIndex >= static_cast<int>(spine.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
int Epub::findVirtualSpineIndex(const std::string& filename) const {
|
int Epub::findVirtualSpineIndex(const std::string& filename) const {
|
||||||
if (!virtualSpineItems) return -1;
|
if (!virtualSpineItems) return -1;
|
||||||
@ -402,9 +394,7 @@ int Epub::findVirtualSpineIndex(const std::string& filename) const {
|
|||||||
for (size_t i = 0; i < virtualSpineItems->size(); i++) {
|
for (size_t i = 0; i < virtualSpineItems->size(); i++) {
|
||||||
std::string virtualPath = (*virtualSpineItems)[i];
|
std::string virtualPath = (*virtualSpineItems)[i];
|
||||||
size_t lastSlash = virtualPath.find_last_of('/');
|
size_t lastSlash = virtualPath.find_last_of('/');
|
||||||
std::string virtualFilename = (lastSlash != std::string::npos)
|
std::string virtualFilename = (lastSlash != std::string::npos) ? virtualPath.substr(lastSlash + 1) : virtualPath;
|
||||||
? virtualPath.substr(lastSlash + 1)
|
|
||||||
: virtualPath;
|
|
||||||
|
|
||||||
if (virtualFilename == filename) {
|
if (virtualFilename == filename) {
|
||||||
return spine.size() + i;
|
return spine.size() + i;
|
||||||
|
|||||||
@ -30,9 +30,7 @@ class Epub {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Epub(std::string filepath, const std::string& cacheDir)
|
explicit Epub(std::string filepath, const std::string& cacheDir)
|
||||||
: filepath(std::move(filepath)),
|
: filepath(std::move(filepath)), footnotePages(nullptr), virtualSpineItems(nullptr) {
|
||||||
footnotePages(nullptr),
|
|
||||||
virtualSpineItems(nullptr) {
|
|
||||||
cachePath = cacheDir + "/epub_" + std::to_string(std::hash<std::string>{}(this->filepath));
|
cachePath = cacheDir + "/epub_" + std::to_string(std::hash<std::string>{}(this->filepath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
#include "Page.h"
|
#include "Page.h"
|
||||||
|
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
#include <Serialization.h>
|
#include <Serialization.h>
|
||||||
|
|
||||||
constexpr uint8_t PAGE_FILE_VERSION = 6; // Incremented
|
constexpr uint8_t PAGE_FILE_VERSION = 6; // Incremented
|
||||||
|
|
||||||
void PageLine::render(GfxRenderer& renderer, const int fontId) {
|
void PageLine::render(GfxRenderer& renderer, const int fontId) { block->render(renderer, fontId, xPos, yPos); }
|
||||||
block->render(renderer, fontId, xPos, yPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageLine::serialize(std::ostream& os) {
|
void PageLine::serialize(std::ostream& os) {
|
||||||
serialization::writePod(os, xPos);
|
serialization::writePod(os, xPos);
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include "FootnoteEntry.h"
|
#include "FootnoteEntry.h"
|
||||||
#include "blocks/TextBlock.h"
|
#include "blocks/TextBlock.h"
|
||||||
@ -24,7 +24,7 @@ class PageElement {
|
|||||||
class PageLine final : public PageElement {
|
class PageLine final : public PageElement {
|
||||||
std::shared_ptr<TextBlock> block;
|
std::shared_ptr<TextBlock> block;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PageLine(std::shared_ptr<TextBlock> block, const int16_t xPos, const int16_t yPos)
|
PageLine(std::shared_ptr<TextBlock> block, const int16_t xPos, const int16_t yPos)
|
||||||
: PageElement(xPos, yPos), block(std::move(block)) {}
|
: PageElement(xPos, yPos), block(std::move(block)) {}
|
||||||
void render(GfxRenderer& renderer, int fontId) override;
|
void render(GfxRenderer& renderer, int fontId) override;
|
||||||
@ -33,14 +33,14 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Page {
|
class Page {
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<PageElement>* elements;
|
std::shared_ptr<PageElement>* elements;
|
||||||
int elementCapacity;
|
int elementCapacity;
|
||||||
|
|
||||||
FootnoteEntry* footnotes;
|
FootnoteEntry* footnotes;
|
||||||
int footnoteCapacity;
|
int footnoteCapacity;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int elementCount;
|
int elementCount;
|
||||||
int footnoteCount;
|
int footnoteCount;
|
||||||
|
|
||||||
|
|||||||
@ -178,9 +178,9 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
|
|||||||
|
|
||||||
const auto sdPath = "/sd" + localPath;
|
const auto sdPath = "/sd" + localPath;
|
||||||
|
|
||||||
ChapterHtmlSlimParser visitor(sdPath.c_str(), renderer, fontId, lineCompression, marginTop, marginRight,
|
ChapterHtmlSlimParser visitor(
|
||||||
marginBottom, marginLeft, extraParagraphSpacing,
|
sdPath.c_str(), renderer, fontId, lineCompression, marginTop, marginRight, marginBottom, marginLeft,
|
||||||
[this](std::unique_ptr<Page> page) { this->onPageComplete(std::move(page)); },
|
extraParagraphSpacing, [this](std::unique_ptr<Page> page) { this->onPageComplete(std::move(page)); },
|
||||||
cachePath);
|
cachePath);
|
||||||
|
|
||||||
bool success = visitor.parseAndBuildPages();
|
bool success = visitor.parseAndBuildPages();
|
||||||
@ -190,7 +190,8 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCacheMetadata(fontId, lineCompression, marginTop, marginRight, marginBottom, marginLeft, extraParagraphSpacing);
|
writeCacheMetadata(fontId, lineCompression, marginTop, marginRight, marginBottom, marginLeft,
|
||||||
|
extraParagraphSpacing);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,10 +210,9 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
|
|||||||
|
|
||||||
const auto sdTmpHtmlPath = "/sd" + tmpHtmlPath;
|
const auto sdTmpHtmlPath = "/sd" + tmpHtmlPath;
|
||||||
|
|
||||||
ChapterHtmlSlimParser visitor(sdTmpHtmlPath.c_str(), renderer, fontId, lineCompression, marginTop, marginRight,
|
ChapterHtmlSlimParser visitor(
|
||||||
marginBottom, marginLeft, extraParagraphSpacing,
|
sdTmpHtmlPath.c_str(), renderer, fontId, lineCompression, marginTop, marginRight, marginBottom, marginLeft,
|
||||||
[this](std::unique_ptr<Page> page) { this->onPageComplete(std::move(page)); },
|
extraParagraphSpacing, [this](std::unique_ptr<Page> page) { this->onPageComplete(std::move(page)); }, cachePath);
|
||||||
cachePath);
|
|
||||||
|
|
||||||
// Track which inline footnotes AND paragraph notes are actually referenced in this file
|
// Track which inline footnotes AND paragraph notes are actually referenced in this file
|
||||||
std::set<std::string> rewrittenInlineIds;
|
std::set<std::string> rewrittenInlineIds;
|
||||||
@ -232,10 +232,9 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
|
|||||||
if (underscorePos != std::string::npos && dotPos != std::string::npos) {
|
if (underscorePos != std::string::npos && dotPos != std::string::npos) {
|
||||||
std::string noteId = href.substr(underscorePos + 1, dotPos - underscorePos - 1);
|
std::string noteId = href.substr(underscorePos + 1, dotPos - underscorePos - 1);
|
||||||
rewrittenInlineIds.insert(noteId);
|
rewrittenInlineIds.insert(noteId);
|
||||||
Serial.printf("[%lu] [SCT] Marked note as rewritten: %s\n",
|
Serial.printf("[%lu] [SCT] Marked note as rewritten: %s\n", millis(), noteId.c_str());
|
||||||
millis(), noteId.c_str());
|
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
// Normal external footnote
|
// Normal external footnote
|
||||||
epub->markAsFootnotePage(noteref.href);
|
epub->markAsFootnotePage(noteref.href);
|
||||||
}
|
}
|
||||||
@ -254,8 +253,8 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOW generate inline footnote HTML files ONLY for rewritten ones
|
// NOW generate inline footnote HTML files ONLY for rewritten ones
|
||||||
Serial.printf("[%lu] [SCT] Found %d inline footnotes, %d were referenced\n",
|
Serial.printf("[%lu] [SCT] Found %d inline footnotes, %d were referenced\n", millis(), visitor.inlineFootnoteCount,
|
||||||
millis(), visitor.inlineFootnoteCount, rewrittenInlineIds.size());
|
rewrittenInlineIds.size());
|
||||||
|
|
||||||
for (int i = 0; i < visitor.inlineFootnoteCount; i++) {
|
for (int i = 0; i < visitor.inlineFootnoteCount; i++) {
|
||||||
const char* inlineId = visitor.inlineFootnotes[i].id;
|
const char* inlineId = visitor.inlineFootnotes[i].id;
|
||||||
@ -263,8 +262,7 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
|
|||||||
|
|
||||||
// Only generate if this inline footnote was actually referenced
|
// Only generate if this inline footnote was actually referenced
|
||||||
if (rewrittenInlineIds.find(std::string(inlineId)) == rewrittenInlineIds.end()) {
|
if (rewrittenInlineIds.find(std::string(inlineId)) == rewrittenInlineIds.end()) {
|
||||||
Serial.printf("[%lu] [SCT] Skipping unreferenced inline footnote: %s\n",
|
Serial.printf("[%lu] [SCT] Skipping unreferenced inline footnote: %s\n", millis(), inlineId);
|
||||||
millis(), inlineId);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,8 +272,7 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.printf("[%lu] [SCT] Processing inline footnote: %s (len=%d)\n",
|
Serial.printf("[%lu] [SCT] Processing inline footnote: %s (len=%d)\n", millis(), inlineId, strlen(inlineText));
|
||||||
millis(), inlineId, strlen(inlineText));
|
|
||||||
|
|
||||||
char inlineFilename[64];
|
char inlineFilename[64];
|
||||||
snprintf(inlineFilename, sizeof(inlineFilename), "inline_%s.html", inlineId);
|
snprintf(inlineFilename, sizeof(inlineFilename), "inline_%s.html", inlineId);
|
||||||
@ -325,10 +322,10 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate paragraph note HTML files
|
// Generate paragraph note HTML files
|
||||||
Serial.printf("[%lu] [SCT] Found %d paragraph notes\n", millis(), visitor.paragraphNoteCount);
|
Serial.printf("[%lu] [SCT] Found %d paragraph notes\n", millis(), visitor.paragraphNoteCount);
|
||||||
|
|
||||||
for (int i = 0; i < visitor.paragraphNoteCount; i++) {
|
for (int i = 0; i < visitor.paragraphNoteCount; i++) {
|
||||||
const char* pnoteId = visitor.paragraphNotes[i].id;
|
const char* pnoteId = visitor.paragraphNotes[i].id;
|
||||||
const char* pnoteText = visitor.paragraphNotes[i].text;
|
const char* pnoteText = visitor.paragraphNotes[i].text;
|
||||||
|
|
||||||
@ -382,7 +379,7 @@ for (int i = 0; i < visitor.paragraphNoteCount; i++) {
|
|||||||
snprintf(newHref, sizeof(newHref), "%s#%s", pnoteFilename, pnoteId);
|
snprintf(newHref, sizeof(newHref), "%s#%s", pnoteFilename, pnoteId);
|
||||||
epub->markAsFootnotePage(newHref);
|
epub->markAsFootnotePage(newHref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.printf("[%lu] [SCT] Total noterefs found: %d\n", millis(), noterefCount);
|
Serial.printf("[%lu] [SCT] Total noterefs found: %d\n", millis(), noterefCount);
|
||||||
|
|
||||||
|
|||||||
@ -90,7 +90,7 @@ void ChapterHtmlSlimParser::addFootnoteToCurrentPage(const char* number, const c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if we have this as a paragraph note
|
// Check if we have this as a paragraph note
|
||||||
if (!foundInline) {
|
if (!foundInline) {
|
||||||
for (int i = 0; i < paragraphNoteCount; i++) {
|
for (int i = 0; i < paragraphNoteCount; i++) {
|
||||||
if (strcmp(paragraphNotes[i].id, inlineId) == 0) {
|
if (strcmp(paragraphNotes[i].id, inlineId) == 0) {
|
||||||
@ -120,10 +120,9 @@ void ChapterHtmlSlimParser::addFootnoteToCurrentPage(const char* number, const c
|
|||||||
|
|
||||||
currentPageFootnoteCount++;
|
currentPageFootnoteCount++;
|
||||||
|
|
||||||
Serial.printf("[%lu] [ADDFT] Stored as: num=%s, href=%s\n",
|
Serial.printf("[%lu] [ADDFT] Stored as: num=%s, href=%s\n", millis(),
|
||||||
millis(),
|
currentPageFootnotes[currentPageFootnoteCount - 1].number,
|
||||||
currentPageFootnotes[currentPageFootnoteCount-1].number,
|
currentPageFootnotes[currentPageFootnoteCount - 1].href);
|
||||||
currentPageFootnotes[currentPageFootnoteCount-1].href);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* name, const XML_Char** atts) {
|
void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* name, const XML_Char** atts) {
|
||||||
@ -173,8 +172,8 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
if (epubType && strcmp(epubType, "footnote") == 0 && id) {
|
if (epubType && strcmp(epubType, "footnote") == 0 && id) {
|
||||||
if (self->isPass1CollectingAsides) {
|
if (self->isPass1CollectingAsides) {
|
||||||
// Pass 1: Collect aside
|
// Pass 1: Collect aside
|
||||||
Serial.printf("[%lu] [ASIDE] Found inline footnote: id=%s (pass1=%d)\n",
|
Serial.printf("[%lu] [ASIDE] Found inline footnote: id=%s (pass1=%d)\n", millis(), id,
|
||||||
millis(), id, self->isPass1CollectingAsides);
|
self->isPass1CollectingAsides);
|
||||||
|
|
||||||
self->insideAsideFootnote = true;
|
self->insideAsideFootnote = true;
|
||||||
self->asideDepth = self->depth;
|
self->asideDepth = self->depth;
|
||||||
@ -189,8 +188,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
|
|
||||||
// Find the inline footnote text
|
// Find the inline footnote text
|
||||||
for (int i = 0; i < self->inlineFootnoteCount; i++) {
|
for (int i = 0; i < self->inlineFootnoteCount; i++) {
|
||||||
if (strcmp(self->inlineFootnotes[i].id, id) == 0 &&
|
if (strcmp(self->inlineFootnotes[i].id, id) == 0 && self->inlineFootnotes[i].text) {
|
||||||
self->inlineFootnotes[i].text) {
|
|
||||||
// Output the footnote text as normal text
|
// Output the footnote text as normal text
|
||||||
const char* text = self->inlineFootnotes[i].text;
|
const char* text = self->inlineFootnotes[i].text;
|
||||||
int textLen = strlen(text);
|
int textLen = strlen(text);
|
||||||
@ -198,8 +196,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
// Process it through characterData
|
// Process it through characterData
|
||||||
self->characterData(self, text, textLen);
|
self->characterData(self, text, textLen);
|
||||||
|
|
||||||
Serial.printf("[%lu] [ASIDE] Rendered aside text: %.80s...\n",
|
Serial.printf("[%lu] [ASIDE] Rendered aside text: %.80s...\n", millis(), text);
|
||||||
millis(), text);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -332,13 +329,13 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char* s, const int len) {
|
void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char* s, const int len) {
|
||||||
auto* self = static_cast<ChapterHtmlSlimParser*>(userData);
|
auto* self = static_cast<ChapterHtmlSlimParser*>(userData);
|
||||||
|
|
||||||
//Collect paragraph note text in Pass 1
|
// Collect paragraph note text in Pass 1
|
||||||
if (self->insideParagraphNote && self->isPass1CollectingAsides) {
|
if (self->insideParagraphNote && self->isPass1CollectingAsides) {
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
if (self->currentParagraphNoteTextLen >= self->MAX_PNOTE_BUFFER - 2) {
|
if (self->currentParagraphNoteTextLen >= self->MAX_PNOTE_BUFFER - 2) {
|
||||||
if (self->currentParagraphNoteTextLen == self->MAX_PNOTE_BUFFER - 2) {
|
if (self->currentParagraphNoteTextLen == self->MAX_PNOTE_BUFFER - 2) {
|
||||||
Serial.printf("[%lu] [PNOTE] WARNING: Note text truncated at %d chars\n",
|
Serial.printf("[%lu] [PNOTE] WARNING: Note text truncated at %d chars\n", millis(),
|
||||||
millis(), self->MAX_PNOTE_BUFFER - 2);
|
self->MAX_PNOTE_BUFFER - 2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -367,8 +364,8 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char
|
|||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
if (self->currentAsideTextLen >= self->MAX_ASIDE_BUFFER - 2) {
|
if (self->currentAsideTextLen >= self->MAX_ASIDE_BUFFER - 2) {
|
||||||
if (self->currentAsideTextLen == self->MAX_ASIDE_BUFFER - 2) {
|
if (self->currentAsideTextLen == self->MAX_ASIDE_BUFFER - 2) {
|
||||||
Serial.printf("[%lu] [ASIDE] WARNING: Footnote text truncated at %d chars (id=%s)\n",
|
Serial.printf("[%lu] [ASIDE] WARNING: Footnote text truncated at %d chars (id=%s)\n", millis(),
|
||||||
millis(), self->MAX_ASIDE_BUFFER - 2, self->currentAsideId);
|
self->MAX_ASIDE_BUFFER - 2, self->currentAsideId);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -376,8 +373,7 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char
|
|||||||
unsigned char c = (unsigned char)s[i]; // Cast to unsigned char
|
unsigned char c = (unsigned char)s[i]; // Cast to unsigned char
|
||||||
|
|
||||||
if (isWhitespace(c)) {
|
if (isWhitespace(c)) {
|
||||||
if (self->currentAsideTextLen > 0 &&
|
if (self->currentAsideTextLen > 0 && self->currentAsideText[self->currentAsideTextLen - 1] != ' ') {
|
||||||
self->currentAsideText[self->currentAsideTextLen - 1] != ' ') {
|
|
||||||
self->currentAsideText[self->currentAsideTextLen++] = ' ';
|
self->currentAsideText[self->currentAsideTextLen++] = ' ';
|
||||||
}
|
}
|
||||||
} else if (c >= 32 || c >= 0x80) { // Accept printable ASCII AND UTF-8 bytes
|
} else if (c >= 32 || c >= 0x80) { // Accept printable ASCII AND UTF-8 bytes
|
||||||
@ -443,32 +439,23 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char
|
|||||||
void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* name) {
|
void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* name) {
|
||||||
auto* self = static_cast<ChapterHtmlSlimParser*>(userData);
|
auto* self = static_cast<ChapterHtmlSlimParser*>(userData);
|
||||||
|
|
||||||
//Closing paragraph note in Pass 1
|
// Closing paragraph note in Pass 1
|
||||||
if (strcmp(name, "p") == 0 && self->insideParagraphNote &&
|
if (strcmp(name, "p") == 0 && self->insideParagraphNote && self->depth - 1 == self->paragraphNoteDepth) {
|
||||||
self->depth - 1 == self->paragraphNoteDepth) {
|
if (self->isPass1CollectingAsides && self->currentParagraphNoteTextLen > 0 && self->paragraphNoteCount < 32 &&
|
||||||
|
|
||||||
if (self->isPass1CollectingAsides &&
|
|
||||||
self->currentParagraphNoteTextLen > 0 &&
|
|
||||||
self->paragraphNoteCount < 32 &&
|
|
||||||
self->currentParagraphNoteId[0] != '\0') {
|
self->currentParagraphNoteId[0] != '\0') {
|
||||||
|
|
||||||
// Copy ID
|
// Copy ID
|
||||||
strncpy(self->paragraphNotes[self->paragraphNoteCount].id,
|
strncpy(self->paragraphNotes[self->paragraphNoteCount].id, self->currentParagraphNoteId, 15);
|
||||||
self->currentParagraphNoteId, 15);
|
|
||||||
self->paragraphNotes[self->paragraphNoteCount].id[15] = '\0';
|
self->paragraphNotes[self->paragraphNoteCount].id[15] = '\0';
|
||||||
|
|
||||||
// Allocate memory for text
|
// Allocate memory for text
|
||||||
size_t textLen = strlen(self->currentParagraphNoteText);
|
size_t textLen = strlen(self->currentParagraphNoteText);
|
||||||
self->paragraphNotes[self->paragraphNoteCount].text =
|
self->paragraphNotes[self->paragraphNoteCount].text = static_cast<char*>(malloc(textLen + 1));
|
||||||
static_cast<char*>(malloc(textLen + 1));
|
|
||||||
|
|
||||||
if (self->paragraphNotes[self->paragraphNoteCount].text) {
|
if (self->paragraphNotes[self->paragraphNoteCount].text) {
|
||||||
strcpy(self->paragraphNotes[self->paragraphNoteCount].text,
|
strcpy(self->paragraphNotes[self->paragraphNoteCount].text, self->currentParagraphNoteText);
|
||||||
self->currentParagraphNoteText);
|
|
||||||
|
|
||||||
Serial.printf("[%lu] [PNOTE] Stored: %s -> %.80s... (allocated %d bytes)\n",
|
Serial.printf("[%lu] [PNOTE] Stored: %s -> %.80s... (allocated %d bytes)\n", millis(),
|
||||||
millis(), self->currentParagraphNoteId,
|
self->currentParagraphNoteId, self->currentParagraphNoteText, textLen + 1);
|
||||||
self->currentParagraphNoteText, textLen + 1);
|
|
||||||
|
|
||||||
self->paragraphNoteCount++;
|
self->paragraphNoteCount++;
|
||||||
}
|
}
|
||||||
@ -480,35 +467,27 @@ void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* n
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Closing aside - handle differently for Pass 1 vs Pass 2
|
// Closing aside - handle differently for Pass 1 vs Pass 2
|
||||||
if (strcmp(name, "aside") == 0 && self->insideAsideFootnote &&
|
if (strcmp(name, "aside") == 0 && self->insideAsideFootnote && self->depth - 1 == self->asideDepth) {
|
||||||
self->depth - 1 == self->asideDepth) {
|
|
||||||
|
|
||||||
// Store footnote ONLY in Pass 1
|
// Store footnote ONLY in Pass 1
|
||||||
if (self->isPass1CollectingAsides &&
|
if (self->isPass1CollectingAsides && self->currentAsideTextLen > 0 && self->inlineFootnoteCount < 16) {
|
||||||
self->currentAsideTextLen > 0 &&
|
|
||||||
self->inlineFootnoteCount < 16) {
|
|
||||||
|
|
||||||
// Copy ID (max 2 digits)
|
// Copy ID (max 2 digits)
|
||||||
strncpy(self->inlineFootnotes[self->inlineFootnoteCount].id,
|
strncpy(self->inlineFootnotes[self->inlineFootnoteCount].id, self->currentAsideId, 2);
|
||||||
self->currentAsideId, 2);
|
|
||||||
self->inlineFootnotes[self->inlineFootnoteCount].id[2] = '\0';
|
self->inlineFootnotes[self->inlineFootnoteCount].id[2] = '\0';
|
||||||
|
|
||||||
// DYNAMIC ALLOCATION: allocate exactly the needed size + 1
|
// DYNAMIC ALLOCATION: allocate exactly the needed size + 1
|
||||||
size_t textLen = strlen(self->currentAsideText);
|
size_t textLen = strlen(self->currentAsideText);
|
||||||
self->inlineFootnotes[self->inlineFootnoteCount].text =
|
self->inlineFootnotes[self->inlineFootnoteCount].text = static_cast<char*>(malloc(textLen + 1));
|
||||||
static_cast<char*>(malloc(textLen + 1));
|
|
||||||
|
|
||||||
if (self->inlineFootnotes[self->inlineFootnoteCount].text) {
|
if (self->inlineFootnotes[self->inlineFootnoteCount].text) {
|
||||||
strcpy(self->inlineFootnotes[self->inlineFootnoteCount].text,
|
strcpy(self->inlineFootnotes[self->inlineFootnoteCount].text, self->currentAsideText);
|
||||||
self->currentAsideText);
|
|
||||||
|
|
||||||
Serial.printf("[%lu] [ASIDE] Stored: %s -> %.80s... (allocated %d bytes)\n",
|
Serial.printf("[%lu] [ASIDE] Stored: %s -> %.80s... (allocated %d bytes)\n", millis(), self->currentAsideId,
|
||||||
millis(), self->currentAsideId, self->currentAsideText, textLen + 1);
|
self->currentAsideText, textLen + 1);
|
||||||
|
|
||||||
self->inlineFootnoteCount++;
|
self->inlineFootnoteCount++;
|
||||||
} else {
|
} else {
|
||||||
Serial.printf("[%lu] [ASIDE] ERROR: Failed to allocate %d bytes for footnote %s\n",
|
Serial.printf("[%lu] [ASIDE] ERROR: Failed to allocate %d bytes for footnote %s\n", millis(), textLen + 1,
|
||||||
millis(), textLen + 1, self->currentAsideId);
|
self->currentAsideId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,9 +508,7 @@ void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* n
|
|||||||
self->insideNoteref = false;
|
self->insideNoteref = false;
|
||||||
|
|
||||||
if (self->currentNoterefTextLen > 0) {
|
if (self->currentNoterefTextLen > 0) {
|
||||||
Serial.printf("[%lu] [NOTEREF] %s -> %s\n", millis(),
|
Serial.printf("[%lu] [NOTEREF] %s -> %s\n", millis(), self->currentNoterefText, self->currentNoterefHref);
|
||||||
self->currentNoterefText,
|
|
||||||
self->currentNoterefHref);
|
|
||||||
|
|
||||||
// Add footnote first (this does the rewriting)
|
// Add footnote first (this does the rewriting)
|
||||||
self->addFootnoteToCurrentPage(self->currentNoterefText, self->currentNoterefHref);
|
self->addFootnoteToCurrentPage(self->currentNoterefText, self->currentNoterefHref);
|
||||||
@ -668,8 +645,7 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
|||||||
done = feof(file);
|
done = feof(file);
|
||||||
|
|
||||||
if (XML_ParseBuffer(parser1, static_cast<int>(len), done) == XML_STATUS_ERROR) {
|
if (XML_ParseBuffer(parser1, static_cast<int>(len), done) == XML_STATUS_ERROR) {
|
||||||
Serial.printf("[%lu] [EHP] Parse error at line %lu:\n%s\n", millis(),
|
Serial.printf("[%lu] [EHP] Parse error at line %lu:\n%s\n", millis(), XML_GetCurrentLineNumber(parser1),
|
||||||
XML_GetCurrentLineNumber(parser1),
|
|
||||||
XML_ErrorString(XML_GetErrorCode(parser1)));
|
XML_ErrorString(XML_GetErrorCode(parser1)));
|
||||||
XML_ParserFree(parser1);
|
XML_ParserFree(parser1);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
@ -680,11 +656,9 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
|||||||
XML_ParserFree(parser1);
|
XML_ParserFree(parser1);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
Serial.printf("[%lu] [PARSER] Pass 1 complete: found %d inline footnotes\n",
|
Serial.printf("[%lu] [PARSER] Pass 1 complete: found %d inline footnotes\n", millis(), inlineFootnoteCount);
|
||||||
millis(), inlineFootnoteCount);
|
|
||||||
for (int i = 0; i < inlineFootnoteCount; i++) {
|
for (int i = 0; i < inlineFootnoteCount; i++) {
|
||||||
Serial.printf("[%lu] [PARSER] - %s: %.80s\n",
|
Serial.printf("[%lu] [PARSER] - %s: %.80s\n", millis(), inlineFootnotes[i].id, inlineFootnotes[i].text);
|
||||||
millis(), inlineFootnotes[i].id, inlineFootnotes[i].text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -743,8 +717,7 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
|||||||
done = feof(file);
|
done = feof(file);
|
||||||
|
|
||||||
if (XML_ParseBuffer(parser2, static_cast<int>(len), done) == XML_STATUS_ERROR) {
|
if (XML_ParseBuffer(parser2, static_cast<int>(len), done) == XML_STATUS_ERROR) {
|
||||||
Serial.printf("[%lu] [EHP] Parse error at line %lu:\n%s\n", millis(),
|
Serial.printf("[%lu] [EHP] Parse error at line %lu:\n%s\n", millis(), XML_GetCurrentLineNumber(parser2),
|
||||||
XML_GetCurrentLineNumber(parser2),
|
|
||||||
XML_ErrorString(XML_GetErrorCode(parser2)));
|
XML_ErrorString(XML_GetErrorCode(parser2)));
|
||||||
XML_ParserFree(parser2);
|
XML_ParserFree(parser2);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
@ -819,4 +792,3 @@ void ChapterHtmlSlimParser::makePages() {
|
|||||||
currentPageNextY += lineHeight / 2;
|
currentPageNextY += lineHeight / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <expat.h>
|
#include <expat.h>
|
||||||
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "../FootnoteEntry.h"
|
||||||
#include "../ParsedText.h"
|
#include "../ParsedText.h"
|
||||||
#include "../blocks/TextBlock.h"
|
#include "../blocks/TextBlock.h"
|
||||||
#include "../FootnoteEntry.h"
|
|
||||||
|
|
||||||
class Page;
|
class Page;
|
||||||
class GfxRenderer;
|
class GfxRenderer;
|
||||||
@ -25,9 +26,7 @@ struct InlineFootnote {
|
|||||||
char id[3];
|
char id[3];
|
||||||
char* text;
|
char* text;
|
||||||
|
|
||||||
InlineFootnote() : text(nullptr) {
|
InlineFootnote() : text(nullptr) { id[0] = '\0'; }
|
||||||
id[0] = '\0';
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Struct to store collected inline footnotes from <p class="note">
|
// Struct to store collected inline footnotes from <p class="note">
|
||||||
@ -35,9 +34,7 @@ struct ParagraphNote {
|
|||||||
char id[16]; // ID from <a id="rnote1">
|
char id[16]; // ID from <a id="rnote1">
|
||||||
char* text; // Pointer to dynamically allocated text
|
char* text; // Pointer to dynamically allocated text
|
||||||
|
|
||||||
ParagraphNote() : text(nullptr) {
|
ParagraphNote() : text(nullptr) { id[0] = '\0'; }
|
||||||
id[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
~ParagraphNote() {
|
~ParagraphNote() {
|
||||||
if (text) {
|
if (text) {
|
||||||
@ -88,7 +85,7 @@ class ChapterHtmlSlimParser {
|
|||||||
int asideDepth = 0;
|
int asideDepth = 0;
|
||||||
char currentAsideId[3] = {0};
|
char currentAsideId[3] = {0};
|
||||||
|
|
||||||
//Paragraph note tracking
|
// Paragraph note tracking
|
||||||
bool insideParagraphNote = false;
|
bool insideParagraphNote = false;
|
||||||
int paragraphNoteDepth = 0;
|
int paragraphNoteDepth = 0;
|
||||||
char currentParagraphNoteId[16] = {0};
|
char currentParagraphNoteId[16] = {0};
|
||||||
@ -120,7 +117,7 @@ class ChapterHtmlSlimParser {
|
|||||||
// inline footnotes
|
// inline footnotes
|
||||||
InlineFootnote inlineFootnotes[16];
|
InlineFootnote inlineFootnotes[16];
|
||||||
int inlineFootnoteCount = 0;
|
int inlineFootnoteCount = 0;
|
||||||
//paragraph notes
|
// paragraph notes
|
||||||
ParagraphNote paragraphNotes[32];
|
ParagraphNote paragraphNotes[32];
|
||||||
int paragraphNoteCount = 0;
|
int paragraphNoteCount = 0;
|
||||||
|
|
||||||
@ -161,7 +158,5 @@ class ChapterHtmlSlimParser {
|
|||||||
bool parseAndBuildPages();
|
bool parseAndBuildPages();
|
||||||
void addLineToPage(std::shared_ptr<TextBlock> line);
|
void addLineToPage(std::shared_ptr<TextBlock> line);
|
||||||
|
|
||||||
void setNoterefCallback(const std::function<void(Noteref&)>& callback) {
|
void setNoterefCallback(const std::function<void(Noteref&)>& callback) { noterefCallback = callback; }
|
||||||
noterefCallback = callback;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
@ -73,8 +73,8 @@ void EpubReaderChapterSelectionScreen::buildFilteredChapterList() {
|
|||||||
filteredSpineIndices.push_back(i);
|
filteredSpineIndices.push_back(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.printf("[%lu] [CHAP] Filtered chapters: %d out of %d\n",
|
Serial.printf("[%lu] [CHAP] Filtered chapters: %d out of %d\n", millis(), filteredSpineIndices.size(),
|
||||||
millis(), filteredSpineIndices.size(), epub->getSpineItemsCount());
|
epub->getSpineItemsCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EpubReaderChapterSelectionScreen::handleInput() {
|
void EpubReaderChapterSelectionScreen::handleInput() {
|
||||||
|
|||||||
@ -27,7 +27,7 @@ class EpubReaderChapterSelectionScreen final : public Screen {
|
|||||||
void renderScreen();
|
void renderScreen();
|
||||||
void buildFilteredChapterList();
|
void buildFilteredChapterList();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit EpubReaderChapterSelectionScreen(GfxRenderer& renderer, InputManager& inputManager,
|
explicit EpubReaderChapterSelectionScreen(GfxRenderer& renderer, InputManager& inputManager,
|
||||||
const std::shared_ptr<Epub>& epub, const int currentSpineIndex,
|
const std::shared_ptr<Epub>& epub, const int currentSpineIndex,
|
||||||
const std::function<void()>& onGoBack,
|
const std::function<void()>& onGoBack,
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
#include "EpubReaderFootnotesScreen.h"
|
#include "EpubReaderFootnotesScreen.h"
|
||||||
#include "config.h"
|
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
void EpubReaderFootnotesScreen::onEnter() {
|
void EpubReaderFootnotesScreen::onEnter() {
|
||||||
selectedIndex = 0;
|
selectedIndex = 0;
|
||||||
render();
|
render();
|
||||||
@ -20,8 +22,7 @@ void EpubReaderFootnotesScreen::handleInput() {
|
|||||||
if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
|
if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
|
||||||
const FootnoteEntry* entry = footnotes.getEntry(selectedIndex);
|
const FootnoteEntry* entry = footnotes.getEntry(selectedIndex);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
Serial.printf("[%lu] [FNS] Selected footnote: %s -> %s\n",
|
Serial.printf("[%lu] [FNS] Selected footnote: %s -> %s\n", millis(), entry->number, entry->href);
|
||||||
millis(), entry->number, entry->href);
|
|
||||||
|
|
||||||
// Appeler le callback - EpubReaderScreen gère la navigation
|
// Appeler le callback - EpubReaderScreen gère la navigation
|
||||||
onSelectFootnote(entry->href);
|
onSelectFootnote(entry->href);
|
||||||
@ -83,8 +84,7 @@ void EpubReaderFootnotesScreen::render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Instructions at bottom
|
// Instructions at bottom
|
||||||
renderer.drawText(SMALL_FONT_ID, marginLeft,
|
renderer.drawText(SMALL_FONT_ID, marginLeft, GfxRenderer::getScreenHeight() - 40,
|
||||||
GfxRenderer::getScreenHeight() - 40,
|
|
||||||
"UP/DOWN: Select CONFIRM: Go to footnote BACK: Return");
|
"UP/DOWN: Select CONFIRM: Go to footnote BACK: Return");
|
||||||
|
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
|
|||||||
@ -1,16 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Screen.h"
|
#include <cstring>
|
||||||
#include "../../lib/Epub/Epub/FootnoteEntry.h"
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cstring>
|
|
||||||
|
#include "../../lib/Epub/Epub/FootnoteEntry.h"
|
||||||
|
#include "Screen.h"
|
||||||
|
|
||||||
class FootnotesData {
|
class FootnotesData {
|
||||||
private:
|
private:
|
||||||
FootnoteEntry entries[32];
|
FootnoteEntry entries[32];
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FootnotesData() : count(0) {}
|
FootnotesData() : count(0) {}
|
||||||
|
|
||||||
void addFootnote(const char* number, const char* href) {
|
void addFootnote(const char* number, const char* href) {
|
||||||
@ -23,13 +24,9 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() { count = 0; }
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getCount() const {
|
int getCount() const { return count; }
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FootnoteEntry* getEntry(int index) const {
|
const FootnoteEntry* getEntry(int index) const {
|
||||||
if (index >= 0 && index < count) {
|
if (index >= 0 && index < count) {
|
||||||
@ -45,11 +42,8 @@ class EpubReaderFootnotesScreen final : public Screen {
|
|||||||
const std::function<void(const char*)> onSelectFootnote;
|
const std::function<void(const char*)> onSelectFootnote;
|
||||||
int selectedIndex;
|
int selectedIndex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EpubReaderFootnotesScreen(
|
EpubReaderFootnotesScreen(GfxRenderer& renderer, InputManager& inputManager, const FootnotesData& footnotes,
|
||||||
GfxRenderer& renderer,
|
|
||||||
InputManager& inputManager,
|
|
||||||
const FootnotesData& footnotes,
|
|
||||||
const std::function<void()>& onGoBack,
|
const std::function<void()>& onGoBack,
|
||||||
const std::function<void(const char*)>& onSelectFootnote)
|
const std::function<void(const char*)>& onSelectFootnote)
|
||||||
: Screen(renderer, inputManager),
|
: Screen(renderer, inputManager),
|
||||||
@ -62,6 +56,6 @@ public:
|
|||||||
void onExit() override;
|
void onExit() override;
|
||||||
void handleInput() override;
|
void handleInput() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void render();
|
void render();
|
||||||
};
|
};
|
||||||
@ -2,7 +2,9 @@
|
|||||||
// Created by jlaunay on 13/12/2025.
|
// Created by jlaunay on 13/12/2025.
|
||||||
//
|
//
|
||||||
#include "EpubReaderMenuScreen.h"
|
#include "EpubReaderMenuScreen.h"
|
||||||
|
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
constexpr int MENU_ITEMS_COUNT = 2;
|
constexpr int MENU_ITEMS_COUNT = 2;
|
||||||
@ -74,10 +76,7 @@ void EpubReaderMenuScreen::renderScreen() {
|
|||||||
const auto pageWidth = renderer.getScreenWidth();
|
const auto pageWidth = renderer.getScreenWidth();
|
||||||
renderer.drawCenteredText(READER_FONT_ID, 10, "Menu", true, BOLD);
|
renderer.drawCenteredText(READER_FONT_ID, 10, "Menu", true, BOLD);
|
||||||
|
|
||||||
const char* menuItems[MENU_ITEMS_COUNT] = {
|
const char* menuItems[MENU_ITEMS_COUNT] = {"Go to chapter", "View footnotes"};
|
||||||
"Go to chapter",
|
|
||||||
"View footnotes"
|
|
||||||
};
|
|
||||||
|
|
||||||
const int startY = 100;
|
const int startY = 100;
|
||||||
const int itemHeight = 40;
|
const int itemHeight = 40;
|
||||||
|
|||||||
@ -12,13 +12,10 @@
|
|||||||
#include "Screen.h"
|
#include "Screen.h"
|
||||||
|
|
||||||
class EpubReaderMenuScreen final : public Screen {
|
class EpubReaderMenuScreen final : public Screen {
|
||||||
public:
|
public:
|
||||||
enum MenuOption {
|
enum MenuOption { CHAPTERS, FOOTNOTES };
|
||||||
CHAPTERS,
|
|
||||||
FOOTNOTES
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TaskHandle_t displayTaskHandle = nullptr;
|
TaskHandle_t displayTaskHandle = nullptr;
|
||||||
SemaphoreHandle_t renderingMutex = nullptr;
|
SemaphoreHandle_t renderingMutex = nullptr;
|
||||||
int selectorIndex = 0;
|
int selectorIndex = 0;
|
||||||
@ -30,13 +27,11 @@ private:
|
|||||||
[[noreturn]] void displayTaskLoop();
|
[[noreturn]] void displayTaskLoop();
|
||||||
void renderScreen();
|
void renderScreen();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit EpubReaderMenuScreen(GfxRenderer& renderer, InputManager& inputManager,
|
explicit EpubReaderMenuScreen(GfxRenderer& renderer, InputManager& inputManager,
|
||||||
const std::function<void()>& onGoBack,
|
const std::function<void()>& onGoBack,
|
||||||
const std::function<void(MenuOption option)>& onSelectOption)
|
const std::function<void(MenuOption option)>& onSelectOption)
|
||||||
: Screen(renderer, inputManager),
|
: Screen(renderer, inputManager), onGoBack(onGoBack), onSelectOption(onSelectOption) {}
|
||||||
onGoBack(onGoBack),
|
|
||||||
onSelectOption(onSelectOption) {}
|
|
||||||
|
|
||||||
void onEnter() override;
|
void onEnter() override;
|
||||||
void onExit() override;
|
void onExit() override;
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#include "EpubReaderScreen.h"
|
#include "EpubReaderScreen.h"
|
||||||
|
|
||||||
#include "EpubReaderFootnotesScreen.h"
|
|
||||||
#include <Epub/Page.h>
|
#include <Epub/Page.h>
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <SD.h>
|
#include <SD.h>
|
||||||
@ -8,6 +7,7 @@
|
|||||||
#include "Battery.h"
|
#include "Battery.h"
|
||||||
#include "CrossPointSettings.h"
|
#include "CrossPointSettings.h"
|
||||||
#include "EpubReaderChapterSelectionScreen.h"
|
#include "EpubReaderChapterSelectionScreen.h"
|
||||||
|
#include "EpubReaderFootnotesScreen.h"
|
||||||
#include "EpubReaderMenuScreen.h"
|
#include "EpubReaderMenuScreen.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@ -46,11 +46,8 @@ void EpubReaderScreen::onEnter() {
|
|||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
|
|
||||||
xTaskCreate(&EpubReaderScreen::taskTrampoline, "EpubReaderScreenTask",
|
xTaskCreate(&EpubReaderScreen::taskTrampoline, "EpubReaderScreenTask",
|
||||||
24576, //32768
|
24576, // 32768
|
||||||
this,
|
this, 1, &displayTaskHandle);
|
||||||
1,
|
|
||||||
&displayTaskHandle
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EpubReaderScreen::onExit() {
|
void EpubReaderScreen::onExit() {
|
||||||
@ -126,8 +123,7 @@ void EpubReaderScreen::handleInput() {
|
|||||||
subScreen->onExit();
|
subScreen->onExit();
|
||||||
|
|
||||||
subScreen.reset(new EpubReaderFootnotesScreen(
|
subScreen.reset(new EpubReaderFootnotesScreen(
|
||||||
this->renderer,
|
this->renderer, this->inputManager,
|
||||||
this->inputManager,
|
|
||||||
currentPageFootnotes, // Pass collected footnotes (reference)
|
currentPageFootnotes, // Pass collected footnotes (reference)
|
||||||
[this] {
|
[this] {
|
||||||
// onGoBack from footnotes
|
// onGoBack from footnotes
|
||||||
@ -460,8 +456,7 @@ void EpubReaderScreen::navigateToHref(const char* href, bool savePosition) {
|
|||||||
savedSpineIndex = currentSpineIndex;
|
savedSpineIndex = currentSpineIndex;
|
||||||
savedPageNumber = section->currentPage;
|
savedPageNumber = section->currentPage;
|
||||||
isViewingFootnote = true;
|
isViewingFootnote = true;
|
||||||
Serial.printf("[%lu] [ERS] Saved position: spine %d, page %d\n",
|
Serial.printf("[%lu] [ERS] Saved position: spine %d, page %d\n", millis(), savedSpineIndex, savedPageNumber);
|
||||||
millis(), savedSpineIndex, savedPageNumber);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse href: "filename.html#anchor"
|
// Parse href: "filename.html#anchor"
|
||||||
@ -483,8 +478,7 @@ void EpubReaderScreen::navigateToHref(const char* href, bool savePosition) {
|
|||||||
filename = filename.substr(lastSlash + 1);
|
filename = filename.substr(lastSlash + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.printf("[%lu] [ERS] Navigate to: %s (anchor: %s)\n",
|
Serial.printf("[%lu] [ERS] Navigate to: %s (anchor: %s)\n", millis(), filename.c_str(), anchor.c_str());
|
||||||
millis(), filename.c_str(), anchor.c_str());
|
|
||||||
|
|
||||||
int targetSpineIndex = -1;
|
int targetSpineIndex = -1;
|
||||||
|
|
||||||
@ -492,23 +486,20 @@ void EpubReaderScreen::navigateToHref(const char* href, bool savePosition) {
|
|||||||
if (!anchor.empty()) {
|
if (!anchor.empty()) {
|
||||||
// Try inline footnote first
|
// Try inline footnote first
|
||||||
std::string inlineFilename = "inline_" + anchor + ".html";
|
std::string inlineFilename = "inline_" + anchor + ".html";
|
||||||
Serial.printf("[%lu] [ERS] Looking for inline footnote: %s\n",
|
Serial.printf("[%lu] [ERS] Looking for inline footnote: %s\n", millis(), inlineFilename.c_str());
|
||||||
millis(), inlineFilename.c_str());
|
|
||||||
|
|
||||||
targetSpineIndex = epub->findVirtualSpineIndex(inlineFilename);
|
targetSpineIndex = epub->findVirtualSpineIndex(inlineFilename);
|
||||||
|
|
||||||
// If not found, try paragraph note
|
// If not found, try paragraph note
|
||||||
if (targetSpineIndex == -1) {
|
if (targetSpineIndex == -1) {
|
||||||
std::string pnoteFilename = "pnote_" + anchor + ".html";
|
std::string pnoteFilename = "pnote_" + anchor + ".html";
|
||||||
Serial.printf("[%lu] [ERS] Looking for paragraph note: %s\n",
|
Serial.printf("[%lu] [ERS] Looking for paragraph note: %s\n", millis(), pnoteFilename.c_str());
|
||||||
millis(), pnoteFilename.c_str());
|
|
||||||
|
|
||||||
targetSpineIndex = epub->findVirtualSpineIndex(pnoteFilename);
|
targetSpineIndex = epub->findVirtualSpineIndex(pnoteFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetSpineIndex != -1) {
|
if (targetSpineIndex != -1) {
|
||||||
Serial.printf("[%lu] [ERS] Found note at virtual index: %d\n",
|
Serial.printf("[%lu] [ERS] Found note at virtual index: %d\n", millis(), targetSpineIndex);
|
||||||
millis(), targetSpineIndex);
|
|
||||||
|
|
||||||
// Navigate to the note
|
// Navigate to the note
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
@ -520,8 +511,7 @@ void EpubReaderScreen::navigateToHref(const char* href, bool savePosition) {
|
|||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
Serial.printf("[%lu] [ERS] No virtual note found, trying normal navigation\n",
|
Serial.printf("[%lu] [ERS] No virtual note found, trying normal navigation\n", millis());
|
||||||
millis());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,9 +521,7 @@ void EpubReaderScreen::navigateToHref(const char* href, bool savePosition) {
|
|||||||
|
|
||||||
std::string spineItem = epub->getSpineItem(i);
|
std::string spineItem = epub->getSpineItem(i);
|
||||||
size_t lastSlash = spineItem.find_last_of('/');
|
size_t lastSlash = spineItem.find_last_of('/');
|
||||||
std::string spineFilename = (lastSlash != std::string::npos)
|
std::string spineFilename = (lastSlash != std::string::npos) ? spineItem.substr(lastSlash + 1) : spineItem;
|
||||||
? spineItem.substr(lastSlash + 1)
|
|
||||||
: spineItem;
|
|
||||||
|
|
||||||
if (spineFilename == filename) {
|
if (spineFilename == filename) {
|
||||||
targetSpineIndex = i;
|
targetSpineIndex = i;
|
||||||
@ -542,8 +530,7 @@ void EpubReaderScreen::navigateToHref(const char* href, bool savePosition) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (targetSpineIndex == -1) {
|
if (targetSpineIndex == -1) {
|
||||||
Serial.printf("[%lu] [ERS] Could not find spine index for: %s\n",
|
Serial.printf("[%lu] [ERS] Could not find spine index for: %s\n", millis(), filename.c_str());
|
||||||
millis(), filename.c_str());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,15 +543,13 @@ void EpubReaderScreen::navigateToHref(const char* href, bool savePosition) {
|
|||||||
|
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
|
|
||||||
Serial.printf("[%lu] [ERS] Navigated to spine index: %d\n",
|
Serial.printf("[%lu] [ERS] Navigated to spine index: %d\n", millis(), targetSpineIndex);
|
||||||
millis(), targetSpineIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to restore saved position
|
// Method to restore saved position
|
||||||
void EpubReaderScreen::restoreSavedPosition() {
|
void EpubReaderScreen::restoreSavedPosition() {
|
||||||
if (savedSpineIndex >= 0 && savedPageNumber >= 0) {
|
if (savedSpineIndex >= 0 && savedPageNumber >= 0) {
|
||||||
Serial.printf("[%lu] [ERS] Restoring position: spine %d, page %d\n",
|
Serial.printf("[%lu] [ERS] Restoring position: spine %d, page %d\n", millis(), savedSpineIndex, savedPageNumber);
|
||||||
millis(), savedSpineIndex, savedPageNumber);
|
|
||||||
|
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
currentSpineIndex = savedSpineIndex;
|
currentSpineIndex = savedSpineIndex;
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
#include <freertos/FreeRTOS.h>
|
#include <freertos/FreeRTOS.h>
|
||||||
#include <freertos/semphr.h>
|
#include <freertos/semphr.h>
|
||||||
#include <freertos/task.h>
|
#include <freertos/task.h>
|
||||||
#include "EpubReaderFootnotesScreen.h"
|
|
||||||
|
|
||||||
|
#include "EpubReaderFootnotesScreen.h"
|
||||||
#include "Screen.h"
|
#include "Screen.h"
|
||||||
|
|
||||||
class EpubReaderScreen final : public Screen {
|
class EpubReaderScreen final : public Screen {
|
||||||
@ -35,7 +35,7 @@ class EpubReaderScreen final : public Screen {
|
|||||||
void navigateToHref(const char* href, bool savePosition = false);
|
void navigateToHref(const char* href, bool savePosition = false);
|
||||||
void restoreSavedPosition();
|
void restoreSavedPosition();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit EpubReaderScreen(GfxRenderer& renderer, InputManager& inputManager, std::unique_ptr<Epub> epub,
|
explicit EpubReaderScreen(GfxRenderer& renderer, InputManager& inputManager, std::unique_ptr<Epub> epub,
|
||||||
const std::function<void()>& onGoBack)
|
const std::function<void()>& onGoBack)
|
||||||
: Screen(renderer, inputManager), epub(std::move(epub)), onGoBack(onGoBack) {}
|
: Screen(renderer, inputManager), epub(std::move(epub)), onGoBack(onGoBack) {}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user