mirror of
https://github.com/esphome/esphome.git
synced 2026-09-03 03:26:02 +00:00
[lvgl] Fix on_value/on_update triggers for LVGL select entities (#18778)
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
82ca5365c9
commit
ae460b430c
@@ -551,21 +551,21 @@ std::string LvSelectable::get_selected_text() {
|
||||
return this->options_[selected];
|
||||
}
|
||||
|
||||
static std::string join_string(std::vector<std::string> options) {
|
||||
static std::string join_string(const FixedVector<const char *> &options) {
|
||||
return std::accumulate(
|
||||
options.begin(), options.end(), std::string(),
|
||||
[](const std::string &a, const std::string &b) -> std::string { return a + (!a.empty() ? "\n" : "") + b; });
|
||||
[](const std::string &a, const char *b) -> std::string { return a + (!a.empty() ? "\n" : "") + b; });
|
||||
}
|
||||
|
||||
void LvSelectable::set_selected_text(const std::string &text, lv_anim_enable_t anim) {
|
||||
auto index = std::find(this->options_.begin(), this->options_.end(), text);
|
||||
auto *index = std::find(this->options_.begin(), this->options_.end(), text);
|
||||
if (index != this->options_.end()) {
|
||||
this->set_selected_index(index - this->options_.begin(), anim);
|
||||
lv_obj_send_event(this->obj, lv_update_event, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void LvSelectable::set_options(std::vector<std::string> options) {
|
||||
void LvSelectable::set_options(FixedVector<const char *> options) {
|
||||
auto index = this->get_selected_index();
|
||||
if (index >= options.size())
|
||||
index = options.size() - 1;
|
||||
|
||||
@@ -499,12 +499,12 @@ class LvSelectable : public LvCompound {
|
||||
virtual void set_selected_index(size_t index, lv_anim_enable_t anim) = 0;
|
||||
void set_selected_text(const std::string &text, lv_anim_enable_t anim);
|
||||
std::string get_selected_text();
|
||||
const std::vector<std::string> &get_options() { return this->options_; }
|
||||
void set_options(std::vector<std::string> options);
|
||||
const FixedVector<const char *> &get_options() { return this->options_; }
|
||||
void set_options(FixedVector<const char *> options);
|
||||
|
||||
protected:
|
||||
virtual void set_option_string(const char *options) = 0;
|
||||
std::vector<std::string> options_{};
|
||||
FixedVector<const char *> options_{};
|
||||
};
|
||||
|
||||
#ifdef USE_LVGL_DROPDOWN
|
||||
|
||||
@@ -50,19 +50,10 @@ class LVGLSelect final : public select::Select, public Component {
|
||||
protected:
|
||||
void control(size_t index) override {
|
||||
this->widget_->set_selected_index(index, this->anim_);
|
||||
this->publish();
|
||||
}
|
||||
void set_options_() {
|
||||
// Widget uses std::vector<std::string>, SelectTraits uses FixedVector<const char*>
|
||||
// Convert by extracting c_str() pointers
|
||||
const auto &opts = this->widget_->get_options();
|
||||
FixedVector<const char *> opt_ptrs;
|
||||
opt_ptrs.init(opts.size());
|
||||
for (const auto &opt : opts) {
|
||||
opt_ptrs.push_back(opt.c_str());
|
||||
}
|
||||
this->traits.set_options(opt_ptrs);
|
||||
// The update event fires the widget's on_value/on_update triggers
|
||||
lv_obj_send_event(this->widget_->obj, lv_update_event, nullptr);
|
||||
}
|
||||
void set_options_() { this->traits.set_options(this->widget_->get_options()); }
|
||||
|
||||
LvSelectable *widget_;
|
||||
lv_anim_enable_t anim_;
|
||||
|
||||
@@ -3,6 +3,8 @@ from esphome.const import CONF_TEXT, CONF_VALUE
|
||||
from esphome.cpp_generator import MockObj
|
||||
from esphome.cpp_types import Component, esphome_ns
|
||||
|
||||
from .defines import CONF_SELECTED_INDEX
|
||||
|
||||
|
||||
class LvType(cg.MockObjClass):
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -112,3 +114,4 @@ class LvSelect(LvType):
|
||||
parents=parens,
|
||||
**kwargs,
|
||||
)
|
||||
self.value_property = CONF_SELECTED_INDEX
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
esphome:
|
||||
name: test-dropdown-update-event
|
||||
on_boot:
|
||||
- lvgl.dropdown.update:
|
||||
id: test_dropdown
|
||||
selected_index: 2
|
||||
|
||||
esp32:
|
||||
board: lolin_c3_mini
|
||||
|
||||
spi:
|
||||
mosi_pin:
|
||||
number: GPIO2
|
||||
ignore_strapping_warning: true
|
||||
clk_pin: GPIO1
|
||||
|
||||
display:
|
||||
- platform: mipi_spi
|
||||
data_rate: 20MHz
|
||||
model: st7735
|
||||
cs_pin:
|
||||
number: GPIO8
|
||||
ignore_strapping_warning: true
|
||||
dc_pin: GPIO3
|
||||
|
||||
lvgl:
|
||||
widgets:
|
||||
- dropdown:
|
||||
id: test_dropdown
|
||||
options:
|
||||
- First
|
||||
- Second
|
||||
- Third
|
||||
on_update:
|
||||
- lambda: |-
|
||||
ESP_LOGD("test", "dropdown updated");
|
||||
@@ -0,0 +1,41 @@
|
||||
"""Regression test: lvgl.dropdown.update with selected_index must fire on_value/on_update.
|
||||
|
||||
LvSelect (backing both dropdown and roller) did not set `value_property`, so the generic
|
||||
update-action machinery in automation.py never sent the synthetic update event for a
|
||||
`selected_index:` change made via `lvgl.dropdown.update`/`lvgl.roller.update`, unlike `value:`
|
||||
on number widgets or `text:` on text widgets. Fixed by setting `LvSelect.value_property` to
|
||||
`CONF_SELECTED_INDEX`.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.__main__ import generate_cpp_contents
|
||||
from esphome.config import read_config
|
||||
from esphome.core import CORE
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def main_cpp(request: pytest.FixtureRequest) -> str:
|
||||
config_path = (
|
||||
Path(request.fspath).parent / "config" / "dropdown_update_fires_event_test.yaml"
|
||||
)
|
||||
original_path = CORE.config_path
|
||||
try:
|
||||
CORE.config_path = config_path
|
||||
CORE.config = read_config({})
|
||||
generate_cpp_contents(CORE.config)
|
||||
return CORE.cpp_main_section
|
||||
finally:
|
||||
CORE.config_path = original_path
|
||||
CORE.reset()
|
||||
|
||||
|
||||
def test_dropdown_update_sends_update_event(main_cpp: str) -> None:
|
||||
assert (
|
||||
"lv_obj_send_event(test_dropdown->obj, lvgl::lv_update_event, nullptr)"
|
||||
in main_cpp
|
||||
)
|
||||
Reference in New Issue
Block a user