Giter Site home page Giter Site logo

luavgl's Introduction

lvgl-lua-binding

lua + lvgl = luavgl

luavgl is currently under development.

A flappy bird game is ready for showoff.

The simulator is built with cmake and has been tested on ubuntu and mac, but not on windows. If you need to build under windows please xmake, which has also been tested under ubuntu.

Introduction

luavgl is a wrapper around lvgl core functions and widgets with class inherence in mind, which is lvgl trying to do in C. Lua makes widgets inherence happens smoothly.

luavgl does not support APIs for low level hardware initialization, lvgl setup etc. Those initialization must be done before executing lua scripts.

luavgl mainly targets for embedded device, a simulator has been provided for preview and tested on Ubuntu/macOS.

local root = lvgl.Object()
root:set { w = lvgl.HOR_RES(), h = lvgl.VER_RES() }

-- flex layout and align
root:set {
    flex = {
        flex_direction = "row",
        flex_wrap = "wrap",
        justify_content = "center",
        align_items = "center",
        align_content = "center",
    },
    w = 300,
    h = 75,
    align = lvgl.ALIGN.CENTER
}

-- create obj on root
local obj = root:Object()

-- create image on root and set position/img src/etc. properties.
local img = root:Image {
    src = "res/image.png",
    x = 0,
    y = 0,
    bg_color = "#112233" -- #RRGGBB, 0xRRGGBB or "#RGB"
    pad_all = 0
}

-- change image properties.

img:set {
    src = "/assets/lvgl-logo.png",
    align = lvgl.ALIGN.CENTER,
}

-- create animation on object
img:Anim {
    run = true,
    start_value = 0,
    end_value = 3600,
    duration = 2000,
    repeat_count = 2,
    path = "bounce",
    exec_cb = function(obj, value)
        obj:set {
            angle = value
        }
    end
}

-- create Label on root and set its font
local label = root:Label {
    text = string.format("Hello %03d", 123),
    text_font = lvgl.Font("montserrat", 24, "normal"),
    -- or builtin font:
    -- text_font = lvgl.BUILTIN_FONT.MONTSERRAT_22,
    align = {
        type = lvgl.ALIGN.CENTER,
        x_ofs = 0,
        y_ofs = 100,
    }
}

Embedded device

For embedded device, lvgl environment must setup before using luavgl. Once lvgl and lua interpreter are up and running, add the luavgl.c to sources for compiling. And make sure luaopen_lvgl is added to global lib. Below is example from simulator/main.c shows this exact method.

  /* add `lvgl` module to global package table */
  luaL_requiref(L, "lvgl", luaopen_luavgl, 1);
  lua_pop(L, 1);

LuaJIT support

Supporting LuaJIT is done by adding deps/lua-compat-5.3.

Developing

I personally using vscode plus extension Lua.

File src/lvgl.lua is used for linting.

Run on RTOS nuttx

Check the ready-to-go examples luavgl-nuttx-example

PC simulator

Currently compile luavgl to so or dll is NOT available.

luavgl depends on lvgl and various configurations(lv_conf.h), thus cannot run without a working lvgl environment. The simulator provided in this repo can be used as example if luavgl is required on PC.

Make sure clone the submodules, luavgl simulator comes directly from lvgl simulator with lua added.

git clone --recursive https://github.com/XuNeo/luavgl.git

# or
git submodule update --init

Dependencies

cmake

To run simulator on PC, make sure lua header is available, you may need to install below packages.

sudo apt install libsdl2-dev lua5.3 liblua5.3-dev

Both lua5.3 and lua5.4 are supported. Versions below 5.2 has not been verified but should work through deps/lua-compat-5.3.

xmake

Compiling with xmake does not require you to install libsdl2 and lua yourself. xmake calls the package manager xrepo, which downloads libsdl2 and lua from github and applies them to the simulator's project.

Build and run

cmake
cmake -Bbuild -DBUILD_SIMULATOR=ON
cd build
make
make run # run simulator
xmake
xmake b simulator
xmake r # run simulator

Custom Widget

luavgl support custom widget, and use them in lua just like lvgl core widgets. An example is provided in simulator/extension.c

For custom widget, it should be registered to Lua after luavgl lib loaded.

luavgl's People

Contributors

underus avatar xuneo avatar xuneo1990 avatar yinntian avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

luavgl's Issues

event: simplify event processing via lv_array module

Introduce the problem

LVGL currently doesn't support return an event handler so it can be removed later.
The only solution is comparing all event dsc user_data.

The issue can be solved by simply storing the event dsc pointer to lvgl internal array and return it to user.

For lua, it needs to remember which events are added from lua side, so when obj is cleaned up, those events can be removed separately with native added events.

Proposal

Use dsc pointer in lvgl internal array, and use lv_array to store events added from lua.

Make full use LVGL's property API

Introduce the problem

Use LVGL's property API instead of manually calling every widget's property API like lv_image_set_rotation could simplify the porting layer between LVGL and LUA.

Also need to finish missing property ID definitions in LVGL.

Proposal

No response

add more documents

Hello Xu,

Thanks for your great work.

Can you add more information about how to prepare the lvgl environment ?

I remember that the luavgl library should be a dynamic library (.so file). so lua can find it when local lvgl = require("lvgl").
It it right ?

lv_disp expected, got no value

Introduce the problem

I am using the lvgl-v8 branch on an ESP32 which doesn't have v9 available yet.
Most things are working, adding this failed: local scr = lvgl.disp.get_scr_act()

I traced down to this:
luavgl_disp_t *v = luaL_checkudata(L, idx, "lv_disp");
p is null, so it calls typeerror()

luavgl_disp_init() is getting called and it makes the metatable.

/init.lua:1: bad argument #1 to 'get_scr_act' (lv_disp expected, got no value)
stack traceback:
	[C]: in field 'get_scr_act'
	/init.lua:1: in main chunk
	[C]: in ?

Proposal

No response

LVGL conditional compliation

Introduce the problem

FYI issue for the future. I had a lot of widgets selectively turned off in LVGL to save RAM on my device. I had to turn a bunch of them back on since Luavgl didn't compile with them turned off. For example I don't need a keyboard and textarea but I had to turn them back on because Luavgl didn't support having them off. This is no big deal, when I get back to minimizing RAM I can #ifdef luavgl as needed for my use case.

things like this....
CONFIG_LV_USE_ROLLER=y
CONFIG_LV_USE_KEYBOARD=y
CONFIG_LV_USE_TEXTAREA=y

BTW, I am using Luavgl with NodeMCU on an ESP32S3 with an RGB LCD.

Proposal

No response

Adding properties to LVGL objects

Introduce the problem

How do I add my own properties to the LVGL objects? I want to do something like this, but this doesn't work quite right.

local function createBtn(parent, x, y, w, h, name, index)
    local root = parent:Object {
        x = x,
        y = y,
        w = w,
        h = h,
    }

    getmetatable(root).__index = {
         index = index
    }

    root:add_style(style_default, lvgl.STATE.DEFAULT)
    root:add_style(style_pressed, lvgl.STATE.PRESSED)

    root:onevent(lvgl.EVENT.CLICKED, function (obj, code)
        print(obj.index_, " clicked")
    end)

Proposal

No response

Events on top level screen

Introduce the problem

How can I attach an event handler to the top level screen? I would like to capture gestures.

void scr_event_cb(lv_obj_t * obj, lv_event_t e)
{
    if(e == LV_EVENT_GESTURE) {
        lv_gesture_dir_t dir = lv_indev_get_gesture_dir(lv_indev_get_act());
        printf("Dir: %d\n", dir);
    }
}

lv_obj_set_event_cb(lv_scr_act(), scr_event_cb);

Proposal

No response

Hosting under LVGL

Introduce the problem

I think Lua is very good language for embedded systems, however LVGL doesn't have an officially supported Lua binding yet.

Your solution seems quite complete and actively maintained.

Proposal

I would be happy to promote your Lua binding (similar to MicroPython), so I wonder if you would be interested migrating this repository under the LVGL organization. Of course you (and anyone you name) would receive maintainer/write permission.

lv_font_load() from file system

Introduce the problem

Could I please get support for lv_font_load()?
LVGL should be able to load fonts from SPIFFS, right?

Custom fonts added at build time are working fine, I already added one to my app.

Proposal

No response

Crash in lv_mem.c

I'm trying to get this to build and run on Win-10 using MSVC /clang-cl. But have nothing but troubles.
But first off, the example on the main page does not even parse with my Lua 5.4: lua.exe test.lua:

lua.exe: test.lua:13: '}' expected (to close '{' at line 8) near 'pad_all'

It should read:

    bg_color = "#112233", -- #RRGGBB, 0xRRGGBB or "#RGB"
    pad_all = 0
}

and not bg_color = "#112233", -- #RRGGBB, 0xRRGGBB or "#RGB",

But then after adding a require "lvgl" at the top, a lua.exe test.lua crashes good inside lv_mem.c. Call-stack:

lvgl!search_suitable_block(struct control_t * control = 0x00000000`00000000, int * fli = 0x000000cc`dedeea20, int * sli = 0x000000cc`dedeea24)+0x40
lvgl!block_locate_free(struct control_t * control = 0x00000000`00000000, unsigned int64 size = 0x38)+0x5e
lvgl!lv_tlsf_malloc(void * tlsf = 0x00000000`00000000, unsigned int64 size = 0x38)+0x3b
lvgl!lv_mem_alloc(unsigned int64 size = 0x38)+0x55
lvgl!lv_obj_class_create_obj(struct _lv_obj_class_t * class_p = 0x00007ffa`d8145098, struct _lv_obj_t * parent = 0x00000000`00000000)+0x2d
lvgl!lv_obj_create(struct _lv_obj_t * parent = 0x00000000`00000000)+0x44
lvgl!luaopen_lvgl(struct lua_State * L = 0x000001ef`00157658)+0x131
lua54_x64!luaD_precall(struct lua_State * L = 0x000001ef`00157658, union StackValue * func = 0x000001ef`00157d80, int nresults = 0n1)+0x22c
lua54_x64!ccall(struct lua_State * L = 0x000001ef`00157658, union StackValue * func = 0x000001ef`00157d80, int nResults = 0n1, int inc = 0n65537)+0x4c
lua54_x64!lua_callk(struct lua_State * L = 0x000001ef`00157658, int nargs = <Value unavailable error>, int nresults = 0n1, int64 ctx = <Value unavailable error>, <function> * k = 0x00000000`00000000)+0x5f
lua54_x64!ll_require(struct lua_State * L = 0x000001ef`00157658)+0x1fc
lua54_x64!luaD_precall(struct lua_State * L = 0x000001ef`00157658, union StackValue * func = 0x000001ef`00157d20, int nresults = 0n0)+0x22c
lua54_x64!luaV_execute(struct lua_State * L = 0x000001ef`00157658, struct CallInfo * ci = 0x000001ef`0017c230)+0x29e4
lua54_x64!ccall(struct lua_State * L = 0x000001ef`00157658, union StackValue * func = 0x000001ef`00157d00, int nResults = 0n-1, int inc = 0n65537)+0x65
lua54_x64!luaD_rawrunprotected(struct lua_State * L = 0x000001ef`00157658, <function> * f = 0x00007ffb`1eeb60c0, void * ud = 0x000000cc`dedef5a0)+0x73
lua54_x64!luaD_pcall(struct lua_State * L = 0x000001ef`00157658, <function> * func = <Value unavailable error>, void * u = <Value unavailable error>, int64 old_top = 0n80, int64 ef = 0n64)+0x40
lua54_x64!lua_pcallk(struct lua_State * L = 0x000001ef`00157658, int nargs = <Value unavailable error>, int nresults = 0n-1, int errfunc = <Value unavailable error>, int64 ctx = 0n0, <function> * k = 0x00000000`00000000)+0x10d
lua!docall(struct lua_State * L = 0x000001ef`00157658, int narg = 0n0, int nres = 0n-1)+0x7c
lua!handle_script(void)+0xfe
lua!pmain(struct lua_State * L = 0x000001ef`00157658)+0x589
lua54_x64!luaD_precall(struct lua_State * L = 0x000001ef`00157658, union StackValue * func = 0x000001ef`00157cc0, int nresults = 0n1)+0x22c
lua54_x64!ccall(struct lua_State * L = 0x000001ef`00157658, union StackValue * func = 0x000001ef`00157cc0, int nResults = 0n1, int inc = 0n65537)+0x4c
lua54_x64!luaD_rawrunprotected(struct lua_State * L = 0x000001ef`00157658, <function> * f = 0x00007ffb`1eeb60c0, void * ud = 0x000000cc`dedef8f0)+0x73
lua54_x64!luaD_pcall(struct lua_State * L = 0x000001ef`00157658, <function> * func = <Value unavailable error>, void * u = <Value unavailable error>, int64 old_top = 0n16, int64 ef = 0n0)+0x40
lua54_x64!lua_pcallk(struct lua_State * L = 0x000001ef`00157658, int nargs = <Value unavailable error>, int nresults = 0n1, int errfunc = <Value unavailable error>, int64 ctx = 0n0, <function> * k = 0x00000000`00000000)+0x10d
lua!main(int argc = <Value unavailable error>, char ** argv = 0x000001ef`00178130)+0xec
lua!invoke_main(void)+0x22
lua!__scrt_common_main_seh(void)+0x10c
KERNEL32!BaseThreadInitThunk+0x14
ntdll!RtlUserThreadStart+0x21

presumably since lv_mem_init() was not called for LV_MEM_CUSTOM == 0.

So I really have no idea how to use this library. Seems not very robust.

And BTW, why is not LuaJIT supported? Much faster AFAICS.
And it does not build with LVGL from master. Why not?

Simulator with luajit crash when click animation example

Crash only happen with luajit but not lua.

Another crash may be related with following reproduce steps:

    1. click test, then indev
    1. click button reload
AddressSanitizer:DEADLYSIGNAL
=================================================================
==1680078==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x5644a0de7ee6 bp 0x7ffe84f88d30 sp 0x7ffe84f88d10 T0)
==1680078==The signal is caused by a READ memory access.
==1680078==Hint: address points to the zero page.
    #0 0x5644a0de7ee5 in luavgl_indev_gc ../src/indev.c:278
    #1 0x7fdeb4679fb6  (/lib/x86_64-linux-gnu/libluajit-5.1.so.2+0x8fb6)
    #2 0x7fdeb4686f59  (/lib/x86_64-linux-gnu/libluajit-5.1.so.2+0x15f59)
    #3 0x7fdeb46a7105  (/lib/x86_64-linux-gnu/libluajit-5.1.so.2+0x36105)
    #4 0x7fdeb46a7267  (/lib/x86_64-linux-gnu/libluajit-5.1.so.2+0x36267)
    #5 0x7fdeb467a325  (/lib/x86_64-linux-gnu/libluajit-5.1.so.2+0x9325)
    #6 0x7fdeb46c8bed in lua_close (/lib/x86_64-linux-gnu/libluajit-5.1.so.2+0x57bed)
    #7 0x5644a0dd2dfc in lua_terminate ../simulator/main.c:290
    #8 0x5644a0dd2e3a in reload_cb ../simulator/main.c:302
    #9 0x5644a0df80fa in event_send_core ../deps/lvgl/src/core/lv_event.c:467
    #10 0x5644a0df4f0c in lv_event_send ../deps/lvgl/src/core/lv_event.c:75
    #11 0x5644a0e011c8 in indev_proc_release ../deps/lvgl/src/core/lv_indev.c:980
    #12 0x5644a0dfd32d in indev_pointer_proc ../deps/lvgl/src/core/lv_indev.c:384
    #13 0x5644a0dfadbd in lv_indev_read_timer_cb ../deps/lvgl/src/core/lv_indev.c:101
    #14 0x5644a0ec0e46 in lv_timer_exec ../deps/lvgl/src/misc/lv_timer.c:313
    #15 0x5644a0ec05b4 in lv_timer_handler ../deps/lvgl/src/misc/lv_timer.c:109
    #16 0x5644a0dd2f43 in main ../simulator/main.c:335
    #17 0x7fdeb4443082 in __libc_start_main ../csu/libc-start.c:308
    #18 0x5644a0dcd58d in _start (/home/neo/projects/luavgl/build/simulator/simulator+0x4d58d)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV ../src/indev.c:278 in luavgl_indev_gc
==1680078==ABORTING

Remove event in event callback

Introduce the problem

Continue of #10.

To free resources added to obj from LUA code, we monitor if obj is deleted by event LV_EVENT_DELETE and clean up in the event callback.

luavgl/src/obj.c

Lines 846 to 847 in 964eeba

lv_array_init(&lobj->events, 0, sizeof(struct event_callback_s *));
lv_obj_add_event_cb(obj, obj_delete_cb, LV_EVENT_DELETE, L);

However, the event callback registered to lvgl is called from below code.

https://github.com/lvgl/lvgl/blob/745ef50e65c2682f87adfa53b42daab9f2dfa685/src/misc/lv_event.c#L63-L86

Note the for loop is actually accessing the event array. So it's crucial not to mess up the array in the event callback we registered.

So below code will report heap-use-after-free, because luavgl_obj_delete will remove events registered from lua, thus modifying event array while iterating it.

luavgl/src/obj.c

Lines 50 to 69 in 964eeba

static void obj_delete_cb(lv_event_t *e)
{
lua_State *L = e->user_data;
lua_pushlightuserdata(L, e->current_target);
lua_rawget(L, LUA_REGISTRYINDEX);
if (lua_isnoneornil(L, -1)) {
goto pop_exit;
}
luavgl_obj_t *lobj = luavgl_to_lobj(L, -1);
if (lobj->lua_created)
goto pop_exit;
luavgl_obj_delete(L);
return;
pop_exit:
lua_pop(L, 1);
return;
}

Proposal

No response

Access to lv palette colors

Introduce the problem

Would need these three API and some constants.

lv_palette_main(LV_PALETTE_...)
lv_palette_lighten(LV_PALETTE_..., v)
lv_palette_darken(LV_PALETTE_..., v)

Proposal

No response

ToDos

  • obj:anim rework to use uservalue table instead of C arrays.
  • obj:anim add done_cb support, so application knows when anim is done.
  • use pcall instead of call in obj event, like luv
  • unified set/get methods
  • auto code generation for widget
  • add documentation for newly added functions

Drawing API?

Introduce the problem

I don't see any way to construct an image, either draw_ctx or canvas. I need to construct RGB and HSL spectrum gradient bitmaps. I can make them in C and pass back to Lua, but do you have plans for a drawing API?

Proposal

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.