Wrap up multiple font styles into EpdFontFamily

This commit is contained in:
Dave Allie 2025-12-06 00:34:16 +11:00
parent fa0f27df6a
commit 05a027e2bf
No known key found for this signature in database
GPG Key ID: F2FDDB3AD8D0276F
13 changed files with 184 additions and 129 deletions

View File

@ -0,0 +1,37 @@
#include "EpdFontFamily.h"
const EpdFont* EpdFontFamily::getFont(const EpdFontStyle style) const {
if (style == BOLD && bold) {
return bold;
}
if (style == ITALIC && italic) {
return italic;
}
if (style == BOLD_ITALIC) {
if (boldItalic) {
return boldItalic;
}
if (bold) {
return bold;
}
if (italic) {
return italic;
}
}
return regular;
}
void EpdFontFamily::getTextDimensions(const char* string, int* w, int* h, const EpdFontStyle style) const {
getFont(style)->getTextDimensions(string, w, h);
}
bool EpdFontFamily::hasPrintableChars(const char* string, const EpdFontStyle style) const {
return getFont(style)->hasPrintableChars(string);
}
const EpdFontData* EpdFontFamily::getData(const EpdFontStyle style) const { return getFont(style)->data; }
const EpdGlyph* EpdFontFamily::getGlyph(const uint32_t cp, const EpdFontStyle style) const {
return getFont(style)->getGlyph(cp);
};

View File

@ -0,0 +1,24 @@
#pragma once
#include "EpdFont.h"
enum EpdFontStyle { REGULAR, BOLD, ITALIC, BOLD_ITALIC };
class EpdFontFamily {
const EpdFont* regular;
const EpdFont* bold;
const EpdFont* italic;
const EpdFont* boldItalic;
const EpdFont* getFont(EpdFontStyle style) const;
public:
explicit EpdFontFamily(const EpdFont* regular, const EpdFont* bold = nullptr, const EpdFont* italic = nullptr,
const EpdFont* boldItalic = nullptr)
: regular(regular), bold(bold), italic(italic), boldItalic(boldItalic) {}
~EpdFontFamily() = default;
void getTextDimensions(const char* string, int* w, int* h, EpdFontStyle style = REGULAR) const;
bool hasPrintableChars(const char* string, EpdFontStyle style = REGULAR) const;
const EpdFontData* getData(EpdFontStyle style = REGULAR) const;
const EpdGlyph* getGlyph(uint32_t cp, EpdFontStyle style = REGULAR) const;
};

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <EpdFont.h> #include <EpdFontFamily.h>
#include <HardwareSerial.h> #include <HardwareSerial.h>
#include <Utf8.h> #include <Utf8.h>
#include <miniz.h> #include <miniz.h>
@ -12,13 +12,14 @@ static tinfl_decompressor decomp;
template <typename Renderable> template <typename Renderable>
class EpdFontRenderer { class EpdFontRenderer {
Renderable* renderer; Renderable* renderer;
void renderChar(uint32_t cp, int* x, const int* y, uint16_t color); void renderChar(uint32_t cp, int* x, const int* y, uint16_t color, EpdFontStyle style = REGULAR);
public: public:
const EpdFont* font; const EpdFontFamily* fontFamily;
explicit EpdFontRenderer(const EpdFont* font, Renderable* renderer); explicit EpdFontRenderer(const EpdFontFamily* fontFamily, Renderable* renderer)
: fontFamily(fontFamily), renderer(renderer) {}
~EpdFontRenderer() = default; ~EpdFontRenderer() = default;
void renderString(const char* string, int* x, int* y, uint16_t color); void renderString(const char* string, int* x, int* y, uint16_t color, EpdFontStyle style = REGULAR);
}; };
inline int uncompress(uint8_t* dest, size_t uncompressedSize, const uint8_t* source, size_t sourceSize) { inline int uncompress(uint8_t* dest, size_t uncompressedSize, const uint8_t* source, size_t sourceSize) {
@ -38,37 +39,33 @@ inline int uncompress(uint8_t* dest, size_t uncompressedSize, const uint8_t* sou
} }
template <typename Renderable> template <typename Renderable>
EpdFontRenderer<Renderable>::EpdFontRenderer(const EpdFont* font, Renderable* renderer) { void EpdFontRenderer<Renderable>::renderString(const char* string, int* x, int* y, const uint16_t color,
this->font = font; const EpdFontStyle style) {
this->renderer = renderer;
}
template <typename Renderable>
void EpdFontRenderer<Renderable>::renderString(const char* string, int* x, int* y, const uint16_t color) {
// cannot draw a NULL / empty string // cannot draw a NULL / empty string
if (string == nullptr || *string == '\0') { if (string == nullptr || *string == '\0') {
return; return;
} }
// no printable characters // no printable characters
if (!font->hasPrintableChars(string)) { if (!fontFamily->hasPrintableChars(string, style)) {
return; return;
} }
uint32_t cp; uint32_t cp;
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&string)))) { while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&string)))) {
renderChar(cp, x, y, color); renderChar(cp, x, y, color, style);
} }
*y += font->data->advanceY; *y += fontFamily->getData(style)->advanceY;
} }
template <typename Renderable> template <typename Renderable>
void EpdFontRenderer<Renderable>::renderChar(const uint32_t cp, int* x, const int* y, uint16_t color) { void EpdFontRenderer<Renderable>::renderChar(const uint32_t cp, int* x, const int* y, uint16_t color,
const EpdGlyph* glyph = font->getGlyph(cp); const EpdFontStyle style) {
const EpdGlyph* glyph = fontFamily->getGlyph(cp, style);
if (!glyph) { if (!glyph) {
// TODO: Replace with fallback glyph property? // TODO: Replace with fallback glyph property?
glyph = font->getGlyph('?'); glyph = fontFamily->getGlyph('?', style);
} }
// no glyph? // no glyph?
@ -86,17 +83,17 @@ void EpdFontRenderer<Renderable>::renderChar(const uint32_t cp, int* x, const in
const unsigned long bitmapSize = byteWidth * height; const unsigned long bitmapSize = byteWidth * height;
const uint8_t* bitmap = nullptr; const uint8_t* bitmap = nullptr;
if (font->data->compressed) { if (fontFamily->getData(style)->compressed) {
auto* tmpBitmap = static_cast<uint8_t*>(malloc(bitmapSize)); auto* tmpBitmap = static_cast<uint8_t*>(malloc(bitmapSize));
if (tmpBitmap == nullptr && bitmapSize) { if (tmpBitmap == nullptr && bitmapSize) {
Serial.println("Failed to allocate memory for decompression buffer"); Serial.println("Failed to allocate memory for decompression buffer");
return; return;
} }
uncompress(tmpBitmap, bitmapSize, &font->data->bitmap[offset], glyph->compressedSize); uncompress(tmpBitmap, bitmapSize, &fontFamily->getData(style)->bitmap[offset], glyph->compressedSize);
bitmap = tmpBitmap; bitmap = tmpBitmap;
} else { } else {
bitmap = &font->data->bitmap[offset]; bitmap = &fontFamily->getData(style)->bitmap[offset];
} }
if (bitmap != nullptr) { if (bitmap != nullptr) {
@ -123,7 +120,7 @@ void EpdFontRenderer<Renderable>::renderChar(const uint32_t cp, int* x, const in
} }
} }
if (font->data->compressed) { if (fontFamily->getData(style)->compressed) {
free(const_cast<uint8_t*>(bitmap)); free(const_cast<uint8_t*>(bitmap));
} }
} }

View File

@ -7,12 +7,13 @@
#include "builtinFonts/bookerly_italic.h" #include "builtinFonts/bookerly_italic.h"
EpdRenderer::EpdRenderer(XteinkDisplay* display) { EpdRenderer::EpdRenderer(XteinkDisplay* display) {
const auto bookerlyFontFamily = new EpdFontFamily(new EpdFont(&bookerly), new EpdFont(&bookerly_bold),
new EpdFont(&bookerly_italic), new EpdFont(&bookerly_bold_italic));
const auto babyblueFontFamily = new EpdFontFamily(new EpdFont(&babyblue));
this->display = display; this->display = display;
this->regularFont = new EpdFontRenderer<XteinkDisplay>(new EpdFont(&bookerly), display); this->regularFontRenderer = new EpdFontRenderer<XteinkDisplay>(bookerlyFontFamily, display);
this->boldFont = new EpdFontRenderer<XteinkDisplay>(new EpdFont(&bookerly_bold), display); this->smallFontRenderer = new EpdFontRenderer<XteinkDisplay>(babyblueFontFamily, display);
this->italicFont = new EpdFontRenderer<XteinkDisplay>(new EpdFont(&bookerly_italic), display);
this->bold_italicFont = new EpdFontRenderer<XteinkDisplay>(new EpdFont(&bookerly_bold_italic), display);
this->smallFont = new EpdFontRenderer<XteinkDisplay>(new EpdFont(&babyblue), display);
this->marginTop = 11; this->marginTop = 11;
this->marginBottom = 30; this->marginBottom = 30;
@ -21,50 +22,38 @@ EpdRenderer::EpdRenderer(XteinkDisplay* display) {
this->lineCompression = 0.95f; this->lineCompression = 0.95f;
} }
EpdFontRenderer<XteinkDisplay>* EpdRenderer::getFontRenderer(const bool bold, const bool italic) const { int EpdRenderer::getTextWidth(const char* text, const EpdFontStyle style) const {
if (bold && italic) {
return bold_italicFont;
}
if (bold) {
return boldFont;
}
if (italic) {
return italicFont;
}
return regularFont;
}
int EpdRenderer::getTextWidth(const char* text, const bool bold, const bool italic) const {
int w = 0, h = 0; int w = 0, h = 0;
getFontRenderer(bold, italic)->font->getTextDimensions(text, &w, &h); regularFontRenderer->fontFamily->getTextDimensions(text, &w, &h, style);
return w; return w;
} }
int EpdRenderer::getSmallTextWidth(const char* text) const { int EpdRenderer::getSmallTextWidth(const char* text, const EpdFontStyle style) const {
int w = 0, h = 0; int w = 0, h = 0;
smallFont->font->getTextDimensions(text, &w, &h); smallFontRenderer->fontFamily->getTextDimensions(text, &w, &h, style);
return w; return w;
} }
void EpdRenderer::drawText(const int x, const int y, const char* text, const bool bold, const bool italic, void EpdRenderer::drawText(const int x, const int y, const char* text, const uint16_t color,
const uint16_t color) const { const EpdFontStyle style) const {
int ypos = y + getLineHeight() + marginTop; int ypos = y + getLineHeight() + marginTop;
int xpos = x + marginLeft; int xpos = x + marginLeft;
getFontRenderer(bold, italic)->renderString(text, &xpos, &ypos, color > 0 ? GxEPD_BLACK : GxEPD_WHITE); regularFontRenderer->renderString(text, &xpos, &ypos, color > 0 ? GxEPD_BLACK : GxEPD_WHITE, style);
} }
void EpdRenderer::drawSmallText(const int x, const int y, const char* text, const uint16_t color) const { void EpdRenderer::drawSmallText(const int x, const int y, const char* text, const uint16_t color,
int ypos = y + smallFont->font->data->advanceY + marginTop; const EpdFontStyle style) const {
int ypos = y + smallFontRenderer->fontFamily->getData(style)->advanceY + marginTop;
int xpos = x + marginLeft; int xpos = x + marginLeft;
smallFont->renderString(text, &xpos, &ypos, color > 0 ? GxEPD_BLACK : GxEPD_WHITE); smallFontRenderer->renderString(text, &xpos, &ypos, color > 0 ? GxEPD_BLACK : GxEPD_WHITE);
} }
void EpdRenderer::drawTextBox(const int x, const int y, const std::string& text, const int width, const int height, void EpdRenderer::drawTextBox(const int x, const int y, const std::string& text, const int width, const int height,
const bool bold, const bool italic) const { const EpdFontStyle style) const {
const size_t length = text.length(); const size_t length = text.length();
// fit the text into the box // fit the text into the box
int start = 0; int start = 0;
@ -72,7 +61,7 @@ void EpdRenderer::drawTextBox(const int x, const int y, const std::string& text,
int ypos = 0; int ypos = 0;
while (true) { while (true) {
if (end >= length) { if (end >= length) {
drawText(x, y + ypos, text.substr(start, length - start).c_str(), bold, italic); drawText(x, y + ypos, text.substr(start, length - start).c_str(), 1, style);
break; break;
} }
@ -81,15 +70,15 @@ void EpdRenderer::drawTextBox(const int x, const int y, const std::string& text,
} }
if (text[end - 1] == '\n') { if (text[end - 1] == '\n') {
drawText(x, y + ypos, text.substr(start, end - start).c_str(), bold, italic); drawText(x, y + ypos, text.substr(start, end - start).c_str(), 1, style);
ypos += getLineHeight(); ypos += getLineHeight();
start = end; start = end;
end = start + 1; end = start + 1;
continue; continue;
} }
if (getTextWidth(text.substr(start, end - start).c_str(), bold, italic) > width) { if (getTextWidth(text.substr(start, end - start).c_str(), style) > width) {
drawText(x, y + ypos, text.substr(start, end - start - 1).c_str(), bold, italic); drawText(x, y + ypos, text.substr(start, end - start - 1).c_str(), 1, style);
ypos += getLineHeight(); ypos += getLineHeight();
start = end - 1; start = end - 1;
continue; continue;
@ -108,11 +97,23 @@ void EpdRenderer::drawRect(const int x, const int y, const int width, const int
display->drawRect(x + marginLeft, y + marginTop, width, height, color > 0 ? GxEPD_BLACK : GxEPD_WHITE); display->drawRect(x + marginLeft, y + marginTop, width, height, color > 0 ? GxEPD_BLACK : GxEPD_WHITE);
} }
void EpdRenderer::fillRect(const int x, const int y, const int width, const int height, void EpdRenderer::fillRect(const int x, const int y, const int width, const int height, const uint16_t color) const {
const uint16_t color = 0) const {
display->fillRect(x + marginLeft, y + marginTop, width, height, color > 0 ? GxEPD_BLACK : GxEPD_WHITE); display->fillRect(x + marginLeft, y + marginTop, width, height, color > 0 ? GxEPD_BLACK : GxEPD_WHITE);
} }
void EpdRenderer::drawCircle(const int x, const int y, const int radius, const uint16_t color) const {
display->drawCircle(x + marginLeft, y + marginTop, radius, color > 0 ? GxEPD_BLACK : GxEPD_WHITE);
}
void EpdRenderer::fillCircle(const int x, const int y, const int radius, const uint16_t color) const {
display->fillCircle(x + marginLeft, y + marginTop, radius, color > 0 ? GxEPD_BLACK : GxEPD_WHITE);
}
void EpdRenderer::drawImage(const uint8_t bitmap[], const int x, const int y, const int width, const int height,
const bool invert) const {
display->drawImage(bitmap, x + marginLeft, y + marginTop, width, height, invert);
}
void EpdRenderer::clearScreen(const bool black) const { void EpdRenderer::clearScreen(const bool black) const {
Serial.println("Clearing screen"); Serial.println("Clearing screen");
display->fillScreen(black ? GxEPD_BLACK : GxEPD_WHITE); display->fillScreen(black ? GxEPD_BLACK : GxEPD_WHITE);
@ -121,30 +122,15 @@ void EpdRenderer::clearScreen(const bool black) const {
void EpdRenderer::flushDisplay(const bool partialUpdate) const { display->display(partialUpdate); } void EpdRenderer::flushDisplay(const bool partialUpdate) const { display->display(partialUpdate); }
void EpdRenderer::flushArea(const int x, const int y, const int width, const int height) const { void EpdRenderer::flushArea(const int x, const int y, const int width, const int height) const {
display->displayWindow(x, y, width, height); display->displayWindow(x + marginLeft, y + marginTop, width, height);
} }
int EpdRenderer::getPageWidth() const { return display->width() - marginLeft - marginRight; } int EpdRenderer::getPageWidth() const { return display->width() - marginLeft - marginRight; }
int EpdRenderer::getPageHeight() const { return display->height() - marginTop - marginBottom; } int EpdRenderer::getPageHeight() const { return display->height() - marginTop - marginBottom; }
int EpdRenderer::getSpaceWidth() const { return regularFont->font->getGlyph(' ')->advanceX; } int EpdRenderer::getSpaceWidth() const { return regularFontRenderer->fontFamily->getGlyph(' ', REGULAR)->advanceX; }
int EpdRenderer::getLineHeight() const { return regularFont->font->data->advanceY * lineCompression; } int EpdRenderer::getLineHeight() const {
return regularFontRenderer->fontFamily->getData(REGULAR)->advanceY * lineCompression;
// deep sleep helper - persist any state to disk that may be needed on wake }
bool EpdRenderer::dehydrate() {
// TODO: Implement
return false;
};
// deep sleep helper - retrieve any state from disk after wake
bool EpdRenderer::hydrate() {
// TODO: Implement
return false;
};
// really really clear the screen
void EpdRenderer::reset() {
// TODO: Implement
};

View File

@ -8,30 +8,28 @@
class EpdRenderer { class EpdRenderer {
XteinkDisplay* display; XteinkDisplay* display;
EpdFontRenderer<XteinkDisplay>* regularFont; EpdFontRenderer<XteinkDisplay>* regularFontRenderer;
EpdFontRenderer<XteinkDisplay>* boldFont; EpdFontRenderer<XteinkDisplay>* smallFontRenderer;
EpdFontRenderer<XteinkDisplay>* italicFont;
EpdFontRenderer<XteinkDisplay>* bold_italicFont;
EpdFontRenderer<XteinkDisplay>* smallFont;
int marginTop; int marginTop;
int marginBottom; int marginBottom;
int marginLeft; int marginLeft;
int marginRight; int marginRight;
float lineCompression; float lineCompression;
EpdFontRenderer<XteinkDisplay>* getFontRenderer(bool bold, bool italic) const;
public: public:
explicit EpdRenderer(XteinkDisplay* display); explicit EpdRenderer(XteinkDisplay* display);
~EpdRenderer() = default; ~EpdRenderer() = default;
int getTextWidth(const char* text, bool bold = false, bool italic = false) const; int getTextWidth(const char* text, EpdFontStyle style = REGULAR) const;
int getSmallTextWidth(const char* text) const; int getSmallTextWidth(const char* text, EpdFontStyle style = REGULAR) const;
void drawText(int x, int y, const char* text, bool bold = false, bool italic = false, uint16_t color = 1) const; void drawText(int x, int y, const char* text, uint16_t color = 1, EpdFontStyle style = REGULAR) const;
void drawSmallText(int x, int y, const char* text, uint16_t color = 1) const; void drawSmallText(int x, int y, const char* text, uint16_t color = 1, EpdFontStyle style = REGULAR) const;
void drawTextBox(int x, int y, const std::string& text, int width, int height, bool bold = false, void drawTextBox(int x, int y, const std::string& text, int width, int height, EpdFontStyle style = REGULAR) const;
bool italic = false) const; void drawLine(int x1, int y1, int x2, int y2, uint16_t color = 1) const;
void drawLine(int x1, int y1, int x2, int y2, uint16_t color) const; void drawRect(int x, int y, int width, int height, uint16_t color = 1) const;
void drawRect(int x, int y, int width, int height, uint16_t color) const; void fillRect(int x, int y, int width, int height, uint16_t color = 1) const;
void fillRect(int x, int y, int width, int height, uint16_t color) const; void drawCircle(int x, int y, int radius, uint16_t color = 1) const;
void fillCircle(int x, int y, int radius, uint16_t color = 1) const;
void drawImage(const uint8_t bitmap[], int x, int y, int width, int height, bool invert = false) const;
void clearScreen(bool black = false) const; void clearScreen(bool black = false) const;
void flushDisplay(bool partialUpdate = true) const; void flushDisplay(bool partialUpdate = true) const;
void flushArea(int x, int y, int width, int height) const; void flushArea(int x, int y, int width, int height) const;
@ -45,12 +43,4 @@ class EpdRenderer {
void setMarginBottom(const int newMarginBottom) { this->marginBottom = newMarginBottom; } void setMarginBottom(const int newMarginBottom) { this->marginBottom = newMarginBottom; }
void setMarginLeft(const int newMarginLeft) { this->marginLeft = newMarginLeft; } void setMarginLeft(const int newMarginLeft) { this->marginLeft = newMarginLeft; }
void setMarginRight(const int newMarginRight) { this->marginRight = newMarginRight; } void setMarginRight(const int newMarginRight) { this->marginRight = newMarginRight; }
// deep sleep helper - persist any state to disk that may be needed on wake
bool dehydrate();
// deep sleep helper - retrieve any state from disk after wake
bool hydrate();
// really really clear the screen
void reset();
uint8_t temperature = 20;
}; };

View File

@ -107,11 +107,11 @@ void Section::renderPage() {
delete p; delete p;
} else if (pageCount == 0) { } else if (pageCount == 0) {
Serial.println("No pages to render"); Serial.println("No pages to render");
const int width = renderer->getTextWidth("Empty chapter", true); const int width = renderer->getTextWidth("Empty chapter", BOLD);
renderer->drawText((renderer->getPageWidth() - width) / 2, 300, "Empty chapter", true); renderer->drawText((renderer->getPageWidth() - width) / 2, 300, "Empty chapter", 1, BOLD);
} else { } else {
Serial.printf("Page out of bounds: %d (max %d)\n", currentPage, pageCount); Serial.printf("Page out of bounds: %d (max %d)\n", currentPage, pageCount);
const int width = renderer->getTextWidth("Out of bounds", true); const int width = renderer->getTextWidth("Out of bounds", BOLD);
renderer->drawText((renderer->getPageWidth() - width) / 2, 300, "Out of bounds", true); renderer->drawText((renderer->getPageWidth() - width) / 2, 300, "Out of bounds", 1, BOLD);
} }
} }

View File

@ -56,7 +56,17 @@ std::list<TextBlock*> TextBlock::splitIntoLines(const EpdRenderer* renderer) {
uint16_t wordWidths[totalWordCount]; uint16_t wordWidths[totalWordCount];
for (int i = 0; i < words.size(); i++) { for (int i = 0; i < words.size(); i++) {
// measure the word // measure the word
const int width = renderer->getTextWidth(words[i].c_str(), wordStyles[i] & BOLD_SPAN, wordStyles[i] & ITALIC_SPAN); EpdFontStyle fontStyle = REGULAR;
if (wordStyles[i] & BOLD_SPAN) {
if (wordStyles[i] & ITALIC_SPAN) {
fontStyle = BOLD_ITALIC;
} else {
fontStyle = BOLD;
}
} else if (wordStyles[i] & ITALIC_SPAN) {
fontStyle = ITALIC;
}
const int width = renderer->getTextWidth(words[i].c_str(), fontStyle);
wordWidths[i] = width; wordWidths[i] = width;
} }
@ -182,7 +192,18 @@ void TextBlock::render(const EpdRenderer* renderer, const int x, const int y) co
// get the style // get the style
const uint8_t wordStyle = wordStyles[i]; const uint8_t wordStyle = wordStyles[i];
// render the word // render the word
renderer->drawText(x + wordXpos[i], y, words[i].c_str(), wordStyle & BOLD_SPAN, wordStyle & ITALIC_SPAN); EpdFontStyle fontStyle = REGULAR;
if (wordStyles[i] & BOLD_SPAN) {
if (wordStyles[i] & ITALIC_SPAN) {
fontStyle = BOLD_ITALIC;
} else {
fontStyle = BOLD;
}
} else if (wordStyles[i] & ITALIC_SPAN) {
fontStyle = ITALIC;
}
renderer->drawText(x + wordXpos[i], y, words[i].c_str(), 1, fontStyle);
} }
} }

View File

@ -89,7 +89,7 @@ void waitForNoButton() {
// Enter deep sleep mode // Enter deep sleep mode
void enterDeepSleep() { void enterDeepSleep() {
enterNewScreen(new FullScreenMessageScreen(renderer, "Sleeping", true, false, true)); enterNewScreen(new FullScreenMessageScreen(renderer, "Sleeping", BOLD, true));
Serial.println("Power button released after a long press. Entering deep sleep."); Serial.println("Power button released after a long press. Entering deep sleep.");
delay(1000); // Allow Serial buffer to empty and display to update delay(1000); // Allow Serial buffer to empty and display to update
@ -137,7 +137,7 @@ void setup() {
display.setTextColor(GxEPD_BLACK); display.setTextColor(GxEPD_BLACK);
Serial.println("Display initialized"); Serial.println("Display initialized");
enterNewScreen(new FullScreenMessageScreen(renderer, "Booting...", true)); enterNewScreen(new FullScreenMessageScreen(renderer, "Booting...", BOLD));
// SD Card Initialization // SD Card Initialization
SD.begin(SD_SPI_CS, SPI, SPI_FQ); SD.begin(SD_SPI_CS, SPI, SPI_FQ);

View File

@ -134,8 +134,8 @@ void EpubReaderScreen::renderPage() {
const int h = renderer->getLineHeight() + margin * 2; const int h = renderer->getLineHeight() + margin * 2;
renderer->fillRect(x, y, w, h, 0); renderer->fillRect(x, y, w, h, 0);
renderer->drawText(x + margin, y + margin, "Indexing..."); renderer->drawText(x + margin, y + margin, "Indexing...");
renderer->drawRect(x + 5, y + 5, w - 10, h - 10, 1); renderer->drawRect(x + 5, y + 5, w - 10, h - 10);
renderer->flushArea(x - 20, y - 20, w + 40, h + 40); renderer->flushArea(x, y, w, h);
} }
section->setupCacheDir(); section->setupCacheDir();
@ -199,23 +199,23 @@ void EpubReaderScreen::renderStatusBar() const {
constexpr int y = 772; constexpr int y = 772;
// Top line // Top line
renderer->drawLine(x, y, x + batteryWidth - 4, y, 1); renderer->drawLine(x, y, x + batteryWidth - 4, y);
// Bottom line // Bottom line
renderer->drawLine(x, y + batteryHeight - 1, x + batteryWidth - 4, y + batteryHeight - 1, 1); renderer->drawLine(x, y + batteryHeight - 1, x + batteryWidth - 4, y + batteryHeight - 1);
// Left line // Left line
renderer->drawLine(x, y, x, y + batteryHeight - 1, 1); renderer->drawLine(x, y, x, y + batteryHeight - 1);
// Battery end // Battery end
renderer->drawLine(x + batteryWidth - 4, y, x + batteryWidth - 4, y + batteryHeight - 1, 1); renderer->drawLine(x + batteryWidth - 4, y, x + batteryWidth - 4, y + batteryHeight - 1);
renderer->drawLine(x + batteryWidth - 3, y + 2, x + batteryWidth - 3, y + batteryHeight - 3, 1); renderer->drawLine(x + batteryWidth - 3, y + 2, x + batteryWidth - 3, y + batteryHeight - 3);
renderer->drawLine(x + batteryWidth - 2, y + 2, x + batteryWidth - 2, y + batteryHeight - 3, 1); renderer->drawLine(x + batteryWidth - 2, y + 2, x + batteryWidth - 2, y + batteryHeight - 3);
renderer->drawLine(x + batteryWidth - 1, y + 2, x + batteryWidth - 1, y + batteryHeight - 3, 1); renderer->drawLine(x + batteryWidth - 1, y + 2, x + batteryWidth - 1, y + batteryHeight - 3);
// The +1 is to round up, so that we always fill at least one pixel // The +1 is to round up, so that we always fill at least one pixel
int filledWidth = percentage * (batteryWidth - 5) / 100 + 1; int filledWidth = percentage * (batteryWidth - 5) / 100 + 1;
if (filledWidth > batteryWidth - 5) { if (filledWidth > batteryWidth - 5) {
filledWidth = batteryWidth - 5; // Ensure we don't overflow filledWidth = batteryWidth - 5; // Ensure we don't overflow
} }
renderer->fillRect(x + 1, y + 1, filledWidth, batteryHeight - 2, 1); renderer->fillRect(x + 1, y + 1, filledWidth, batteryHeight - 2);
// Page width minus existing content with 30px padding on each side // Page width minus existing content with 30px padding on each side
const int leftMargin = 20 + percentageTextWidth + 30; const int leftMargin = 20 + percentageTextWidth + 30;

View File

@ -91,14 +91,14 @@ void FileSelectionScreen::render() const {
renderer->clearScreen(); renderer->clearScreen();
const auto pageWidth = renderer->getPageWidth(); const auto pageWidth = renderer->getPageWidth();
const auto titleWidth = renderer->getTextWidth("CrossPoint Reader", true); const auto titleWidth = renderer->getTextWidth("CrossPoint Reader", BOLD);
renderer->drawText((pageWidth - titleWidth) / 2, 0, "CrossPoint Reader", true); renderer->drawText((pageWidth - titleWidth) / 2, 0, "CrossPoint Reader", 1, BOLD);
if (files.empty()) { if (files.empty()) {
renderer->drawSmallText(50, 50, "No EPUBs found"); renderer->drawSmallText(50, 50, "No EPUBs found");
} else { } else {
// Draw selection // Draw selection
renderer->fillRect(0, 50 + selectorIndex * 20 + 2, pageWidth - 1, 20, 1); renderer->fillRect(0, 50 + selectorIndex * 20 + 2, pageWidth - 1, 20);
for (size_t i = 0; i < files.size(); i++) { for (size_t i = 0; i < files.size(); i++) {
const auto file = files[i]; const auto file = files[i];

View File

@ -21,7 +21,7 @@ class FileSelectionScreen final : public Screen {
void render() const; void render() const;
void loadFiles(); void loadFiles();
public: public:
explicit FileSelectionScreen(EpdRenderer* renderer, const std::function<void(const std::string&)>& onSelect) explicit FileSelectionScreen(EpdRenderer* renderer, const std::function<void(const std::string&)>& onSelect)
: Screen(renderer), onSelect(onSelect) {} : Screen(renderer), onSelect(onSelect) {}
void onEnter() override; void onEnter() override;

View File

@ -3,13 +3,13 @@
#include <EpdRenderer.h> #include <EpdRenderer.h>
void FullScreenMessageScreen::onEnter() { void FullScreenMessageScreen::onEnter() {
const auto width = renderer->getTextWidth(text.c_str(), bold, italic); const auto width = renderer->getTextWidth(text.c_str(), style);
const auto height = renderer->getLineHeight(); const auto height = renderer->getLineHeight();
const auto left = (renderer->getPageWidth() - width) / 2; const auto left = (renderer->getPageWidth() - width) / 2;
const auto top = (renderer->getPageHeight() - height) / 2; const auto top = (renderer->getPageHeight() - height) / 2;
renderer->clearScreen(invert); renderer->clearScreen(invert);
renderer->drawText(left, top, text.c_str(), bold, italic, invert ? 0 : 1); renderer->drawText(left, top, text.c_str(), invert ? 0 : 1, style);
// If inverted, do a full screen update to ensure no ghosting // If inverted, do a full screen update to ensure no ghosting
renderer->flushDisplay(!invert); renderer->flushDisplay(!invert);
} }

View File

@ -2,17 +2,17 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include "EpdFontFamily.h"
#include "Screen.h" #include "Screen.h"
class FullScreenMessageScreen final : public Screen { class FullScreenMessageScreen final : public Screen {
std::string text; std::string text;
bool bold; EpdFontStyle style;
bool italic;
bool invert; bool invert;
public: public:
explicit FullScreenMessageScreen(EpdRenderer* renderer, std::string text, const bool bold = false, explicit FullScreenMessageScreen(EpdRenderer* renderer, std::string text, const EpdFontStyle style = REGULAR,
const bool italic = false, const bool invert = false) const bool invert = false)
: Screen(renderer), text(std::move(text)), bold(bold), italic(italic), invert(invert) {} : Screen(renderer), text(std::move(text)), style(style), invert(invert) {}
void onEnter() override; void onEnter() override;
}; };