153 lines
6.6 KiB
C++
153 lines
6.6 KiB
C++
#pragma once
|
||
|
||
#include <Arduino.h>
|
||
#include <ArduinoJson.h>
|
||
#include <GxEPD2_BW.h>
|
||
#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<uint8_t>(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 <typename GxEPD2_Type>
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
}
|