#include "IconWidget.hpp" #include "../Fonts.hpp" #include "esp_log.h" static const char* TAG = "IconWidget"; IconWidget::IconWidget(const WidgetConfig& config) : Widget(config) , iconLabel_(nullptr) { } int IconWidget::encodeUtf8(uint32_t codepoint, char* buf) { if (codepoint < 0x80) { buf[0] = static_cast(codepoint); buf[1] = '\0'; return 1; } else if (codepoint < 0x800) { buf[0] = static_cast(0xC0 | (codepoint >> 6)); buf[1] = static_cast(0x80 | (codepoint & 0x3F)); buf[2] = '\0'; return 2; } else if (codepoint < 0x10000) { buf[0] = static_cast(0xE0 | (codepoint >> 12)); buf[1] = static_cast(0x80 | ((codepoint >> 6) & 0x3F)); buf[2] = static_cast(0x80 | (codepoint & 0x3F)); buf[3] = '\0'; return 3; } else if (codepoint < 0x110000) { buf[0] = static_cast(0xF0 | (codepoint >> 18)); buf[1] = static_cast(0x80 | ((codepoint >> 12) & 0x3F)); buf[2] = static_cast(0x80 | ((codepoint >> 6) & 0x3F)); buf[3] = static_cast(0x80 | (codepoint & 0x3F)); buf[4] = '\0'; return 4; } buf[0] = '\0'; return 0; } lv_obj_t* IconWidget::create(lv_obj_t* parent) { // Create container for the icon obj_ = lv_obj_create(parent); if (obj_ == nullptr) { ESP_LOGE(TAG, "Failed to create icon widget object"); return nullptr; } lv_obj_remove_style_all(obj_); lv_obj_set_pos(obj_, config_.x, config_.y); lv_obj_set_size(obj_, config_.width > 0 ? config_.width : 48, config_.height > 0 ? config_.height : 48); // Create icon label iconLabel_ = lv_label_create(obj_); if (config_.iconCodepoint > 0) { char iconText[5]; encodeUtf8(config_.iconCodepoint, iconText); lv_label_set_text(iconLabel_, iconText); } else { lv_label_set_text(iconLabel_, "?"); } lv_obj_center(iconLabel_); ESP_LOGI(TAG, "Created icon widget (codepoint: 0x%lx) at %d,%d", (unsigned long)config_.iconCodepoint, config_.x, config_.y); return obj_; } void IconWidget::applyStyle() { if (obj_ == nullptr) return; // Background if (config_.bgOpacity > 0) { lv_obj_set_style_bg_color(obj_, lv_color_make( config_.bgColor.r, config_.bgColor.g, config_.bgColor.b), 0); lv_obj_set_style_bg_opa(obj_, config_.bgOpacity, 0); } // Border radius if (config_.borderRadius > 0) { lv_obj_set_style_radius(obj_, config_.borderRadius, 0); } // Apply icon style if (iconLabel_ != nullptr) { lv_obj_set_style_text_color(iconLabel_, lv_color_make( config_.textColor.r, config_.textColor.g, config_.textColor.b), 0); // Use icon font uint8_t sizeIdx = config_.iconSize < 6 ? config_.iconSize : config_.fontSize; if (Fonts::hasIconFont()) { lv_obj_set_style_text_font(iconLabel_, Fonts::iconFont(sizeIdx), 0); } else { // Fallback to text font (won't show correct icon, but won't crash) lv_obj_set_style_text_font(iconLabel_, Fonts::bySizeIndex(sizeIdx), 0); } } } void IconWidget::onKnxSwitch(bool value) { if (iconLabel_ == nullptr) return; if (config_.textSource != TextSource::KNX_DPT_SWITCH) return; // Change icon color based on switch state if (value) { // Use text color for "on" state (default) lv_obj_set_style_text_color(iconLabel_, lv_color_make( config_.textColor.r, config_.textColor.g, config_.textColor.b), 0); } else { // Dim color for "off" state (50% brightness) lv_obj_set_style_text_color(iconLabel_, lv_color_make( config_.textColor.r / 2, config_.textColor.g / 2, config_.textColor.b / 2), 0); } }