#pragma once #include #include #include #include "icons.h" // ── Font size helper ────────────────────────────────────────────────────────── /** * Map an API font_size value (typically 8–40) to GFX setTextSize(1–5). * font_size / 8, clamped to [1, 5]. */ static inline uint8_t mapFontSize(int fontSize) { int s = fontSize / 8; if (s < 1) s = 1; if (s > 5) s = 5; return static_cast(s); } // ── Render all elements from JSON array ─────────────────────────────────────── /** * Iterates every element in the JsonArray and draws it onto `display`. * Must be called inside a firstPage/nextPage loop so that display is * already prepared for drawing. */ template void renderElements(GxEPD2_Type& display, JsonArray elements) { for (JsonObject el : elements) { const char* type = el["type"] | ""; int x = el["x"] | 0; int y = el["y"] | 0; int w = el["w"] | 0; int h = el["h"] | 0; // ── line ───────────────────────────────────────────────────────────── if (strcmp(type, "line") == 0) { // Use fillRect: height==1 → horizontal, width==1 → vertical int thickness = el["thickness"] | 1; if (h <= 1 && w > 1) { // horizontal line display.fillRect(x, y, w, (thickness > 0 ? thickness : 1), GxEPD_BLACK); } else if (w <= 1 && h > 1) { // vertical line display.fillRect(x, y, (thickness > 0 ? thickness : 1), h, GxEPD_BLACK); } else { // generic: draw as thin rect display.fillRect(x, y, w, h, GxEPD_BLACK); } } // ── rect ───────────────────────────────────────────────────────────── else if (strcmp(type, "rect") == 0) { display.drawRect(x, y, w, h, GxEPD_BLACK); } // ── label ──────────────────────────────────────────────────────────── else if (strcmp(type, "label") == 0) { const char* text = el["text"] | ""; int fontSize = el["font_size"] | 8; const char* textAlign = el["text_align"] | "left"; uint8_t sz = mapFontSize(fontSize); display.setTextColor(GxEPD_BLACK); display.setTextSize(sz); if (strcmp(textAlign, "center") == 0) { // Calculate approximate text width: each char is 6px wide at size 1 int charWidth = 6 * sz; int textLen = strlen(text); int textWidth = charWidth * textLen; int textHeight = 8 * sz; display.setCursor(x - textWidth / 2, y - textHeight / 2); } else if (strcmp(textAlign, "right") == 0) { int charWidth = 6 * sz; int textLen = strlen(text); int textWidth = charWidth * textLen; display.setCursor(x - textWidth, y); } else { // left (default) display.setCursor(x, y); } display.print(text); } // ── value ───────────────────────────────────────────────────────────── else if (strcmp(type, "value") == 0) { const char* style = el["style"] | "plain"; const char* label = el["label"] | ""; const char* value = el["value"] | ""; const char* unit = el["unit"] | ""; const char* iconName = el["icon"] | ""; int fontSize = el["font_size"] | 16; if (strcmp(style, "card") == 0) { // ── card style ───────────────────────────────────────────── // Border display.drawRoundRect(x, y, w, h, 4, GxEPD_BLACK); // Icon top-left (24x24), with small padding const unsigned char* iconData = getIcon(iconName); if (iconData != nullptr) { display.drawBitmap(x + 4, y + 4, iconData, 24, 24, GxEPD_BLACK); } // Label text (small, below icon) display.setTextColor(GxEPD_BLACK); display.setTextSize(1); display.setCursor(x + 4, y + 32); display.print(label); // Value + unit (large, bottom-right) uint8_t valSize = mapFontSize(fontSize); display.setTextSize(valSize); // Build value string with unit String valStr = String(value); if (strlen(unit) > 0) { valStr += " "; valStr += unit; } // Right-align inside card int charWidth = 6 * valSize; int valWidth = charWidth * valStr.length(); int valX = x + w - valWidth - 4; int valY = y + h - 8 * valSize - 4; if (valX < x + 4) valX = x + 4; display.setCursor(valX, valY); display.print(valStr); } else { // ── plain style ───────────────────────────────────────────── uint8_t sz = mapFontSize(fontSize); display.setTextColor(GxEPD_BLACK); display.setTextSize(sz); display.setCursor(x, y); // "Label: value unit" String line; if (strlen(label) > 0) { line += label; line += ": "; } line += value; if (strlen(unit) > 0) { line += " "; line += unit; } display.print(line); } } } }