Support for touch/key events in LUA widgets
This commit is contained in:
committed by
Raphael Coeffic
parent
93797a3e14
commit
a3424d5bc0
+68
-500
@@ -29,40 +29,45 @@
|
||||
#include "api_colorlcd.h"
|
||||
#include "view_main.h"
|
||||
|
||||
#include "lua_widget.h"
|
||||
#include "lua_widget_factory.h"
|
||||
|
||||
#define MAX_INSTRUCTIONS (20000/100)
|
||||
#define LUA_WARNING_INFO_LEN 64
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
#include "touch.h"
|
||||
#define EVT_TOUCH_SWIPE_LOCK 4
|
||||
#define EVT_TOUCH_SWIPE_SPEED 60
|
||||
#define EVT_TOUCH_SWIPE_TIMEOUT 50
|
||||
#endif
|
||||
// #if defined(HARDWARE_TOUCH)
|
||||
// #include "touch.h"
|
||||
// #define EVT_TOUCH_SWIPE_LOCK 4
|
||||
// #define EVT_TOUCH_SWIPE_SPEED 60
|
||||
// #define EVT_TOUCH_SWIPE_TIMEOUT 50
|
||||
// #endif
|
||||
|
||||
lua_State * lsWidgets = NULL;
|
||||
|
||||
extern int custom_lua_atpanic(lua_State *L);
|
||||
|
||||
#define LUA_WIDGET_FILENAME "/main.lua"
|
||||
#define LUA_FULLPATH_MAXLEN (LEN_FILE_PATH_MAX + LEN_SCRIPT_FILENAME + LEN_FILE_EXTENSION_MAX) // max length (example: /SCRIPTS/THEMES/mytheme.lua)
|
||||
#define LUA_WIDGET_FILENAME "/main.lua"
|
||||
#define LUA_FULLPATH_MAXLEN \
|
||||
(LEN_FILE_PATH_MAX + LEN_SCRIPT_FILENAME + \
|
||||
LEN_FILE_EXTENSION_MAX) // max length (example:
|
||||
// /SCRIPTS/THEMES/mytheme.lua)
|
||||
|
||||
static void luaHook(lua_State * L, lua_Debug *ar)
|
||||
static void luaHook(lua_State *L, lua_Debug *ar)
|
||||
{
|
||||
if (ar->event == LUA_HOOKCOUNT) {
|
||||
instructionsPercent++;
|
||||
#if defined(DEBUG)
|
||||
// Disable Lua script instructions limit in DEBUG mode,
|
||||
// just report max value reached
|
||||
static uint16_t max = 0;
|
||||
if (instructionsPercent > 100) {
|
||||
if (max + 10 < instructionsPercent) {
|
||||
max = instructionsPercent;
|
||||
TRACE("LUA instructionsPercent %u%%", (uint32_t)max);
|
||||
// Disable Lua script instructions limit in DEBUG mode,
|
||||
// just report max value reached
|
||||
static uint16_t max = 0;
|
||||
if (instructionsPercent > 100) {
|
||||
if (max + 10 < instructionsPercent) {
|
||||
max = instructionsPercent;
|
||||
TRACE("LUA instructionsPercent %u%%", (uint32_t)max);
|
||||
}
|
||||
} else if (instructionsPercent < 10) {
|
||||
max = 0;
|
||||
}
|
||||
}
|
||||
else if (instructionsPercent < 10) {
|
||||
max = 0;
|
||||
}
|
||||
#else
|
||||
if (instructionsPercent > 100) {
|
||||
// From now on, as soon as a line is executed, error
|
||||
@@ -75,16 +80,17 @@ static void luaHook(lua_State * L, lua_Debug *ar)
|
||||
#if defined(LUA_ALLOCATOR_TRACER)
|
||||
else if (ar->event == LUA_HOOKLINE) {
|
||||
lua_getinfo(L, "nSl", ar);
|
||||
LuaMemTracer * tracer = GET_TRACER(L);
|
||||
LuaMemTracer *tracer = GET_TRACER(L);
|
||||
if (tracer->alloc || tracer->free) {
|
||||
TRACE("LT: [+%u,-%u] %s:%d", tracer->alloc, tracer->free, tracer->script, tracer->lineno);
|
||||
TRACE("LT: [+%u,-%u] %s:%d", tracer->alloc, tracer->free, tracer->script,
|
||||
tracer->lineno);
|
||||
}
|
||||
tracer->script = ar->source;
|
||||
tracer->lineno = ar->currentline;
|
||||
tracer->alloc = 0;
|
||||
tracer->free = 0;
|
||||
}
|
||||
#endif // #if defined(LUA_ALLOCATOR_TRACER)
|
||||
#endif // #if defined(LUA_ALLOCATOR_TRACER)
|
||||
}
|
||||
|
||||
void luaSetInstructionsLimit(lua_State * L, int count)
|
||||
@@ -97,7 +103,7 @@ void luaSetInstructionsLimit(lua_State * L, int count)
|
||||
#endif
|
||||
}
|
||||
|
||||
ZoneOption * createOptionsArray(int reference, uint8_t maxOptions)
|
||||
ZoneOption *createOptionsArray(int reference, uint8_t maxOptions)
|
||||
{
|
||||
if (reference == 0) {
|
||||
// TRACE("createOptionsArray() no options");
|
||||
@@ -116,30 +122,33 @@ ZoneOption * createOptionsArray(int reference, uint8_t maxOptions)
|
||||
// TRACE("limited to %d options", count);
|
||||
}
|
||||
|
||||
ZoneOption * options = (ZoneOption *)malloc(sizeof(ZoneOption) * (count+1));
|
||||
ZoneOption *options = (ZoneOption *)malloc(sizeof(ZoneOption) * (count + 1));
|
||||
if (!options) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PROTECT_LUA() {
|
||||
PROTECT_LUA()
|
||||
{
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference);
|
||||
ZoneOption * option = options;
|
||||
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2), count-- > 0; lua_pop(lsWidgets, 1)) {
|
||||
ZoneOption *option = options;
|
||||
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2), count-- > 0;
|
||||
lua_pop(lsWidgets, 1)) {
|
||||
// TRACE("parsing option %d", count);
|
||||
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
|
||||
luaL_checktype(lsWidgets, -1, LUA_TTABLE); // value is table
|
||||
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
|
||||
luaL_checktype(lsWidgets, -1, LUA_TTABLE); // value is table
|
||||
uint8_t field = 0;
|
||||
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2) && field<5; lua_pop(lsWidgets, 1), field++) {
|
||||
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2) && field < 5;
|
||||
lua_pop(lsWidgets, 1), field++) {
|
||||
switch (field) {
|
||||
case 0:
|
||||
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
|
||||
luaL_checktype(lsWidgets, -1, LUA_TSTRING); // value is string
|
||||
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
|
||||
luaL_checktype(lsWidgets, -1, LUA_TSTRING); // value is string
|
||||
option->name = lua_tostring(lsWidgets, -1);
|
||||
// TRACE("name = %s", option->name);
|
||||
break;
|
||||
case 1:
|
||||
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
option->type = (ZoneOption::Type)lua_tointeger(lsWidgets, -1);
|
||||
// TRACE("type = %d", option->type);
|
||||
if (option->type > ZoneOption::Color) {
|
||||
@@ -154,44 +163,42 @@ ZoneOption * createOptionsArray(int reference, uint8_t maxOptions)
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
|
||||
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
|
||||
if (option->type == ZoneOption::Integer) {
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
option->deflt.signedValue = lua_tointeger(lsWidgets, -1);
|
||||
// TRACE("default signed = %d", option->deflt.signedValue);
|
||||
}
|
||||
else if (option->type == ZoneOption::Source ||
|
||||
option->type == ZoneOption::TextSize) {
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
} else if (option->type == ZoneOption::Source ||
|
||||
option->type == ZoneOption::TextSize) {
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
option->deflt.unsignedValue = lua_tounsigned(lsWidgets, -1);
|
||||
// TRACE("default unsigned = %u", option->deflt.unsignedValue);
|
||||
}
|
||||
else if (option->type == ZoneOption::Color) {
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
option->deflt.unsignedValue = COLOR_VAL(flagsRGB(lua_tounsigned(lsWidgets, -1)));
|
||||
} else if (option->type == ZoneOption::Color) {
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
option->deflt.unsignedValue =
|
||||
COLOR_VAL(flagsRGB(lua_tounsigned(lsWidgets, -1)));
|
||||
// TRACE("default unsigned = %u", option->deflt.unsignedValue);
|
||||
}
|
||||
else if (option->type == ZoneOption::Bool) {
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
} else if (option->type == ZoneOption::Bool) {
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
option->deflt.boolValue = (lua_tounsigned(lsWidgets, -1) != 0);
|
||||
// TRACE("default bool = %d", (int)(option->deflt.boolValue));
|
||||
}
|
||||
else if (option->type == ZoneOption::String) {
|
||||
strncpy(option->deflt.stringValue, lua_tostring(lsWidgets, -1), LEN_ZONE_OPTION_STRING);
|
||||
} else if (option->type == ZoneOption::String) {
|
||||
strncpy(option->deflt.stringValue, lua_tostring(lsWidgets, -1),
|
||||
LEN_ZONE_OPTION_STRING);
|
||||
// TRACE("default string = %s", lua_tostring(lsWidgets, -1));
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (option->type == ZoneOption::Integer) {
|
||||
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
option->min.signedValue = lua_tointeger(lsWidgets, -1);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (option->type == ZoneOption::Integer) {
|
||||
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
|
||||
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
|
||||
option->max.signedValue = lua_tointeger(lsWidgets, -1);
|
||||
}
|
||||
break;
|
||||
@@ -199,9 +206,10 @@ ZoneOption * createOptionsArray(int reference, uint8_t maxOptions)
|
||||
}
|
||||
option++;
|
||||
}
|
||||
option->name = NULL; // sentinel
|
||||
option->name = NULL; // sentinel
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
TRACE("error in theme/widget options");
|
||||
free(options);
|
||||
return NULL;
|
||||
@@ -210,452 +218,13 @@ ZoneOption * createOptionsArray(int reference, uint8_t maxOptions)
|
||||
return options;
|
||||
}
|
||||
|
||||
struct eventData {
|
||||
event_t event;
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
coord_t touchX;
|
||||
coord_t touchY;
|
||||
coord_t startX;
|
||||
coord_t startY;
|
||||
coord_t slideX;
|
||||
coord_t slideY;
|
||||
short tapCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
class LuaWidget: public Widget
|
||||
{
|
||||
friend class LuaWidgetFactory;
|
||||
|
||||
public:
|
||||
LuaWidget(const WidgetFactory * factory, Window* parent, const rect_t & rect, WidgetPersistentData * persistentData, int luaWidgetDataRef):
|
||||
Widget(factory, parent, rect, persistentData),
|
||||
luaWidgetDataRef(luaWidgetDataRef),
|
||||
errorMessage(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
~LuaWidget() override
|
||||
{
|
||||
luaL_unref(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef);
|
||||
free(errorMessage);
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "LuaWidget";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Widget interface
|
||||
const char * getErrorMessage() const override;
|
||||
void update() override;
|
||||
void background() override;
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchStart(coord_t x, coord_t y) override;
|
||||
bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
bool onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) override;
|
||||
#endif
|
||||
|
||||
// Calls LUA widget 'refresh' method
|
||||
void refresh(BitmapBuffer* dc) override;
|
||||
|
||||
protected:
|
||||
int luaWidgetDataRef;
|
||||
char * errorMessage;
|
||||
bool refreshed = false;
|
||||
|
||||
static eventData events[EVENT_BUFFER_SIZE];
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
static bool fingerDown;
|
||||
static tmr10ms_t swipeTimeOut;
|
||||
#endif
|
||||
|
||||
void checkEvents() override;
|
||||
void setErrorMessage(const char * funcName);
|
||||
|
||||
private:
|
||||
eventData* findOpenEventSlot(event_t event = 0);
|
||||
};
|
||||
|
||||
eventData LuaWidget::events[EVENT_BUFFER_SIZE] = { 0 };
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool LuaWidget::fingerDown = false;
|
||||
tmr10ms_t LuaWidget::swipeTimeOut = 0;
|
||||
#endif
|
||||
|
||||
static void l_pushtableint(const char * key, int value)
|
||||
{
|
||||
lua_pushstring(lsWidgets, key);
|
||||
lua_pushinteger(lsWidgets, value);
|
||||
lua_settable(lsWidgets, -3);
|
||||
}
|
||||
|
||||
static void l_pushtablebool(const char * key, bool value)
|
||||
{
|
||||
lua_pushstring(lsWidgets, key);
|
||||
lua_pushboolean(lsWidgets, value);
|
||||
lua_settable(lsWidgets, -3);
|
||||
}
|
||||
|
||||
class LuaWidgetFactory: public WidgetFactory
|
||||
{
|
||||
friend void luaLoadWidgetCallback();
|
||||
friend class LuaWidget;
|
||||
|
||||
public:
|
||||
LuaWidgetFactory(const char * name, ZoneOption * widgetOptions, int createFunction):
|
||||
WidgetFactory(name, widgetOptions),
|
||||
createFunction(createFunction),
|
||||
updateFunction(0),
|
||||
refreshFunction(0),
|
||||
backgroundFunction(0)
|
||||
{
|
||||
}
|
||||
|
||||
~LuaWidgetFactory()
|
||||
{
|
||||
unregisterWidget(this);
|
||||
}
|
||||
|
||||
Widget * create(Window* parent, const rect_t & rect, Widget::PersistentData * persistentData, bool init=true) const override
|
||||
{
|
||||
if (lsWidgets == 0) return 0;
|
||||
initPersistentData(persistentData, init);
|
||||
|
||||
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, createFunction);
|
||||
|
||||
lua_newtable(lsWidgets);
|
||||
l_pushtableint("x", 0);
|
||||
l_pushtableint("y", 0);
|
||||
l_pushtableint("w", rect.w);
|
||||
l_pushtableint("h", rect.h);
|
||||
l_pushtableint("xabs", rect.x);
|
||||
l_pushtableint("yabs", rect.y);
|
||||
|
||||
lua_newtable(lsWidgets);
|
||||
int i = 0;
|
||||
for (const ZoneOption * option = options; option->name; option++, i++) {
|
||||
if (option->type == ZoneOption::String) {
|
||||
lua_pushstring(lsWidgets, option->name);
|
||||
char str[LEN_ZONE_OPTION_STRING + 1] = {0}; // Zero-terminated string for Lua
|
||||
strncpy(str, persistentData->options[i].value.stringValue, LEN_ZONE_OPTION_STRING);
|
||||
lua_pushstring(lsWidgets, &str[0]);
|
||||
lua_settable(lsWidgets, -3);
|
||||
} else if (option->type == ZoneOption::Color) {
|
||||
int32_t value = persistentData->options[i].value.signedValue;
|
||||
l_pushtableint(option->name, COLOR2FLAGS(value) | RGB_FLAG);
|
||||
} else {
|
||||
int32_t value = persistentData->options[i].value.signedValue;
|
||||
l_pushtableint(option->name, value);
|
||||
}
|
||||
}
|
||||
|
||||
bool err = lua_pcall(lsWidgets, 2, 1, 0);
|
||||
int widgetData = err ? LUA_NOREF : luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
|
||||
LuaWidget* lw = new LuaWidget(this, parent, rect, persistentData, widgetData);
|
||||
if (err)
|
||||
lw->setErrorMessage("create()");
|
||||
return lw;
|
||||
}
|
||||
|
||||
protected:
|
||||
int createFunction;
|
||||
int updateFunction;
|
||||
int refreshFunction;
|
||||
int backgroundFunction;
|
||||
};
|
||||
|
||||
// Look for a slot in the event buffer that is either unused (zero) or matches event
|
||||
eventData* LuaWidget::findOpenEventSlot(event_t event)
|
||||
{
|
||||
for (int i = 0; i < EVENT_BUFFER_SIZE; i++) {
|
||||
if (events[i].event == event || events[i].event == 0)
|
||||
return &events[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LuaWidget::checkEvents()
|
||||
{
|
||||
Widget::checkEvents();
|
||||
|
||||
// paint has not been called
|
||||
if (!refreshed) {
|
||||
background();
|
||||
refreshed = true;
|
||||
}
|
||||
|
||||
refreshed = false;
|
||||
invalidate();
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
TRACE_WINDOWS("# refresh: %s", getWindowDebugString().c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void LuaWidget::update()
|
||||
{
|
||||
Widget::update();
|
||||
|
||||
if (lsWidgets == 0 || errorMessage) return;
|
||||
|
||||
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
|
||||
LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory;
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->updateFunction);
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef);
|
||||
|
||||
lua_newtable(lsWidgets);
|
||||
int i = 0;
|
||||
for (const ZoneOption * option = getOptions(); option->name; option++, i++) {
|
||||
if (option->type == ZoneOption::String) {
|
||||
lua_pushstring(lsWidgets, option->name);
|
||||
char str[LEN_ZONE_OPTION_STRING + 1] = {0}; // Zero-terminated string for Lua
|
||||
strncpy(str, persistentData->options[i].value.stringValue, LEN_ZONE_OPTION_STRING);
|
||||
lua_pushstring(lsWidgets, &str[0]);
|
||||
lua_settable(lsWidgets, -3);
|
||||
} else if (option->type == ZoneOption::Color) {
|
||||
int32_t value = persistentData->options[i].value.signedValue;
|
||||
l_pushtableint(option->name, COLOR2FLAGS(value) | RGB_FLAG);
|
||||
} else {
|
||||
int32_t value = persistentData->options[i].value.signedValue;
|
||||
l_pushtableint(option->name, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (lua_pcall(lsWidgets, 2, 0, 0) != 0) {
|
||||
setErrorMessage("update()");
|
||||
}
|
||||
}
|
||||
|
||||
void LuaWidget::setErrorMessage(const char * funcName)
|
||||
{
|
||||
TRACE("Error in widget %s %s function: %s", factory->getName(), funcName, lua_tostring(lsWidgets, -1));
|
||||
TRACE("Widget disabled");
|
||||
size_t needed = snprintf(NULL, 0, "ERROR in %s: %s", funcName, lua_tostring(lsWidgets, -1)) + 1;
|
||||
errorMessage = (char *)malloc(needed + 1);
|
||||
if (errorMessage) {
|
||||
snprintf(errorMessage, needed, "ERROR in %s: %s", funcName, lua_tostring(lsWidgets, -1));
|
||||
errorMessage[needed] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
const char * LuaWidget::getErrorMessage() const
|
||||
{
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
void LuaWidget::refresh(BitmapBuffer* dc)
|
||||
{
|
||||
if (lsWidgets == 0) return;
|
||||
|
||||
if (errorMessage) {
|
||||
drawTextLines(dc, 0, 0, fullscreen ? LCD_W : rect.w, fullscreen ? LCD_H : rect.h, errorMessage, FONT(XS) | COLOR_THEME_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
|
||||
LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory;
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->refreshFunction);
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef);
|
||||
|
||||
// Pass key event to fullscreen Lua widget
|
||||
eventData* es = &events[0];
|
||||
if (fullscreen)
|
||||
lua_pushinteger(lsWidgets, es->event);
|
||||
else
|
||||
lua_pushnil(lsWidgets);
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
if (fullscreen && IS_TOUCH_EVENT(es->event)) {
|
||||
lua_newtable(lsWidgets);
|
||||
l_pushtableint("x", es->touchX);
|
||||
l_pushtableint("y", es->touchY);
|
||||
l_pushtableint("tapCount", es->tapCount);
|
||||
|
||||
if (es->event == EVT_TOUCH_SLIDE) {
|
||||
l_pushtableint("startX", es->startX);
|
||||
l_pushtableint("startY", es->startY);
|
||||
l_pushtableint("slideX", es->slideX);
|
||||
l_pushtableint("slideY", es->slideY);
|
||||
|
||||
// Do we have a swipe? Only one at a time!
|
||||
if (get_tmr10ms() > swipeTimeOut) {
|
||||
coord_t absX = (es->slideX < 0) ? -(es->slideX) : es->slideX;
|
||||
coord_t absY = (es->slideY < 0) ? -(es->slideY) : es->slideY;
|
||||
bool swiped = false;
|
||||
|
||||
if (absX > EVT_TOUCH_SWIPE_LOCK * absY) {
|
||||
if ((swiped = (es->slideX > EVT_TOUCH_SWIPE_SPEED)))
|
||||
l_pushtablebool("swipeRight", true);
|
||||
else if ((swiped = (es->slideX < -EVT_TOUCH_SWIPE_SPEED)))
|
||||
l_pushtablebool("swipeLeft", true);
|
||||
}
|
||||
else if (absY > EVT_TOUCH_SWIPE_LOCK * absX) {
|
||||
if ((swiped = (es->slideY > EVT_TOUCH_SWIPE_SPEED)))
|
||||
l_pushtablebool("swipeDown", true);
|
||||
else if ((swiped = (es->slideY < -EVT_TOUCH_SWIPE_SPEED)))
|
||||
l_pushtablebool("swipeUp", true);
|
||||
}
|
||||
|
||||
if (swiped)
|
||||
swipeTimeOut = get_tmr10ms() + EVT_TOUCH_SWIPE_TIMEOUT;
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
lua_pushnil(lsWidgets);
|
||||
|
||||
// Move the event buffer forward
|
||||
for (int i = 1; i < EVENT_BUFFER_SIZE; i++)
|
||||
events[i - 1] = events[i];
|
||||
memclear(&events[EVENT_BUFFER_SIZE - 1], sizeof(eventData));
|
||||
|
||||
// Enable drawing into the current LCD buffer
|
||||
luaLcdBuffer = dc;
|
||||
|
||||
// This little hack is needed to not interfere with the LCD usage of preempted scripts
|
||||
bool lla = luaLcdAllowed;
|
||||
luaLcdAllowed = true;
|
||||
runningFS = this;
|
||||
|
||||
if (lua_pcall(lsWidgets, 3, 0, 0) != 0) {
|
||||
setErrorMessage("refresh()");
|
||||
}
|
||||
runningFS = nullptr;
|
||||
// Remove LCD
|
||||
luaLcdAllowed = lla;
|
||||
luaLcdBuffer = nullptr;
|
||||
|
||||
// mark as refreshed
|
||||
refreshed = true;
|
||||
}
|
||||
|
||||
void LuaWidget::background()
|
||||
{
|
||||
if (lsWidgets == 0 || errorMessage) return;
|
||||
|
||||
// TRACE("LuaWidget::background()");
|
||||
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
|
||||
LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory;
|
||||
if (factory->backgroundFunction) {
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->backgroundFunction);
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef);
|
||||
runningFS = this;
|
||||
if (lua_pcall(lsWidgets, 1, 0, 0) != 0) {
|
||||
setErrorMessage("background()");
|
||||
}
|
||||
runningFS = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void LuaWidget::onEvent(event_t event)
|
||||
{
|
||||
if (fullscreen) {
|
||||
if (EVT_KEY_LONG(KEY_EXIT) == event) {
|
||||
// Clear event buffer on full screen exit
|
||||
memclear(&events, EVENT_BUFFER_SIZE * sizeof(eventData));
|
||||
} else {
|
||||
eventData* es = findOpenEventSlot();
|
||||
|
||||
if (es)
|
||||
es->event = event;
|
||||
}
|
||||
}
|
||||
Widget::onEvent(event);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool LuaWidget::onTouchStart(coord_t x, coord_t y)
|
||||
{
|
||||
TRACE_WINDOWS("LuaWidget received touch start (%d) x=%d;y=%d", hasFocus(), x, y);
|
||||
|
||||
// Only one EVT_TOUCH_FIRST at a time
|
||||
if (fullscreen) {
|
||||
if (!fingerDown) {
|
||||
eventData* es = findOpenEventSlot();
|
||||
|
||||
if (es) {
|
||||
es->event = EVT_TOUCH_FIRST;
|
||||
es->touchX = x;
|
||||
es->touchY = y;
|
||||
}
|
||||
|
||||
fingerDown = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return Widget::onTouchStart(x, y);
|
||||
}
|
||||
|
||||
bool LuaWidget::onTouchEnd(coord_t x, coord_t y)
|
||||
{
|
||||
TRACE_WINDOWS("LuaWidget received touch end (%d) x=%d;y=%d", hasFocus(), x, y);
|
||||
|
||||
if (fullscreen) {
|
||||
eventData* es = findOpenEventSlot();
|
||||
|
||||
if (es) {
|
||||
if (touchState.tapCount > 0) {
|
||||
es->event = EVT_TOUCH_TAP;
|
||||
es->tapCount = touchState.tapCount;
|
||||
} else
|
||||
es->event = EVT_TOUCH_BREAK;
|
||||
es->touchX = x;
|
||||
es->touchY = y;
|
||||
}
|
||||
|
||||
fingerDown = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Widget::onTouchEnd(x, y);
|
||||
}
|
||||
|
||||
bool LuaWidget::onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY)
|
||||
{
|
||||
TRACE_WINDOWS("LuaWidget touch slide");
|
||||
if (fullscreen) {
|
||||
// If we already have a SLIDE going, then accumulate slide values instead of allocating an empty slot
|
||||
eventData* es = findOpenEventSlot(EVT_TOUCH_SLIDE);
|
||||
|
||||
if (es) {
|
||||
ViewMain* vm = ViewMain::instance();
|
||||
es->event = EVT_TOUCH_SLIDE;
|
||||
// es->touchX = x + vm->getScrollPositionX();
|
||||
// es->touchY = y + vm->getScrollPositionY();
|
||||
es->startX = startX;
|
||||
es->startY = startY;
|
||||
es->slideX += slideX;
|
||||
es->slideY += slideY;
|
||||
}
|
||||
|
||||
fingerDown = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Widget::onTouchSlide(x, y, startX, startY, slideX, slideY);
|
||||
}
|
||||
#endif
|
||||
|
||||
void luaLoadWidgetCallback()
|
||||
{
|
||||
TRACE("luaLoadWidgetCallback()");
|
||||
const char * name=NULL;
|
||||
int widgetOptions=0, createFunction=0, updateFunction=0, refreshFunction=0, backgroundFunction=0;
|
||||
|
||||
int widgetOptions = 0, createFunction = 0, updateFunction = 0,
|
||||
refreshFunction = 0, backgroundFunction = 0;
|
||||
|
||||
luaL_checktype(lsWidgets, -1, LUA_TTABLE);
|
||||
|
||||
@@ -798,7 +367,6 @@ void luaInitThemesAndWidgets()
|
||||
}
|
||||
UNPROTECT_LUA();
|
||||
TRACE("lsWidgets %p", lsWidgets);
|
||||
//luaLoadFiles(THEMES_PATH, luaLoadThemeCallback);
|
||||
luaLoadFiles(WIDGETS_PATH, luaLoadWidgetCallback);
|
||||
luaDoGc(lsWidgets, true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user