Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example of mixed UI programming with Lua and C #65

Merged
merged 3 commits into from
Aug 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deps/lvgl
1 change: 1 addition & 0 deletions examples/examples.lua
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ end

createBtn(container, "keyboard")
createBtn(container, "animation")
createBtn(container, "luaC")
createBtn(container, "declarative")
createBtn(container, "pointer")
createBtn(container, "analogTime")
Expand Down
4 changes: 4 additions & 0 deletions examples/luaC.lua
Original file line number Diff line number Diff line change
@@ -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()
46 changes: 46 additions & 0 deletions examples/objid.lua
Original file line number Diff line number Diff line change
@@ -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")
}
1 change: 1 addition & 0 deletions examples/tests.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion simulator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
62 changes: 62 additions & 0 deletions simulator/lua_in_C.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "lua.h"
#include <luavgl.h>
#include <lvgl.h>
#include <src/core/lv_obj.h>
#include <src/core/lv_obj_event.h>
#include <src/lv_api_map_v8.h>
#include <src/misc/lv_event.h>

#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");
}
2 changes: 1 addition & 1 deletion simulator/lv_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions simulator/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.*/
Expand Down
79 changes: 79 additions & 0 deletions src/obj.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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} },
Expand Down Expand Up @@ -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");
}

/**
Expand Down