#include "WidgetConfig.hpp" #include #include // WidgetConfig implementation void WidgetConfig::serialize(uint8_t* buf) const { memset(buf, 0, SERIALIZED_SIZE); size_t pos = 0; buf[pos++] = id; buf[pos++] = static_cast(type); buf[pos++] = x & 0xFF; buf[pos++] = (x >> 8) & 0xFF; buf[pos++] = y & 0xFF; buf[pos++] = (y >> 8) & 0xFF; buf[pos++] = width & 0xFF; buf[pos++] = (width >> 8) & 0xFF; buf[pos++] = height & 0xFF; buf[pos++] = (height >> 8) & 0xFF; buf[pos++] = visible ? 1 : 0; buf[pos++] = static_cast(textSource); memcpy(&buf[pos], text, MAX_TEXT_LEN); pos += MAX_TEXT_LEN; buf[pos++] = knxAddress & 0xFF; buf[pos++] = (knxAddress >> 8) & 0xFF; buf[pos++] = fontSize; buf[pos++] = textColor.r; buf[pos++] = textColor.g; buf[pos++] = textColor.b; buf[pos++] = bgColor.r; buf[pos++] = bgColor.g; buf[pos++] = bgColor.b; buf[pos++] = bgOpacity; buf[pos++] = borderRadius; buf[pos++] = shadow.offsetX; buf[pos++] = shadow.offsetY; buf[pos++] = shadow.blur; buf[pos++] = shadow.spread; buf[pos++] = shadow.color.r; buf[pos++] = shadow.color.g; buf[pos++] = shadow.color.b; buf[pos++] = shadow.enabled ? 1 : 0; buf[pos++] = isToggle ? 1 : 0; buf[pos++] = knxAddressWrite & 0xFF; buf[pos++] = (knxAddressWrite >> 8) & 0xFF; buf[pos++] = static_cast(action); buf[pos++] = targetScreen; } void WidgetConfig::deserialize(const uint8_t* buf) { size_t pos = 0; id = buf[pos++]; type = static_cast(buf[pos++]); x = buf[pos] | (buf[pos+1] << 8); pos += 2; y = buf[pos] | (buf[pos+1] << 8); pos += 2; width = buf[pos] | (buf[pos+1] << 8); pos += 2; height = buf[pos] | (buf[pos+1] << 8); pos += 2; visible = buf[pos++] != 0; textSource = static_cast(buf[pos++]); memcpy(text, &buf[pos], MAX_TEXT_LEN); pos += MAX_TEXT_LEN; text[MAX_TEXT_LEN - 1] = '\0'; knxAddress = buf[pos] | (buf[pos+1] << 8); pos += 2; fontSize = buf[pos++]; textColor.r = buf[pos++]; textColor.g = buf[pos++]; textColor.b = buf[pos++]; bgColor.r = buf[pos++]; bgColor.g = buf[pos++]; bgColor.b = buf[pos++]; bgOpacity = buf[pos++]; borderRadius = buf[pos++]; shadow.offsetX = static_cast(buf[pos++]); shadow.offsetY = static_cast(buf[pos++]); shadow.blur = buf[pos++]; shadow.spread = buf[pos++]; shadow.color.r = buf[pos++]; shadow.color.g = buf[pos++]; shadow.color.b = buf[pos++]; shadow.enabled = buf[pos++] != 0; isToggle = buf[pos++] != 0; knxAddressWrite = buf[pos] | (buf[pos+1] << 8); pos += 2; action = static_cast(buf[pos++]); targetScreen = buf[pos++]; } WidgetConfig WidgetConfig::createLabel(uint8_t id, int16_t x, int16_t y, const char* labelText) { WidgetConfig cfg = {}; cfg.id = id; cfg.type = WidgetType::LABEL; cfg.x = x; cfg.y = y; cfg.width = 150; cfg.height = 40; cfg.visible = true; cfg.textSource = TextSource::STATIC; strncpy(cfg.text, labelText, MAX_TEXT_LEN - 1); cfg.fontSize = 1; // 18pt cfg.textColor = {255, 255, 255}; cfg.bgColor = {0, 0, 0}; cfg.bgOpacity = 0; cfg.borderRadius = 0; cfg.shadow.enabled = false; return cfg; } WidgetConfig WidgetConfig::createKnxLabel(uint8_t id, int16_t x, int16_t y, TextSource source, uint16_t knxAddr, const char* format) { WidgetConfig cfg = createLabel(id, x, y, format); cfg.textSource = source; cfg.knxAddress = knxAddr; return cfg; } WidgetConfig WidgetConfig::createButton(uint8_t id, int16_t x, int16_t y, const char* labelText, uint16_t knxAddrWrite, bool toggle) { WidgetConfig cfg = {}; cfg.id = id; cfg.type = WidgetType::BUTTON; cfg.x = x; cfg.y = y; cfg.width = 120; cfg.height = 50; cfg.visible = true; cfg.textSource = TextSource::STATIC; strncpy(cfg.text, labelText, MAX_TEXT_LEN - 1); cfg.fontSize = 1; cfg.textColor = {255, 255, 255}; cfg.bgColor = {33, 150, 243}; // Blue cfg.bgOpacity = 255; cfg.borderRadius = 8; cfg.shadow.enabled = true; cfg.shadow.offsetX = 2; cfg.shadow.offsetY = 2; cfg.shadow.blur = 8; cfg.shadow.spread = 0; cfg.shadow.color = {0, 0, 0}; cfg.isToggle = toggle; cfg.knxAddressWrite = knxAddrWrite; cfg.action = ButtonAction::KNX; cfg.targetScreen = 0; return cfg; } // ScreenConfig implementation void ScreenConfig::clear(uint8_t newId, const char* newName) { id = newId; mode = ScreenMode::FULLSCREEN; backgroundColor = {26, 26, 46}; // Dark blue background widgetCount = 0; memset(widgets, 0, sizeof(widgets)); memset(name, 0, sizeof(name)); if (newName && newName[0] != '\0') { strncpy(name, newName, sizeof(name) - 1); } // Modal defaults modalX = 0; // 0 = centered modalY = 0; // 0 = centered modalWidth = 0; // 0 = auto modalHeight = 0; // 0 = auto modalBorderRadius = 12; modalDimBackground = true; } int ScreenConfig::addWidget(const WidgetConfig& widget) { if (widgetCount >= MAX_WIDGETS) return -1; // Find next free ID uint8_t newId = 0; for (uint8_t i = 0; i < widgetCount; i++) { if (widgets[i].id >= newId) newId = widgets[i].id + 1; } widgets[widgetCount] = widget; widgets[widgetCount].id = newId; widgetCount++; return newId; } bool ScreenConfig::removeWidget(uint8_t id) { for (uint8_t i = 0; i < widgetCount; i++) { if (widgets[i].id == id) { // Shift remaining widgets for (uint8_t j = i; j < widgetCount - 1; j++) { widgets[j] = widgets[j + 1]; } widgetCount--; return true; } } return false; } WidgetConfig* ScreenConfig::findWidget(uint8_t id) { for (uint8_t i = 0; i < widgetCount; i++) { if (widgets[i].id == id) return &widgets[i]; } return nullptr; } const WidgetConfig* ScreenConfig::findWidget(uint8_t id) const { for (uint8_t i = 0; i < widgetCount; i++) { if (widgets[i].id == id) return &widgets[i]; } return nullptr; } // GuiConfig implementation void GuiConfig::clear() { screenCount = 0; startScreenId = 0; standbyEnabled = false; standbyScreenId = 0xFF; standbyMinutes = 0; for (size_t i = 0; i < MAX_SCREENS; i++) { screens[i].clear(static_cast(i), nullptr); } } ScreenConfig* GuiConfig::findScreen(uint8_t id) { for (uint8_t i = 0; i < screenCount; i++) { if (screens[i].id == id) return &screens[i]; } return nullptr; } const ScreenConfig* GuiConfig::findScreen(uint8_t id) const { for (uint8_t i = 0; i < screenCount; i++) { if (screens[i].id == id) return &screens[i]; } return nullptr; }