mirror of
https://github.com/esphome/esphome.git
synced 2024-11-21 14:38:10 +01:00
[lvgl] Implement better software rotation (#7595)
This commit is contained in:
parent
b274d6901a
commit
6a86d92781
7 changed files with 201 additions and 58 deletions
|
@ -48,6 +48,7 @@ from .types import (
|
|||
FontEngine,
|
||||
IdleTrigger,
|
||||
ObjUpdateAction,
|
||||
PauseTrigger,
|
||||
lv_font_t,
|
||||
lv_group_t,
|
||||
lv_style_t,
|
||||
|
@ -233,6 +234,8 @@ async def to_code(config):
|
|||
frac = 8
|
||||
cg.add(lv_component.set_buffer_frac(int(frac)))
|
||||
cg.add(lv_component.set_full_refresh(config[df.CONF_FULL_REFRESH]))
|
||||
cg.add(lv_component.set_draw_rounding(config[df.CONF_DRAW_ROUNDING]))
|
||||
cg.add(lv_component.set_resume_on_input(config[df.CONF_RESUME_ON_INPUT]))
|
||||
|
||||
for font in helpers.esphome_fonts_used:
|
||||
await cg.get_variable(font)
|
||||
|
@ -272,11 +275,19 @@ async def to_code(config):
|
|||
async with LvContext(lv_component):
|
||||
await generate_triggers(lv_component)
|
||||
await generate_page_triggers(lv_component, config)
|
||||
await initial_focus_to_code(config)
|
||||
for conf in config.get(CONF_ON_IDLE, ()):
|
||||
templ = await cg.templatable(conf[CONF_TIMEOUT], [], cg.uint32)
|
||||
idle_trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], lv_component, templ)
|
||||
await build_automation(idle_trigger, [], conf)
|
||||
await initial_focus_to_code(config)
|
||||
for conf in config.get(df.CONF_ON_PAUSE, ()):
|
||||
pause_trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], lv_component, True)
|
||||
await build_automation(pause_trigger, [], conf)
|
||||
for conf in config.get(df.CONF_ON_RESUME, ()):
|
||||
resume_trigger = cg.new_Pvariable(
|
||||
conf[CONF_TRIGGER_ID], lv_component, False
|
||||
)
|
||||
await build_automation(resume_trigger, [], conf)
|
||||
|
||||
for comp in helpers.lvgl_components_required:
|
||||
CORE.add_define(f"USE_LVGL_{comp.upper()}")
|
||||
|
@ -314,6 +325,7 @@ CONFIG_SCHEMA = (
|
|||
cv.Optional(df.CONF_COLOR_DEPTH, default=16): cv.one_of(16),
|
||||
cv.Optional(df.CONF_DEFAULT_FONT, default="montserrat_14"): lvalid.lv_font,
|
||||
cv.Optional(df.CONF_FULL_REFRESH, default=False): cv.boolean,
|
||||
cv.Optional(df.CONF_DRAW_ROUNDING, default=2): cv.positive_int,
|
||||
cv.Optional(CONF_BUFFER_SIZE, default="100%"): cv.percentage,
|
||||
cv.Optional(df.CONF_LOG_LEVEL, default="WARN"): cv.one_of(
|
||||
*df.LOG_LEVELS, upper=True
|
||||
|
@ -341,6 +353,16 @@ CONFIG_SCHEMA = (
|
|||
),
|
||||
}
|
||||
),
|
||||
cv.Optional(df.CONF_ON_PAUSE): validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PauseTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(df.CONF_ON_RESUME): validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PauseTrigger),
|
||||
}
|
||||
),
|
||||
cv.Exclusive(df.CONF_WIDGETS, CONF_PAGES): cv.ensure_list(WIDGET_SCHEMA),
|
||||
cv.Exclusive(CONF_PAGES, CONF_PAGES): cv.ensure_list(
|
||||
container_schema(page_spec)
|
||||
|
@ -356,6 +378,7 @@ CONFIG_SCHEMA = (
|
|||
cv.Optional(df.CONF_TOUCHSCREENS, default=None): touchscreen_schema,
|
||||
cv.Optional(df.CONF_ENCODERS, default=None): ENCODERS_CONFIG,
|
||||
cv.GenerateID(df.CONF_DEFAULT_GROUP): cv.declare_id(lv_group_t),
|
||||
cv.Optional(df.CONF_RESUME_ON_INPUT, default=True): cv.boolean,
|
||||
}
|
||||
)
|
||||
.extend(DISP_BG_SCHEMA)
|
||||
|
|
|
@ -408,6 +408,7 @@ CONF_DEFAULT_FONT = "default_font"
|
|||
CONF_DEFAULT_GROUP = "default_group"
|
||||
CONF_DIR = "dir"
|
||||
CONF_DISPLAYS = "displays"
|
||||
CONF_DRAW_ROUNDING = "draw_rounding"
|
||||
CONF_EDITING = "editing"
|
||||
CONF_ENCODERS = "encoders"
|
||||
CONF_END_ANGLE = "end_angle"
|
||||
|
@ -451,6 +452,8 @@ CONF_OFFSET_X = "offset_x"
|
|||
CONF_OFFSET_Y = "offset_y"
|
||||
CONF_ONE_CHECKED = "one_checked"
|
||||
CONF_ONE_LINE = "one_line"
|
||||
CONF_ON_PAUSE = "on_pause"
|
||||
CONF_ON_RESUME = "on_resume"
|
||||
CONF_ON_SELECT = "on_select"
|
||||
CONF_OPA = "opa"
|
||||
CONF_NEXT = "next"
|
||||
|
@ -466,6 +469,7 @@ CONF_POINTS = "points"
|
|||
CONF_PREVIOUS = "previous"
|
||||
CONF_REPEAT_COUNT = "repeat_count"
|
||||
CONF_RECOLOR = "recolor"
|
||||
CONF_RESUME_ON_INPUT = "resume_on_input"
|
||||
CONF_RIGHT_BUTTON = "right_button"
|
||||
CONF_ROLLOVER = "rollover"
|
||||
CONF_ROOT_BACK_BTN = "root_back_btn"
|
||||
|
|
|
@ -69,30 +69,38 @@ std::string lv_event_code_name_for(uint8_t event_code) {
|
|||
}
|
||||
return str_sprintf("%2d", event_code);
|
||||
}
|
||||
|
||||
static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) {
|
||||
// make sure all coordinates are even
|
||||
if (area->x1 & 1)
|
||||
area->x1--;
|
||||
if (!(area->x2 & 1))
|
||||
area->x2++;
|
||||
if (area->y1 & 1)
|
||||
area->y1--;
|
||||
if (!(area->y2 & 1))
|
||||
area->y2++;
|
||||
// cater for display driver chips with special requirements for bounds of partial
|
||||
// draw areas. Extend the draw area to satisfy:
|
||||
// * Coordinates must be a multiple of draw_rounding
|
||||
auto *comp = static_cast<LvglComponent *>(disp_drv->user_data);
|
||||
auto draw_rounding = comp->draw_rounding;
|
||||
// round down the start coordinates
|
||||
area->x1 = area->x1 / draw_rounding * draw_rounding;
|
||||
area->y1 = area->y1 / draw_rounding * draw_rounding;
|
||||
// round up the end coordinates
|
||||
area->x2 = (area->x2 + draw_rounding) / draw_rounding * draw_rounding - 1;
|
||||
area->y2 = (area->y2 + draw_rounding) / draw_rounding * draw_rounding - 1;
|
||||
}
|
||||
|
||||
lv_event_code_t lv_api_event; // NOLINT
|
||||
lv_event_code_t lv_update_event; // NOLINT
|
||||
void LvglComponent::dump_config() { ESP_LOGCONFIG(TAG, "LVGL:"); }
|
||||
void LvglComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "LVGL:");
|
||||
ESP_LOGCONFIG(TAG, " Rotation: %d", this->rotation);
|
||||
ESP_LOGCONFIG(TAG, " Draw rounding: %d", (int) this->draw_rounding);
|
||||
}
|
||||
void LvglComponent::set_paused(bool paused, bool show_snow) {
|
||||
this->paused_ = paused;
|
||||
this->show_snow_ = show_snow;
|
||||
this->snow_line_ = 0;
|
||||
if (!paused && lv_scr_act() != nullptr) {
|
||||
lv_disp_trig_activity(this->disp_); // resets the inactivity time
|
||||
lv_obj_invalidate(lv_scr_act());
|
||||
}
|
||||
this->pause_callbacks_.call(paused);
|
||||
}
|
||||
|
||||
void LvglComponent::add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event) {
|
||||
lv_obj_add_event_cb(obj, callback, event, this);
|
||||
}
|
||||
|
@ -133,19 +141,64 @@ void LvglComponent::show_prev_page(lv_scr_load_anim_t anim, uint32_t time) {
|
|||
} while (this->pages_[this->current_page_]->skip); // skip empty pages()
|
||||
this->show_page(this->current_page_, anim, time);
|
||||
}
|
||||
void LvglComponent::draw_buffer_(const lv_area_t *area, const uint8_t *ptr) {
|
||||
void LvglComponent::draw_buffer_(const lv_area_t *area, lv_color_t *ptr) {
|
||||
auto width = lv_area_get_width(area);
|
||||
auto height = lv_area_get_height(area);
|
||||
auto x1 = area->x1;
|
||||
auto y1 = area->y1;
|
||||
lv_color_t *dst = this->rotate_buf_;
|
||||
switch (this->rotation) {
|
||||
case display::DISPLAY_ROTATION_90_DEGREES:
|
||||
for (lv_coord_t x = height - 1; x-- != 0;) {
|
||||
for (lv_coord_t y = 0; y != width; y++) {
|
||||
dst[y * height + x] = *ptr++;
|
||||
}
|
||||
}
|
||||
y1 = x1;
|
||||
x1 = this->disp_drv_.ver_res - area->y1 - height;
|
||||
width = height;
|
||||
height = lv_area_get_width(area);
|
||||
break;
|
||||
|
||||
case display::DISPLAY_ROTATION_180_DEGREES:
|
||||
for (lv_coord_t y = height; y-- != 0;) {
|
||||
for (lv_coord_t x = width; x-- != 0;) {
|
||||
dst[y * width + x] = *ptr++;
|
||||
}
|
||||
}
|
||||
x1 = this->disp_drv_.hor_res - x1 - width;
|
||||
y1 = this->disp_drv_.ver_res - y1 - height;
|
||||
break;
|
||||
|
||||
case display::DISPLAY_ROTATION_270_DEGREES:
|
||||
for (lv_coord_t x = 0; x != height; x++) {
|
||||
for (lv_coord_t y = width; y-- != 0;) {
|
||||
dst[y * height + x] = *ptr++;
|
||||
}
|
||||
}
|
||||
x1 = y1;
|
||||
y1 = this->disp_drv_.hor_res - area->x1 - width;
|
||||
width = height;
|
||||
height = lv_area_get_width(area);
|
||||
break;
|
||||
|
||||
default:
|
||||
dst = ptr;
|
||||
break;
|
||||
}
|
||||
for (auto *display : this->displays_) {
|
||||
display->draw_pixels_at(area->x1, area->y1, lv_area_get_width(area), lv_area_get_height(area), ptr,
|
||||
display::COLOR_ORDER_RGB, LV_BITNESS, LV_COLOR_16_SWAP);
|
||||
ESP_LOGV(TAG, "draw buffer x1=%d, y1=%d, width=%d, height=%d", x1, y1, width, height);
|
||||
display->draw_pixels_at(x1, y1, width, height, (const uint8_t *) dst, display::COLOR_ORDER_RGB, LV_BITNESS,
|
||||
LV_COLOR_16_SWAP);
|
||||
}
|
||||
}
|
||||
|
||||
void LvglComponent::flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) {
|
||||
if (!this->paused_) {
|
||||
auto now = millis();
|
||||
this->draw_buffer_(area, (const uint8_t *) color_p);
|
||||
ESP_LOGV(TAG, "flush_cb, area=%d/%d, %d/%d took %dms", area->x1, area->y1, lv_area_get_width(area),
|
||||
lv_area_get_height(area), (int) (millis() - now));
|
||||
this->draw_buffer_(area, color_p);
|
||||
ESP_LOGVV(TAG, "flush_cb, area=%d/%d, %d/%d took %dms", area->x1, area->y1, lv_area_get_width(area),
|
||||
lv_area_get_height(area), (int) (millis() - now));
|
||||
}
|
||||
lv_disp_flush_ready(disp_drv);
|
||||
}
|
||||
|
@ -160,6 +213,13 @@ IdleTrigger::IdleTrigger(LvglComponent *parent, TemplatableValue<uint32_t> timeo
|
|||
});
|
||||
}
|
||||
|
||||
PauseTrigger::PauseTrigger(LvglComponent *parent, TemplatableValue<bool> paused) : paused_(std::move(paused)) {
|
||||
parent->add_on_pause_callback([this](bool pausing) {
|
||||
if (this->paused_.value() == pausing)
|
||||
this->trigger();
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef USE_LVGL_TOUCHSCREEN
|
||||
LVTouchListener::LVTouchListener(uint16_t long_press_time, uint16_t long_press_repeat_time) {
|
||||
lv_indev_drv_init(&this->drv_);
|
||||
|
@ -261,23 +321,31 @@ void LvKeyboardType::set_obj(lv_obj_t *lv_obj) {
|
|||
#endif // USE_LVGL_KEYBOARD
|
||||
|
||||
void LvglComponent::write_random_() {
|
||||
// length of 2 lines in 32 bit units
|
||||
// we write 2 lines for the benefit of displays that won't write one line at a time.
|
||||
size_t line_len = this->disp_drv_.hor_res * LV_COLOR_DEPTH / 8 / 4 * 2;
|
||||
for (size_t i = 0; i != line_len; i++) {
|
||||
((uint32_t *) (this->draw_buf_.buf1))[i] = random_uint32();
|
||||
int iterations = 6 - lv_disp_get_inactive_time(this->disp_) / 60000;
|
||||
if (iterations <= 0)
|
||||
iterations = 1;
|
||||
while (iterations-- != 0) {
|
||||
auto col = random_uint32() % this->disp_drv_.hor_res;
|
||||
col = col / this->draw_rounding * this->draw_rounding;
|
||||
auto row = random_uint32() % this->disp_drv_.ver_res;
|
||||
row = row / this->draw_rounding * this->draw_rounding;
|
||||
auto size = (random_uint32() % 32) / this->draw_rounding * this->draw_rounding - 1;
|
||||
lv_area_t area;
|
||||
area.x1 = col;
|
||||
area.y1 = row;
|
||||
area.x2 = col + size;
|
||||
area.y2 = row + size;
|
||||
if (area.x2 >= this->disp_drv_.hor_res)
|
||||
area.x2 = this->disp_drv_.hor_res - 1;
|
||||
if (area.y2 >= this->disp_drv_.ver_res)
|
||||
area.y2 = this->disp_drv_.ver_res - 1;
|
||||
|
||||
size_t line_len = lv_area_get_width(&area) * lv_area_get_height(&area) / 2;
|
||||
for (size_t i = 0; i != line_len; i++) {
|
||||
((uint32_t *) (this->draw_buf_.buf1))[i] = random_uint32();
|
||||
}
|
||||
this->draw_buffer_(&area, (lv_color_t *) this->draw_buf_.buf1);
|
||||
}
|
||||
lv_area_t area;
|
||||
area.x1 = 0;
|
||||
area.x2 = this->disp_drv_.hor_res - 1;
|
||||
if (this->snow_line_ == this->disp_drv_.ver_res / 2) {
|
||||
area.y1 = static_cast<lv_coord_t>(random_uint32() % (this->disp_drv_.ver_res / 2) * 2);
|
||||
} else {
|
||||
area.y1 = this->snow_line_++ * 2;
|
||||
}
|
||||
// write 2 lines
|
||||
area.y2 = area.y1 + 1;
|
||||
this->draw_buffer_(&area, (const uint8_t *) this->draw_buf_.buf1);
|
||||
}
|
||||
|
||||
void LvglComponent::setup() {
|
||||
|
@ -291,7 +359,7 @@ void LvglComponent::setup() {
|
|||
auto *display = this->displays_[0];
|
||||
size_t buffer_pixels = display->get_width() * display->get_height() / this->buffer_frac_;
|
||||
auto buf_bytes = buffer_pixels * LV_COLOR_DEPTH / 8;
|
||||
auto *buf = lv_custom_mem_alloc(buf_bytes);
|
||||
auto *buf = lv_custom_mem_alloc(buf_bytes); // NOLINT
|
||||
if (buf == nullptr) {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR
|
||||
ESP_LOGE(TAG, "Malloc failed to allocate %zu bytes", buf_bytes);
|
||||
|
@ -307,26 +375,30 @@ void LvglComponent::setup() {
|
|||
this->disp_drv_.full_refresh = this->full_refresh_;
|
||||
this->disp_drv_.flush_cb = static_flush_cb;
|
||||
this->disp_drv_.rounder_cb = rounder_cb;
|
||||
switch (display->get_rotation()) {
|
||||
case display::DISPLAY_ROTATION_0_DEGREES:
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_90_DEGREES:
|
||||
this->disp_drv_.sw_rotate = true;
|
||||
this->disp_drv_.rotated = LV_DISP_ROT_90;
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_180_DEGREES:
|
||||
this->disp_drv_.sw_rotate = true;
|
||||
this->disp_drv_.rotated = LV_DISP_ROT_180;
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_270_DEGREES:
|
||||
this->disp_drv_.sw_rotate = true;
|
||||
this->disp_drv_.rotated = LV_DISP_ROT_270;
|
||||
break;
|
||||
this->rotation = display->get_rotation();
|
||||
if (this->rotation != display::DISPLAY_ROTATION_0_DEGREES) {
|
||||
this->rotate_buf_ = static_cast<lv_color_t *>(lv_custom_mem_alloc(buf_bytes)); // NOLINT
|
||||
if (this->rotate_buf_ == nullptr) {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR
|
||||
ESP_LOGE(TAG, "Malloc failed to allocate %zu bytes", buf_bytes);
|
||||
#endif
|
||||
this->mark_failed();
|
||||
this->status_set_error("Memory allocation failure");
|
||||
return;
|
||||
}
|
||||
}
|
||||
display->set_rotation(display::DISPLAY_ROTATION_0_DEGREES);
|
||||
this->disp_drv_.hor_res = (lv_coord_t) display->get_width();
|
||||
this->disp_drv_.ver_res = (lv_coord_t) display->get_height();
|
||||
ESP_LOGV(TAG, "sw_rotate = %d, rotated=%d", this->disp_drv_.sw_rotate, this->disp_drv_.rotated);
|
||||
switch (this->rotation) {
|
||||
default:
|
||||
this->disp_drv_.hor_res = (lv_coord_t) display->get_width();
|
||||
this->disp_drv_.ver_res = (lv_coord_t) display->get_height();
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_90_DEGREES:
|
||||
case display::DISPLAY_ROTATION_270_DEGREES:
|
||||
this->disp_drv_.ver_res = (lv_coord_t) display->get_width();
|
||||
this->disp_drv_.hor_res = (lv_coord_t) display->get_height();
|
||||
break;
|
||||
}
|
||||
this->disp_ = lv_disp_drv_register(&this->disp_drv_);
|
||||
for (const auto &v : this->init_lambdas_)
|
||||
v(this);
|
||||
|
|
|
@ -119,6 +119,7 @@ class LvglComponent : public PollingComponent {
|
|||
void add_on_idle_callback(std::function<void(uint32_t)> &&callback) {
|
||||
this->idle_callbacks_.add(std::move(callback));
|
||||
}
|
||||
void add_on_pause_callback(std::function<void(bool)> &&callback) { this->pause_callbacks_.add(std::move(callback)); }
|
||||
void add_display(display::Display *display) { this->displays_.push_back(display); }
|
||||
void add_init_lambda(const std::function<void(LvglComponent *)> &lamb) { this->init_lambdas_.push_back(lamb); }
|
||||
void dump_config() override;
|
||||
|
@ -126,12 +127,22 @@ class LvglComponent : public PollingComponent {
|
|||
bool is_idle(uint32_t idle_ms) { return lv_disp_get_inactive_time(this->disp_) > idle_ms; }
|
||||
void set_buffer_frac(size_t frac) { this->buffer_frac_ = frac; }
|
||||
lv_disp_t *get_disp() { return this->disp_; }
|
||||
// Pause or resume the display.
|
||||
// @param paused If true, pause the display. If false, resume the display.
|
||||
// @param show_snow If true, show the snow effect when paused.
|
||||
void set_paused(bool paused, bool show_snow);
|
||||
bool is_paused() const { return this->paused_; }
|
||||
// If the display is paused and we have resume_on_input_ set to true, resume the display.
|
||||
void maybe_wakeup() {
|
||||
if (this->paused_ && this->resume_on_input_) {
|
||||
this->set_paused(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event);
|
||||
void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, lv_event_code_t event2);
|
||||
void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, lv_event_code_t event2,
|
||||
lv_event_code_t event3);
|
||||
bool is_paused() const { return this->paused_; }
|
||||
void add_page(LvPageType *page);
|
||||
void show_page(size_t index, lv_scr_load_anim_t anim, uint32_t time);
|
||||
void show_next_page(lv_scr_load_anim_t anim, uint32_t time);
|
||||
|
@ -144,10 +155,17 @@ class LvglComponent : public PollingComponent {
|
|||
lv_group_focus_obj(mark);
|
||||
}
|
||||
}
|
||||
// rounding factor to align bounds of update area when drawing
|
||||
size_t draw_rounding{2};
|
||||
void set_draw_rounding(size_t rounding) { this->draw_rounding = rounding; }
|
||||
void set_resume_on_input(bool resume_on_input) { this->resume_on_input_ = resume_on_input; }
|
||||
|
||||
// if set to true, the bounds of the update area will always start at 0,0
|
||||
display::DisplayRotation rotation{display::DISPLAY_ROTATION_0_DEGREES};
|
||||
|
||||
protected:
|
||||
void write_random_();
|
||||
void draw_buffer_(const lv_area_t *area, const uint8_t *ptr);
|
||||
void draw_buffer_(const lv_area_t *area, lv_color_t *ptr);
|
||||
void flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
|
||||
std::vector<display::Display *> displays_{};
|
||||
lv_disp_draw_buf_t draw_buf_{};
|
||||
|
@ -157,14 +175,16 @@ class LvglComponent : public PollingComponent {
|
|||
std::vector<LvPageType *> pages_{};
|
||||
size_t current_page_{0};
|
||||
bool show_snow_{};
|
||||
lv_coord_t snow_line_{};
|
||||
bool page_wrap_{true};
|
||||
bool resume_on_input_{};
|
||||
std::map<lv_group_t *, lv_obj_t *> focus_marks_{};
|
||||
|
||||
std::vector<std::function<void(LvglComponent *lv_component)>> init_lambdas_;
|
||||
CallbackManager<void(uint32_t)> idle_callbacks_{};
|
||||
CallbackManager<void(bool)> pause_callbacks_{};
|
||||
size_t buffer_frac_{1};
|
||||
bool full_refresh_{};
|
||||
lv_color_t *rotate_buf_{};
|
||||
};
|
||||
|
||||
class IdleTrigger : public Trigger<> {
|
||||
|
@ -176,6 +196,14 @@ class IdleTrigger : public Trigger<> {
|
|||
bool is_idle_{};
|
||||
};
|
||||
|
||||
class PauseTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit PauseTrigger(LvglComponent *parent, TemplatableValue<bool> paused);
|
||||
|
||||
protected:
|
||||
TemplatableValue<bool> paused_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class LvglAction : public Action<Ts...>, public Parented<LvglComponent> {
|
||||
public:
|
||||
explicit LvglAction(std::function<void(LvglComponent *)> &&lamb) : action_(std::move(lamb)) {}
|
||||
|
@ -200,7 +228,10 @@ class LVTouchListener : public touchscreen::TouchListener, public Parented<LvglC
|
|||
public:
|
||||
LVTouchListener(uint16_t long_press_time, uint16_t long_press_repeat_time);
|
||||
void update(const touchscreen::TouchPoints_t &tpoints) override;
|
||||
void release() override { touch_pressed_ = false; }
|
||||
void release() override {
|
||||
touch_pressed_ = false;
|
||||
this->parent_->maybe_wakeup();
|
||||
}
|
||||
lv_indev_drv_t *get_drv() { return &this->drv_; }
|
||||
|
||||
protected:
|
||||
|
@ -236,12 +267,18 @@ class LVEncoderListener : public Parented<LvglComponent> {
|
|||
if (!this->parent_->is_paused()) {
|
||||
this->pressed_ = pressed;
|
||||
this->key_ = key;
|
||||
} else if (!pressed) {
|
||||
// maybe wakeup on release if paused
|
||||
this->parent_->maybe_wakeup();
|
||||
}
|
||||
}
|
||||
|
||||
void set_count(int32_t count) {
|
||||
if (!this->parent_->is_paused())
|
||||
if (!this->parent_->is_paused()) {
|
||||
this->count_ = count;
|
||||
} else {
|
||||
this->parent_->maybe_wakeup();
|
||||
}
|
||||
}
|
||||
|
||||
lv_indev_drv_t *get_drv() { return &this->drv_; }
|
||||
|
|
|
@ -40,6 +40,7 @@ lv_event_code_t = cg.global_ns.enum("lv_event_code_t")
|
|||
lv_indev_type_t = cg.global_ns.enum("lv_indev_type_t")
|
||||
FontEngine = lvgl_ns.class_("FontEngine")
|
||||
IdleTrigger = lvgl_ns.class_("IdleTrigger", automation.Trigger.template())
|
||||
PauseTrigger = lvgl_ns.class_("PauseTrigger", automation.Trigger.template())
|
||||
ObjUpdateAction = lvgl_ns.class_("ObjUpdateAction", automation.Action)
|
||||
LvglCondition = lvgl_ns.class_("LvglCondition", automation.Condition)
|
||||
LvglAction = lvgl_ns.class_("LvglAction", automation.Action)
|
||||
|
|
|
@ -12,6 +12,11 @@ substitutions:
|
|||
arrow_down: "\U000F004B"
|
||||
|
||||
lvgl:
|
||||
resume_on_input: true
|
||||
on_pause:
|
||||
logger.log: LVGL is Paused
|
||||
on_resume:
|
||||
logger.log: LVGL has resumed
|
||||
log_level: TRACE
|
||||
bg_color: light_blue
|
||||
disp_bg_color: color_id
|
||||
|
|
|
@ -44,6 +44,7 @@ binary_sensor:
|
|||
number: GPIO39
|
||||
inverted: true
|
||||
lvgl:
|
||||
draw_rounding: 8
|
||||
encoders:
|
||||
group: switches
|
||||
initial_focus: button_button
|
||||
|
|
Loading…
Reference in a new issue