Fork of Tangara with customizations
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
tangara-fw/lib/luavgl/simulator/main.c

340 lines
8.8 KiB

#include <stdlib.h>
#include <unistd.h>
#define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" \
issue*/
#include "demos/lv_demos.h"
#include "examples/lv_examples.h"
#include "sdl/sdl.h"
#include <SDL2/SDL.h>
#include <lvgl.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <luavgl.h>
#include "widgets/widgets.h"
typedef struct {
lua_State *L;
lv_obj_t *root;
} lua_context_t;
typedef struct {
lv_obj_t *root;
make_font_cb make_font;
delete_font_cb delete_font;
} luavgl_args_t;
/**
* Initialize the Hardware Abstraction Layer (HAL) for the LVGL graphics
* library
*/
static void hal_init(void)
{
/* Use the 'monitor' driver which creates window on PC's monitor to simulate a
* display*/
sdl_init();
/*Create a display buffer*/
static lv_disp_draw_buf_t disp_buf1;
static lv_color_t buf1_1[SDL_HOR_RES * SDL_VER_RES];
lv_disp_draw_buf_init(&disp_buf1, buf1_1, NULL, SDL_HOR_RES * SDL_VER_RES);
/*Create a display*/
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
disp_drv.draw_buf = &disp_buf1;
disp_drv.flush_cb = sdl_display_flush;
disp_drv.hor_res = SDL_HOR_RES;
disp_drv.ver_res = SDL_VER_RES;
lv_disp_t *disp = lv_disp_drv_register(&disp_drv);
lv_theme_t *th = lv_theme_default_init(
disp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED),
LV_THEME_DEFAULT_DARK, LV_FONT_DEFAULT);
lv_disp_set_theme(disp, th);
lv_group_t *g = lv_group_create();
lv_group_set_default(g);
/* Add the mouse as input device
* Use the 'mouse' driver which reads the PC's mouse*/
static lv_indev_drv_t indev_drv_1;
lv_indev_drv_init(&indev_drv_1); /*Basic initialization*/
indev_drv_1.type = LV_INDEV_TYPE_POINTER;
/*This function will be called periodically (by the library) to get the mouse
* position and state*/
indev_drv_1.read_cb = sdl_mouse_read;
lv_indev_t *mouse_indev = lv_indev_drv_register(&indev_drv_1);
static lv_indev_drv_t indev_drv_2;
lv_indev_drv_init(&indev_drv_2); /*Basic initialization*/
indev_drv_2.type = LV_INDEV_TYPE_KEYPAD;
indev_drv_2.read_cb = sdl_keyboard_read;
lv_indev_t *kb_indev = lv_indev_drv_register(&indev_drv_2);
lv_indev_set_group(kb_indev, g);
static lv_indev_drv_t indev_drv_3;
lv_indev_drv_init(&indev_drv_3); /*Basic initialization*/
indev_drv_3.type = LV_INDEV_TYPE_ENCODER;
indev_drv_3.read_cb = sdl_mousewheel_read;
lv_indev_t *enc_indev = lv_indev_drv_register(&indev_drv_3);
lv_indev_set_group(enc_indev, g);
/*Set a cursor for the mouse*/
LV_IMG_DECLARE(mouse_cursor_icon); /*Declare the image file.*/
lv_obj_t *cursor_obj =
lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
lv_img_set_src(cursor_obj, &mouse_cursor_icon); /*Set the image source*/
lv_indev_set_cursor(mouse_indev,
cursor_obj); /*Connect the image object to the driver*/
}
/*
** Prints an error message, adding the program name in front of it
** (if present)
*/
static void l_message(const char *pname, const char *msg)
{
printf("%s: %s\n", pname ? pname : " ", msg);
}
/*
** Check whether 'status' is not OK and, if so, prints the error
** message on the top of the stack. It assumes that the error object
** is a string, as it was either generated by Lua or by 'msghandler'.
*/
static int report(lua_State *L, int status)
{
if (status != LUA_OK) {
const char *msg = lua_tostring(L, -1);
l_message("luactx", msg);
lua_pop(L, 1); /* remove message */
}
return status;
}
/*
** Message handler used to run all chunks
*/
static int msghandler(lua_State *L)
{
const char *msg = lua_tostring(L, 1);
if (msg == NULL) { /* is error object not a string? */
if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */
lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */
return 1; /* that is the message */
else
msg = lua_pushfstring(L, "(error object is a %s value)",
luaL_typename(L, 1));
}
/* append a standard traceback */
luaL_traceback(L, L, msg, 1);
msg = lua_tostring(L, -1);
lua_pop(L, 1);
lv_obj_t *root = NULL;
luavgl_ctx_t *ctx = luavgl_context(L);
root = ctx->root ? ctx->root : lv_scr_act();
lv_obj_t *label = lv_label_create(root);
lv_label_set_text(label, msg);
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
lv_obj_set_style_text_font(label, LV_FONT_DEFAULT, 0);
lv_obj_set_width(label, LV_PCT(80));
lv_obj_center(label);
printf("trace back: \n%s\n", msg);
return 0; /* return no trace, since we already processed it. */
}
static int lua_panic(lua_State *L)
{
printf("LUA panic:\n%s\n", lua_tostring(L, -1));
return 0; /* return to Lua to abort */
}
/*
** protected main entry
*/
static int pmain(lua_State *L)
{
int status;
const char *script = lua_tostring(L, 1);
luavgl_args_t *args = lua_touserdata(L, 2);
if (args == NULL || args->root == NULL) {
printf("Null root object.\n");
return 0;
}
luavgl_set_root(L, args->root);
luavgl_set_font_extension(L, args->make_font, args->delete_font);
/**
* Set global variable SCRIPT_PATH, to make image src path easier.
*/
char *path = strdup(script);
if (path == NULL) {
printf("no memory.\n");
return 0;
}
int i = strlen(path);
for (; i; i--) {
if (path[i] == '/') {
path[i + 1] = '\0';
break;
}
}
printf("script path: %s\n", path);
lua_pushstring(L, path);
lua_setglobal(L, "SCRIPT_PATH");
luaL_openlibs(L);
lua_getglobal(L, "package");
lua_getfield(L, -1, "path");
const char *pkg_path = lua_tostring(L, -1);
char *new_path = malloc(strlen(pkg_path) + strlen(script) + 2);
strcpy(new_path, pkg_path);
strcat(new_path, ";"), strcat(new_path, path), strcat(new_path, "?.lua");
lua_pop(L, 1);
lua_pushstring(L, new_path);
lua_setfield(L, -2, "path");
lua_pop(L, 1);
free(path);
free(new_path);
lua_atpanic(L, &lua_panic);
luaL_requiref(L, "lvgl", luaopen_lvgl, 1);
lua_pop(L, 1);
luavgl_widgets_init(L);
lua_pushcfunction(L, msghandler); /* push message handler */
int base = lua_gettop(L);
status = luaL_loadfile(L, script);
if (status != LUA_OK) {
lua_pushfstring(L, "failed to load: %s\n", script);
/* manually show the error to screen. */
lua_insert(L, 1);
msghandler(L);
return 0;
}
status = lua_pcall(L, 0, 0, base);
lua_remove(L, base); /* remove message handler from the stack */
report(L, status);
lua_pushboolean(L, 1); /* signal no errors */
return 1;
}
lua_context_t *lua_load_script(const char *script, luavgl_args_t *args)
{
int ret, status;
/* create the thread to run script. */
if (script == NULL) {
printf("args error.\n");
return NULL;
}
printf("run script: %s\n", script);
lua_State *L = luaL_newstate(); /* create state */
if (L == NULL) {
printf("no mem for lua state.\n");
return NULL;
}
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
lua_pushstring(L, script);
lua_pushlightuserdata(L, args);
status = lua_pcall(L, 2, 1, 0); /* do the call */
ret = lua_toboolean(L, -1);
report(L, status);
if (!ret || status != LUA_OK) {
/* This should never happen */
printf("pcall failed.\n");
lua_close(L);
return NULL;
}
/* script may fail, but we continue until page destoried. */
lua_context_t *luactx = calloc(sizeof(*luactx), 1);
if (luactx == NULL) {
printf("no memory.\n");
goto lua_exit;
}
luactx->L = L;
luactx->root = args->root;
return luactx;
lua_exit:
lua_close(L);
return NULL;
}
int lua_terminate(lua_context_t *luactx)
{
lua_State *L = luactx->L;
lua_close(L);
free(luactx);
return 0;
}
static lua_context_t *lua_ctx;
static luavgl_args_t args;
static void reload_cb(lv_event_t *e)
{
(void)e;
if (lua_ctx != NULL) {
lua_terminate(lua_ctx);
}
lua_ctx = lua_load_script(LUAVGL_EXAMPLE_DIR "/examples.lua", &args);
}
int main(int argc, char **argv)
{
(void)argc; /*Unused*/
(void)argv; /*Unused*/
/*Initialize LVGL*/
lv_init();
/*Initialize the HAL (display, input devices, tick) for LVGL*/
hal_init();
args.root = lv_scr_act();
lua_ctx = lua_load_script(LUAVGL_EXAMPLE_DIR "/examples.lua", &args);
lv_obj_t *btn = lv_btn_create(lv_layer_sys());
lv_obj_align(btn, LV_ALIGN_BOTTOM_RIGHT, 0, -50);
lv_obj_set_size(btn, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_style_pad_all(btn, 5, 0);
lv_obj_add_event_cb(btn, reload_cb, LV_EVENT_CLICKED, NULL);
lv_obj_t* label = lv_label_create(btn);
lv_label_set_text(label, "RELOAD");
lv_obj_center(label);
while (1) {
/* Periodically call the lv_task handler.
* It could be done in a timer interrupt or an OS task too.*/
lv_timer_handler();
usleep(5 * 1000);
}
return 0;
}