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.
196 lines
4.9 KiB
196 lines
4.9 KiB
#include "luavgl.h"
|
|
#include "private.h"
|
|
|
|
#include "esp_heap_caps.h"
|
|
|
|
static void luavgl_obj_event_cb(lv_event_t *e)
|
|
{
|
|
lua_State *L = e->user_data;
|
|
if (L == NULL) {
|
|
debug("Null user data, should be L.\n");
|
|
}
|
|
|
|
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)
|
|
goto event_exit;
|
|
|
|
int ref = LUA_NOREF;
|
|
for (int i = 0; i < lobj->n_events; i++) {
|
|
if (lobj->events[i].code == LV_EVENT_ALL ||
|
|
lobj->events[i].code == e->code) {
|
|
ref = lobj->events[i].ref;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ref == LUA_NOREF) {
|
|
/* nobody cares this event, something went wrong but can be ignored. */
|
|
goto event_exit;
|
|
}
|
|
|
|
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);
|
|
|
|
event_exit:
|
|
lua_settop(L, top);
|
|
}
|
|
|
|
static void luavgl_obj_remove_event(lua_State *L, lv_obj_t *obj,
|
|
struct event_callback_s *event)
|
|
{
|
|
luaL_unref(L, LUA_REGISTRYINDEX, event->ref);
|
|
event->code = -1; /* mark it as unused. */
|
|
event->ref = LUA_NOREF;
|
|
lv_obj_remove_event_dsc(obj, event->dsc);
|
|
event->dsc = NULL;
|
|
}
|
|
|
|
/* obj:onevent(luavgl.EVENT.PRESSED, function(code, value) -- end) */
|
|
static int luavgl_obj_on_event(lua_State *L)
|
|
{
|
|
bool remove_all; /* if third parameter is noneornil, remove all events. */
|
|
|
|
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;
|
|
}
|
|
|
|
remove_all = lua_isnoneornil(L, 3);
|
|
|
|
/* check if event code already added, find a slot to store this callback */
|
|
int slot = 0;
|
|
if (lobj && lobj->events) {
|
|
for (; slot < lobj->n_events; slot++) {
|
|
struct event_callback_s *event = &lobj->events[slot];
|
|
if (event->code == code) { /* same event can only be added once. */
|
|
luavgl_obj_remove_event(L, obj, event);
|
|
if (remove_all)
|
|
continue; /* continue to remove all events associated. */
|
|
else
|
|
break; /* use this slot for our new event callback */
|
|
}
|
|
|
|
if (event->code == -1) {
|
|
/* this callback has been removed, thus, we can use this slot */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (remove_all) /* no need to add, just return */
|
|
return 0;
|
|
|
|
struct event_callback_s *events = lobj->events;
|
|
|
|
/* create obj->lobj->events, if NULL, realloc if existing and find no slot
|
|
*/
|
|
if (events == NULL) {
|
|
events =
|
|
heap_caps_calloc(sizeof(struct event_callback_s), 1, MALLOC_CAP_SPIRAM);
|
|
if (events == NULL) {
|
|
return luaL_error(L, "No memory.");
|
|
}
|
|
|
|
lobj->events = events;
|
|
lobj->n_events = 1;
|
|
} else {
|
|
/* realloc? */
|
|
if (slot && slot == lobj->n_events) {
|
|
struct event_callback_s *_events;
|
|
_events = heap_caps_realloc(lobj->events,
|
|
(lobj->n_events + 1) * sizeof(*_events),
|
|
MALLOC_CAP_SPIRAM);
|
|
if (_events == NULL) {
|
|
return luaL_error(L, "No memory.");
|
|
}
|
|
events = _events;
|
|
lobj->n_events++; /* now we have +1 event */
|
|
lobj->events = events;
|
|
}
|
|
/* else: we have found a slot to reuse, use it. */
|
|
}
|
|
|
|
/* setup event callback */
|
|
|
|
void *dsc = lv_obj_add_event_cb(obj, luavgl_obj_event_cb, code, L);
|
|
struct event_callback_s *event = &events[slot];
|
|
event->code = code;
|
|
event->ref = luavgl_check_continuation(L, 3);
|
|
event->dsc = dsc;
|
|
|
|
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);
|
|
}
|
|
|
|
static void luavgl_obj_event_init(luavgl_obj_t *lobj) { lobj->n_events = 0; }
|
|
|
|
/**
|
|
* 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 || lobj->events == NULL) {
|
|
return;
|
|
}
|
|
|
|
struct event_callback_s *events = lobj->events;
|
|
|
|
int i = 0;
|
|
for (; i < lobj->n_events; i++) {
|
|
struct event_callback_s *event = &lobj->events[i];
|
|
if (event->code != -1) {
|
|
luavgl_obj_remove_event(L, lobj->obj, event);
|
|
}
|
|
}
|
|
|
|
free(events);
|
|
lobj->n_events = 0;
|
|
lobj->events = NULL;
|
|
}
|
|
|