- Update open-x4-sdk submodule to 9f76376 (BatteryMonitor ESP-IDF 5.x compat) - Add RTC_NOINIT bounds check for logHead in Logging.cpp - Add drawTextRotated90CCW to GfxRenderer for dictionary UI - Add getWordXpos() accessor to TextBlock for dictionary word selection - Fix bare include paths (ActivityResult.h, RenderLock.h) across 10 files - Fix rvalue ref binding in setResult() lambdas (std::move pattern) - Fix std::max type mismatch (uint8_t vs int) in EpubReaderActivity - Fix FsFile forward declaration conflict in Dictionary.h - Restore StringUtils::checkFileExtension() and sortFileList() - Restore RecentBooksStore::removeBook() Made-with: Cursor
162 lines
8.4 KiB
C++
162 lines
8.4 KiB
C++
#pragma once
|
|
|
|
#include <EpdFontFamily.h>
|
|
#include <FontDecompressor.h>
|
|
#include <HalDisplay.h>
|
|
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "Bitmap.h"
|
|
|
|
// Color representation: uint8_t mapped to 4x4 Bayer matrix dithering levels
|
|
// 0 = transparent, 1-16 = gray levels (white to black)
|
|
enum Color : uint8_t { Clear = 0x00, White = 0x01, LightGray = 0x05, DarkGray = 0x0A, Black = 0x10 };
|
|
|
|
class GfxRenderer {
|
|
public:
|
|
enum RenderMode { BW, GRAYSCALE_LSB, GRAYSCALE_MSB };
|
|
|
|
// Logical screen orientation from the perspective of callers
|
|
enum Orientation {
|
|
Portrait, // 480x800 logical coordinates (current default)
|
|
LandscapeClockwise, // 800x480 logical coordinates, rotated 180° (swap top/bottom)
|
|
PortraitInverted, // 480x800 logical coordinates, inverted
|
|
LandscapeCounterClockwise // 800x480 logical coordinates, native panel orientation
|
|
};
|
|
|
|
private:
|
|
static constexpr size_t BW_BUFFER_CHUNK_SIZE = 8000; // 8KB chunks to allow for non-contiguous memory
|
|
static constexpr size_t BW_BUFFER_NUM_CHUNKS = HalDisplay::BUFFER_SIZE / BW_BUFFER_CHUNK_SIZE;
|
|
static_assert(BW_BUFFER_CHUNK_SIZE * BW_BUFFER_NUM_CHUNKS == HalDisplay::BUFFER_SIZE,
|
|
"BW buffer chunking does not line up with display buffer size");
|
|
|
|
HalDisplay& display;
|
|
RenderMode renderMode;
|
|
Orientation orientation;
|
|
bool fadingFix;
|
|
uint8_t* frameBuffer = nullptr;
|
|
uint8_t* bwBufferChunks[BW_BUFFER_NUM_CHUNKS] = {nullptr};
|
|
std::map<int, EpdFontFamily> fontMap;
|
|
FontDecompressor* fontDecompressor = nullptr;
|
|
void freeBwBufferChunks();
|
|
template <Color color>
|
|
void drawPixelDither(int x, int y) const;
|
|
template <Color color>
|
|
void fillArc(int maxRadius, int cx, int cy, int xDir, int yDir) const;
|
|
// Write a patterned horizontal span directly to the physical framebuffer using byte-level operations.
|
|
// phyY: physical row; phyX_start/phyX_end: inclusive physical column range.
|
|
// patternByte is repeated across the span; partial edge bytes are blended with existing content.
|
|
// Bit layout: MSB-first (bit 7 = phyX=0); 0 bits = dark pixel, 1 bits = white pixel.
|
|
void fillPhysicalHSpanByte(int phyY, int phyX_start, int phyX_end, uint8_t patternByte) const;
|
|
// Write a solid horizontal span directly to the physical framebuffer using byte-level operations.
|
|
// Thin wrapper around fillPhysicalHSpanByte: state=true → 0x00 (dark), false → 0xFF (white).
|
|
void fillPhysicalHSpan(int phyY, int phyX_start, int phyX_end, bool state) const;
|
|
|
|
public:
|
|
explicit GfxRenderer(HalDisplay& halDisplay)
|
|
: display(halDisplay), renderMode(BW), orientation(Portrait), fadingFix(false) {}
|
|
~GfxRenderer() { freeBwBufferChunks(); }
|
|
|
|
static constexpr int VIEWABLE_MARGIN_TOP = 9;
|
|
static constexpr int VIEWABLE_MARGIN_RIGHT = 3;
|
|
static constexpr int VIEWABLE_MARGIN_BOTTOM = 3;
|
|
static constexpr int VIEWABLE_MARGIN_LEFT = 3;
|
|
|
|
// Setup
|
|
void begin(); // must be called right after display.begin()
|
|
void insertFont(int fontId, EpdFontFamily font);
|
|
void setFontDecompressor(FontDecompressor* d) { fontDecompressor = d; }
|
|
void clearFontCache() {
|
|
if (fontDecompressor) fontDecompressor->clearCache();
|
|
}
|
|
|
|
// Orientation control (affects logical width/height and coordinate transforms)
|
|
void setOrientation(const Orientation o) { orientation = o; }
|
|
Orientation getOrientation() const { return orientation; }
|
|
|
|
// Fading fix control
|
|
void setFadingFix(const bool enabled) { fadingFix = enabled; }
|
|
|
|
// Screen ops
|
|
int getScreenWidth() const;
|
|
int getScreenHeight() const;
|
|
void displayBuffer(HalDisplay::RefreshMode refreshMode = HalDisplay::FAST_REFRESH) const;
|
|
// EXPERIMENTAL: Windowed update - display only a rectangular region
|
|
// void displayWindow(int x, int y, int width, int height) const;
|
|
void invertScreen() const;
|
|
void clearScreen(uint8_t color = 0xFF) const;
|
|
void getOrientedViewableTRBL(int* outTop, int* outRight, int* outBottom, int* outLeft) const;
|
|
|
|
// Drawing
|
|
void drawPixel(int x, int y, bool state = true) const;
|
|
void drawPixelGray(int x, int y, uint8_t val2bit) const;
|
|
void drawLine(int x1, int y1, int x2, int y2, bool state = true) const;
|
|
void drawLine(int x1, int y1, int x2, int y2, int lineWidth, bool state) const;
|
|
void drawArc(int maxRadius, int cx, int cy, int xDir, int yDir, int lineWidth, bool state) 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, int lineWidth, bool state) const;
|
|
void drawRoundedRect(int x, int y, int width, int height, int lineWidth, int cornerRadius, bool state) const;
|
|
void drawRoundedRect(int x, int y, int width, int height, int lineWidth, int cornerRadius, bool roundTopLeft,
|
|
bool roundTopRight, bool roundBottomLeft, bool roundBottomRight, bool state) const;
|
|
void fillRect(int x, int y, int width, int height, bool state = true) const;
|
|
void fillRectDither(int x, int y, int width, int height, Color color) const;
|
|
void fillRoundedRect(int x, int y, int width, int height, int cornerRadius, Color color) const;
|
|
void fillRoundedRect(int x, int y, int width, int height, int cornerRadius, bool roundTopLeft, bool roundTopRight,
|
|
bool roundBottomLeft, bool roundBottomRight, Color color) const;
|
|
void drawImage(const uint8_t bitmap[], int x, int y, int width, int height) const;
|
|
void drawIcon(const uint8_t bitmap[], int x, int y, int width, int height) const;
|
|
void drawBitmap(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight, float cropX = 0,
|
|
float cropY = 0) const;
|
|
void drawBitmap1Bit(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight) const;
|
|
void fillPolygon(const int* xPoints, const int* yPoints, int numPoints, bool state = true) const;
|
|
|
|
// Text
|
|
int getTextWidth(int fontId, const char* text, EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
|
void drawCenteredText(int fontId, 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;
|
|
int getSpaceWidth(int fontId, EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
|
/// Returns the kerning adjustment for a space between two codepoints:
|
|
/// kern(leftCp, ' ') + kern(' ', rightCp). Returns 0 if kerning is unavailable.
|
|
int getSpaceKernAdjust(int fontId, uint32_t leftCp, uint32_t rightCp, EpdFontFamily::Style style) const;
|
|
/// Returns the kerning adjustment between two adjacent codepoints.
|
|
int getKerning(int fontId, uint32_t leftCp, uint32_t rightCp, EpdFontFamily::Style style) const;
|
|
int getTextAdvanceX(int fontId, const char* text, EpdFontFamily::Style style) const;
|
|
int getFontAscenderSize(int fontId) const;
|
|
int getLineHeight(int fontId) const;
|
|
std::string truncatedText(int fontId, const char* text, int maxWidth,
|
|
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
|
/// Word-wrap \p text into at most \p maxLines lines, each no wider than
|
|
/// \p maxWidth pixels. Overflowing words and excess lines are UTF-8-safely
|
|
/// truncated with an ellipsis (U+2026).
|
|
std::vector<std::string> wrappedText(int fontId, const char* text, int maxWidth, int maxLines,
|
|
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
|
|
|
// Helpers for drawing rotated text (for side buttons)
|
|
void drawTextRotated90CW(int fontId, int x, int y, const char* text, bool black = true,
|
|
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
|
void drawTextRotated90CCW(int fontId, int x, int y, const char* text, bool black = true,
|
|
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
|
int getTextHeight(int fontId) const;
|
|
|
|
// Grayscale functions
|
|
void setRenderMode(const RenderMode mode) { this->renderMode = mode; }
|
|
RenderMode getRenderMode() const { return renderMode; }
|
|
void copyGrayscaleLsbBuffers() const;
|
|
void copyGrayscaleMsbBuffers() const;
|
|
void displayGrayBuffer() const;
|
|
bool storeBwBuffer(); // Returns true if buffer was stored successfully
|
|
void restoreBwBuffer(); // Restore and free the stored buffer
|
|
void cleanupGrayscaleWithFrameBuffer() const;
|
|
|
|
// Font helpers
|
|
const uint8_t* getGlyphBitmap(const EpdFontData* fontData, const EpdGlyph* glyph) const;
|
|
|
|
// Low level functions
|
|
uint8_t* getFrameBuffer() const;
|
|
static size_t getBufferSize();
|
|
};
|