mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 14:47:37 +03:00
fix(cppcheck}: clang format
This commit is contained in:
parent
bb05b5ae6d
commit
2cd569bb1f
@ -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)
|
||||||
@ -63,14 +61,14 @@ void GfxRenderer::drawPixel(const int x, const int y, const bool state) const {
|
|||||||
const uint8_t bitPosition = 7 - (rotatedX % 8); // MSB first
|
const uint8_t bitPosition = 7 - (rotatedX % 8); // MSB first
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
frameBuffer[byteIndex] &= ~(1 << bitPosition); // Clear bit
|
frameBuffer[byteIndex] &= ~(1 << bitPosition); // Clear bit
|
||||||
} else {
|
} else {
|
||||||
frameBuffer[byteIndex] |= 1 << bitPosition; // Set bit
|
frameBuffer[byteIndex] |= 1 << bitPosition; // Set bit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GfxRenderer::readPixel(const int x, const int y) const {
|
bool GfxRenderer::readPixel(const int x, const int y) const {
|
||||||
uint8_t *frameBuffer = display.getFrameBuffer();
|
uint8_t* frameBuffer = display.getFrameBuffer();
|
||||||
if (!frameBuffer) {
|
if (!frameBuffer) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
@ -135,13 +128,12 @@ void GfxRenderer::drawText(const int fontId, const int x, const int y,
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t cp;
|
uint32_t cp;
|
||||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t **>(&text)))) {
|
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
||||||
renderChar(font, cp, &xpos, &yPos, black, style);
|
renderChar(font, cp, &xpos, &yPos, black, style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@ -151,9 +143,9 @@ void GfxRenderer::drawLine(int x1, int y1, int x2, int y2,
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
drawPixel(x1, y1, state);
|
drawPixel(x1, y1, state);
|
||||||
|
|
||||||
if (x1 == x2 && y1 == y2) break;
|
if (x1 == x2 && y1 == y2) break;
|
||||||
|
|
||||||
int e2 = 2 * err;
|
int e2 = 2 * err;
|
||||||
if (e2 > -dy) {
|
if (e2 > -dy) {
|
||||||
err -= dy;
|
err -= dy;
|
||||||
@ -166,17 +158,15 @@ 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,13 +193,12 @@ 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
|
||||||
} else {
|
} else {
|
||||||
frameBuffer[byteIndex] |= mask; // White
|
frameBuffer[byteIndex] |= mask; // White
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
|
|
||||||
@ -292,7 +279,7 @@ void GfxRenderer::fillRectDithered(const int x, const int y, const int width,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (grayLevel >= 0xF0) {
|
if (grayLevel >= 0xF0) {
|
||||||
fillRect(x, y, width, height, false); // Solid white
|
fillRect(x, y, width, height, false); // Solid white
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,12 +522,11 @@ void GfxRenderer::drawBitmap(const Bitmap &bitmap, const int x, const int y,
|
|||||||
// IMPORTANT: Use int, not uint8_t, to avoid overflow for images > 1020 pixels
|
// IMPORTANT: Use int, not uint8_t, to avoid overflow for images > 1020 pixels
|
||||||
// wide
|
// wide
|
||||||
const int outputRowSize = (bitmap.getWidth() + 3) / 4;
|
const int outputRowSize = (bitmap.getWidth() + 3) / 4;
|
||||||
auto *outputRow = static_cast<uint8_t *>(malloc(outputRowSize));
|
auto* outputRow = static_cast<uint8_t*>(malloc(outputRowSize));
|
||||||
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,19 +535,17 @@ 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);
|
||||||
}
|
}
|
||||||
screenY += y; // the offset should not be scaled
|
screenY += y; // the offset should not be scaled
|
||||||
if (screenY >= getScreenHeight()) {
|
if (screenY >= getScreenHeight()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@ -574,7 +565,7 @@ void GfxRenderer::drawBitmap(const Bitmap &bitmap, const int x, const int y,
|
|||||||
if (isScaled) {
|
if (isScaled) {
|
||||||
screenX = std::floor(screenX * scale);
|
screenX = std::floor(screenX * scale);
|
||||||
}
|
}
|
||||||
screenX += x; // the offset should not be scaled
|
screenX += x; // the offset should not be scaled
|
||||||
if (screenX >= getScreenWidth()) {
|
if (screenX >= getScreenWidth()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -604,9 +595,8 @@ 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,17 +612,15 @@ 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;
|
||||||
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;
|
|
||||||
|
|
||||||
// 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,10 +630,9 @@ 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,31 +721,27 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For 1-bit BMP, output is still 2-bit packed (for consistency with
|
// For 1-bit BMP, output is still 2-bit packed (for consistency with
|
||||||
// readNextRow)
|
// readNextRow)
|
||||||
const int outputRowSize = (bitmap.getWidth() + 3) / 4;
|
const int outputRowSize = (bitmap.getWidth() + 3) / 4;
|
||||||
auto *outputRow = static_cast<uint8_t *>(malloc(outputRowSize));
|
auto* outputRow = static_cast<uint8_t*>(malloc(outputRowSize));
|
||||||
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,29 +750,24 @@ 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
|
||||||
}
|
}
|
||||||
if (screenY < 0) {
|
if (screenY < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
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,19 +1251,18 @@ 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);
|
||||||
|
|
||||||
const int pageHeight = getScreenHeight();
|
const int pageHeight = getScreenHeight();
|
||||||
constexpr int buttonWidth = 106;
|
constexpr int buttonWidth = 106;
|
||||||
constexpr int buttonHeight = 40;
|
constexpr int buttonHeight = 40;
|
||||||
constexpr int buttonY = 40; // Distance from bottom
|
constexpr int buttonY = 40; // Distance from bottom
|
||||||
constexpr int textYOffset = 7; // Distance from top of button to text baseline
|
constexpr int textYOffset = 7; // Distance from top of button to text baseline
|
||||||
constexpr int buttonPositions[] = {25, 130, 245, 350};
|
constexpr int buttonPositions[] = {25, 130, 245, 350};
|
||||||
const char *labels[] = {btn1, btn2, btn3, btn4};
|
const char* labels[] = {btn1, btn2, btn3, btn4};
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
// Only draw if the label is non-empty
|
// Only draw if the label is non-empty
|
||||||
@ -1318,44 +1279,41 @@ 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)
|
||||||
constexpr int buttonX = 5; // Distance from right edge
|
constexpr int buttonX = 5; // Distance from right edge
|
||||||
// Position for the button group - buttons share a border so they're adjacent
|
// Position for the button group - buttons share a border so they're adjacent
|
||||||
constexpr int topButtonY = 345; // Top button position
|
constexpr int topButtonY = 345; // Top button position
|
||||||
|
|
||||||
const char *labels[] = {topBtn, bottomBtn};
|
const char* labels[] = {topBtn, bottomBtn};
|
||||||
|
|
||||||
// Draw the shared border for both buttons as one unit
|
// Draw the shared border for both buttons as one unit
|
||||||
const int x = screenWidth - buttonX - buttonWidth;
|
const int x = screenWidth - buttonX - buttonWidth;
|
||||||
|
|
||||||
// Draw top button outline (3 sides, bottom open)
|
// Draw top button outline (3 sides, bottom open)
|
||||||
if (topBtn != nullptr && topBtn[0] != '\0') {
|
if (topBtn != nullptr && topBtn[0] != '\0') {
|
||||||
drawLine(x, topButtonY, x + buttonWidth - 1, topButtonY); // Top
|
drawLine(x, topButtonY, x + buttonWidth - 1, topButtonY); // Top
|
||||||
drawLine(x, topButtonY, x, topButtonY + buttonHeight - 1); // Left
|
drawLine(x, topButtonY, x, topButtonY + buttonHeight - 1); // Left
|
||||||
drawLine(x + buttonWidth - 1, topButtonY, x + buttonWidth - 1,
|
drawLine(x + buttonWidth - 1, topButtonY, x + buttonWidth - 1,
|
||||||
topButtonY + buttonHeight - 1); // Right
|
topButtonY + buttonHeight - 1); // Right
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw bottom button outline (3 sides, top is shared)
|
// Draw bottom button outline (3 sides, top is shared)
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw text for each button
|
// Draw text for each button
|
||||||
@ -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') {
|
||||||
@ -1408,11 +1364,11 @@ void GfxRenderer::drawTextRotated90CW(const int fontId, const int x,
|
|||||||
// Original (glyphX, glyphY) -> Rotated (glyphY, -glyphX)
|
// Original (glyphX, glyphY) -> Rotated (glyphY, -glyphX)
|
||||||
// Text reads from bottom to top
|
// Text reads from bottom to top
|
||||||
|
|
||||||
int yPos = y; // Current Y position (decreases as we draw characters)
|
int yPos = y; // Current Y position (decreases as we draw characters)
|
||||||
|
|
||||||
uint32_t cp;
|
uint32_t cp;
|
||||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t **>(&text)))) {
|
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
||||||
const EpdGlyph *glyph = font.getGlyph(cp, style);
|
const EpdGlyph* glyph = font.getGlyph(cp, style);
|
||||||
if (!glyph) {
|
if (!glyph) {
|
||||||
glyph = font.getGlyph(REPLACEMENT_GLYPH, style);
|
glyph = font.getGlyph(REPLACEMENT_GLYPH, style);
|
||||||
}
|
}
|
||||||
@ -1427,7 +1383,7 @@ void GfxRenderer::drawTextRotated90CW(const int fontId, const int x,
|
|||||||
const int left = glyph->left;
|
const int left = glyph->left;
|
||||||
const int top = glyph->top;
|
const int top = glyph->top;
|
||||||
|
|
||||||
const uint8_t *bitmap = &font.getData(style)->bitmap[offset];
|
const uint8_t* bitmap = &font.getData(style)->bitmap[offset];
|
||||||
|
|
||||||
if (bitmap != nullptr) {
|
if (bitmap != nullptr) {
|
||||||
for (int glyphY = 0; glyphY < height; glyphY++) {
|
for (int glyphY = 0; glyphY < height; glyphY++) {
|
||||||
@ -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);
|
||||||
@ -1485,7 +1439,7 @@ void GfxRenderer::copyGrayscaleMsbBuffers() const { display.copyGrayscaleMsbBuff
|
|||||||
void GfxRenderer::displayGrayBuffer() const { display.displayGrayBuffer(); }
|
void GfxRenderer::displayGrayBuffer() const { display.displayGrayBuffer(); }
|
||||||
|
|
||||||
void GfxRenderer::freeBwBufferChunks() {
|
void GfxRenderer::freeBwBufferChunks() {
|
||||||
for (auto &bwBufferChunk : bwBufferChunks) {
|
for (auto& bwBufferChunk : bwBufferChunks) {
|
||||||
if (bwBufferChunk) {
|
if (bwBufferChunk) {
|
||||||
free(bwBufferChunk);
|
free(bwBufferChunk);
|
||||||
bwBufferChunk = nullptr;
|
bwBufferChunk = nullptr;
|
||||||
@ -1511,20 +1465,20 @@ 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(
|
||||||
"is likely a bug, freeing chunk\n",
|
"[%lu] [GFX] !! BW buffer chunk %zu already stored - this "
|
||||||
millis(), i);
|
"is likely a bug, freeing chunk\n",
|
||||||
|
millis(), i);
|
||||||
free(bwBufferChunks[i]);
|
free(bwBufferChunks[i]);
|
||||||
bwBufferChunks[i] = nullptr;
|
bwBufferChunks[i] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t offset = i * BW_BUFFER_CHUNK_SIZE;
|
const size_t offset = i * BW_BUFFER_CHUNK_SIZE;
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1546,7 +1500,7 @@ bool GfxRenderer::storeBwBuffer() {
|
|||||||
void GfxRenderer::restoreBwBuffer() {
|
void GfxRenderer::restoreBwBuffer() {
|
||||||
// Check if any all chunks are allocated
|
// Check if any all chunks are allocated
|
||||||
bool missingChunks = false;
|
bool missingChunks = false;
|
||||||
for (const auto &bwBufferChunk : bwBufferChunks) {
|
for (const auto& bwBufferChunk : bwBufferChunks) {
|
||||||
if (!bwBufferChunk) {
|
if (!bwBufferChunk) {
|
||||||
missingChunks = true;
|
missingChunks = true;
|
||||||
break;
|
break;
|
||||||
@ -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,10 +1548,9 @@ 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);
|
||||||
}
|
}
|
||||||
@ -1617,7 +1567,7 @@ void GfxRenderer::renderChar(const EpdFontFamily &fontFamily, const uint32_t cp,
|
|||||||
const uint8_t height = glyph->height;
|
const uint8_t height = glyph->height;
|
||||||
const int left = glyph->left;
|
const int left = glyph->left;
|
||||||
|
|
||||||
const uint8_t *bitmap = nullptr;
|
const uint8_t* bitmap = nullptr;
|
||||||
bitmap = &fontFamily.getData(style)->bitmap[offset];
|
bitmap = &fontFamily.getData(style)->bitmap[offset];
|
||||||
|
|
||||||
if (bitmap != nullptr) {
|
if (bitmap != nullptr) {
|
||||||
@ -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,32 +1613,31 @@ 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;
|
||||||
*outRight = VIEWABLE_MARGIN_RIGHT;
|
*outRight = VIEWABLE_MARGIN_RIGHT;
|
||||||
*outBottom = VIEWABLE_MARGIN_BOTTOM;
|
*outBottom = VIEWABLE_MARGIN_BOTTOM;
|
||||||
*outLeft = VIEWABLE_MARGIN_LEFT;
|
*outLeft = VIEWABLE_MARGIN_LEFT;
|
||||||
break;
|
break;
|
||||||
case LandscapeClockwise:
|
case LandscapeClockwise:
|
||||||
*outTop = VIEWABLE_MARGIN_LEFT;
|
*outTop = VIEWABLE_MARGIN_LEFT;
|
||||||
*outRight = VIEWABLE_MARGIN_TOP;
|
*outRight = VIEWABLE_MARGIN_TOP;
|
||||||
*outBottom = VIEWABLE_MARGIN_RIGHT;
|
*outBottom = VIEWABLE_MARGIN_RIGHT;
|
||||||
*outLeft = VIEWABLE_MARGIN_BOTTOM;
|
*outLeft = VIEWABLE_MARGIN_BOTTOM;
|
||||||
break;
|
break;
|
||||||
case PortraitInverted:
|
case PortraitInverted:
|
||||||
*outTop = VIEWABLE_MARGIN_BOTTOM;
|
*outTop = VIEWABLE_MARGIN_BOTTOM;
|
||||||
*outRight = VIEWABLE_MARGIN_LEFT;
|
*outRight = VIEWABLE_MARGIN_LEFT;
|
||||||
*outBottom = VIEWABLE_MARGIN_TOP;
|
*outBottom = VIEWABLE_MARGIN_TOP;
|
||||||
*outLeft = VIEWABLE_MARGIN_RIGHT;
|
*outLeft = VIEWABLE_MARGIN_RIGHT;
|
||||||
break;
|
break;
|
||||||
case LandscapeCounterClockwise:
|
case LandscapeCounterClockwise:
|
||||||
*outTop = VIEWABLE_MARGIN_RIGHT;
|
*outTop = VIEWABLE_MARGIN_RIGHT;
|
||||||
*outRight = VIEWABLE_MARGIN_BOTTOM;
|
*outRight = VIEWABLE_MARGIN_BOTTOM;
|
||||||
*outBottom = VIEWABLE_MARGIN_LEFT;
|
*outBottom = VIEWABLE_MARGIN_LEFT;
|
||||||
*outLeft = VIEWABLE_MARGIN_TOP;
|
*outLeft = VIEWABLE_MARGIN_TOP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,17 +8,17 @@
|
|||||||
#include "Bitmap.h"
|
#include "Bitmap.h"
|
||||||
|
|
||||||
class GfxRenderer {
|
class GfxRenderer {
|
||||||
public:
|
public:
|
||||||
enum RenderMode { BW, GRAYSCALE_LSB, GRAYSCALE_MSB };
|
enum RenderMode { BW, GRAYSCALE_LSB, GRAYSCALE_MSB };
|
||||||
|
|
||||||
// Logical screen orientation from the perspective of callers
|
// Logical screen orientation from the perspective of callers
|
||||||
enum Orientation {
|
enum Orientation {
|
||||||
Portrait, // 480x800 logical coordinates (current default)
|
Portrait, // 480x800 logical coordinates (current default)
|
||||||
LandscapeClockwise, // 800x480 logical coordinates, rotated 180° (swap
|
LandscapeClockwise, // 800x480 logical coordinates, rotated 180° (swap
|
||||||
// top/bottom)
|
// top/bottom)
|
||||||
PortraitInverted, // 480x800 logical coordinates, inverted
|
PortraitInverted, // 480x800 logical coordinates, inverted
|
||||||
LandscapeCounterClockwise // 800x480 logical coordinates, native panel
|
LandscapeCounterClockwise // 800x480 logical coordinates, native panel
|
||||||
// orientation
|
// orientation
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -30,13 +30,12 @@ public:
|
|||||||
HalDisplay& display;
|
HalDisplay& display;
|
||||||
RenderMode renderMode;
|
RenderMode renderMode;
|
||||||
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;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit GfxRenderer(HalDisplay& halDisplay) : display(halDisplay), renderMode(BW), orientation(Portrait) {}
|
explicit GfxRenderer(HalDisplay& halDisplay) : display(halDisplay), renderMode(BW), orientation(Portrait) {}
|
||||||
@ -66,7 +65,7 @@ public:
|
|||||||
|
|
||||||
// Drawing
|
// Drawing
|
||||||
void drawPixel(int x, int y, bool state = true) const;
|
void drawPixel(int x, int y, bool state = true) const;
|
||||||
bool readPixel(int x, int y) const; // Returns true if pixel is black
|
bool readPixel(int x, int y) const; // Returns true if pixel is black
|
||||||
void drawLine(int x1, int y1, int x2, int y2, bool state = true) const;
|
void drawLine(int x1, int y1, int x2, int y2, bool state = true) const;
|
||||||
void drawRect(int x, int y, int width, int height, bool state = true) const;
|
void drawRect(int x, int y, int width, int height, bool state = true) const;
|
||||||
void fillRect(int x, int y, int width, int height, bool state = true) const;
|
void fillRect(int x, int y, int width, int height, bool state = true) const;
|
||||||
@ -74,69 +73,57 @@ 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
|
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
||||||
drawCenteredText(int fontId, 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;
|
|
||||||
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;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Grayscale functions
|
// Grayscale functions
|
||||||
void setRenderMode(const RenderMode mode) { this->renderMode = mode; }
|
void setRenderMode(const RenderMode mode) { this->renderMode = mode; }
|
||||||
void copyGrayscaleLsbBuffers() const;
|
void copyGrayscaleLsbBuffers() const;
|
||||||
void copyGrayscaleMsbBuffers() const;
|
void copyGrayscaleMsbBuffers() const;
|
||||||
void displayGrayBuffer() const;
|
void displayGrayBuffer() const;
|
||||||
bool storeBwBuffer(); // Returns true if buffer was stored successfully
|
bool storeBwBuffer(); // Returns true if buffer was stored successfully
|
||||||
void restoreBwBuffer(); // Restore and free the stored buffer
|
void restoreBwBuffer(); // Restore and free the stored buffer
|
||||||
void cleanupGrayscaleWithFrameBuffer() const;
|
void cleanupGrayscaleWithFrameBuffer() const;
|
||||||
|
|
||||||
// Low level functions
|
// Low level functions
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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", &CrossPointSettings::extraParagraphSpacing),
|
||||||
SettingInfo::Toggle("Extra Paragraph Spacing",
|
SettingInfo::Toggle("Text Anti-Aliasing", &CrossPointSettings::textAntiAliasing)};
|
||||||
&CrossPointSettings::extraParagraphSpacing),
|
|
||||||
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,11 +67,10 @@ 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}};
|
|
||||||
|
|
||||||
void updateContextForSetting(ThemeEngine::ThemeContext& ctx, const std::string& prefix, int i, const SettingInfo& info,
|
void updateContextForSetting(ThemeEngine::ThemeContext& ctx, const std::string& prefix, int i, const SettingInfo& info,
|
||||||
bool isSelected, bool fullUpdate) {
|
bool isSelected, bool fullUpdate) {
|
||||||
@ -123,8 +110,8 @@ void updateContextForSetting(ThemeEngine::ThemeContext& ctx, const std::string&
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void SettingsActivity::taskTrampoline(void *param) {
|
void SettingsActivity::taskTrampoline(void* param) {
|
||||||
auto *self = static_cast<SettingsActivity *>(param);
|
auto* self = static_cast<SettingsActivity*>(param);
|
||||||
self->displayTaskLoop();
|
self->displayTaskLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,16 +123,16 @@ void SettingsActivity::onEnter() {
|
|||||||
|
|
||||||
// For themed mode, provide all data upfront
|
// For themed mode, provide all data upfront
|
||||||
if (ThemeEngine::ThemeManager::get().getElement("Settings")) {
|
if (ThemeEngine::ThemeManager::get().getElement("Settings")) {
|
||||||
updateThemeContext(true); // Full update
|
updateThemeContext(true); // Full update
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
|
|
||||||
xTaskCreate(&SettingsActivity::taskTrampoline, "SettingsActivityTask",
|
xTaskCreate(&SettingsActivity::taskTrampoline, "SettingsActivityTask",
|
||||||
4096, // Stack size
|
4096, // Stack size
|
||||||
this, // Parameters
|
this, // Parameters
|
||||||
1, // Priority
|
1, // Priority
|
||||||
&displayTaskHandle // Task handle
|
&displayTaskHandle // Task handle
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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,13 +196,12 @@ 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;
|
}));
|
||||||
}));
|
|
||||||
xSemaphoreGive(renderingMutex);
|
xSemaphoreGive(renderingMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,29 +233,24 @@ 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);
|
||||||
|
|
||||||
for (int i = 0; i < categoryCount; i++) {
|
for (int i = 0; i < categoryCount; i++) {
|
||||||
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,
|
pageHeight - 60, CROSSPOINT_VERSION);
|
||||||
pageWidth - 20 - renderer.getTextWidth(SMALL_FONT_ID, 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();
|
||||||
}
|
}
|
||||||
@ -285,7 +262,7 @@ void SettingsActivity::updateThemeContext(bool fullUpdate) {
|
|||||||
if (fullUpdate) {
|
if (fullUpdate) {
|
||||||
themeContext.setInt("Categories.Count", categoryCount);
|
themeContext.setInt("Categories.Count", categoryCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
themeContext.setInt("Categories.Selected", selectedCategoryIndex);
|
themeContext.setInt("Categories.Selected", selectedCategoryIndex);
|
||||||
|
|
||||||
for (int i = 0; i < categoryCount; i++) {
|
for (int i = 0; i < categoryCount; i++) {
|
||||||
@ -308,9 +285,9 @@ void SettingsActivity::updateThemeContext(bool fullUpdate) {
|
|||||||
|
|
||||||
// Also provide current category's settings as "Settings" for simpler themes
|
// Also provide current category's settings as "Settings" for simpler themes
|
||||||
if (fullUpdate) {
|
if (fullUpdate) {
|
||||||
themeContext.setInt("Settings.Count", allCategories[selectedCategoryIndex].count);
|
themeContext.setInt("Settings.Count", allCategories[selectedCategoryIndex].count);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < allCategories[selectedCategoryIndex].count; i++) {
|
for (int i = 0; i < allCategories[selectedCategoryIndex].count; i++) {
|
||||||
updateContextForSetting(themeContext, "Settings", i, allCategories[selectedCategoryIndex].settings[i],
|
updateContextForSetting(themeContext, "Settings", i, allCategories[selectedCategoryIndex].settings[i],
|
||||||
i == selectedSettingIndex, fullUpdate);
|
i == selectedSettingIndex, fullUpdate);
|
||||||
@ -323,14 +300,14 @@ void SettingsActivity::handleThemeInput() {
|
|||||||
// Up/Down navigates settings within current category
|
// Up/Down navigates settings within current category
|
||||||
if (mappedInput.wasPressed(MappedInputManager::Button::Up)) {
|
if (mappedInput.wasPressed(MappedInputManager::Button::Up)) {
|
||||||
selectedSettingIndex = (selectedSettingIndex > 0) ? (selectedSettingIndex - 1) : (currentCategorySettingsCount - 1);
|
selectedSettingIndex = (selectedSettingIndex > 0) ? (selectedSettingIndex - 1) : (currentCategorySettingsCount - 1);
|
||||||
updateThemeContext(false); // Partial update
|
updateThemeContext(false); // Partial update
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mappedInput.wasPressed(MappedInputManager::Button::Down)) {
|
if (mappedInput.wasPressed(MappedInputManager::Button::Down)) {
|
||||||
selectedSettingIndex = (selectedSettingIndex < currentCategorySettingsCount - 1) ? (selectedSettingIndex + 1) : 0;
|
selectedSettingIndex = (selectedSettingIndex < currentCategorySettingsCount - 1) ? (selectedSettingIndex + 1) : 0;
|
||||||
updateThemeContext(false); // Partial update
|
updateThemeContext(false); // Partial update
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -340,7 +317,7 @@ void SettingsActivity::handleThemeInput() {
|
|||||||
mappedInput.wasPressed(MappedInputManager::Button::PageBack)) {
|
mappedInput.wasPressed(MappedInputManager::Button::PageBack)) {
|
||||||
selectedCategoryIndex = (selectedCategoryIndex > 0) ? (selectedCategoryIndex - 1) : (categoryCount - 1);
|
selectedCategoryIndex = (selectedCategoryIndex > 0) ? (selectedCategoryIndex - 1) : (categoryCount - 1);
|
||||||
selectedSettingIndex = 0; // Reset to first setting in new category
|
selectedSettingIndex = 0; // Reset to first setting in new category
|
||||||
updateThemeContext(true); // Full update (category changed)
|
updateThemeContext(true); // Full update (category changed)
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -349,7 +326,7 @@ void SettingsActivity::handleThemeInput() {
|
|||||||
mappedInput.wasPressed(MappedInputManager::Button::PageForward)) {
|
mappedInput.wasPressed(MappedInputManager::Button::PageForward)) {
|
||||||
selectedCategoryIndex = (selectedCategoryIndex < categoryCount - 1) ? (selectedCategoryIndex + 1) : 0;
|
selectedCategoryIndex = (selectedCategoryIndex < categoryCount - 1) ? (selectedCategoryIndex + 1) : 0;
|
||||||
selectedSettingIndex = 0;
|
selectedSettingIndex = 0;
|
||||||
updateThemeContext(true); // Full update
|
updateThemeContext(true); // Full update
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -357,7 +334,7 @@ void SettingsActivity::handleThemeInput() {
|
|||||||
// Confirm toggles/activates current setting
|
// Confirm toggles/activates current setting
|
||||||
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
|
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
|
||||||
toggleCurrentSetting();
|
toggleCurrentSetting();
|
||||||
updateThemeContext(false); // Values changed, partial update is enough (names don't change)
|
updateThemeContext(false); // Values changed, partial update is enough (names don't change)
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
113
src/main.cpp
113
src/main.cpp
@ -38,94 +38,78 @@ 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(¬osans_12_regular);
|
EpdFont notosans12RegularFont(¬osans_12_regular);
|
||||||
EpdFont notosans12BoldFont(¬osans_12_bold);
|
EpdFont notosans12BoldFont(¬osans_12_bold);
|
||||||
EpdFont notosans12ItalicFont(¬osans_12_italic);
|
EpdFont notosans12ItalicFont(¬osans_12_italic);
|
||||||
EpdFont notosans12BoldItalicFont(¬osans_12_bolditalic);
|
EpdFont notosans12BoldItalicFont(¬osans_12_bolditalic);
|
||||||
EpdFontFamily notosans12FontFamily(¬osans12RegularFont, ¬osans12BoldFont,
|
EpdFontFamily notosans12FontFamily(¬osans12RegularFont, ¬osans12BoldFont, ¬osans12ItalicFont,
|
||||||
¬osans12ItalicFont,
|
|
||||||
¬osans12BoldItalicFont);
|
¬osans12BoldItalicFont);
|
||||||
EpdFont notosans14RegularFont(¬osans_14_regular);
|
EpdFont notosans14RegularFont(¬osans_14_regular);
|
||||||
EpdFont notosans14BoldFont(¬osans_14_bold);
|
EpdFont notosans14BoldFont(¬osans_14_bold);
|
||||||
EpdFont notosans14ItalicFont(¬osans_14_italic);
|
EpdFont notosans14ItalicFont(¬osans_14_italic);
|
||||||
EpdFont notosans14BoldItalicFont(¬osans_14_bolditalic);
|
EpdFont notosans14BoldItalicFont(¬osans_14_bolditalic);
|
||||||
EpdFontFamily notosans14FontFamily(¬osans14RegularFont, ¬osans14BoldFont,
|
EpdFontFamily notosans14FontFamily(¬osans14RegularFont, ¬osans14BoldFont, ¬osans14ItalicFont,
|
||||||
¬osans14ItalicFont,
|
|
||||||
¬osans14BoldItalicFont);
|
¬osans14BoldItalicFont);
|
||||||
EpdFont notosans16RegularFont(¬osans_16_regular);
|
EpdFont notosans16RegularFont(¬osans_16_regular);
|
||||||
EpdFont notosans16BoldFont(¬osans_16_bold);
|
EpdFont notosans16BoldFont(¬osans_16_bold);
|
||||||
EpdFont notosans16ItalicFont(¬osans_16_italic);
|
EpdFont notosans16ItalicFont(¬osans_16_italic);
|
||||||
EpdFont notosans16BoldItalicFont(¬osans_16_bolditalic);
|
EpdFont notosans16BoldItalicFont(¬osans_16_bolditalic);
|
||||||
EpdFontFamily notosans16FontFamily(¬osans16RegularFont, ¬osans16BoldFont,
|
EpdFontFamily notosans16FontFamily(¬osans16RegularFont, ¬osans16BoldFont, ¬osans16ItalicFont,
|
||||||
¬osans16ItalicFont,
|
|
||||||
¬osans16BoldItalicFont);
|
¬osans16BoldItalicFont);
|
||||||
EpdFont notosans18RegularFont(¬osans_18_regular);
|
EpdFont notosans18RegularFont(¬osans_18_regular);
|
||||||
EpdFont notosans18BoldFont(¬osans_18_bold);
|
EpdFont notosans18BoldFont(¬osans_18_bold);
|
||||||
EpdFont notosans18ItalicFont(¬osans_18_italic);
|
EpdFont notosans18ItalicFont(¬osans_18_italic);
|
||||||
EpdFont notosans18BoldItalicFont(¬osans_18_bolditalic);
|
EpdFont notosans18BoldItalicFont(¬osans_18_bolditalic);
|
||||||
EpdFontFamily notosans18FontFamily(¬osans18RegularFont, ¬osans18BoldFont,
|
EpdFontFamily notosans18FontFamily(¬osans18RegularFont, ¬osans18BoldFont, ¬osans18ItalicFont,
|
||||||
¬osans18ItalicFont,
|
|
||||||
¬osans18BoldItalicFont);
|
¬osans18BoldItalicFont);
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
EpdFont smallFont(¬osans_8_regular);
|
EpdFont smallFont(¬osans_8_regular);
|
||||||
EpdFontFamily smallFontFamily(&smallFont);
|
EpdFontFamily smallFontFamily(&smallFont);
|
||||||
@ -150,7 +134,7 @@ void exitActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void enterNewActivity(Activity *activity) {
|
void enterNewActivity(Activity* activity) {
|
||||||
currentActivity = activity;
|
currentActivity = activity;
|
||||||
currentActivity->onEnter();
|
currentActivity->onEnter();
|
||||||
}
|
}
|
||||||
@ -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() {
|
||||||
@ -291,7 +261,7 @@ void setupDisplayAndFonts() {
|
|||||||
renderer.insertFont(OPENDYSLEXIC_10_FONT_ID, opendyslexic10FontFamily);
|
renderer.insertFont(OPENDYSLEXIC_10_FONT_ID, opendyslexic10FontFamily);
|
||||||
renderer.insertFont(OPENDYSLEXIC_12_FONT_ID, opendyslexic12FontFamily);
|
renderer.insertFont(OPENDYSLEXIC_12_FONT_ID, opendyslexic12FontFamily);
|
||||||
renderer.insertFont(OPENDYSLEXIC_14_FONT_ID, opendyslexic14FontFamily);
|
renderer.insertFont(OPENDYSLEXIC_14_FONT_ID, opendyslexic14FontFamily);
|
||||||
#endif // OMIT_FONTS
|
#endif // OMIT_FONTS
|
||||||
renderer.insertFont(UI_10_FONT_ID, ui10FontFamily);
|
renderer.insertFont(UI_10_FONT_ID, ui10FontFamily);
|
||||||
renderer.insertFont(UI_12_FONT_ID, ui12FontFamily);
|
renderer.insertFont(UI_12_FONT_ID, ui12FontFamily);
|
||||||
renderer.insertFont(SMALL_FONT_ID, smallFontFamily);
|
renderer.insertFont(SMALL_FONT_ID, smallFontFamily);
|
||||||
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,8 +389,8 @@ void loop() {
|
|||||||
// When an activity requests skip loop delay (e.g., webserver running), use
|
// When an activity requests skip loop delay (e.g., webserver running), use
|
||||||
// yield() for faster response Otherwise, use longer delay to save power
|
// yield() for faster response Otherwise, use longer delay to save power
|
||||||
if (currentActivity && currentActivity->skipLoopDelay()) {
|
if (currentActivity && currentActivity->skipLoopDelay()) {
|
||||||
yield(); // Give FreeRTOS a chance to run tasks, but return immediately
|
yield(); // Give FreeRTOS a chance to run tasks, but return immediately
|
||||||
} else {
|
} else {
|
||||||
delay(10); // Normal delay when no activity requires fast response
|
delay(10); // Normal delay when no activity requires fast response
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user