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/src/event.c

186 lines
4.5 KiB

#include "luavgl.h"
#include "private.h"
static void luavgl_obj_event_cb(lv_event_t *e)
{
struct event_callback_s *event = e->user_data;
if (event == NULL)
return;
lua_State *L = event->L;
int top = lua_gettop(L);
lv_obj_t *obj = e->current_target;
lua_pushlightuserdata(L, obj);
lua_rawget(L, LUA_REGISTRYINDEX);
luavgl_obj_t *lobj = luavgl_to_lobj(L, -1);
if (lobj == NULL || lobj->obj == NULL) {
lua_settop(L, top);
return;
}
int ref = event->ref;
if (ref == LUA_NOREF) {
/* nobody cares this event, something went wrong but can be ignored. */
lua_settop(L, top);
return;
}
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
lua_pushlightuserdata(L, obj);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushinteger(L, e->code);
/* args: obj, code */
luavgl_pcall_int(L, 2, 0);
}
/* obj:onevent(luavgl.EVENT.PRESSED, function(code, value) -- end) */
static int luavgl_obj_on_event(lua_State *L)
{
luavgl_obj_t *lobj = luavgl_to_lobj(L, 1);
lv_obj_t *obj = lobj->obj;
if (obj == NULL) {
luaL_argerror(L, 1, "expect obj userdata.\n");
return 0;
}
lv_event_code_t code = lua_tointeger(L, 2);
if (code >= _LV_EVENT_LAST) {
luaL_argerror(L, 2, "event code illegal");
return 0;
}
int size = lv_array_size(&lobj->events);
struct event_callback_s *event = NULL;
struct event_callback_s **events = lv_array_front(&lobj->events);
/* if third parameter is none or nil, remove this events */
if (lua_isnoneornil(L, 3)) {
for (int i = 0; i < size; i++) {
event = events[i];
if (event->code == code) {
events[i] = NULL; /* Remove it from array */
lv_result_t res = lv_obj_remove_event_dsc(lobj->obj, event->dsc);
luaL_unref(L, LUA_REGISTRYINDEX, event->ref);
event->dsc = NULL;
event->L = NULL;
event->ref = LUA_NOREF;
event->code = _LV_EVENT_LAST;
if (res != LV_RESULT_OK) {
return luaL_error(L, "Failed to remove event dsc: %d\n", res);
}
return 0;
}
}
return luaL_error(L, "No such event to remove: %d", code);
}
/* Check if the event code already exists, only one callback per code. */
for (int i = 0; i < size; i++) {
if (events[i]->code == code) {
luaL_unref(L, LUA_REGISTRYINDEX, event->ref);
event = events[i];
break;
}
if (events[i]->code == _LV_EVENT_LAST) {
/* code marked as _LV_EVENT_LAST means this event has been removed, we can
* reuse it. */
event = events[i];
break;
}
}
if (event == NULL) {
/* Create a new one if not exist */
event = lv_malloc_zeroed(sizeof(*event));
if (event == NULL) {
return luaL_error(L, "No memory");
}
lv_array_push_back(&lobj->events, &event);
LV_LOG_INFO("obj: %p, push back event: %d", obj, code);
}
event->code = code;
event->L = L;
event->ref = luavgl_check_continuation(L, 3);
event->dsc = lv_obj_add_event_cb(obj, luavgl_obj_event_cb, code, event);
if (event->dsc == NULL) {
lv_free(event);
return luaL_error(L, "Failed to add event callback");
}
return 0;
}
/* obj:onClicked(function(code, value) end) */
static int luavgl_obj_on_clicked(lua_State *L)
{
/* stack: obj, function cb */
lua_pushinteger(L, LV_EVENT_CLICKED);
lua_insert(L, 2);
return luavgl_obj_on_event(L);
}
/* obj:onShortClicked(function(code, value) end) */
static int luavgl_obj_on_short_clicked(lua_State *L)
{
/* stack: obj, function cb */
lua_pushinteger(L, LV_EVENT_SHORT_CLICKED);
lua_insert(L, 2);
return luavgl_obj_on_event(L);
}
/* obj:onPressed(function(code, value) end) */
static int luavgl_obj_on_pressed(lua_State *L)
{
lua_pushinteger(L, LV_EVENT_PRESSED);
lua_insert(L, 2);
return luavgl_obj_on_event(L);
}
/**
* Remove all events added, and free memory of events
*/
static void luavgl_obj_remove_event_all(lua_State *L, luavgl_obj_t *lobj)
{
if (lobj == NULL) {
return;
}
int size = lv_array_size(&lobj->events);
struct event_callback_s *event;
struct event_callback_s **events = lv_array_front(&lobj->events);
for (int i = 0; i < size; i++) {
event = events[i];
if (event == NULL) {
continue;
}
events[i] = NULL;
if (event->dsc == NULL) {
continue;
}
lv_result_t res = lv_obj_remove_event_dsc(lobj->obj, event->dsc);
if (res != LV_RESULT_OK) {
LV_LOG_WARN("Failed to remove event dsc: %d", res);
/* Ignore this error, remove from it anyway */
}
luaL_unref(L, LUA_REGISTRYINDEX, event->ref);
lv_free(event);
}
lv_array_deinit(&lobj->events);
}