mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2025-12-18 15:17:42 +03:00
Wrap up multiple font styles into EpdFontFamily
This commit is contained in:
parent
fa0f27df6a
commit
05a027e2bf
37
lib/EpdFont/EpdFontFamily.cpp
Normal file
37
lib/EpdFont/EpdFontFamily.cpp
Normal 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);
|
||||
};
|
||||
24
lib/EpdFont/EpdFontFamily.h
Normal file
24
lib/EpdFont/EpdFontFamily.h
Normal 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;
|
||||
};
|
||||
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include <EpdFont.h>
|
||||
#include <EpdFontFamily.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Utf8.h>
|
||||
#include <miniz.h>
|
||||
@ -12,13 +12,14 @@ static tinfl_decompressor decomp;
|
||||
template <typename Renderable>
|
||||
class EpdFontRenderer {
|
||||
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:
|
||||
const EpdFont* font;
|
||||
explicit EpdFontRenderer(const EpdFont* font, Renderable* renderer);
|
||||
const EpdFontFamily* fontFamily;
|
||||
explicit EpdFontRenderer(const EpdFontFamily* fontFamily, Renderable* renderer)
|
||||
: fontFamily(fontFamily), renderer(renderer) {}
|
||||
~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) {
|
||||
@ -38,37 +39,33 @@ inline int uncompress(uint8_t* dest, size_t uncompressedSize, const uint8_t* sou
|
||||
}
|
||||
|
||||
template <typename Renderable>
|
||||
EpdFontRenderer<Renderable>::EpdFontRenderer(const EpdFont* font, Renderable* renderer) {
|
||||
this->font = font;
|
||||
this->renderer = renderer;
|
||||
}
|
||||
|
||||
template <typename Renderable>
|
||||
void EpdFontRenderer<Renderable>::renderString(const char* string, int* x, int* y, const uint16_t color) {
|
||||
void EpdFontRenderer<Renderable>::renderString(const char* string, int* x, int* y, const uint16_t color,
|
||||
const EpdFontStyle style) {
|
||||
// cannot draw a NULL / empty string
|
||||
if (string == nullptr || *string == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
// no printable characters
|
||||
if (!font->hasPrintableChars(string)) {
|
||||
if (!fontFamily->hasPrintableChars(string, style)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t cp;
|
||||
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>
|
||||
void EpdFontRenderer<Renderable>::renderChar(const uint32_t cp, int* x, const int* y, uint16_t color) {
|
||||
const EpdGlyph* glyph = font->getGlyph(cp);
|
||||
void EpdFontRenderer<Renderable>::renderChar(const uint32_t cp, int* x, const int* y, uint16_t color,
|
||||
const EpdFontStyle style) {
|
||||
const EpdGlyph* glyph = fontFamily->getGlyph(cp, style);
|
||||
if (!glyph) {
|
||||
// TODO: Replace with fallback glyph property?
|
||||
glyph = font->getGlyph('?');
|
||||
glyph = fontFamily->getGlyph('?', style);
|
||||
}
|
||||
|
||||
// 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 uint8_t* bitmap = nullptr;
|
||||
|
||||
if (font->data->compressed) {
|
||||
if (fontFamily->getData(style)->compressed) {
|
||||
auto* tmpBitmap = static_cast<uint8_t*>(malloc(bitmapSize));
|
||||
if (tmpBitmap == nullptr && bitmapSize) {
|
||||
Serial.println("Failed to allocate memory for decompression buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
uncompress(tmpBitmap, bitmapSize, &font->data->bitmap[offset], glyph->compressedSize);
|
||||
uncompress(tmpBitmap, bitmapSize, &fontFamily->getData(style)->bitmap[offset], glyph->compressedSize);
|
||||
bitmap = tmpBitmap;
|
||||
} else {
|
||||
bitmap = &font->data->bitmap[offset];
|
||||
bitmap = &fontFamily->getData(style)->bitmap[offset];
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,12 +7,13 @@
|
||||
#include "builtinFonts/bookerly_italic.h"
|
||||
|
||||
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->regularFont = new EpdFontRenderer<XteinkDisplay>(new EpdFont(&bookerly), display);
|
||||
this->boldFont = new EpdFontRenderer<XteinkDisplay>(new EpdFont(&bookerly_bold), 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->regularFontRenderer = new EpdFontRenderer<XteinkDisplay>(bookerlyFontFamily, display);
|
||||
this->smallFontRenderer = new EpdFontRenderer<XteinkDisplay>(babyblueFontFamily, display);
|
||||
|
||||
this->marginTop = 11;
|
||||
this->marginBottom = 30;
|
||||
@ -21,50 +22,38 @@ EpdRenderer::EpdRenderer(XteinkDisplay* display) {
|
||||
this->lineCompression = 0.95f;
|
||||
}
|
||||
|
||||
EpdFontRenderer<XteinkDisplay>* EpdRenderer::getFontRenderer(const bool bold, const bool italic) 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 EpdRenderer::getTextWidth(const char* text, const EpdFontStyle style) const {
|
||||
int w = 0, h = 0;
|
||||
|
||||
getFontRenderer(bold, italic)->font->getTextDimensions(text, &w, &h);
|
||||
regularFontRenderer->fontFamily->getTextDimensions(text, &w, &h, style);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
int EpdRenderer::getSmallTextWidth(const char* text) const {
|
||||
int EpdRenderer::getSmallTextWidth(const char* text, const EpdFontStyle style) const {
|
||||
int w = 0, h = 0;
|
||||
|
||||
smallFont->font->getTextDimensions(text, &w, &h);
|
||||
smallFontRenderer->fontFamily->getTextDimensions(text, &w, &h, style);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
void EpdRenderer::drawText(const int x, const int y, const char* text, const bool bold, const bool italic,
|
||||
const uint16_t color) const {
|
||||
void EpdRenderer::drawText(const int x, const int y, const char* text, const uint16_t color,
|
||||
const EpdFontStyle style) const {
|
||||
int ypos = y + getLineHeight() + marginTop;
|
||||
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 {
|
||||
int ypos = y + smallFont->font->data->advanceY + marginTop;
|
||||
void EpdRenderer::drawSmallText(const int x, const int y, const char* text, const uint16_t color,
|
||||
const EpdFontStyle style) const {
|
||||
int ypos = y + smallFontRenderer->fontFamily->getData(style)->advanceY + marginTop;
|
||||
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,
|
||||
const bool bold, const bool italic) const {
|
||||
const EpdFontStyle style) const {
|
||||
const size_t length = text.length();
|
||||
// fit the text into the box
|
||||
int start = 0;
|
||||
@ -72,7 +61,7 @@ void EpdRenderer::drawTextBox(const int x, const int y, const std::string& text,
|
||||
int ypos = 0;
|
||||
while (true) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -81,15 +70,15 @@ void EpdRenderer::drawTextBox(const int x, const int y, const std::string& text,
|
||||
}
|
||||
|
||||
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();
|
||||
start = end;
|
||||
end = start + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (getTextWidth(text.substr(start, end - start).c_str(), bold, italic) > width) {
|
||||
drawText(x, y + ypos, text.substr(start, end - start - 1).c_str(), bold, italic);
|
||||
if (getTextWidth(text.substr(start, end - start).c_str(), style) > width) {
|
||||
drawText(x, y + ypos, text.substr(start, end - start - 1).c_str(), 1, style);
|
||||
ypos += getLineHeight();
|
||||
start = end - 1;
|
||||
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);
|
||||
}
|
||||
|
||||
void EpdRenderer::fillRect(const int x, const int y, const int width, const int height,
|
||||
const uint16_t color = 0) const {
|
||||
void EpdRenderer::fillRect(const int x, const int y, const int width, const int height, const uint16_t color) const {
|
||||
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 {
|
||||
Serial.println("Clearing screen");
|
||||
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::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::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; }
|
||||
|
||||
// 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
|
||||
};
|
||||
int EpdRenderer::getLineHeight() const {
|
||||
return regularFontRenderer->fontFamily->getData(REGULAR)->advanceY * lineCompression;
|
||||
}
|
||||
|
||||
@ -8,30 +8,28 @@
|
||||
|
||||
class EpdRenderer {
|
||||
XteinkDisplay* display;
|
||||
EpdFontRenderer<XteinkDisplay>* regularFont;
|
||||
EpdFontRenderer<XteinkDisplay>* boldFont;
|
||||
EpdFontRenderer<XteinkDisplay>* italicFont;
|
||||
EpdFontRenderer<XteinkDisplay>* bold_italicFont;
|
||||
EpdFontRenderer<XteinkDisplay>* smallFont;
|
||||
EpdFontRenderer<XteinkDisplay>* regularFontRenderer;
|
||||
EpdFontRenderer<XteinkDisplay>* smallFontRenderer;
|
||||
int marginTop;
|
||||
int marginBottom;
|
||||
int marginLeft;
|
||||
int marginRight;
|
||||
float lineCompression;
|
||||
EpdFontRenderer<XteinkDisplay>* getFontRenderer(bool bold, bool italic) const;
|
||||
|
||||
public:
|
||||
explicit EpdRenderer(XteinkDisplay* display);
|
||||
~EpdRenderer() = default;
|
||||
int getTextWidth(const char* text, bool bold = false, bool italic = false) const;
|
||||
int getSmallTextWidth(const char* text) const;
|
||||
void drawText(int x, int y, const char* text, bool bold = false, bool italic = false, uint16_t color = 1) const;
|
||||
void drawSmallText(int x, int y, const char* text, uint16_t color = 1) const;
|
||||
void drawTextBox(int x, int y, const std::string& text, int width, int height, bool bold = false,
|
||||
bool italic = false) 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) const;
|
||||
void fillRect(int x, int y, int width, int height, uint16_t color) const;
|
||||
int getTextWidth(const char* text, EpdFontStyle style = REGULAR) const;
|
||||
int getSmallTextWidth(const char* text, EpdFontStyle style = REGULAR) 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, EpdFontStyle style = REGULAR) const;
|
||||
void drawTextBox(int x, int y, const std::string& text, int width, int height, EpdFontStyle style = REGULAR) const;
|
||||
void drawLine(int x1, int y1, int x2, int y2, uint16_t color = 1) const;
|
||||
void drawRect(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 = 1) 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 flushDisplay(bool partialUpdate = true) 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 setMarginLeft(const int newMarginLeft) { this->marginLeft = newMarginLeft; }
|
||||
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;
|
||||
};
|
||||
|
||||
@ -107,11 +107,11 @@ void Section::renderPage() {
|
||||
delete p;
|
||||
} else if (pageCount == 0) {
|
||||
Serial.println("No pages to render");
|
||||
const int width = renderer->getTextWidth("Empty chapter", true);
|
||||
renderer->drawText((renderer->getPageWidth() - width) / 2, 300, "Empty chapter", true);
|
||||
const int width = renderer->getTextWidth("Empty chapter", BOLD);
|
||||
renderer->drawText((renderer->getPageWidth() - width) / 2, 300, "Empty chapter", 1, BOLD);
|
||||
} else {
|
||||
Serial.printf("Page out of bounds: %d (max %d)\n", currentPage, pageCount);
|
||||
const int width = renderer->getTextWidth("Out of bounds", true);
|
||||
renderer->drawText((renderer->getPageWidth() - width) / 2, 300, "Out of bounds", true);
|
||||
const int width = renderer->getTextWidth("Out of bounds", BOLD);
|
||||
renderer->drawText((renderer->getPageWidth() - width) / 2, 300, "Out of bounds", 1, BOLD);
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +56,17 @@ std::list<TextBlock*> TextBlock::splitIntoLines(const EpdRenderer* renderer) {
|
||||
uint16_t wordWidths[totalWordCount];
|
||||
for (int i = 0; i < words.size(); i++) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -182,7 +192,18 @@ void TextBlock::render(const EpdRenderer* renderer, const int x, const int y) co
|
||||
// get the style
|
||||
const uint8_t wordStyle = wordStyles[i];
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -89,7 +89,7 @@ void waitForNoButton() {
|
||||
|
||||
// Enter deep sleep mode
|
||||
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.");
|
||||
delay(1000); // Allow Serial buffer to empty and display to update
|
||||
@ -137,7 +137,7 @@ void setup() {
|
||||
display.setTextColor(GxEPD_BLACK);
|
||||
Serial.println("Display initialized");
|
||||
|
||||
enterNewScreen(new FullScreenMessageScreen(renderer, "Booting...", true));
|
||||
enterNewScreen(new FullScreenMessageScreen(renderer, "Booting...", BOLD));
|
||||
|
||||
// SD Card Initialization
|
||||
SD.begin(SD_SPI_CS, SPI, SPI_FQ);
|
||||
|
||||
@ -134,8 +134,8 @@ void EpubReaderScreen::renderPage() {
|
||||
const int h = renderer->getLineHeight() + margin * 2;
|
||||
renderer->fillRect(x, y, w, h, 0);
|
||||
renderer->drawText(x + margin, y + margin, "Indexing...");
|
||||
renderer->drawRect(x + 5, y + 5, w - 10, h - 10, 1);
|
||||
renderer->flushArea(x - 20, y - 20, w + 40, h + 40);
|
||||
renderer->drawRect(x + 5, y + 5, w - 10, h - 10);
|
||||
renderer->flushArea(x, y, w, h);
|
||||
}
|
||||
|
||||
section->setupCacheDir();
|
||||
@ -199,23 +199,23 @@ void EpubReaderScreen::renderStatusBar() const {
|
||||
constexpr int y = 772;
|
||||
|
||||
// Top line
|
||||
renderer->drawLine(x, y, x + batteryWidth - 4, y, 1);
|
||||
renderer->drawLine(x, y, x + batteryWidth - 4, y);
|
||||
// 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
|
||||
renderer->drawLine(x, y, x, y + batteryHeight - 1, 1);
|
||||
renderer->drawLine(x, y, x, y + batteryHeight - 1);
|
||||
// Battery end
|
||||
renderer->drawLine(x + batteryWidth - 4, y, x + batteryWidth - 4, y + batteryHeight - 1, 1);
|
||||
renderer->drawLine(x + batteryWidth - 3, y + 2, x + batteryWidth - 3, y + batteryHeight - 3, 1);
|
||||
renderer->drawLine(x + batteryWidth - 2, y + 2, x + batteryWidth - 2, y + batteryHeight - 3, 1);
|
||||
renderer->drawLine(x + batteryWidth - 1, y + 2, x + batteryWidth - 1, y + batteryHeight - 3, 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);
|
||||
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);
|
||||
|
||||
// The +1 is to round up, so that we always fill at least one pixel
|
||||
int filledWidth = percentage * (batteryWidth - 5) / 100 + 1;
|
||||
if (filledWidth > batteryWidth - 5) {
|
||||
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
|
||||
const int leftMargin = 20 + percentageTextWidth + 30;
|
||||
|
||||
@ -91,14 +91,14 @@ void FileSelectionScreen::render() const {
|
||||
renderer->clearScreen();
|
||||
|
||||
const auto pageWidth = renderer->getPageWidth();
|
||||
const auto titleWidth = renderer->getTextWidth("CrossPoint Reader", true);
|
||||
renderer->drawText((pageWidth - titleWidth) / 2, 0, "CrossPoint Reader", true);
|
||||
const auto titleWidth = renderer->getTextWidth("CrossPoint Reader", BOLD);
|
||||
renderer->drawText((pageWidth - titleWidth) / 2, 0, "CrossPoint Reader", 1, BOLD);
|
||||
|
||||
if (files.empty()) {
|
||||
renderer->drawSmallText(50, 50, "No EPUBs found");
|
||||
} else {
|
||||
// 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++) {
|
||||
const auto file = files[i];
|
||||
|
||||
@ -3,13 +3,13 @@
|
||||
#include <EpdRenderer.h>
|
||||
|
||||
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 left = (renderer->getPageWidth() - width) / 2;
|
||||
const auto top = (renderer->getPageHeight() - height) / 2;
|
||||
|
||||
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
|
||||
renderer->flushDisplay(!invert);
|
||||
}
|
||||
|
||||
@ -2,17 +2,17 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "EpdFontFamily.h"
|
||||
#include "Screen.h"
|
||||
|
||||
class FullScreenMessageScreen final : public Screen {
|
||||
std::string text;
|
||||
bool bold;
|
||||
bool italic;
|
||||
EpdFontStyle style;
|
||||
bool invert;
|
||||
|
||||
public:
|
||||
explicit FullScreenMessageScreen(EpdRenderer* renderer, std::string text, const bool bold = false,
|
||||
const bool italic = false, const bool invert = false)
|
||||
: Screen(renderer), text(std::move(text)), bold(bold), italic(italic), invert(invert) {}
|
||||
explicit FullScreenMessageScreen(EpdRenderer* renderer, std::string text, const EpdFontStyle style = REGULAR,
|
||||
const bool invert = false)
|
||||
: Screen(renderer), text(std::move(text)), style(style), invert(invert) {}
|
||||
void onEnter() override;
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user