diff --git a/.cache/clangd/index/ButtonWidget.hpp.551D0D3595AEDB81.idx b/.cache/clangd/index/ButtonWidget.hpp.551D0D3595AEDB81.idx index 9175233..4cbad88 100644 Binary files a/.cache/clangd/index/ButtonWidget.hpp.551D0D3595AEDB81.idx and b/.cache/clangd/index/ButtonWidget.hpp.551D0D3595AEDB81.idx differ diff --git a/.cache/clangd/index/Widget.cpp.63DB7B9186B85891.idx b/.cache/clangd/index/Widget.cpp.63DB7B9186B85891.idx index 2c96fe4..fcdc0f4 100644 Binary files a/.cache/clangd/index/Widget.cpp.63DB7B9186B85891.idx and b/.cache/clangd/index/Widget.cpp.63DB7B9186B85891.idx differ diff --git a/main/widgets/ButtonWidget.cpp b/main/widgets/ButtonWidget.cpp index 0e5eff3..265d3a4 100644 --- a/main/widgets/ButtonWidget.cpp +++ b/main/widgets/ButtonWidget.cpp @@ -41,6 +41,7 @@ ButtonWidget::ButtonWidget(const WidgetConfig& config) , contentContainer_(nullptr) , label_(nullptr) , iconLabel_(nullptr) + , shadowObj_(nullptr) { } @@ -49,6 +50,11 @@ ButtonWidget::~ButtonWidget() { if (obj_) { lv_obj_remove_event_cb(obj_, clickCallback); } + // Delete fake shadow (not a child of obj_, so must delete separately) + if (shadowObj_ && lv_obj_is_valid(shadowObj_)) { + lv_obj_delete(shadowObj_); + } + shadowObj_ = nullptr; contentContainer_ = nullptr; label_ = nullptr; iconLabel_ = nullptr; @@ -128,6 +134,11 @@ void ButtonWidget::applyTextAlignment() { } lv_obj_t* ButtonWidget::create(lv_obj_t* parent) { + // Create fake shadow FIRST (so it's behind the button in z-order) + if (config_.shadow.enabled) { + createFakeShadow(parent); + } + obj_ = lv_btn_create(parent); lv_obj_set_pos(obj_, config_.x, config_.y); lv_obj_set_size(obj_, config_.width > 0 ? config_.width : 100, @@ -200,9 +211,12 @@ lv_obj_t* ButtonWidget::create(lv_obj_t* parent) { void ButtonWidget::applyStyle() { if (obj_ == nullptr) return; - // Apply common style to button + // Apply common style to button (shadows skipped for buttons in Widget::applyShadowStyle) applyCommonStyle(); + // Apply fake shadow style + applyFakeShadowStyle(); + // Apply text style to label if (label_ != nullptr) { lv_obj_set_style_text_color(label_, lv_color_make( @@ -224,3 +238,47 @@ bool ButtonWidget::isChecked() const { if (obj_ == nullptr) return false; return (lv_obj_get_state(obj_) & LV_STATE_CHECKED) != 0; } + +void ButtonWidget::createFakeShadow(lv_obj_t* parent) { + // Create a simple rectangle as fake shadow (no LVGL shadow rendering) + shadowObj_ = lv_obj_create(parent); + if (!shadowObj_) return; + + lv_obj_remove_style_all(shadowObj_); + lv_obj_clear_flag(shadowObj_, static_cast(LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_SCROLLABLE)); + + // Position: offset from button position by shadow offset + int16_t shadowX = config_.x + config_.shadow.offsetX; + int16_t shadowY = config_.y + config_.shadow.offsetY; + + // Size: slightly larger than button (spread effect) + int16_t spread = config_.shadow.spread > 8 ? 8 : config_.shadow.spread; + int16_t shadowW = (config_.width > 0 ? config_.width : 100) + spread * 2; + int16_t shadowH = (config_.height > 0 ? config_.height : 50) + spread * 2; + + // Adjust position for spread + shadowX -= spread; + shadowY -= spread; + + lv_obj_set_pos(shadowObj_, shadowX, shadowY); + lv_obj_set_size(shadowObj_, shadowW, shadowH); +} + +void ButtonWidget::applyFakeShadowStyle() { + if (!shadowObj_) return; + + lv_color_t shadowColor = lv_color_make( + config_.shadow.color.r, config_.shadow.color.g, config_.shadow.color.b); + + // Blur simulation: use lower opacity for softer look + uint8_t blur = config_.shadow.blur > 15 ? 15 : config_.shadow.blur; + uint8_t opa = blur > 0 ? (uint8_t)(120 - blur * 4) : 120; // Less blur = more solid + + lv_obj_set_style_bg_color(shadowObj_, shadowColor, 0); + lv_obj_set_style_bg_opa(shadowObj_, opa, 0); + + // Match button's border radius + if (config_.borderRadius > 0) { + lv_obj_set_style_radius(shadowObj_, config_.borderRadius + config_.shadow.spread, 0); + } +} diff --git a/main/widgets/ButtonWidget.hpp b/main/widgets/ButtonWidget.hpp index ceaa638..1eab728 100644 --- a/main/widgets/ButtonWidget.hpp +++ b/main/widgets/ButtonWidget.hpp @@ -17,9 +17,12 @@ private: lv_obj_t* contentContainer_ = nullptr; lv_obj_t* label_ = nullptr; lv_obj_t* iconLabel_ = nullptr; + lv_obj_t* shadowObj_ = nullptr; // Fake shadow rectangle behind button void setupFlexLayout(); void applyTextAlignment(); + void createFakeShadow(lv_obj_t* parent); + void applyFakeShadowStyle(); static int encodeUtf8(uint32_t codepoint, char* buf); static void clickCallback(lv_event_t* e); };