knxdisplay/main/widgets/Widget.cpp
2026-01-30 23:08:31 +01:00

115 lines
3.1 KiB
C++

#include "Widget.hpp"
#include "../Fonts.hpp"
#include "lvgl.h"
Widget::Widget(const WidgetConfig& config)
: config_(config)
, obj_(nullptr)
{
}
Widget::~Widget() {
destroy();
}
void Widget::destroy() {
if (obj_ != nullptr) {
if (lv_obj_is_valid(obj_)) {
lv_obj_delete(obj_);
}
obj_ = nullptr;
}
}
void Widget::applyStyle() {
if (obj_ == nullptr) return;
applyCommonStyle();
}
void Widget::onKnxValue(float /*value*/) {
// Default: do nothing
}
void Widget::onKnxSwitch(bool /*value*/) {
// Default: do nothing
}
void Widget::onKnxText(const char* /*text*/) {
// Default: do nothing
}
void Widget::onKnxTime(const struct tm& /*value*/, TextSource /*source*/) {
// Default: do nothing
}
void Widget::onHistoryUpdate() {
// Default: do nothing
}
void Widget::applyCommonStyle() {
if (obj_ == nullptr) return;
// Text color
lv_obj_set_style_text_color(obj_, lv_color_make(
config_.textColor.r, config_.textColor.g, config_.textColor.b), 0);
// Font
lv_obj_set_style_text_font(obj_, getFontBySize(config_.fontSize), 0);
// Background (for buttons and labels with bg)
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);
}
// Shadow
applyShadowStyle();
}
void Widget::applyShadowStyle() {
return;
if (obj_ == nullptr || !config_.shadow.enabled) return;
// Limit shadow values to prevent memory issues on ESP32
constexpr int16_t MAX_SHADOW_BLUR = 15;
constexpr int16_t MAX_SHADOW_SPREAD = 8;
int16_t blur = config_.shadow.blur;
int16_t spread = config_.shadow.spread;
if (blur > MAX_SHADOW_BLUR) blur = MAX_SHADOW_BLUR;
if (blur < 0) blur = 0;
if (spread > MAX_SHADOW_SPREAD) spread = MAX_SHADOW_SPREAD;
if (spread < 0) spread = 0;
if (blur == 0) return;
lv_color_t shadowColor = lv_color_make(
config_.shadow.color.r, config_.shadow.color.g, config_.shadow.color.b);
// Default state shadow
lv_obj_set_style_shadow_color(obj_, shadowColor, 0);
lv_obj_set_style_shadow_opa(obj_, 180, 0);
lv_obj_set_style_shadow_width(obj_, blur, 0);
lv_obj_set_style_shadow_spread(obj_, spread, 0);
lv_obj_set_style_shadow_offset_x(obj_, config_.shadow.offsetX, 0);
lv_obj_set_style_shadow_offset_y(obj_, config_.shadow.offsetY, 0);
// For clickable widgets: explicitly define PRESSED state with no shadow
// This prevents PPA/DMA2D freeze when shadow needs recalculation during state change
if (lv_obj_has_flag(obj_, LV_OBJ_FLAG_CLICKABLE)) {
lv_obj_set_style_shadow_width(obj_, 0, LV_STATE_PRESSED);
lv_obj_set_style_shadow_spread(obj_, 0, LV_STATE_PRESSED);
lv_obj_set_style_shadow_opa(obj_, 0, LV_STATE_PRESSED);
}
}
const lv_font_t* Widget::getFontBySize(uint8_t sizeIndex) {
return Fonts::bySizeIndex(sizeIndex);
}