#pragma once #include #include #include // Maximum number of widgets static constexpr size_t MAX_WIDGETS = 32; static constexpr size_t MAX_SCREENS = 8; static constexpr size_t MAX_TEXT_LEN = 32; static constexpr size_t MAX_SCREEN_NAME_LEN = 24; enum class WidgetType : uint8_t { LABEL = 0, BUTTON = 1, LED = 2, ICON = 3, }; enum class IconPosition : uint8_t { LEFT = 0, RIGHT = 1, TOP = 2, BOTTOM = 3, }; enum class ScreenMode : uint8_t { FULLSCREEN = 0, MODAL = 1, }; enum class ButtonAction : uint8_t { KNX = 0, JUMP = 1, BACK = 2, }; // Text source: static text or KNX group address enum class TextSource : uint8_t { STATIC = 0, // Static text KNX_DPT_TEMP = 1, // KNX Temperature (DPT 9.001) KNX_DPT_SWITCH = 2, // KNX Switch (DPT 1.001) KNX_DPT_PERCENT = 3, // KNX Percent (DPT 5.001) KNX_DPT_TEXT = 4, // KNX Text (DPT 16.000) }; // Color as RGB888 struct Color { uint8_t r, g, b; uint32_t toLvColor() const { return (r << 16) | (g << 8) | b; } static Color fromHex(uint32_t hex) { return { .r = static_cast((hex >> 16) & 0xFF), .g = static_cast((hex >> 8) & 0xFF), .b = static_cast(hex & 0xFF) }; } }; // Shadow configuration struct ShadowConfig { int8_t offsetX; int8_t offsetY; uint8_t blur; uint8_t spread; Color color; bool enabled; }; // Widget configuration struct WidgetConfig { // Basic properties uint8_t id; // Unique ID (0-255) WidgetType type; int16_t x, y; int16_t width, height; bool visible; // Text properties TextSource textSource; char text[MAX_TEXT_LEN]; // Static text or format string uint16_t knxAddress; // KNX group address (if textSource != STATIC) uint8_t fontSize; // Font size index (0=14, 1=18, 2=22, 3=28, 4=36, 5=48) // Colors Color textColor; Color bgColor; uint8_t bgOpacity; // 0-255 uint8_t borderRadius; // Shadow ShadowConfig shadow; // Button specific bool isToggle; // For buttons: toggle mode uint16_t knxAddressWrite; // KNX address to write on click ButtonAction action; // Button action (KNX, Jump, Back) uint8_t targetScreen; // Target screen ID for jump // Icon properties (for Label, Button, Icon widgets) uint32_t iconCodepoint; // Unicode codepoint (0 = no icon) uint8_t iconPosition; // IconPosition: 0=left, 1=right, 2=top, 3=bottom uint8_t iconSize; // Font size index (0-5), same as fontSize int8_t iconGap; // Gap between icon and text (px) // Hierarchy int8_t parentId; // ID of parent widget (-1 = root/screen) // Serialization size (fixed for NVS storage) static constexpr size_t SERIALIZED_SIZE = 77; void serialize(uint8_t* buf) const; void deserialize(const uint8_t* buf); // Create default label static WidgetConfig createLabel(uint8_t id, int16_t x, int16_t y, const char* text); // Create KNX-bound label static WidgetConfig createKnxLabel(uint8_t id, int16_t x, int16_t y, TextSource source, uint16_t knxAddr, const char* format); // Create button static WidgetConfig createButton(uint8_t id, int16_t x, int16_t y, const char* text, uint16_t knxAddrWrite, bool toggle); }; // Screen configuration (holds all widgets) struct ScreenConfig { uint8_t id; char name[MAX_SCREEN_NAME_LEN]; ScreenMode mode; Color backgroundColor; uint8_t widgetCount; WidgetConfig widgets[MAX_WIDGETS]; // Modal-specific properties (only used when mode == MODAL) int16_t modalX; // Modal position X (0 = centered) int16_t modalY; // Modal position Y (0 = centered) int16_t modalWidth; // Modal width (0 = auto from content) int16_t modalHeight; // Modal height (0 = auto from content) uint8_t modalBorderRadius; bool modalDimBackground; // Dim the background behind modal void clear(uint8_t newId = 0, const char* newName = nullptr); int addWidget(const WidgetConfig& widget); // Returns widget ID or -1 bool removeWidget(uint8_t id); WidgetConfig* findWidget(uint8_t id); const WidgetConfig* findWidget(uint8_t id) const; }; struct GuiConfig { uint8_t screenCount; ScreenConfig screens[MAX_SCREENS]; uint8_t startScreenId; bool standbyEnabled; uint8_t standbyScreenId; uint16_t standbyMinutes; void clear(); ScreenConfig* findScreen(uint8_t id); const ScreenConfig* findScreen(uint8_t id) const; };