fix(cppcheck}: clang format

This commit is contained in:
Brackyt 2026-01-29 13:59:19 +01:00
parent bb05b5ae6d
commit 2cd569bb1f
4 changed files with 303 additions and 428 deletions

View File

@ -1,14 +1,12 @@
#include "GfxRenderer.h" #include "GfxRenderer.h"
#include <Utf8.h> #include <Utf8.h>
#include <algorithm> #include <algorithm>
void GfxRenderer::insertFont(const int fontId, EpdFontFamily font) { void GfxRenderer::insertFont(const int fontId, EpdFontFamily font) { fontMap.insert({fontId, font}); }
fontMap.insert({fontId, font});
}
void GfxRenderer::rotateCoordinates(const int x, const int y, int *rotatedX, void GfxRenderer::rotateCoordinates(const int x, const int y, int* rotatedX, int* rotatedY) const {
int *rotatedY) const {
switch (orientation) { switch (orientation) {
case Portrait: { case Portrait: {
// Logical portrait (480x800) → panel (800x480) // Logical portrait (480x800) → panel (800x480)
@ -80,21 +78,18 @@ bool GfxRenderer::readPixel(const int x, const int y) const {
rotateCoordinates(x, y, &rotatedX, &rotatedY); rotateCoordinates(x, y, &rotatedX, &rotatedY);
// Bounds checking against physical panel dimensions // Bounds checking against physical panel dimensions
if (rotatedX < 0 || rotatedX >= HalDisplay::DISPLAY_WIDTH || if (rotatedX < 0 || rotatedX >= HalDisplay::DISPLAY_WIDTH || rotatedY < 0 || rotatedY >= HalDisplay::DISPLAY_HEIGHT) {
rotatedY < 0 || rotatedY >= HalDisplay::DISPLAY_HEIGHT) {
return false; return false;
} }
const uint16_t byteIndex = const uint16_t byteIndex = rotatedY * HalDisplay::DISPLAY_WIDTH_BYTES + (rotatedX / 8);
rotatedY * HalDisplay::DISPLAY_WIDTH_BYTES + (rotatedX / 8);
const uint8_t bitPosition = 7 - (rotatedX % 8); const uint8_t bitPosition = 7 - (rotatedX % 8);
// Bit cleared = black, bit set = white // Bit cleared = black, bit set = white
return !(frameBuffer[byteIndex] & (1 << bitPosition)); return !(frameBuffer[byteIndex] & (1 << bitPosition));
} }
int GfxRenderer::getTextWidth(const int fontId, const char *text, int GfxRenderer::getTextWidth(const int fontId, const char* text, const EpdFontFamily::Style style) const {
const EpdFontFamily::Style style) const {
if (fontMap.count(fontId) == 0) { if (fontMap.count(fontId) == 0) {
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId); Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
return 0; return 0;
@ -105,15 +100,13 @@ int GfxRenderer::getTextWidth(const int fontId, const char *text,
return w; return w;
} }
void GfxRenderer::drawCenteredText(const int fontId, const int y, void GfxRenderer::drawCenteredText(const int fontId, const int y, const char* text, const bool black,
const char *text, const bool black,
const EpdFontFamily::Style style) const { const EpdFontFamily::Style style) const {
const int x = (getScreenWidth() - getTextWidth(fontId, text, style)) / 2; const int x = (getScreenWidth() - getTextWidth(fontId, text, style)) / 2;
drawText(fontId, x, y, text, black, style); drawText(fontId, x, y, text, black, style);
} }
void GfxRenderer::drawText(const int fontId, const int x, const int y, void GfxRenderer::drawText(const int fontId, const int x, const int y, const char* text, const bool black,
const char *text, const bool black,
const EpdFontFamily::Style style) const { const EpdFontFamily::Style style) const {
const int yPos = y + getFontAscenderSize(fontId); const int yPos = y + getFontAscenderSize(fontId);
int xpos = x; int xpos = x;
@ -140,8 +133,7 @@ void GfxRenderer::drawText(const int fontId, const int x, const int y,
} }
} }
void GfxRenderer::drawLine(int x1, int y1, int x2, int y2, void GfxRenderer::drawLine(int x1, int y1, int x2, int y2, const bool state) const {
const bool state) const {
// Bresenham's line algorithm // Bresenham's line algorithm
int dx = abs(x2 - x1); int dx = abs(x2 - x1);
int dy = abs(y2 - y1); int dy = abs(y2 - y1);
@ -166,16 +158,14 @@ void GfxRenderer::drawLine(int x1, int y1, int x2, int y2,
} }
} }
void GfxRenderer::drawRect(const int x, const int y, const int width, void GfxRenderer::drawRect(const int x, const int y, const int width, const int height, const bool state) const {
const int height, const bool state) const {
drawLine(x, y, x + width - 1, y, state); drawLine(x, y, x + width - 1, y, state);
drawLine(x + width - 1, y, x + width - 1, y + height - 1, state); drawLine(x + width - 1, y, x + width - 1, y + height - 1, state);
drawLine(x + width - 1, y + height - 1, x, y + height - 1, state); drawLine(x + width - 1, y + height - 1, x, y + height - 1, state);
drawLine(x, y, x, y + height - 1, state); drawLine(x, y, x, y + height - 1, state);
} }
void GfxRenderer::fillRect(const int x, const int y, const int width, void GfxRenderer::fillRect(const int x, const int y, const int width, const int height, const bool state) const {
const int height, const bool state) const {
uint8_t* frameBuffer = display.getFrameBuffer(); uint8_t* frameBuffer = display.getFrameBuffer();
if (!frameBuffer) { if (!frameBuffer) {
return; return;
@ -190,8 +180,7 @@ void GfxRenderer::fillRect(const int x, const int y, const int width,
const int x2 = std::min(screenWidth - 1, x + width - 1); const int x2 = std::min(screenWidth - 1, x + width - 1);
const int y2 = std::min(screenHeight - 1, y + height - 1); const int y2 = std::min(screenHeight - 1, y + height - 1);
if (x1 > x2 || y1 > y2) if (x1 > x2 || y1 > y2) return;
return;
// Optimized path for Portrait mode (most common) // Optimized path for Portrait mode (most common)
if (orientation == Portrait) { if (orientation == Portrait) {
@ -204,8 +193,7 @@ void GfxRenderer::fillRect(const int x, const int y, const int width,
for (int sx = x1; sx <= x2; sx++) { for (int sx = x1; sx <= x2; sx++) {
const int physY = HalDisplay::DISPLAY_HEIGHT - 1 - sx; const int physY = HalDisplay::DISPLAY_HEIGHT - 1 - sx;
const uint16_t byteIndex = const uint16_t byteIndex = physY * HalDisplay::DISPLAY_WIDTH_BYTES + physXByte;
physY * HalDisplay::DISPLAY_WIDTH_BYTES + physXByte;
if (state) { if (state) {
frameBuffer[byteIndex] &= ~mask; // Black frameBuffer[byteIndex] &= ~mask; // Black
@ -227,8 +215,7 @@ void GfxRenderer::fillRect(const int x, const int y, const int width,
for (int sx = x1; sx <= x2; sx++) { for (int sx = x1; sx <= x2; sx++) {
const int physY = sx; const int physY = sx;
const uint16_t byteIndex = const uint16_t byteIndex = physY * HalDisplay::DISPLAY_WIDTH_BYTES + physXByte;
physY * HalDisplay::DISPLAY_WIDTH_BYTES + physXByte;
if (state) { if (state) {
frameBuffer[byteIndex] &= ~mask; frameBuffer[byteIndex] &= ~mask;
@ -282,8 +269,8 @@ void GfxRenderer::fillRect(const int x, const int y, const int width,
} }
} }
void GfxRenderer::fillRectDithered(const int x, const int y, const int width, void GfxRenderer::fillRectDithered(const int x, const int y, const int width, const int height,
const int height, const uint8_t grayLevel) const { const uint8_t grayLevel) const {
// Simulate grayscale using dithering patterns // Simulate grayscale using dithering patterns
// 0x00 = black, 0xFF = white, values in between = dithered // 0x00 = black, 0xFF = white, values in between = dithered
@ -314,10 +301,14 @@ void GfxRenderer::fillRectDithered(const int x, const int y, const int width,
int bayerValue; int bayerValue;
int px = sx % 2; int px = sx % 2;
int py = sy % 2; int py = sy % 2;
if (px == 0 && py == 0) bayerValue = 0; if (px == 0 && py == 0)
else if (px == 1 && py == 0) bayerValue = 2; bayerValue = 0;
else if (px == 0 && py == 1) bayerValue = 3; else if (px == 1 && py == 0)
else bayerValue = 1; bayerValue = 2;
else if (px == 0 && py == 1)
bayerValue = 3;
else
bayerValue = 1;
bool isBlack = bayerValue >= threshold; bool isBlack = bayerValue >= threshold;
drawPixel(sx, sy, isBlack); drawPixel(sx, sy, isBlack);
@ -325,8 +316,8 @@ void GfxRenderer::fillRectDithered(const int x, const int y, const int width,
} }
} }
void GfxRenderer::drawRoundedRect(const int x, const int y, const int width, void GfxRenderer::drawRoundedRect(const int x, const int y, const int width, const int height, const int radius,
const int height, const int radius, const bool state) const { const bool state) const {
if (radius <= 0) { if (radius <= 0) {
drawRect(x, y, width, height, state); drawRect(x, y, width, height, state);
return; return;
@ -338,19 +329,23 @@ void GfxRenderer::drawRoundedRect(const int x, const int y, const int width,
int d = 1 - r; int d = 1 - r;
while (px <= py) { while (px <= py) {
cx = x + r; cy = y + r; cx = x + r;
cy = y + r;
drawPixel(cx - py, cy - px, state); drawPixel(cx - py, cy - px, state);
drawPixel(cx - px, cy - py, state); drawPixel(cx - px, cy - py, state);
cx = x + width - 1 - r; cy = y + r; cx = x + width - 1 - r;
cy = y + r;
drawPixel(cx + py, cy - px, state); drawPixel(cx + py, cy - px, state);
drawPixel(cx + px, cy - py, state); drawPixel(cx + px, cy - py, state);
cx = x + r; cy = y + height - 1 - r; cx = x + r;
cy = y + height - 1 - r;
drawPixel(cx - py, cy + px, state); drawPixel(cx - py, cy + px, state);
drawPixel(cx - px, cy + py, state); drawPixel(cx - px, cy + py, state);
cx = x + width - 1 - r; cy = y + height - 1 - r; cx = x + width - 1 - r;
cy = y + height - 1 - r;
drawPixel(cx + py, cy + px, state); drawPixel(cx + py, cy + px, state);
drawPixel(cx + px, cy + py, state); drawPixel(cx + px, cy + py, state);
@ -369,8 +364,8 @@ void GfxRenderer::drawRoundedRect(const int x, const int y, const int width,
drawLine(x + width - 1, y + r, x + width - 1, y + height - 1 - r, state); drawLine(x + width - 1, y + r, x + width - 1, y + height - 1 - r, state);
} }
void GfxRenderer::fillRoundedRect(const int x, const int y, const int width, void GfxRenderer::fillRoundedRect(const int x, const int y, const int width, const int height, const int radius,
const int height, const int radius, const bool state) const { const bool state) const {
if (radius <= 0) { if (radius <= 0) {
fillRect(x, y, width, height, state); fillRect(x, y, width, height, state);
return; return;
@ -405,8 +400,7 @@ void GfxRenderer::fillRoundedRect(const int x, const int y, const int width,
} }
} }
void GfxRenderer::fillRoundedRectDithered(const int x, const int y, const int width, void GfxRenderer::fillRoundedRectDithered(const int x, const int y, const int width, const int height, const int radius,
const int height, const int radius,
const uint8_t grayLevel) const { const uint8_t grayLevel) const {
if (grayLevel == 0x00) { if (grayLevel == 0x00) {
fillRoundedRect(x, y, width, height, radius, true); fillRoundedRect(x, y, width, height, radius, true);
@ -463,10 +457,14 @@ void GfxRenderer::fillRoundedRectDithered(const int x, const int y, const int wi
int bayerValue; int bayerValue;
int bx = sx % 2; int bx = sx % 2;
int by = sy % 2; int by = sy % 2;
if (bx == 0 && by == 0) bayerValue = 0; if (bx == 0 && by == 0)
else if (bx == 1 && by == 0) bayerValue = 2; bayerValue = 0;
else if (bx == 0 && by == 1) bayerValue = 3; else if (bx == 1 && by == 0)
else bayerValue = 1; bayerValue = 2;
else if (bx == 0 && by == 1)
bayerValue = 3;
else
bayerValue = 1;
bool isBlack = bayerValue >= threshold; bool isBlack = bayerValue >= threshold;
drawPixel(sx, sy, isBlack); drawPixel(sx, sy, isBlack);
@ -497,8 +495,7 @@ void GfxRenderer::drawImage(const uint8_t bitmap[], const int x, const int y, co
display.drawImage(bitmap, rotatedX, rotatedY, width, height); display.drawImage(bitmap, rotatedX, rotatedY, width, height);
} }
void GfxRenderer::drawBitmap(const Bitmap &bitmap, const int x, const int y, void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, const int maxWidth, const int maxHeight,
const int maxWidth, const int maxHeight,
const float cropX, const float cropY) const { const float cropX, const float cropY) const {
// For 1-bit bitmaps, use optimized 1-bit rendering path (no crop support for // For 1-bit bitmaps, use optimized 1-bit rendering path (no crop support for
// 1-bit) // 1-bit)
@ -513,14 +510,11 @@ void GfxRenderer::drawBitmap(const Bitmap &bitmap, const int x, const int y,
int cropPixY = std::floor(bitmap.getHeight() * cropY / 2.0f); int cropPixY = std::floor(bitmap.getHeight() * cropY / 2.0f);
if (maxWidth > 0 && (1.0f - cropX) * bitmap.getWidth() > maxWidth) { if (maxWidth > 0 && (1.0f - cropX) * bitmap.getWidth() > maxWidth) {
scale = static_cast<float>(maxWidth) / scale = static_cast<float>(maxWidth) / static_cast<float>((1.0f - cropX) * bitmap.getWidth());
static_cast<float>((1.0f - cropX) * bitmap.getWidth());
isScaled = true; isScaled = true;
} }
if (maxHeight > 0 && (1.0f - cropY) * bitmap.getHeight() > maxHeight) { if (maxHeight > 0 && (1.0f - cropY) * bitmap.getHeight() > maxHeight) {
scale = std::min( scale = std::min(scale, static_cast<float>(maxHeight) / static_cast<float>((1.0f - cropY) * bitmap.getHeight()));
scale, static_cast<float>(maxHeight) /
static_cast<float>((1.0f - cropY) * bitmap.getHeight()));
isScaled = true; isScaled = true;
} }
@ -532,8 +526,7 @@ void GfxRenderer::drawBitmap(const Bitmap &bitmap, const int x, const int y,
auto* rowBytes = static_cast<uint8_t*>(malloc(bitmap.getRowBytes())); auto* rowBytes = static_cast<uint8_t*>(malloc(bitmap.getRowBytes()));
if (!outputRow || !rowBytes) { if (!outputRow || !rowBytes) {
Serial.printf("[%lu] [GFX] !! Failed to allocate BMP row buffers\n", Serial.printf("[%lu] [GFX] !! Failed to allocate BMP row buffers\n", millis());
millis());
free(outputRow); free(outputRow);
free(rowBytes); free(rowBytes);
return; return;
@ -542,8 +535,7 @@ void GfxRenderer::drawBitmap(const Bitmap &bitmap, const int x, const int y,
for (int bmpY = 0; bmpY < (bitmap.getHeight() - cropPixY); bmpY++) { for (int bmpY = 0; bmpY < (bitmap.getHeight() - cropPixY); bmpY++) {
// The BMP's (0, 0) is the bottom-left corner (if the height is positive, // The BMP's (0, 0) is the bottom-left corner (if the height is positive,
// top-left if negative). Screen's (0, 0) is the top-left corner. // top-left if negative). Screen's (0, 0) is the top-left corner.
int screenY = int screenY = -cropPixY + (bitmap.isTopDown() ? bmpY : bitmap.getHeight() - 1 - bmpY);
-cropPixY + (bitmap.isTopDown() ? bmpY : bitmap.getHeight() - 1 - bmpY);
if (isScaled) { if (isScaled) {
screenY = std::floor(screenY * scale); screenY = std::floor(screenY * scale);
} }
@ -553,8 +545,7 @@ void GfxRenderer::drawBitmap(const Bitmap &bitmap, const int x, const int y,
} }
if (bitmap.readNextRow(outputRow, rowBytes) != BmpReaderError::Ok) { if (bitmap.readNextRow(outputRow, rowBytes) != BmpReaderError::Ok) {
Serial.printf("[%lu] [GFX] Failed to read row %d from bitmap\n", millis(), Serial.printf("[%lu] [GFX] Failed to read row %d from bitmap\n", millis(), bmpY);
bmpY);
free(outputRow); free(outputRow);
free(rowBytes); free(rowBytes);
return; return;
@ -604,8 +595,7 @@ void GfxRenderer::drawBitmap(const Bitmap &bitmap, const int x, const int y,
free(rowBytes); free(rowBytes);
} }
void GfxRenderer::draw2BitImage(const uint8_t data[], int x, int y, int w, void GfxRenderer::draw2BitImage(const uint8_t data[], int x, int y, int w, int h) const {
int h) const {
uint8_t* frameBuffer = display.getFrameBuffer(); uint8_t* frameBuffer = display.getFrameBuffer();
if (!frameBuffer) { if (!frameBuffer) {
return; return;
@ -622,8 +612,7 @@ void GfxRenderer::draw2BitImage(const uint8_t data[], int x, int y, int w,
if (orientation == Portrait && renderMode == BW) { if (orientation == Portrait && renderMode == BW) {
for (int row = 0; row < h; row++) { for (int row = 0; row < h; row++) {
const int screenY = y + row; const int screenY = y + row;
if (screenY < 0 || screenY >= screenHeight) if (screenY < 0 || screenY >= screenHeight) continue;
continue;
// In Portrait, screenY maps to physical X coordinate // In Portrait, screenY maps to physical X coordinate
const int physX = screenY; const int physX = screenY;
@ -631,8 +620,7 @@ void GfxRenderer::draw2BitImage(const uint8_t data[], int x, int y, int w,
for (int col = 0; col < w; col++) { for (int col = 0; col < w; col++) {
const int screenX = x + col; const int screenX = x + col;
if (screenX < 0 || screenX >= screenWidth) if (screenX < 0 || screenX >= screenWidth) continue;
continue;
// Extract 2-bit value (4 pixels per byte) // Extract 2-bit value (4 pixels per byte)
const uint8_t val = (srcRow[col / 4] >> (6 - ((col % 4) * 2))) & 0x3; const uint8_t val = (srcRow[col / 4] >> (6 - ((col % 4) * 2))) & 0x3;
@ -642,8 +630,7 @@ void GfxRenderer::draw2BitImage(const uint8_t data[], int x, int y, int w,
if (val < 2) { if (val < 2) {
// In Portrait: physical Y = DISPLAY_HEIGHT - 1 - screenX // In Portrait: physical Y = DISPLAY_HEIGHT - 1 - screenX
const int physY = HalDisplay::DISPLAY_HEIGHT - 1 - screenX; const int physY = HalDisplay::DISPLAY_HEIGHT - 1 - screenX;
const uint16_t byteIndex = const uint16_t byteIndex = physY * HalDisplay::DISPLAY_WIDTH_BYTES + (physX / 8);
physY * HalDisplay::DISPLAY_WIDTH_BYTES + (physX / 8);
const uint8_t bitPosition = 7 - (physX % 8); const uint8_t bitPosition = 7 - (physX % 8);
frameBuffer[byteIndex] &= ~(1 << bitPosition); // Clear bit = black frameBuffer[byteIndex] &= ~(1 << bitPosition); // Clear bit = black
} }
@ -656,15 +643,13 @@ void GfxRenderer::draw2BitImage(const uint8_t data[], int x, int y, int w,
if (orientation == PortraitInverted && renderMode == BW) { if (orientation == PortraitInverted && renderMode == BW) {
for (int row = 0; row < h; row++) { for (int row = 0; row < h; row++) {
const int screenY = y + row; const int screenY = y + row;
if (screenY < 0 || screenY >= screenHeight) if (screenY < 0 || screenY >= screenHeight) continue;
continue;
const uint8_t* srcRow = data + row * srcRowBytes; const uint8_t* srcRow = data + row * srcRowBytes;
for (int col = 0; col < w; col++) { for (int col = 0; col < w; col++) {
const int screenX = x + col; const int screenX = x + col;
if (screenX < 0 || screenX >= screenWidth) if (screenX < 0 || screenX >= screenWidth) continue;
continue;
const uint8_t val = (srcRow[col / 4] >> (6 - ((col % 4) * 2))) & 0x3; const uint8_t val = (srcRow[col / 4] >> (6 - ((col % 4) * 2))) & 0x3;
@ -673,8 +658,7 @@ void GfxRenderer::draw2BitImage(const uint8_t data[], int x, int y, int w,
// physical Y = screenX // physical Y = screenX
const int physX = HalDisplay::DISPLAY_WIDTH - 1 - screenY; const int physX = HalDisplay::DISPLAY_WIDTH - 1 - screenY;
const int physY = screenX; const int physY = screenX;
const uint16_t byteIndex = const uint16_t byteIndex = physY * HalDisplay::DISPLAY_WIDTH_BYTES + (physX / 8);
physY * HalDisplay::DISPLAY_WIDTH_BYTES + (physX / 8);
const uint8_t bitPosition = 7 - (physX % 8); const uint8_t bitPosition = 7 - (physX % 8);
frameBuffer[byteIndex] &= ~(1 << bitPosition); frameBuffer[byteIndex] &= ~(1 << bitPosition);
} }
@ -684,20 +668,16 @@ void GfxRenderer::draw2BitImage(const uint8_t data[], int x, int y, int w,
} }
// Optimized path for Landscape modes with BW rendering // Optimized path for Landscape modes with BW rendering
if ((orientation == LandscapeClockwise || if ((orientation == LandscapeClockwise || orientation == LandscapeCounterClockwise) && renderMode == BW) {
orientation == LandscapeCounterClockwise) &&
renderMode == BW) {
for (int row = 0; row < h; row++) { for (int row = 0; row < h; row++) {
const int screenY = y + row; const int screenY = y + row;
if (screenY < 0 || screenY >= screenHeight) if (screenY < 0 || screenY >= screenHeight) continue;
continue;
const uint8_t* srcRow = data + row * srcRowBytes; const uint8_t* srcRow = data + row * srcRowBytes;
for (int col = 0; col < w; col++) { for (int col = 0; col < w; col++) {
const int screenX = x + col; const int screenX = x + col;
if (screenX < 0 || screenX >= screenWidth) if (screenX < 0 || screenX >= screenWidth) continue;
continue;
const uint8_t val = (srcRow[col / 4] >> (6 - ((col % 4) * 2))) & 0x3; const uint8_t val = (srcRow[col / 4] >> (6 - ((col % 4) * 2))) & 0x3;
@ -710,8 +690,7 @@ void GfxRenderer::draw2BitImage(const uint8_t data[], int x, int y, int w,
physX = screenX; physX = screenX;
physY = screenY; physY = screenY;
} }
const uint16_t byteIndex = const uint16_t byteIndex = physY * HalDisplay::DISPLAY_WIDTH_BYTES + (physX / 8);
physY * HalDisplay::DISPLAY_WIDTH_BYTES + (physX / 8);
const uint8_t bitPosition = 7 - (physX % 8); const uint8_t bitPosition = 7 - (physX % 8);
frameBuffer[byteIndex] &= ~(1 << bitPosition); frameBuffer[byteIndex] &= ~(1 << bitPosition);
} }
@ -723,15 +702,13 @@ void GfxRenderer::draw2BitImage(const uint8_t data[], int x, int y, int w,
// Fallback: generic path for grayscale modes // Fallback: generic path for grayscale modes
for (int row = 0; row < h; row++) { for (int row = 0; row < h; row++) {
const int screenY = y + row; const int screenY = y + row;
if (screenY < 0 || screenY >= screenHeight) if (screenY < 0 || screenY >= screenHeight) continue;
continue;
const uint8_t* srcRow = data + row * srcRowBytes; const uint8_t* srcRow = data + row * srcRowBytes;
for (int col = 0; col < w; col++) { for (int col = 0; col < w; col++) {
const int screenX = x + col; const int screenX = x + col;
if (screenX < 0 || screenX >= screenWidth) if (screenX < 0 || screenX >= screenWidth) continue;
continue;
const uint8_t val = (srcRow[col / 4] >> (6 - ((col % 4) * 2))) & 0x3; const uint8_t val = (srcRow[col / 4] >> (6 - ((col % 4) * 2))) & 0x3;
@ -744,19 +721,16 @@ void GfxRenderer::draw2BitImage(const uint8_t data[], int x, int y, int w,
} }
} }
void GfxRenderer::drawBitmap1Bit(const Bitmap &bitmap, const int x, const int y, void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y, const int maxWidth,
const int maxWidth,
const int maxHeight) const { const int maxHeight) const {
float scale = 1.0f; float scale = 1.0f;
bool isScaled = false; bool isScaled = false;
if (maxWidth > 0 && bitmap.getWidth() > maxWidth) { if (maxWidth > 0 && bitmap.getWidth() > maxWidth) {
scale = scale = static_cast<float>(maxWidth) / static_cast<float>(bitmap.getWidth());
static_cast<float>(maxWidth) / static_cast<float>(bitmap.getWidth());
isScaled = true; isScaled = true;
} }
if (maxHeight > 0 && bitmap.getHeight() > maxHeight) { if (maxHeight > 0 && bitmap.getHeight() > maxHeight) {
scale = std::min(scale, static_cast<float>(maxHeight) / scale = std::min(scale, static_cast<float>(maxHeight) / static_cast<float>(bitmap.getHeight()));
static_cast<float>(bitmap.getHeight()));
isScaled = true; isScaled = true;
} }
@ -767,8 +741,7 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap &bitmap, const int x, const int y,
auto* rowBytes = static_cast<uint8_t*>(malloc(bitmap.getRowBytes())); auto* rowBytes = static_cast<uint8_t*>(malloc(bitmap.getRowBytes()));
if (!outputRow || !rowBytes) { if (!outputRow || !rowBytes) {
Serial.printf("[%lu] [GFX] !! Failed to allocate 1-bit BMP row buffers\n", Serial.printf("[%lu] [GFX] !! Failed to allocate 1-bit BMP row buffers\n", millis());
millis());
free(outputRow); free(outputRow);
free(rowBytes); free(rowBytes);
return; return;
@ -777,19 +750,15 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap &bitmap, const int x, const int y,
for (int bmpY = 0; bmpY < bitmap.getHeight(); bmpY++) { for (int bmpY = 0; bmpY < bitmap.getHeight(); bmpY++) {
// Read rows sequentially using readNextRow // Read rows sequentially using readNextRow
if (bitmap.readNextRow(outputRow, rowBytes) != BmpReaderError::Ok) { if (bitmap.readNextRow(outputRow, rowBytes) != BmpReaderError::Ok) {
Serial.printf("[%lu] [GFX] Failed to read row %d from 1-bit bitmap\n", Serial.printf("[%lu] [GFX] Failed to read row %d from 1-bit bitmap\n", millis(), bmpY);
millis(), bmpY);
free(outputRow); free(outputRow);
free(rowBytes); free(rowBytes);
return; return;
} }
// Calculate screen Y based on whether BMP is top-down or bottom-up // Calculate screen Y based on whether BMP is top-down or bottom-up
const int bmpYOffset = const int bmpYOffset = bitmap.isTopDown() ? bmpY : bitmap.getHeight() - 1 - bmpY;
bitmap.isTopDown() ? bmpY : bitmap.getHeight() - 1 - bmpY; int screenY = y + (isScaled ? static_cast<int>(std::floor(bmpYOffset * scale)) : bmpYOffset);
int screenY =
y + (isScaled ? static_cast<int>(std::floor(bmpYOffset * scale))
: bmpYOffset);
if (screenY >= getScreenHeight()) { if (screenY >= getScreenHeight()) {
continue; // Continue reading to keep row counter in sync continue; // Continue reading to keep row counter in sync
} }
@ -798,8 +767,7 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap &bitmap, const int x, const int y,
} }
for (int bmpX = 0; bmpX < bitmap.getWidth(); bmpX++) { for (int bmpX = 0; bmpX < bitmap.getWidth(); bmpX++) {
int screenX = int screenX = x + (isScaled ? static_cast<int>(std::floor(bmpX * scale)) : bmpX);
x + (isScaled ? static_cast<int>(std::floor(bmpX * scale)) : bmpX);
if (screenX >= getScreenWidth()) { if (screenX >= getScreenWidth()) {
break; break;
} }
@ -1008,31 +976,24 @@ void GfxRenderer::drawRoundedBitmap(const Bitmap& bitmap, const int x, const int
free(rowBytes); free(rowBytes);
} }
void GfxRenderer::fillPolygon(const int *xPoints, const int *yPoints, void GfxRenderer::fillPolygon(const int* xPoints, const int* yPoints, int numPoints, bool state) const {
int numPoints, bool state) const { if (numPoints < 3) return;
if (numPoints < 3)
return;
// Find bounding box // Find bounding box
int minY = yPoints[0], maxY = yPoints[0]; int minY = yPoints[0], maxY = yPoints[0];
for (int i = 1; i < numPoints; i++) { for (int i = 1; i < numPoints; i++) {
if (yPoints[i] < minY) if (yPoints[i] < minY) minY = yPoints[i];
minY = yPoints[i]; if (yPoints[i] > maxY) maxY = yPoints[i];
if (yPoints[i] > maxY)
maxY = yPoints[i];
} }
// Clip to screen // Clip to screen
if (minY < 0) if (minY < 0) minY = 0;
minY = 0; if (maxY >= getScreenHeight()) maxY = getScreenHeight() - 1;
if (maxY >= getScreenHeight())
maxY = getScreenHeight() - 1;
// Allocate node buffer for scanline algorithm // Allocate node buffer for scanline algorithm
auto* nodeX = static_cast<int*>(malloc(numPoints * sizeof(int))); auto* nodeX = static_cast<int*>(malloc(numPoints * sizeof(int)));
if (!nodeX) { if (!nodeX) {
Serial.printf("[%lu] [GFX] !! Failed to allocate polygon node buffer\n", Serial.printf("[%lu] [GFX] !! Failed to allocate polygon node buffer\n", millis());
millis());
return; return;
} }
@ -1043,13 +1004,11 @@ void GfxRenderer::fillPolygon(const int *xPoints, const int *yPoints,
// Find all intersection points with edges // Find all intersection points with edges
int j = numPoints - 1; int j = numPoints - 1;
for (int i = 0; i < numPoints; i++) { for (int i = 0; i < numPoints; i++) {
if ((yPoints[i] < scanY && yPoints[j] >= scanY) || if ((yPoints[i] < scanY && yPoints[j] >= scanY) || (yPoints[j] < scanY && yPoints[i] >= scanY)) {
(yPoints[j] < scanY && yPoints[i] >= scanY)) {
// Calculate X intersection using fixed-point to avoid float // Calculate X intersection using fixed-point to avoid float
int dy = yPoints[j] - yPoints[i]; int dy = yPoints[j] - yPoints[i];
if (dy != 0) { if (dy != 0) {
nodeX[nodes++] = xPoints[i] + (scanY - yPoints[i]) * nodeX[nodes++] = xPoints[i] + (scanY - yPoints[i]) * (xPoints[j] - xPoints[i]) / dy;
(xPoints[j] - xPoints[i]) / dy;
} }
} }
j = i; j = i;
@ -1072,10 +1031,8 @@ void GfxRenderer::fillPolygon(const int *xPoints, const int *yPoints,
int endX = nodeX[i + 1]; int endX = nodeX[i + 1];
// Clip to screen // Clip to screen
if (startX < 0) if (startX < 0) startX = 0;
startX = 0; if (endX >= getScreenWidth()) endX = getScreenWidth() - 1;
if (endX >= getScreenWidth())
endX = getScreenWidth() - 1;
// Draw horizontal line // Draw horizontal line
for (int x = startX; x <= endX; x++) { for (int x = startX; x <= endX; x++) {
@ -1097,8 +1054,14 @@ uint8_t* GfxRenderer::captureRegion(int x, int y, int width, int height, size_t*
// Clip to screen bounds // Clip to screen bounds
const int screenWidth = getScreenWidth(); const int screenWidth = getScreenWidth();
const int screenHeight = getScreenHeight(); const int screenHeight = getScreenHeight();
if (x < 0) { width += x; x = 0; } if (x < 0) {
if (y < 0) { height += y; y = 0; } width += x;
x = 0;
}
if (y < 0) {
height += y;
y = 0;
}
if (x + width > screenWidth) width = screenWidth - x; if (x + width > screenWidth) width = screenWidth - x;
if (y + height > screenHeight) height = screenHeight - y; if (y + height > screenHeight) height = screenHeight - y;
@ -1220,8 +1183,7 @@ void GfxRenderer::invertScreen() const {
void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const { display.displayBuffer(refreshMode); } void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const { display.displayBuffer(refreshMode); }
std::string GfxRenderer::truncatedText(const int fontId, const char *text, std::string GfxRenderer::truncatedText(const int fontId, const char* text, const int maxWidth,
const int maxWidth,
const EpdFontFamily::Style style) const { const EpdFontFamily::Style style) const {
std::string item = text; std::string item = text;
int itemWidth = getTextWidth(fontId, item.c_str(), style); int itemWidth = getTextWidth(fontId, item.c_str(), style);
@ -1289,8 +1251,7 @@ int GfxRenderer::getLineHeight(const int fontId) const {
return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->advanceY; return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->advanceY;
} }
void GfxRenderer::drawButtonHints(const int fontId, const char *btn1, void GfxRenderer::drawButtonHints(const int fontId, const char* btn1, const char* btn2, const char* btn3,
const char *btn2, const char *btn3,
const char* btn4) { const char* btn4) {
const Orientation orig_orientation = getOrientation(); const Orientation orig_orientation = getOrientation();
setOrientation(Orientation::Portrait); setOrientation(Orientation::Portrait);
@ -1318,8 +1279,7 @@ void GfxRenderer::drawButtonHints(const int fontId, const char *btn1,
setOrientation(orig_orientation); setOrientation(orig_orientation);
} }
void GfxRenderer::drawSideButtonHints(const int fontId, const char *topBtn, void GfxRenderer::drawSideButtonHints(const int fontId, const char* topBtn, const char* bottomBtn) const {
const char *bottomBtn) const {
const int screenWidth = getScreenWidth(); const int screenWidth = getScreenWidth();
constexpr int buttonWidth = 40; // Width on screen (height when rotated) constexpr int buttonWidth = 40; // Width on screen (height when rotated)
constexpr int buttonHeight = 80; // Height on screen (width when rotated) constexpr int buttonHeight = 80; // Height on screen (width when rotated)
@ -1341,8 +1301,7 @@ void GfxRenderer::drawSideButtonHints(const int fontId, const char *topBtn,
} }
// Draw shared middle border // Draw shared middle border
if ((topBtn != nullptr && topBtn[0] != '\0') || if ((topBtn != nullptr && topBtn[0] != '\0') || (bottomBtn != nullptr && bottomBtn[0] != '\0')) {
(bottomBtn != nullptr && bottomBtn[0] != '\0')) {
drawLine(x, topButtonY + buttonHeight, x + buttonWidth - 1, drawLine(x, topButtonY + buttonHeight, x + buttonWidth - 1,
topButtonY + buttonHeight); // Shared border topButtonY + buttonHeight); // Shared border
} }
@ -1351,8 +1310,7 @@ void GfxRenderer::drawSideButtonHints(const int fontId, const char *topBtn,
if (bottomBtn != nullptr && bottomBtn[0] != '\0') { if (bottomBtn != nullptr && bottomBtn[0] != '\0') {
drawLine(x, topButtonY + buttonHeight, x, drawLine(x, topButtonY + buttonHeight, x,
topButtonY + 2 * buttonHeight - 1); // Left topButtonY + 2 * buttonHeight - 1); // Left
drawLine(x + buttonWidth - 1, topButtonY + buttonHeight, drawLine(x + buttonWidth - 1, topButtonY + buttonHeight, x + buttonWidth - 1,
x + buttonWidth - 1,
topButtonY + 2 * buttonHeight - 1); // Right topButtonY + 2 * buttonHeight - 1); // Right
drawLine(x, topButtonY + 2 * buttonHeight - 1, x + buttonWidth - 1, drawLine(x, topButtonY + 2 * buttonHeight - 1, x + buttonWidth - 1,
topButtonY + 2 * buttonHeight - 1); // Bottom topButtonY + 2 * buttonHeight - 1); // Bottom
@ -1384,9 +1342,7 @@ int GfxRenderer::getTextHeight(const int fontId) const {
return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->ascender; return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->ascender;
} }
void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, const int y, const char* text, const bool black,
const int y, const char *text,
const bool black,
const EpdFontFamily::Style style) const { const EpdFontFamily::Style style) const {
// Cannot draw a NULL / empty string // Cannot draw a NULL / empty string
if (text == nullptr || *text == '\0') { if (text == nullptr || *text == '\0') {
@ -1437,8 +1393,7 @@ void GfxRenderer::drawTextRotated90CW(const int fontId, const int x,
// 90° clockwise rotation transformation: // 90° clockwise rotation transformation:
// screenX = x + (ascender - top + glyphY) // screenX = x + (ascender - top + glyphY)
// screenY = yPos - (left + glyphX) // screenY = yPos - (left + glyphX)
const int screenX = const int screenX = x + (font.getData(style)->ascender - top + glyphY);
x + (font.getData(style)->ascender - top + glyphY);
const int screenY = yPos - left - glyphX; const int screenY = yPos - left - glyphX;
if (is2Bit) { if (is2Bit) {
@ -1448,8 +1403,7 @@ void GfxRenderer::drawTextRotated90CW(const int fontId, const int x,
if (renderMode == BW && bmpVal < 3) { if (renderMode == BW && bmpVal < 3) {
drawPixel(screenX, screenY, black); drawPixel(screenX, screenY, black);
} else if (renderMode == GRAYSCALE_MSB && } else if (renderMode == GRAYSCALE_MSB && (bmpVal == 1 || bmpVal == 2)) {
(bmpVal == 1 || bmpVal == 2)) {
drawPixel(screenX, screenY, false); drawPixel(screenX, screenY, false);
} else if (renderMode == GRAYSCALE_LSB && bmpVal == 1) { } else if (renderMode == GRAYSCALE_LSB && bmpVal == 1) {
drawPixel(screenX, screenY, false); drawPixel(screenX, screenY, false);
@ -1511,7 +1465,8 @@ bool GfxRenderer::storeBwBuffer() {
for (size_t i = 0; i < BW_BUFFER_NUM_CHUNKS; i++) { for (size_t i = 0; i < BW_BUFFER_NUM_CHUNKS; i++) {
// Check if any chunks are already allocated // Check if any chunks are already allocated
if (bwBufferChunks[i]) { if (bwBufferChunks[i]) {
Serial.printf("[%lu] [GFX] !! BW buffer chunk %zu already stored - this " Serial.printf(
"[%lu] [GFX] !! BW buffer chunk %zu already stored - this "
"is likely a bug, freeing chunk\n", "is likely a bug, freeing chunk\n",
millis(), i); millis(), i);
free(bwBufferChunks[i]); free(bwBufferChunks[i]);
@ -1522,9 +1477,8 @@ bool GfxRenderer::storeBwBuffer() {
bwBufferChunks[i] = static_cast<uint8_t*>(malloc(BW_BUFFER_CHUNK_SIZE)); bwBufferChunks[i] = static_cast<uint8_t*>(malloc(BW_BUFFER_CHUNK_SIZE));
if (!bwBufferChunks[i]) { if (!bwBufferChunks[i]) {
Serial.printf( Serial.printf("[%lu] [GFX] !! Failed to allocate BW buffer chunk %zu (%zu bytes)\n", millis(), i,
"[%lu] [GFX] !! Failed to allocate BW buffer chunk %zu (%zu bytes)\n", BW_BUFFER_CHUNK_SIZE);
millis(), i, BW_BUFFER_CHUNK_SIZE);
// Free previously allocated chunks // Free previously allocated chunks
freeBwBufferChunks(); freeBwBufferChunks();
return false; return false;
@ -1533,8 +1487,8 @@ bool GfxRenderer::storeBwBuffer() {
memcpy(bwBufferChunks[i], frameBuffer + offset, BW_BUFFER_CHUNK_SIZE); memcpy(bwBufferChunks[i], frameBuffer + offset, BW_BUFFER_CHUNK_SIZE);
} }
Serial.printf("[%lu] [GFX] Stored BW buffer in %zu chunks (%zu bytes each)\n", Serial.printf("[%lu] [GFX] Stored BW buffer in %zu chunks (%zu bytes each)\n", millis(), BW_BUFFER_NUM_CHUNKS,
millis(), BW_BUFFER_NUM_CHUNKS, BW_BUFFER_CHUNK_SIZE); BW_BUFFER_CHUNK_SIZE);
return true; return true;
} }
@ -1560,8 +1514,7 @@ void GfxRenderer::restoreBwBuffer() {
uint8_t* frameBuffer = display.getFrameBuffer(); uint8_t* frameBuffer = display.getFrameBuffer();
if (!frameBuffer) { if (!frameBuffer) {
Serial.printf("[%lu] [GFX] !! No framebuffer in restoreBwBuffer\n", Serial.printf("[%lu] [GFX] !! No framebuffer in restoreBwBuffer\n", millis());
millis());
freeBwBufferChunks(); freeBwBufferChunks();
return; return;
} }
@ -1569,9 +1522,7 @@ void GfxRenderer::restoreBwBuffer() {
for (size_t i = 0; i < BW_BUFFER_NUM_CHUNKS; i++) { for (size_t i = 0; i < BW_BUFFER_NUM_CHUNKS; i++) {
// Check if chunk is missing // Check if chunk is missing
if (!bwBufferChunks[i]) { if (!bwBufferChunks[i]) {
Serial.printf( Serial.printf("[%lu] [GFX] !! BW buffer chunks not stored - this is likely a bug\n", millis());
"[%lu] [GFX] !! BW buffer chunks not stored - this is likely a bug\n",
millis());
freeBwBufferChunks(); freeBwBufferChunks();
return; return;
} }
@ -1597,9 +1548,8 @@ void GfxRenderer::cleanupGrayscaleWithFrameBuffer() const {
} }
} }
void GfxRenderer::renderChar(const EpdFontFamily &fontFamily, const uint32_t cp, void GfxRenderer::renderChar(const EpdFontFamily& fontFamily, const uint32_t cp, int* x, const int* y,
int *x, const int *y, const bool pixelState, const bool pixelState, const EpdFontFamily::Style style) const {
const EpdFontFamily::Style style) const {
const EpdGlyph* glyph = fontFamily.getGlyph(cp, style); const EpdGlyph* glyph = fontFamily.getGlyph(cp, style);
if (!glyph) { if (!glyph) {
glyph = fontFamily.getGlyph(REPLACEMENT_GLYPH, style); glyph = fontFamily.getGlyph(REPLACEMENT_GLYPH, style);
@ -1639,8 +1589,7 @@ void GfxRenderer::renderChar(const EpdFontFamily &fontFamily, const uint32_t cp,
if (renderMode == BW && bmpVal < 3) { if (renderMode == BW && bmpVal < 3) {
// Black (also paints over the grays in BW mode) // Black (also paints over the grays in BW mode)
drawPixel(screenX, screenY, pixelState); drawPixel(screenX, screenY, pixelState);
} else if (renderMode == GRAYSCALE_MSB && } else if (renderMode == GRAYSCALE_MSB && (bmpVal == 1 || bmpVal == 2)) {
(bmpVal == 1 || bmpVal == 2)) {
// Light gray (also mark the MSB if it's going to be a dark gray // Light gray (also mark the MSB if it's going to be a dark gray
// too) We have to flag pixels in reverse for the gray buffers, as 0 // too) We have to flag pixels in reverse for the gray buffers, as 0
// leave alone, 1 update // leave alone, 1 update
@ -1664,8 +1613,7 @@ void GfxRenderer::renderChar(const EpdFontFamily &fontFamily, const uint32_t cp,
*x += glyph->advanceX; *x += glyph->advanceX;
} }
void GfxRenderer::getOrientedViewableTRBL(int *outTop, int *outRight, void GfxRenderer::getOrientedViewableTRBL(int* outTop, int* outRight, int* outBottom, int* outLeft) const {
int *outBottom, int *outLeft) const {
switch (orientation) { switch (orientation) {
case Portrait: case Portrait:
*outTop = VIEWABLE_MARGIN_TOP; *outTop = VIEWABLE_MARGIN_TOP;

View File

@ -32,8 +32,7 @@ public:
Orientation orientation; Orientation orientation;
uint8_t* bwBufferChunks[BW_BUFFER_NUM_CHUNKS] = {nullptr}; uint8_t* bwBufferChunks[BW_BUFFER_NUM_CHUNKS] = {nullptr};
std::map<int, EpdFontFamily> fontMap; std::map<int, EpdFontFamily> fontMap;
void renderChar(const EpdFontFamily &fontFamily, uint32_t cp, int *x, void renderChar(const EpdFontFamily& fontFamily, uint32_t cp, int* x, const int* y, bool pixelState,
const int *y, bool pixelState,
EpdFontFamily::Style style) const; EpdFontFamily::Style style) const;
void freeBwBufferChunks(); void freeBwBufferChunks();
void rotateCoordinates(int x, int y, int* rotatedX, int* rotatedY) const; void rotateCoordinates(int x, int y, int* rotatedX, int* rotatedY) const;
@ -74,52 +73,41 @@ public:
void drawRoundedRect(int x, int y, int width, int height, int radius, bool state = true) const; void drawRoundedRect(int x, int y, int width, int height, int radius, bool state = true) const;
void fillRoundedRect(int x, int y, int width, int height, int radius, bool state = true) const; void fillRoundedRect(int x, int y, int width, int height, int radius, bool state = true) const;
void fillRoundedRectDithered(int x, int y, int width, int height, int radius, uint8_t grayLevel) const; void fillRoundedRectDithered(int x, int y, int width, int height, int radius, uint8_t grayLevel) const;
void drawImage(const uint8_t bitmap[], int x, int y, int width, void drawImage(const uint8_t bitmap[], int x, int y, int width, int height) const;
int height) const; void drawBitmap(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight, float cropX = 0,
void drawBitmap(const Bitmap &bitmap, int x, int y, int maxWidth, float cropY = 0) const;
int maxHeight, float cropX = 0, float cropY = 0) const; void drawBitmap1Bit(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight) const;
void drawBitmap1Bit(const Bitmap &bitmap, int x, int y, int maxWidth,
int maxHeight) const;
void drawTransparentBitmap(const Bitmap& bitmap, int x, int y, int w, int h) const; void drawTransparentBitmap(const Bitmap& bitmap, int x, int y, int w, int h) const;
void drawRoundedBitmap(const Bitmap& bitmap, int x, int y, int w, int h, int radius) const; void drawRoundedBitmap(const Bitmap& bitmap, int x, int y, int w, int h, int radius) const;
void draw2BitImage(const uint8_t data[], int x, int y, int w, int h) const; void draw2BitImage(const uint8_t data[], int x, int y, int w, int h) const;
void fillPolygon(const int *xPoints, const int *yPoints, int numPoints, void fillPolygon(const int* xPoints, const int* yPoints, int numPoints, bool state = true) const;
bool state = true) const;
// Region caching - copies a rectangular region to/from a buffer // Region caching - copies a rectangular region to/from a buffer
// Returns allocated buffer on success, nullptr on failure. Caller owns the // Returns allocated buffer on success, nullptr on failure. Caller owns the
// memory. // memory.
uint8_t *captureRegion(int x, int y, int width, int height, uint8_t* captureRegion(int x, int y, int width, int height, size_t* outSize) const;
size_t *outSize) const;
// Restores a previously captured region. Buffer must match dimensions. // Restores a previously captured region. Buffer must match dimensions.
void restoreRegion(const uint8_t *buffer, int x, int y, int width, void restoreRegion(const uint8_t* buffer, int x, int y, int width, int height) const;
int height) const;
// Text // Text
int getTextWidth(int fontId, const char *text, int getTextWidth(int fontId, const char* text, EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const; void drawCenteredText(int fontId, int y, const char* text, bool black = true,
void
drawCenteredText(int fontId, int y, const char *text, bool black = true,
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const; EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
void drawText(int fontId, int x, int y, const char* text, bool black = true, void drawText(int fontId, int x, int y, const char* text, bool black = true,
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const; EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
int getSpaceWidth(int fontId) const; int getSpaceWidth(int fontId) const;
int getFontAscenderSize(int fontId) const; int getFontAscenderSize(int fontId) const;
int getLineHeight(int fontId) const; int getLineHeight(int fontId) const;
std::string std::string truncatedText(int fontId, const char* text, int maxWidth,
truncatedText(int fontId, const char *text, int maxWidth,
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const; EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
// UI Components // UI Components
void drawButtonHints(int fontId, const char *btn1, const char *btn2, void drawButtonHints(int fontId, const char* btn1, const char* btn2, const char* btn3, const char* btn4);
const char *btn3, const char *btn4); void drawSideButtonHints(int fontId, const char* topBtn, const char* bottomBtn) const;
void drawSideButtonHints(int fontId, const char *topBtn,
const char *bottomBtn) const;
private: private:
// Helper for drawing rotated text (90 degrees clockwise, for side buttons) // Helper for drawing rotated text (90 degrees clockwise, for side buttons)
void drawTextRotated90CW( void drawTextRotated90CW(int fontId, int x, int y, const char* text, bool black = true,
int fontId, int x, int y, const char *text, bool black = true,
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const; EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
int getTextHeight(int fontId) const; int getTextHeight(int fontId) const;
@ -137,6 +125,5 @@ public:
uint8_t* getFrameBuffer() const; uint8_t* getFrameBuffer() const;
static size_t getBufferSize(); static size_t getBufferSize();
void grayscaleRevert() const; void grayscaleRevert() const;
void getOrientedViewableTRBL(int *outTop, int *outRight, int *outBottom, void getOrientedViewableTRBL(int* outTop, int* outRight, int* outBottom, int* outLeft) const;
int *outLeft) const;
}; };

View File

@ -13,8 +13,7 @@
#include "ThemeSelectionActivity.h" #include "ThemeSelectionActivity.h"
#include "fontIds.h" #include "fontIds.h"
const char *SettingsActivity::categoryNames[categoryCount] = { const char* SettingsActivity::categoryNames[categoryCount] = {"Display", "Reader", "Controls", "System"};
"Display", "Reader", "Controls", "System"};
namespace { namespace {
constexpr int displaySettingsCount = 7; constexpr int displaySettingsCount = 7;
@ -32,25 +31,17 @@ const SettingInfo displaySettings[displaySettingsCount] = {
constexpr int readerSettingsCount = 9; constexpr int readerSettingsCount = 9;
const SettingInfo readerSettings[readerSettingsCount] = { const SettingInfo readerSettings[readerSettingsCount] = {
SettingInfo::Enum("Font Family", &CrossPointSettings::fontFamily, SettingInfo::Enum("Font Family", &CrossPointSettings::fontFamily, {"Bookerly", "Noto Sans", "Open Dyslexic"}),
{"Bookerly", "Noto Sans", "Open Dyslexic"}), SettingInfo::Enum("Font Size", &CrossPointSettings::fontSize, {"Small", "Medium", "Large", "X Large"}),
SettingInfo::Enum("Font Size", &CrossPointSettings::fontSize, SettingInfo::Enum("Line Spacing", &CrossPointSettings::lineSpacing, {"Tight", "Normal", "Wide"}),
{"Small", "Medium", "Large", "X Large"}), SettingInfo::Value("Screen Margin", &CrossPointSettings::screenMargin, {5, 40, 5}),
SettingInfo::Enum("Line Spacing", &CrossPointSettings::lineSpacing, SettingInfo::Enum("Paragraph Alignment", &CrossPointSettings::paragraphAlignment,
{"Tight", "Normal", "Wide"}),
SettingInfo::Value("Screen Margin", &CrossPointSettings::screenMargin,
{5, 40, 5}),
SettingInfo::Enum("Paragraph Alignment",
&CrossPointSettings::paragraphAlignment,
{"Justify", "Left", "Center", "Right"}), {"Justify", "Left", "Center", "Right"}),
SettingInfo::Toggle("Hyphenation", &CrossPointSettings::hyphenationEnabled), SettingInfo::Toggle("Hyphenation", &CrossPointSettings::hyphenationEnabled),
SettingInfo::Enum( SettingInfo::Enum("Reading Orientation", &CrossPointSettings::orientation,
"Reading Orientation", &CrossPointSettings::orientation,
{"Portrait", "Landscape CW", "Inverted", "Landscape CCW"}), {"Portrait", "Landscape CW", "Inverted", "Landscape CCW"}),
SettingInfo::Toggle("Extra Paragraph Spacing", SettingInfo::Toggle("Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing),
&CrossPointSettings::extraParagraphSpacing), SettingInfo::Toggle("Text Anti-Aliasing", &CrossPointSettings::textAntiAliasing)};
SettingInfo::Toggle("Text Anti-Aliasing",
&CrossPointSettings::textAntiAliasing)};
constexpr int controlsSettingsCount = 4; constexpr int controlsSettingsCount = 4;
const SettingInfo controlsSettings[controlsSettingsCount] = { const SettingInfo controlsSettings[controlsSettingsCount] = {
@ -59,11 +50,8 @@ const SettingInfo controlsSettings[controlsSettingsCount] = {
{"Bck, Cnfrm, Lft, Rght", "Lft, Rght, Bck, Cnfrm", "Lft, Bck, Cnfrm, Rght", "Bck, Cnfrm, Rght, Lft"}), {"Bck, Cnfrm, Lft, Rght", "Lft, Rght, Bck, Cnfrm", "Lft, Bck, Cnfrm, Rght", "Bck, Cnfrm, Rght, Lft"}),
SettingInfo::Enum("Side Button Layout (reader)", &CrossPointSettings::sideButtonLayout, SettingInfo::Enum("Side Button Layout (reader)", &CrossPointSettings::sideButtonLayout,
{"Prev, Next", "Next, Prev"}), {"Prev, Next", "Next, Prev"}),
SettingInfo::Toggle("Long-press Chapter Skip", SettingInfo::Toggle("Long-press Chapter Skip", &CrossPointSettings::longPressChapterSkip),
&CrossPointSettings::longPressChapterSkip), SettingInfo::Enum("Short Power Button Click", &CrossPointSettings::shortPwrBtn, {"Ignore", "Sleep", "Page Turn"})};
SettingInfo::Enum("Short Power Button Click",
&CrossPointSettings::shortPwrBtn,
{"Ignore", "Sleep", "Page Turn"})};
constexpr int systemSettingsCount = 5; constexpr int systemSettingsCount = 5;
const SettingInfo systemSettings[systemSettingsCount] = { const SettingInfo systemSettings[systemSettingsCount] = {
@ -79,8 +67,7 @@ struct CategoryData {
int count; int count;
}; };
const CategoryData allCategories[4] = { const CategoryData allCategories[4] = {{"Display", displaySettings, displaySettingsCount},
{"Display", displaySettings, displaySettingsCount},
{"Reader", readerSettings, readerSettingsCount}, {"Reader", readerSettings, readerSettingsCount},
{"Controls", controlsSettings, controlsSettingsCount}, {"Controls", controlsSettings, controlsSettingsCount},
{"System", systemSettings, systemSettingsCount}}; {"System", systemSettings, systemSettingsCount}};
@ -194,16 +181,12 @@ void SettingsActivity::loop() {
if (mappedInput.wasPressed(MappedInputManager::Button::Up) || if (mappedInput.wasPressed(MappedInputManager::Button::Up) ||
mappedInput.wasPressed(MappedInputManager::Button::Left)) { mappedInput.wasPressed(MappedInputManager::Button::Left)) {
// Move selection up (with wrap-around) // Move selection up (with wrap-around)
selectedCategoryIndex = (selectedCategoryIndex > 0) selectedCategoryIndex = (selectedCategoryIndex > 0) ? (selectedCategoryIndex - 1) : (categoryCount - 1);
? (selectedCategoryIndex - 1)
: (categoryCount - 1);
updateRequired = true; updateRequired = true;
} else if (mappedInput.wasPressed(MappedInputManager::Button::Down) || } else if (mappedInput.wasPressed(MappedInputManager::Button::Down) ||
mappedInput.wasPressed(MappedInputManager::Button::Right)) { mappedInput.wasPressed(MappedInputManager::Button::Right)) {
// Move selection down (with wrap around) // Move selection down (with wrap around)
selectedCategoryIndex = (selectedCategoryIndex < categoryCount - 1) selectedCategoryIndex = (selectedCategoryIndex < categoryCount - 1) ? (selectedCategoryIndex + 1) : 0;
? (selectedCategoryIndex + 1)
: 0;
updateRequired = true; updateRequired = true;
} }
} }
@ -213,10 +196,9 @@ void SettingsActivity::enterCategoryLegacy(int categoryIndex) {
xSemaphoreTake(renderingMutex, portMAX_DELAY); xSemaphoreTake(renderingMutex, portMAX_DELAY);
exitActivity(); exitActivity();
enterNewActivity(new CategorySettingsActivity( enterNewActivity(new CategorySettingsActivity(renderer, mappedInput, allCategories[categoryIndex].name,
renderer, mappedInput, allCategories[categoryIndex].name, allCategories[categoryIndex].settings,
allCategories[categoryIndex].settings, allCategories[categoryIndex].count, allCategories[categoryIndex].count, [this] {
[this] {
exitActivity(); exitActivity();
updateRequired = true; updateRequired = true;
})); }));
@ -251,8 +233,7 @@ void SettingsActivity::render() const {
const auto pageHeight = renderer.getScreenHeight(); const auto pageHeight = renderer.getScreenHeight();
// Draw header // Draw header
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Settings", true, renderer.drawCenteredText(UI_12_FONT_ID, 15, "Settings", true, EpdFontFamily::BOLD);
EpdFontFamily::BOLD);
// Draw selection // Draw selection
renderer.fillRect(0, 60 + selectedCategoryIndex * 30 - 2, pageWidth - 1, 30); renderer.fillRect(0, 60 + selectedCategoryIndex * 30 - 2, pageWidth - 1, 30);
@ -261,19 +242,15 @@ void SettingsActivity::render() const {
const int categoryY = 60 + i * 30; // 30 pixels between categories const int categoryY = 60 + i * 30; // 30 pixels between categories
// Draw category name // Draw category name
renderer.drawText(UI_10_FONT_ID, 20, categoryY, categoryNames[i], renderer.drawText(UI_10_FONT_ID, 20, categoryY, categoryNames[i], i != selectedCategoryIndex);
i != selectedCategoryIndex);
} }
// Draw version text above button hints // Draw version text above button hints
renderer.drawText( renderer.drawText(SMALL_FONT_ID, pageWidth - 20 - renderer.getTextWidth(SMALL_FONT_ID, CROSSPOINT_VERSION),
SMALL_FONT_ID,
pageWidth - 20 - renderer.getTextWidth(SMALL_FONT_ID, CROSSPOINT_VERSION),
pageHeight - 60, CROSSPOINT_VERSION); pageHeight - 60, CROSSPOINT_VERSION);
const auto labels = mappedInput.mapLabels("« Back", "Select", "", ""); const auto labels = mappedInput.mapLabels("« Back", "Select", "", "");
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
labels.btn4);
renderer.displayBuffer(); renderer.displayBuffer();
} }

View File

@ -38,92 +38,76 @@ EpdFont bookerly14RegularFont(&bookerly_14_regular);
EpdFont bookerly14BoldFont(&bookerly_14_bold); EpdFont bookerly14BoldFont(&bookerly_14_bold);
EpdFont bookerly14ItalicFont(&bookerly_14_italic); EpdFont bookerly14ItalicFont(&bookerly_14_italic);
EpdFont bookerly14BoldItalicFont(&bookerly_14_bolditalic); EpdFont bookerly14BoldItalicFont(&bookerly_14_bolditalic);
EpdFontFamily bookerly14FontFamily(&bookerly14RegularFont, &bookerly14BoldFont, EpdFontFamily bookerly14FontFamily(&bookerly14RegularFont, &bookerly14BoldFont, &bookerly14ItalicFont,
&bookerly14ItalicFont,
&bookerly14BoldItalicFont); &bookerly14BoldItalicFont);
#ifndef OMIT_FONTS #ifndef OMIT_FONTS
EpdFont bookerly12RegularFont(&bookerly_12_regular); EpdFont bookerly12RegularFont(&bookerly_12_regular);
EpdFont bookerly12BoldFont(&bookerly_12_bold); EpdFont bookerly12BoldFont(&bookerly_12_bold);
EpdFont bookerly12ItalicFont(&bookerly_12_italic); EpdFont bookerly12ItalicFont(&bookerly_12_italic);
EpdFont bookerly12BoldItalicFont(&bookerly_12_bolditalic); EpdFont bookerly12BoldItalicFont(&bookerly_12_bolditalic);
EpdFontFamily bookerly12FontFamily(&bookerly12RegularFont, &bookerly12BoldFont, EpdFontFamily bookerly12FontFamily(&bookerly12RegularFont, &bookerly12BoldFont, &bookerly12ItalicFont,
&bookerly12ItalicFont,
&bookerly12BoldItalicFont); &bookerly12BoldItalicFont);
EpdFont bookerly16RegularFont(&bookerly_16_regular); EpdFont bookerly16RegularFont(&bookerly_16_regular);
EpdFont bookerly16BoldFont(&bookerly_16_bold); EpdFont bookerly16BoldFont(&bookerly_16_bold);
EpdFont bookerly16ItalicFont(&bookerly_16_italic); EpdFont bookerly16ItalicFont(&bookerly_16_italic);
EpdFont bookerly16BoldItalicFont(&bookerly_16_bolditalic); EpdFont bookerly16BoldItalicFont(&bookerly_16_bolditalic);
EpdFontFamily bookerly16FontFamily(&bookerly16RegularFont, &bookerly16BoldFont, EpdFontFamily bookerly16FontFamily(&bookerly16RegularFont, &bookerly16BoldFont, &bookerly16ItalicFont,
&bookerly16ItalicFont,
&bookerly16BoldItalicFont); &bookerly16BoldItalicFont);
EpdFont bookerly18RegularFont(&bookerly_18_regular); EpdFont bookerly18RegularFont(&bookerly_18_regular);
EpdFont bookerly18BoldFont(&bookerly_18_bold); EpdFont bookerly18BoldFont(&bookerly_18_bold);
EpdFont bookerly18ItalicFont(&bookerly_18_italic); EpdFont bookerly18ItalicFont(&bookerly_18_italic);
EpdFont bookerly18BoldItalicFont(&bookerly_18_bolditalic); EpdFont bookerly18BoldItalicFont(&bookerly_18_bolditalic);
EpdFontFamily bookerly18FontFamily(&bookerly18RegularFont, &bookerly18BoldFont, EpdFontFamily bookerly18FontFamily(&bookerly18RegularFont, &bookerly18BoldFont, &bookerly18ItalicFont,
&bookerly18ItalicFont,
&bookerly18BoldItalicFont); &bookerly18BoldItalicFont);
EpdFont notosans12RegularFont(&notosans_12_regular); EpdFont notosans12RegularFont(&notosans_12_regular);
EpdFont notosans12BoldFont(&notosans_12_bold); EpdFont notosans12BoldFont(&notosans_12_bold);
EpdFont notosans12ItalicFont(&notosans_12_italic); EpdFont notosans12ItalicFont(&notosans_12_italic);
EpdFont notosans12BoldItalicFont(&notosans_12_bolditalic); EpdFont notosans12BoldItalicFont(&notosans_12_bolditalic);
EpdFontFamily notosans12FontFamily(&notosans12RegularFont, &notosans12BoldFont, EpdFontFamily notosans12FontFamily(&notosans12RegularFont, &notosans12BoldFont, &notosans12ItalicFont,
&notosans12ItalicFont,
&notosans12BoldItalicFont); &notosans12BoldItalicFont);
EpdFont notosans14RegularFont(&notosans_14_regular); EpdFont notosans14RegularFont(&notosans_14_regular);
EpdFont notosans14BoldFont(&notosans_14_bold); EpdFont notosans14BoldFont(&notosans_14_bold);
EpdFont notosans14ItalicFont(&notosans_14_italic); EpdFont notosans14ItalicFont(&notosans_14_italic);
EpdFont notosans14BoldItalicFont(&notosans_14_bolditalic); EpdFont notosans14BoldItalicFont(&notosans_14_bolditalic);
EpdFontFamily notosans14FontFamily(&notosans14RegularFont, &notosans14BoldFont, EpdFontFamily notosans14FontFamily(&notosans14RegularFont, &notosans14BoldFont, &notosans14ItalicFont,
&notosans14ItalicFont,
&notosans14BoldItalicFont); &notosans14BoldItalicFont);
EpdFont notosans16RegularFont(&notosans_16_regular); EpdFont notosans16RegularFont(&notosans_16_regular);
EpdFont notosans16BoldFont(&notosans_16_bold); EpdFont notosans16BoldFont(&notosans_16_bold);
EpdFont notosans16ItalicFont(&notosans_16_italic); EpdFont notosans16ItalicFont(&notosans_16_italic);
EpdFont notosans16BoldItalicFont(&notosans_16_bolditalic); EpdFont notosans16BoldItalicFont(&notosans_16_bolditalic);
EpdFontFamily notosans16FontFamily(&notosans16RegularFont, &notosans16BoldFont, EpdFontFamily notosans16FontFamily(&notosans16RegularFont, &notosans16BoldFont, &notosans16ItalicFont,
&notosans16ItalicFont,
&notosans16BoldItalicFont); &notosans16BoldItalicFont);
EpdFont notosans18RegularFont(&notosans_18_regular); EpdFont notosans18RegularFont(&notosans_18_regular);
EpdFont notosans18BoldFont(&notosans_18_bold); EpdFont notosans18BoldFont(&notosans_18_bold);
EpdFont notosans18ItalicFont(&notosans_18_italic); EpdFont notosans18ItalicFont(&notosans_18_italic);
EpdFont notosans18BoldItalicFont(&notosans_18_bolditalic); EpdFont notosans18BoldItalicFont(&notosans_18_bolditalic);
EpdFontFamily notosans18FontFamily(&notosans18RegularFont, &notosans18BoldFont, EpdFontFamily notosans18FontFamily(&notosans18RegularFont, &notosans18BoldFont, &notosans18ItalicFont,
&notosans18ItalicFont,
&notosans18BoldItalicFont); &notosans18BoldItalicFont);
EpdFont opendyslexic8RegularFont(&opendyslexic_8_regular); EpdFont opendyslexic8RegularFont(&opendyslexic_8_regular);
EpdFont opendyslexic8BoldFont(&opendyslexic_8_bold); EpdFont opendyslexic8BoldFont(&opendyslexic_8_bold);
EpdFont opendyslexic8ItalicFont(&opendyslexic_8_italic); EpdFont opendyslexic8ItalicFont(&opendyslexic_8_italic);
EpdFont opendyslexic8BoldItalicFont(&opendyslexic_8_bolditalic); EpdFont opendyslexic8BoldItalicFont(&opendyslexic_8_bolditalic);
EpdFontFamily opendyslexic8FontFamily(&opendyslexic8RegularFont, EpdFontFamily opendyslexic8FontFamily(&opendyslexic8RegularFont, &opendyslexic8BoldFont, &opendyslexic8ItalicFont,
&opendyslexic8BoldFont,
&opendyslexic8ItalicFont,
&opendyslexic8BoldItalicFont); &opendyslexic8BoldItalicFont);
EpdFont opendyslexic10RegularFont(&opendyslexic_10_regular); EpdFont opendyslexic10RegularFont(&opendyslexic_10_regular);
EpdFont opendyslexic10BoldFont(&opendyslexic_10_bold); EpdFont opendyslexic10BoldFont(&opendyslexic_10_bold);
EpdFont opendyslexic10ItalicFont(&opendyslexic_10_italic); EpdFont opendyslexic10ItalicFont(&opendyslexic_10_italic);
EpdFont opendyslexic10BoldItalicFont(&opendyslexic_10_bolditalic); EpdFont opendyslexic10BoldItalicFont(&opendyslexic_10_bolditalic);
EpdFontFamily opendyslexic10FontFamily(&opendyslexic10RegularFont, EpdFontFamily opendyslexic10FontFamily(&opendyslexic10RegularFont, &opendyslexic10BoldFont, &opendyslexic10ItalicFont,
&opendyslexic10BoldFont,
&opendyslexic10ItalicFont,
&opendyslexic10BoldItalicFont); &opendyslexic10BoldItalicFont);
EpdFont opendyslexic12RegularFont(&opendyslexic_12_regular); EpdFont opendyslexic12RegularFont(&opendyslexic_12_regular);
EpdFont opendyslexic12BoldFont(&opendyslexic_12_bold); EpdFont opendyslexic12BoldFont(&opendyslexic_12_bold);
EpdFont opendyslexic12ItalicFont(&opendyslexic_12_italic); EpdFont opendyslexic12ItalicFont(&opendyslexic_12_italic);
EpdFont opendyslexic12BoldItalicFont(&opendyslexic_12_bolditalic); EpdFont opendyslexic12BoldItalicFont(&opendyslexic_12_bolditalic);
EpdFontFamily opendyslexic12FontFamily(&opendyslexic12RegularFont, EpdFontFamily opendyslexic12FontFamily(&opendyslexic12RegularFont, &opendyslexic12BoldFont, &opendyslexic12ItalicFont,
&opendyslexic12BoldFont,
&opendyslexic12ItalicFont,
&opendyslexic12BoldItalicFont); &opendyslexic12BoldItalicFont);
EpdFont opendyslexic14RegularFont(&opendyslexic_14_regular); EpdFont opendyslexic14RegularFont(&opendyslexic_14_regular);
EpdFont opendyslexic14BoldFont(&opendyslexic_14_bold); EpdFont opendyslexic14BoldFont(&opendyslexic_14_bold);
EpdFont opendyslexic14ItalicFont(&opendyslexic_14_italic); EpdFont opendyslexic14ItalicFont(&opendyslexic_14_italic);
EpdFont opendyslexic14BoldItalicFont(&opendyslexic_14_bolditalic); EpdFont opendyslexic14BoldItalicFont(&opendyslexic_14_bolditalic);
EpdFontFamily opendyslexic14FontFamily(&opendyslexic14RegularFont, EpdFontFamily opendyslexic14FontFamily(&opendyslexic14RegularFont, &opendyslexic14BoldFont, &opendyslexic14ItalicFont,
&opendyslexic14BoldFont,
&opendyslexic14ItalicFont,
&opendyslexic14BoldItalicFont); &opendyslexic14BoldItalicFont);
#endif // OMIT_FONTS #endif // OMIT_FONTS
@ -173,9 +157,7 @@ void verifyPowerButtonDuration() {
// now from millis()==0 (i.e. device start time). // now from millis()==0 (i.e. device start time).
const uint16_t calibration = start; const uint16_t calibration = start;
const uint16_t calibratedPressDuration = const uint16_t calibratedPressDuration =
(calibration < SETTINGS.getPowerButtonDuration()) (calibration < SETTINGS.getPowerButtonDuration()) ? SETTINGS.getPowerButtonDuration() - calibration : 1;
? SETTINGS.getPowerButtonDuration() - calibration
: 1;
gpio.update(); gpio.update();
// Needed because inputManager.isPressed() may take up to ~500ms to return the correct state // Needed because inputManager.isPressed() may take up to ~500ms to return the correct state
@ -223,55 +205,43 @@ void enterDeepSleep() {
} }
void onGoHome(); void onGoHome();
void onGoToMyLibraryWithTab(const std::string &path, void onGoToMyLibraryWithTab(const std::string& path, MyLibraryActivity::Tab tab);
MyLibraryActivity::Tab tab); void onGoToReader(const std::string& initialEpubPath, MyLibraryActivity::Tab fromTab) {
void onGoToReader(const std::string &initialEpubPath,
MyLibraryActivity::Tab fromTab) {
exitActivity(); exitActivity();
enterNewActivity(new ReaderActivity(renderer, mappedInputManager, enterNewActivity(
initialEpubPath, fromTab, onGoHome, new ReaderActivity(renderer, mappedInputManager, initialEpubPath, fromTab, onGoHome, onGoToMyLibraryWithTab));
onGoToMyLibraryWithTab));
}
void onContinueReading() {
onGoToReader(APP_STATE.openEpubPath, MyLibraryActivity::Tab::Recent);
} }
void onContinueReading() { onGoToReader(APP_STATE.openEpubPath, MyLibraryActivity::Tab::Recent); }
void onGoToFileTransfer() { void onGoToFileTransfer() {
exitActivity(); exitActivity();
enterNewActivity( enterNewActivity(new CrossPointWebServerActivity(renderer, mappedInputManager, onGoHome));
new CrossPointWebServerActivity(renderer, mappedInputManager, onGoHome));
} }
void onGoToSettings() { void onGoToSettings() {
exitActivity(); exitActivity();
enterNewActivity( enterNewActivity(new SettingsActivity(renderer, mappedInputManager, onGoHome));
new SettingsActivity(renderer, mappedInputManager, onGoHome));
} }
void onGoToMyLibrary() { void onGoToMyLibrary() {
exitActivity(); exitActivity();
enterNewActivity(new MyLibraryActivity(renderer, mappedInputManager, onGoHome, enterNewActivity(new MyLibraryActivity(renderer, mappedInputManager, onGoHome, onGoToReader));
onGoToReader));
} }
void onGoToMyLibraryWithTab(const std::string &path, void onGoToMyLibraryWithTab(const std::string& path, MyLibraryActivity::Tab tab) {
MyLibraryActivity::Tab tab) {
exitActivity(); exitActivity();
enterNewActivity(new MyLibraryActivity(renderer, mappedInputManager, onGoHome, enterNewActivity(new MyLibraryActivity(renderer, mappedInputManager, onGoHome, onGoToReader, tab, path));
onGoToReader, tab, path));
} }
void onGoToBrowser() { void onGoToBrowser() {
exitActivity(); exitActivity();
enterNewActivity( enterNewActivity(new OpdsBookBrowserActivity(renderer, mappedInputManager, onGoHome));
new OpdsBookBrowserActivity(renderer, mappedInputManager, onGoHome));
} }
void onGoHome() { void onGoHome() {
exitActivity(); exitActivity();
enterNewActivity(new HomeActivity( enterNewActivity(new HomeActivity(renderer, mappedInputManager, onContinueReading, onGoToMyLibrary, onGoToSettings,
renderer, mappedInputManager, onContinueReading, onGoToMyLibrary, onGoToFileTransfer, onGoToBrowser));
onGoToSettings, onGoToFileTransfer, onGoToBrowser));
} }
void setupDisplayAndFonts() { void setupDisplayAndFonts() {
@ -319,8 +289,7 @@ void setup() {
Serial.printf("[%lu] [ ] SD card initialization failed\n", millis()); Serial.printf("[%lu] [ ] SD card initialization failed\n", millis());
setupDisplayAndFonts(); setupDisplayAndFonts();
exitActivity(); exitActivity();
enterNewActivity(new FullScreenMessageActivity( enterNewActivity(new FullScreenMessageActivity(renderer, mappedInputManager, "SD card error", EpdFontFamily::BOLD));
renderer, mappedInputManager, "SD card error", EpdFontFamily::BOLD));
return; return;
} }
@ -335,9 +304,7 @@ void setup() {
// First serial output only here to avoid timing inconsistencies for power // First serial output only here to avoid timing inconsistencies for power
// button press duration verification // button press duration verification
Serial.printf("[%lu] [ ] Starting CrossPoint version " CROSSPOINT_VERSION Serial.printf("[%lu] [ ] Starting CrossPoint version " CROSSPOINT_VERSION "\n", millis());
"\n",
millis());
setupDisplayAndFonts(); setupDisplayAndFonts();
@ -377,9 +344,8 @@ void loop() {
gpio.update(); gpio.update();
if (Serial && millis() - lastMemPrint >= 10000) { if (Serial && millis() - lastMemPrint >= 10000) {
Serial.printf( Serial.printf("[%lu] [MEM] Free: %d bytes, Total: %d bytes, Min Free: %d bytes\n", millis(), ESP.getFreeHeap(),
"[%lu] [MEM] Free: %d bytes, Total: %d bytes, Min Free: %d bytes\n", ESP.getHeapSize(), ESP.getMinFreeHeap());
millis(), ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getMinFreeHeap());
lastMemPrint = millis(); lastMemPrint = millis();
} }
@ -392,9 +358,7 @@ void loop() {
const unsigned long sleepTimeoutMs = SETTINGS.getSleepTimeoutMs(); const unsigned long sleepTimeoutMs = SETTINGS.getSleepTimeoutMs();
if (millis() - lastActivityTime >= sleepTimeoutMs) { if (millis() - lastActivityTime >= sleepTimeoutMs) {
Serial.printf( Serial.printf("[%lu] [SLP] Auto-sleep triggered after %lu ms of inactivity\n", millis(), sleepTimeoutMs);
"[%lu] [SLP] Auto-sleep triggered after %lu ms of inactivity\n",
millis(), sleepTimeoutMs);
enterDeepSleep(); enterDeepSleep();
// This should never be hit as `enterDeepSleep` calls esp_deep_sleep_start // This should never be hit as `enterDeepSleep` calls esp_deep_sleep_start
return; return;
@ -416,9 +380,8 @@ void loop() {
if (loopDuration > maxLoopDuration) { if (loopDuration > maxLoopDuration) {
maxLoopDuration = loopDuration; maxLoopDuration = loopDuration;
if (maxLoopDuration > 50) { if (maxLoopDuration > 50) {
Serial.printf( Serial.printf("[%lu] [LOOP] New max loop duration: %lu ms (activity: %lu ms)\n", millis(), maxLoopDuration,
"[%lu] [LOOP] New max loop duration: %lu ms (activity: %lu ms)\n", activityDuration);
millis(), maxLoopDuration, activityDuration);
} }
} }