diff --git a/deps/lvgl b/deps/lvgl index fae5f28..e0221e6 160000 --- a/deps/lvgl +++ b/deps/lvgl @@ -1 +1 @@ -Subproject commit fae5f28a441ec3544703b43aca5e0abd2aa96709 +Subproject commit e0221e686501adbccc525dc987f48dd4218a6b00 diff --git a/examples/examples.lua b/examples/examples.lua index dddd057..0103853 100644 --- a/examples/examples.lua +++ b/examples/examples.lua @@ -41,6 +41,7 @@ end createBtn(container, "keyboard") createBtn(container, "animation") +createBtn(container, "luaC") createBtn(container, "declarative") createBtn(container, "pointer") createBtn(container, "analogTime") diff --git a/examples/luaC.lua b/examples/luaC.lua new file mode 100644 index 0000000..18627bf --- /dev/null +++ b/examples/luaC.lua @@ -0,0 +1,4 @@ +-- Everything is already setup in C code, check mixed.c +-- This file is just to trigger the demo + +embed_lua_in_c() diff --git a/examples/objid.lua b/examples/objid.lua new file mode 100644 index 0000000..17d0a9d --- /dev/null +++ b/examples/objid.lua @@ -0,0 +1,46 @@ +local lvgl = require("lvgl") + +local container = lvgl.Label { + w = lvgl.HOR_RES(), + h = lvgl.VER_RES(), + bg_color = "#888", + bg_opa = lvgl.OPA(100), + border_width = 0, + radius = 0, + flex = { + flex_direction = "row", + flex_wrap = "wrap" + } +} + +local obj1 = container:Object() +obj1.id = "Obj1" + +local obj2 = obj1:Object() +obj2.id = "child" + +local obj3 = container:Object() +obj3.id = "Obj3" + +local obj4 = obj3:Object() +obj4.id = "child" + +local failed = false +local obj = lvgl.get_child_by_id("Obj1") -- obj1 +failed = failed or obj ~= obj1 +print("obj id", obj.id) + +local obj = obj1:get_child_by_id("child") -- obj1 +print("obj id", obj.id, obj == obj2) +failed = failed or obj ~= obj2 + + +local obj = obj3:get_child_by_id("child") -- obj1 +print("obj id", obj.id, obj == obj4) +failed = failed or obj ~= obj4 + +lvgl.Label{ + text_color = "#333", + align = lvgl.ALIGN.CENTER, + text = "Test " .. (failed and "Failed" or "Success") +} \ No newline at end of file diff --git a/examples/tests.lua b/examples/tests.lua index 5047439..9413447 100644 --- a/examples/tests.lua +++ b/examples/tests.lua @@ -35,6 +35,7 @@ local function createBtn(parent, name) end createBtn(container, "gesture") +createBtn(container, "objid") createBtn(container, "font") createBtn(container, "uservalue") createBtn(container, "roller") diff --git a/simulator/CMakeLists.txt b/simulator/CMakeLists.txt index f7c28d2..852f99d 100644 --- a/simulator/CMakeLists.txt +++ b/simulator/CMakeLists.txt @@ -5,7 +5,7 @@ project(simulator) add_custom_target(run COMMAND simulator USES_TERMINAL) file(GLOB_RECURSE WIDGETS ${CMAKE_CURRENT_SOURCE_DIR}/widgets/*.c) -add_executable(simulator main.c mouse_cursor_icon.c ${WIDGETS}) +add_executable(simulator main.c lua_in_C.c mouse_cursor_icon.c ${WIDGETS}) target_include_directories(simulator PRIVATE widgets) # add_subdirectory(widgets) diff --git a/simulator/lua_in_C.c b/simulator/lua_in_C.c new file mode 100644 index 0000000..1918234 --- /dev/null +++ b/simulator/lua_in_C.c @@ -0,0 +1,62 @@ +#include "lua.h" +#include +#include +#include +#include +#include +#include + +#define _STRINGIZE(...) #__VA_ARGS__ +#define STRINGIZE(...) _STRINGIZE(__VA_ARGS__) + +static const char lua_code_string[] = STRINGIZE( + local root = lvgl.get_child_by_id("luaUIroot") + root.w = lvgl.VER_RES(), + root.h = lvgl.HOR_RES(), + + btn = Button(root, { + id = "Button in Lua", + Label { + text = "Hello, lua, C and lvgl!", + align = lvgl.ALIGN_CENTER + } + }):center() +); + +static void button_clicked(lv_event_t *e) +{ + (void)e; + lua_State *L = lv_event_get_user_data(e); + LV_LOG_USER("Button clicked"); + luaL_dostring(L, "\ + local btn = lvgl.get_child_by_id('Button in Lua')\n\ + local label = btn:get_child(0)\n\ + label.text = 'Button clicked'\n\ + "); +} + +static int embed_lua_in_c(lua_State *L) +{ + /* We create a root obj in C and create other UIs in lua. */ + lv_obj_t *root = lv_obj_create(lv_screen_active()); + luavgl_add_lobj(L, root)->lua_created = false; + lv_obj_set_id(root, lv_strdup("luaUIroot")); + int ret = luaL_dostring(L, lua_code_string); + if (ret != 0) { + LV_LOG_USER("luaL_dostring error: %d", ret); + return -1; + } + + lv_obj_t *btn = lv_obj_get_child_by_id(root, "Button in Lua"); + if (btn) { + lv_obj_add_event_cb(btn, button_clicked, LV_EVENT_CLICKED, L); + } + + return 0; +} + +void lua_c_lvgl_mix_example(lua_State *L) +{ + lua_pushcfunction(L, embed_lua_in_c); + lua_setglobal(L, "embed_lua_in_c"); +} diff --git a/simulator/lv_conf.h b/simulator/lv_conf.h index 5d99678..775e233 100644 --- a/simulator/lv_conf.h +++ b/simulator/lv_conf.h @@ -303,7 +303,7 @@ #define LV_USE_OBJ_ID 1 /* Use lvgl builtin method for obj ID */ -#define LV_USE_OBJ_ID_BUILTIN 1 +#define LV_USE_OBJ_ID_BUILTIN 0 /*Use obj property set/get API*/ #define LV_USE_OBJ_PROPERTY 1 diff --git a/simulator/main.c b/simulator/main.c index 083d01c..c04cc8a 100644 --- a/simulator/main.c +++ b/simulator/main.c @@ -319,6 +319,10 @@ int main(int argc, char **argv) lv_label_set_text(label, "RELOAD"); lv_obj_center(label); + void lua_c_lvgl_mix_example(lua_State *L); + lua_c_lvgl_mix_example(lua_ctx->L); + + while (1) { /* Periodically call the lv_task handler. * It could be done in a timer interrupt or an OS task too.*/ diff --git a/src/obj.c b/src/obj.c index f184cb6..ca23b5e 100644 --- a/src/obj.c +++ b/src/obj.c @@ -608,6 +608,33 @@ static int luavgl_obj_get_pos(lua_State *L) return 1; } +static int luavgl_obj_get_child_by_id(lua_State *L) +{ + lv_obj_t *obj; + const char *id; + if (lua_type(L, 1) == LUA_TSTRING) { + obj = NULL; + id = lua_tostring(L, 1); + } else { + obj = luavgl_to_obj(L, 1); + id = luaL_checkstring(L, 2); + } + + lv_obj_t *child = lv_obj_get_child_by_id(obj, id); + if (child == NULL) { + lua_pushnil(L); + return 1; + } + + lua_pushlightuserdata(L, child); + lua_rawget(L, LUA_REGISTRYINDEX); + if (lua_isnil(L, -1)) { + luavgl_add_lobj(L, child)->lua_created = false; + } + + return 1; +} + /** * Remove all animations associates to this object */ @@ -719,6 +746,52 @@ LUALIB_API int luavgl_obj_get_property(lua_State *L) return obj_property(L, obj); } +#if LV_USE_OBJ_ID_BUILTIN == 0 +/* For luavgl, we only support string as ID. */ +void lv_obj_assign_id(const lv_obj_class_t *class_p, lv_obj_t *obj) {} + +void lv_obj_free_id(lv_obj_t *obj) +{ + if (obj->id) { + lv_free(obj->id); + obj->id = NULL; + } +} + +const char *lv_obj_stringify_id(lv_obj_t *obj, char *buf, uint32_t len) +{ + if (obj->id == NULL) + return NULL; + lv_strlcpy(buf, (const char *)obj->id, len); + return buf; +} + +int lv_obj_id_compare(const void *id1, const void *id2) +{ + if (id1 == NULL || id2 == NULL) + return -1; + return lv_strcmp(id1, id2); +} + +#endif + +static int obj_property_id(lua_State *L, lv_obj_t *obj, bool set) +{ + if (set) { + if (!lua_isstring(L, -1)) { + return luaL_error(L, "id should be string"); + } + + lv_obj_set_id(obj, lv_strdup(lua_tostring(L, -1))); + return 0; + } else { + /* get property */ + void *id = lv_obj_get_id(obj); + id == NULL ? lua_pushnil(L) : lua_pushstring(L, id); + return 1; + } +} + static int obj_property_align(lua_State *L, lv_obj_t *obj, bool set) { if (set) { @@ -790,6 +863,7 @@ static int obj_property_user_data(lua_State *L, lv_obj_t *obj, bool set) static const luavgl_property_ops_t obj_property_ops[] = { {.name = "align", .ops = obj_property_align }, + {.name = "id", .ops = obj_property_id }, {.name = "h", .ops = obj_property_h }, {.name = "w", .ops = obj_property_w }, {.name = "user_data", .ops = obj_property_user_data}, @@ -844,6 +918,7 @@ static const rotable_Reg luavgl_obj_methods[] = { {"indev_search", LUA_TFUNCTION, {luavgl_obj_indev_search} }, {"get_coords", LUA_TFUNCTION, {luavgl_obj_get_coords} }, {"get_pos", LUA_TFUNCTION, {luavgl_obj_get_pos} }, + {"get_child_by_id", LUA_TFUNCTION, {luavgl_obj_get_child_by_id} }, {"onevent", LUA_TFUNCTION, {luavgl_obj_on_event} }, {"onPressed", LUA_TFUNCTION, {luavgl_obj_on_pressed} }, @@ -958,6 +1033,10 @@ static void luavgl_obj_init(lua_State *L) /* 3. Base lv_obj metatable */ luavgl_obj_newmetatable(L, &lv_obj_class, "lv_obj", luavgl_obj_methods); lua_pop(L, 1); /* remove obj metatable */ + + /* Register to global function */ + lua_pushcfunction(L, luavgl_obj_get_child_by_id); + lua_setfield(L, -2, "get_child_by_id"); } /**