From 4b978c347de8c86d45e85ae61896f2ed2f0214c8 Mon Sep 17 00:00:00 2001 From: philmoz Date: Mon, 5 Aug 2024 09:27:25 +1000 Subject: [PATCH] fix(color): flickering Lua widgets when full screen is refreshed (#5364) --- radio/src/gui/colorlcd/libui/bitmapbuffer.cpp | 19 ++++++++++-- radio/src/gui/colorlcd/libui/bitmapbuffer.h | 29 +++++++++++++++++++ .../libui/bitmapbuffer_draw_extra.cpp | 16 ++++++++++ radio/src/lua/lua_widget.cpp | 4 +++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/radio/src/gui/colorlcd/libui/bitmapbuffer.cpp b/radio/src/gui/colorlcd/libui/bitmapbuffer.cpp index 1520216db..2b4458423 100644 --- a/radio/src/gui/colorlcd/libui/bitmapbuffer.cpp +++ b/radio/src/gui/colorlcd/libui/bitmapbuffer.cpp @@ -90,7 +90,7 @@ void BitmapBuffer::setData(uint16_t *d) void BitmapBuffer::clear(LcdFlags flags) { - drawSolidFilledRect(0, 0, _width, _height, flags); + drawSolidFilledRect(0, 0, _width - offsetX, _height - offsetY, flags); } void BitmapBuffer::clearClippingRect() @@ -151,11 +151,18 @@ bool BitmapBuffer::applyClippingRect(coord_t& x, coord_t& y, coord_t& w, return data && h > 0 && w > 0; } +void BitmapBuffer::setOffset(coord_t offsetX, coord_t offsetY) +{ + this->offsetX = offsetX; + this->offsetY = offsetY; +} + void BitmapBuffer::drawBitmap(coord_t x, coord_t y, const BitmapBuffer *bmp, coord_t srcx, coord_t srcy, coord_t srcw, coord_t srch, float scale) { if (!data || !bmp) return; + APPLY_OFFSET(); if (x >= xmax || y >= ymax) return; coord_t bmpw = bmp->width(); @@ -292,6 +299,8 @@ void BitmapBuffer::drawHorizontalLine(coord_t x, coord_t y, coord_t w, { if (opacity == OPACITY_MAX) return; + APPLY_OFFSET(); + coord_t h = 1; if (!applyClippingRect(x, y, w, h)) return; @@ -343,6 +352,8 @@ void BitmapBuffer::drawVerticalLine(coord_t x, coord_t y, coord_t h, { if (opacity == OPACITY_MAX) return; + APPLY_OFFSET(); + coord_t w = 1; if (!applyClippingRect(x, y, w, h)) return; @@ -406,6 +417,7 @@ void BitmapBuffer::drawFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, { if (opacity == OPACITY_MAX) return; + APPLY_OFFSET(); if (!applyClippingRect(x, y, w, h)) return; if (SOLID != pat) { @@ -448,6 +460,7 @@ coord_t BitmapBuffer::drawSizedText(coord_t x, coord_t y, const char *s, uint8_t len, LcdFlags flags) { if (!s) return x; + MOVE_OFFSET(); // LVGL does not handle non-null terminated strings static char buffer[256]; @@ -509,9 +522,11 @@ coord_t BitmapBuffer::drawSizedText(coord_t x, coord_t y, const char *s, } #endif + RESTORE_OFFSET(); + pos += p.x; - return ((flags & RIGHT) ? orig_pos : pos); + return ((flags & RIGHT) ? orig_pos : pos) - offsetX; } // Resize and convert to LVGL image data format with alpha blending to diff --git a/radio/src/gui/colorlcd/libui/bitmapbuffer.h b/radio/src/gui/colorlcd/libui/bitmapbuffer.h index 4fb056e91..c1814e0fa 100644 --- a/radio/src/gui/colorlcd/libui/bitmapbuffer.h +++ b/radio/src/gui/colorlcd/libui/bitmapbuffer.h @@ -27,6 +27,20 @@ constexpr uint8_t SOLID = 0xFF; constexpr uint8_t DOTTED = 0x55; constexpr uint8_t STASHED = 0x33; +#define MOVE_OFFSET() \ + coord_t offsetX = this->offsetX; \ + x += offsetX; \ + this->offsetX = 0; \ + coord_t offsetY = this->offsetY; \ + y += offsetY; \ + this->offsetY = 0 + +#define APPLY_OFFSET() \ + x += this->offsetX; \ + y += this->offsetY + +#define RESTORE_OFFSET() this->offsetX = offsetX, this->offsetY = offsetY + #define MOVE_PIXEL_RIGHT(p, count) p += count #define MOVE_TO_NEXT_RIGHT_PIXEL(p) MOVE_PIXEL_RIGHT(p, 1) @@ -61,6 +75,8 @@ class BitmapBuffer inline void drawPixel(coord_t x, coord_t y, pixel_t value) { + APPLY_OFFSET(); + coord_t w = 1, h = 1; if (!applyClippingRect(x, y, w, h)) return; @@ -72,6 +88,8 @@ class BitmapBuffer inline void drawAlphaPixel(coord_t x, coord_t y, uint8_t opacity, pixel_t value) { + APPLY_OFFSET(); + coord_t w = 1, h = 1; if (!applyClippingRect(x, y, w, h)) return; @@ -122,11 +140,20 @@ class BitmapBuffer void clearClippingRect(); + void setOffset(coord_t offsetX, coord_t offsetY); + + inline void clearOffset() { setOffset(0, 0); } + inline void reset() { + clearOffset(); clearClippingRect(); } + coord_t getOffsetX() const { return offsetX; } + + coord_t getOffsetY() const { return offsetY; } + inline uint16_t width() const { return _width; } inline uint16_t height() const { return _height; } @@ -222,6 +249,8 @@ class BitmapBuffer coord_t xmax; coord_t ymin = 0; coord_t ymax; + coord_t offsetX = 0; + coord_t offsetY = 0; pixel_t* data; pixel_t* data_end; diff --git a/radio/src/gui/colorlcd/libui/bitmapbuffer_draw_extra.cpp b/radio/src/gui/colorlcd/libui/bitmapbuffer_draw_extra.cpp index 8dc20cbd7..262c20958 100644 --- a/radio/src/gui/colorlcd/libui/bitmapbuffer_draw_extra.cpp +++ b/radio/src/gui/colorlcd/libui/bitmapbuffer_draw_extra.cpp @@ -32,6 +32,8 @@ void BitmapBuffer::invertRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags flags) { + APPLY_OFFSET(); + if (!applyClippingRect(x, y, w, h)) return; // No 'opacity' here, only 'color' @@ -331,6 +333,12 @@ bool BitmapBuffer::liangBarskyClipper(coord_t &x1, coord_t &y1, coord_t &x2, void BitmapBuffer::drawLine(coord_t x1, coord_t y1, coord_t x2, coord_t y2, uint8_t pat, LcdFlags flags) { + // Offsets + x1 += offsetX; + y1 += offsetY; + x2 += offsetX; + y2 += offsetY; + if (!liangBarskyClipper(x1, y1, x2, y2)) return; // TODO; Replace with LVGL line draw - currently does not support dotted line drawing @@ -485,6 +493,8 @@ void BitmapBuffer::drawFilledTriangle(coord_t x0, coord_t y0, coord_t x1, void BitmapBuffer::drawFilledCircle(coord_t x, coord_t y, coord_t radius, LcdFlags flags) { + APPLY_OFFSET(); + lv_draw_rect_dsc_t rect_dsc; lv_draw_rect_dsc_init(&rect_dsc); rect_dsc.bg_opa = LV_OPA_COVER; @@ -517,6 +527,8 @@ void BitmapBuffer::drawFilledCircle(coord_t x, coord_t y, coord_t radius, void BitmapBuffer::drawCircle(coord_t x, coord_t y, coord_t radius, LcdFlags flags, coord_t thickness) { + APPLY_OFFSET(); + lv_draw_rect_dsc_t rect_dsc; lv_draw_rect_dsc_init(&rect_dsc); rect_dsc.bg_opa = LV_OPA_TRANSP; @@ -678,6 +690,8 @@ void BitmapBuffer::drawAnnulusSector(coord_t x, coord_t y, coord_t externalRadius, int startAngle, int endAngle, LcdFlags flags) { + APPLY_OFFSET(); + if (endAngle == startAngle) endAngle += 1; @@ -746,6 +760,8 @@ void BitmapBuffer::drawBitmapPattern(coord_t x, coord_t y, const MaskBitmap *bmp LcdFlags flags, coord_t offset, coord_t width) { + APPLY_OFFSET(); + coord_t bmpw = bmp->width; coord_t bmph = bmp->height; diff --git a/radio/src/lua/lua_widget.cpp b/radio/src/lua/lua_widget.cpp index 0ca43c7b0..3575e080e 100644 --- a/radio/src/lua/lua_widget.cpp +++ b/radio/src/lua/lua_widget.cpp @@ -210,6 +210,10 @@ void LuaWidget::redraw_cb(lv_event_t* e) buf.setDrawCtx(draw_ctx); + buf.setOffset(draw_ctx->clip_area->x1 - draw_ctx->buf_area->x1, draw_ctx->clip_area->y1 - draw_ctx->buf_area->y1); + buf.setClippingRect(draw_ctx->clip_area->x1 - draw_ctx->buf_area->x1, draw_ctx->clip_area->x2 - draw_ctx->buf_area->x1 + 1, + draw_ctx->clip_area->y1 - draw_ctx->buf_area->y1, draw_ctx->clip_area->y2 - draw_ctx->buf_area->y1 + 1); + widget->refresh(&buf); } }