From 58b420c21afe6b041eae034b99d093d0c48bc0c7 Mon Sep 17 00:00:00 2001 From: Neo Xu Date: Mon, 14 Oct 2024 19:22:15 +0800 Subject: [PATCH] feat: add basic canvas widget support Signed-off-by: Neo Xu --- examples/canvas.lua | 38 +++++++ examples/examples.lua | 1 + src/private.h | 3 +- src/style.c | 2 +- src/widgets/canvas.c | 242 ++++++++++++++++++++++++++++++++++++++++++ src/widgets/img.c | 2 +- src/widgets/widgets.c | 11 ++ 7 files changed, 295 insertions(+), 4 deletions(-) create mode 100644 examples/canvas.lua create mode 100644 src/widgets/canvas.c diff --git a/examples/canvas.lua b/examples/canvas.lua new file mode 100644 index 0000000..c9e6c45 --- /dev/null +++ b/examples/canvas.lua @@ -0,0 +1,38 @@ +local root = lvgl.Object(nil, { + w = 120, + h = 120, + border_width = 1, + border_color = "#000", + radius = 10, + align = lvgl.ALIGN.CENTER, +}) + +local canvas = lvgl.Canvas(root, { + border_width = 1, + border_color = "#F00", + align = lvgl.ALIGN.CENTER, +}) + +canvas:set { + buffer = { + w = 100, + h = 100, + cf = 5, + }, +} + +canvas:set { + img_recolor = 0xff0000ff, +} + +canvas:fill_bg("#000", lvgl.OPA(100)) + +canvas:blur_ver( + { + x1 = 10, + y1 = 10, + x2 = 90, + y2 = 90, + }, + 80 +) diff --git a/examples/examples.lua b/examples/examples.lua index 64e0b63..19a221c 100644 --- a/examples/examples.lua +++ b/examples/examples.lua @@ -38,6 +38,7 @@ end createBtn(container, "keyboard") createBtn(container, "animation") +createBtn(container, "canvas") createBtn(container, "pointer") createBtn(container, "analogTime") createBtn(container, "flappyBird/flappyBird") diff --git a/src/private.h b/src/private.h index 20aa802..bb1cf4f 100644 --- a/src/private.h +++ b/src/private.h @@ -9,8 +9,7 @@ #include /* clang-format off */ -#define debug(format, ...) -// fprintf(stderr, "[luavgl] %s: " format, __FUNCTION__, ##__VA_ARGS__) +#define debug(format, ...) fprintf(stderr, "[luavgl] %s: " format, __FUNCTION__, ##__VA_ARGS__) // syslog(LOG_DEBUG, "[luavgl] %s: " format, __FUNCTION__, ##__VA_ARGS__) /* clang-format on */ diff --git a/src/style.c b/src/style.c index 2f3bd5c..9c53625 100644 --- a/src/style.c +++ b/src/style.c @@ -574,8 +574,8 @@ static int luavgl_style_gc(lua_State *L) { luavgl_style_t *s = luavgl_check_style(L, 1); lv_style_reset(&s->style); - free(s); debug("gc style:%p\n", s); + free(s); return 0; } diff --git a/src/widgets/canvas.c b/src/widgets/canvas.c new file mode 100644 index 0000000..3fd7bb8 --- /dev/null +++ b/src/widgets/canvas.c @@ -0,0 +1,242 @@ +#include "luavgl.h" +#include "private.h" + +static int luavgl_canvas_create(lua_State *L) +{ + return luavgl_obj_create_helper(L, lv_canvas_create); +} + +static void _lv_canvas_set_buffer(void *obj, lua_State *L) +{ + luaL_argcheck(L, lua_istable(L, -1), -1, "expect a table."); + + lua_getfield(L, -1, "w"); + int w = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "h"); + int h = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "cf"); + lv_img_cf_t cf = lua_tointeger(L, -1); + lua_pop(L, 1); + + lv_img_dsc_t *dsc = (lv_img_dsc_t *)lv_img_get_src(obj); + if (dsc->data != NULL) { + luaL_error(L, "canvas buffer already set."); + } + + void *buf = lv_mem_alloc(lv_img_buf_get_img_size(w, h, cf)); + if (buf == NULL) { + luaL_error(L, "No memory."); + } + + lv_canvas_set_buffer(obj, buf, w, h, cf); +} + +static void _lv_canvas_set_px(void *obj, lua_State *L) +{ + luaL_argcheck(L, lua_istable(L, -1), -1, "expect a table."); + + lua_getfield(L, -1, "x"); + int x = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "y"); + int y = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "color"); + lv_color_t color = luavgl_tocolor(L, -1); + lua_pop(L, 1); + + lv_canvas_set_px(obj, x, y, color); +} + +static void _lv_canvas_set_px_opa(void *obj, lua_State *L) +{ + luaL_argcheck(L, lua_istable(L, -1), -1, "expect a table."); + + lua_getfield(L, -1, "x"); + int x = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "y"); + int y = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "opa"); + lv_opa_t opa = lua_tointeger(L, -1); + lua_pop(L, 1); + + lv_canvas_set_px_opa(obj, x, y, opa); +} + +static void _lv_canvas_set_palette(void *obj, lua_State *L) +{ + luaL_argcheck(L, lua_istable(L, 2), 2, "expect a table."); + + lua_getfield(L, 2, "id"); + int id = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, 2, "color"); + lv_color_t color = luavgl_tocolor(L, -1); + lua_pop(L, 1); + + lv_canvas_set_palette(obj, id, color); +} + +static const luavgl_value_setter_t canvas_property_table[] = { + {"buffer", SETTER_TYPE_STACK, {.setter_stack = _lv_canvas_set_buffer} }, + {"px", SETTER_TYPE_STACK, {.setter_stack = _lv_canvas_set_px} }, + {"px_opa", SETTER_TYPE_STACK, {.setter_stack = _lv_canvas_set_px_opa} }, + {"palette", SETTER_TYPE_STACK, {.setter_stack = _lv_canvas_set_palette}}, +}; + +LUALIB_API int luavgl_canvas_set_property_kv(lua_State *L, void *data) +{ + lv_obj_t *obj = data; + int ret = luavgl_set_property(L, obj, canvas_property_table); + + if (ret == 0) { + return 0; + } + + /* a base obj property? */ + ret = luavgl_img_set_property_kv(L, obj); + if (ret != 0) { + debug("unkown property for canvas.\n"); + } + + return ret; +} + +static int luavgl_canvas_set(lua_State *L) +{ + lv_obj_t *obj = luavgl_to_obj(L, 1); + + if (!lua_istable(L, -1)) { + luaL_error(L, "expect a table on 2nd para."); + return 0; + } + + luavgl_iterate(L, -1, luavgl_canvas_set_property_kv, obj); + + return 0; +} + +static int luavgl_canvas_get_px(lua_State *L) +{ + lv_obj_t *obj = luavgl_to_obj(L, 1); + int x = luaL_checkinteger(L, 2); + int y = luaL_checkinteger(L, 3); + + lv_color_t c = lv_canvas_get_px(obj, x, y); + lua_newtable(L); + lua_pushinteger(L, c.ch.red); + lua_setfield(L, -2, "r"); + lua_pushinteger(L, c.ch.green); + lua_setfield(L, -2, "g"); + lua_pushinteger(L, c.ch.blue); + lua_setfield(L, -2, "b"); + + return 1; +} + +static int luavgl_canvas_get_img(lua_State *L) +{ + lv_obj_t *obj = luavgl_to_obj(L, 1); + lv_img_dsc_t *img = lv_canvas_get_img(obj); + if (img == NULL) { + lua_pushnil(L); + return 1; + } + + lua_pushlightuserdata(L, img); + return 1; +} + +static int luavgl_canvas_blur_hor(lua_State *L) +{ + lv_obj_t *obj = luavgl_to_obj(L, 1); + lv_area_t area; + + if (!lua_istable(L, 2)) { + luaL_error(L, "expect a table on 2nd para."); + return 0; + } + + lua_getfield(L, 2, "x1"); + area.x1 = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, 2, "y1"); + area.y1 = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, 2, "x2"); + area.x2 = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, 2, "y2"); + area.y2 = lua_tointeger(L, -1); + lua_pop(L, 1); + + uint16_t r = luaL_checkinteger(L, 3); + lv_canvas_blur_hor(obj, &area, r); + return 0; +} + +static int luavgl_canvas_blur_ver(lua_State *L) +{ + lv_obj_t *obj = luavgl_to_obj(L, 1); + lv_area_t area; + + if (!lua_istable(L, 2)) { + luaL_error(L, "expect a table on 2nd para."); + return 0; + } + + lua_getfield(L, 2, "x1"); + area.x1 = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, 2, "y1"); + area.y1 = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, 2, "x2"); + area.x2 = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, 2, "y2"); + area.y2 = lua_tointeger(L, -1); + lua_pop(L, 1); + + uint16_t r = luaL_checkinteger(L, 3); + lv_canvas_blur_ver(obj, &area, r); + return 0; +} + +static int luavgl_canvas_fill_bg(lua_State *L) +{ + lv_obj_t *obj = luavgl_to_obj(L, 1); + lv_color_t color = luavgl_tocolor(L, 2); + lv_opa_t opa = luaL_checkinteger(L, 3); + lv_canvas_fill_bg(obj, color, opa); + return 0; +} + +static const luaL_Reg luavgl_canvas_methods[] = { + {"set", luavgl_canvas_set }, + {"get_px", luavgl_canvas_get_px }, + {"get_img", luavgl_canvas_get_img }, + {"blur_hor", luavgl_canvas_blur_hor}, + {"blur_ver", luavgl_canvas_blur_ver}, + {"fill_bg", luavgl_canvas_fill_bg }, + + {NULL, NULL }, +}; + +static void luavgl_canvas_init(lua_State *L) +{ + luavgl_obj_newmetatable(L, &lv_canvas_class, "lv_canvas", + luavgl_canvas_methods); + lua_pop(L, 1); +} diff --git a/src/widgets/img.c b/src/widgets/img.c index 9332cd9..aba6c00 100644 --- a/src/widgets/img.c +++ b/src/widgets/img.c @@ -48,7 +48,7 @@ LUALIB_API int luavgl_img_set_property_kv(lua_State *L, void *data) /* a base obj property? */ ret = luavgl_obj_set_property_kv(L, obj); if (ret != 0) { - debug("unkown property for image.\n"); + debug("unkown property for image: %s\n", lua_tostring(L, -2)); } return ret; diff --git a/src/widgets/widgets.c b/src/widgets/widgets.c index d26cdf9..658aad5 100644 --- a/src/widgets/widgets.c +++ b/src/widgets/widgets.c @@ -5,6 +5,10 @@ #include "calendar.c" #endif +#if LV_USE_CANVAS +#include "canvas.c" +#endif + #if LV_USE_CHECKBOX #include "checkbox.c" #endif @@ -50,6 +54,10 @@ static const luaL_Reg widget_create_methods[] = { {"Calendar", luavgl_calendar_create}, #endif +#if LV_USE_CANVAS + {"Canvas", luavgl_canvas_create}, +#endif + #if LV_USE_CHECKBOX {"Checkbox", luavgl_checkbox_create}, #endif @@ -130,4 +138,7 @@ static void luavgl_widgets_init(lua_State *L) luavgl_dropdown_init(L); #endif +#if LV_USE_CALENDAR + luavgl_canvas_init(L); +#endif }