diff --git a/radio/src/gui/colorlcd/standalone_lua.cpp b/radio/src/gui/colorlcd/standalone_lua.cpp index 8d2d59124..c8e2efc21 100644 --- a/radio/src/gui/colorlcd/standalone_lua.cpp +++ b/radio/src/gui/colorlcd/standalone_lua.cpp @@ -21,9 +21,10 @@ #include "standalone_lua.h" #include "view_main.h" -#include "lua/lua_api.h" +#include "touch.h" using std::string; +extern BitmapBuffer* luaLcdBuffer; void LuaPopup::paint(BitmapBuffer* dc, uint8_t type, const char* text, const char* info) { @@ -50,6 +51,10 @@ void LuaPopup::paint(BitmapBuffer* dc, uint8_t type, const char* text, const cha // singleton instance StandaloneLuaWindow* StandaloneLuaWindow::_instance; +#if defined(HARDWARE_TOUCH) + bool StandaloneLuaWindow::fingerDown = false; +#endif + // LUA lcd buffer uint16_t* lcdGetBackupBuffer(); @@ -103,8 +108,43 @@ void StandaloneLuaWindow::paint(BitmapBuffer* dc) void StandaloneLuaWindow::checkEvents() { Window::checkEvents(); - runLua(event); + + // Set global LUA LCD buffer + luaLcdBuffer = &lcdBuffer; + + if (luaState != INTERPRETER_RELOAD_PERMANENT_SCRIPTS) { +#if defined(HARDWARE_TOUCH) + // Stick touch in the same slot of touches as luaTask sticks evt in events + if (IS_TOUCH_EVENT(event)) { + for (int i = 0; i < EVENT_BUFFER_SIZE; i++) { + if (events[i] == 0) { + touches[i] = touch; + break; + } + } + } +#endif + if (luaTask(event, true)) { +#if defined(DEBUG_WINDOWS) + TRACE("# StandaloneLuaWindow::invalidate()"); +#endif + invalidate(); + } + } + event = 0; +#if defined(HARDWARE_TOUCH) + memclear(&touch, sizeof(touch)); +#endif + + if (luaState == INTERPRETER_RELOAD_PERMANENT_SCRIPTS) { + // Script does not run anymore... + TRACE("LUA standalone script exited: deleting window!"); + deleteLater(); + } + + // Kill global LUA LCD buffer + luaLcdBuffer = nullptr; } #if defined(HARDWARE_KEYS) @@ -114,6 +154,49 @@ void StandaloneLuaWindow::onEvent(event_t evt) } #endif +#if defined(HARDWARE_TOUCH) +bool StandaloneLuaWindow::onTouchStart(coord_t x, coord_t y) +{ + TRACE_WINDOWS("StandaloneLuaWindow received touch start (%d) x=%d;y=%d", hasFocus(), x, y); + // Only one EVT_TOUCH_FIRST at a time + if (!fingerDown) { + event = EVT_TOUCH_FIRST; + touch.touchX = x; + touch.touchY = y; + fingerDown = true; + } + return true; +} + +bool StandaloneLuaWindow::onTouchEnd(coord_t x, coord_t y) +{ + TRACE_WINDOWS("StandaloneLuaWindow received touch end (%d) x=%d;y=%d", hasFocus(), x, y); + if (touchState.tapCount > 0) { + event = EVT_TOUCH_TAP; + touch.tapCount = touchState.tapCount; + } else + event = EVT_TOUCH_BREAK; + touch.touchX = x; + touch.touchY = y; + fingerDown = false; + return true; +} + +bool StandaloneLuaWindow::onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) +{ + TRACE_WINDOWS("StandaloneLuaWindow touch slide"); + event = EVT_TOUCH_SLIDE; + touch.touchX = x; + touch.touchY = y; + touch.startX = startX; + touch.startY = startY; + touch.slideX = slideX; + touch.slideY = slideY; + fingerDown = false; + return true; +} +#endif + bool StandaloneLuaWindow::displayPopup(event_t event, uint8_t type, const char* text, const char* info, bool& result) { @@ -138,30 +221,4 @@ bool StandaloneLuaWindow::displayPopup(event_t event, uint8_t type, const char* } return false; -} - -extern BitmapBuffer* luaLcdBuffer; - -void StandaloneLuaWindow::runLua(event_t evt) -{ - // Set global LUA LCD buffer - luaLcdBuffer = &lcdBuffer; - - if (luaState != INTERPRETER_RELOAD_PERMANENT_SCRIPTS) { - if (luaTask(evt, true)) { -#if defined(DEBUG_WINDOWS) - TRACE("# StandaloneLuaWindow::invalidate()"); -#endif - invalidate(); - } - } - - if (luaState == INTERPRETER_RELOAD_PERMANENT_SCRIPTS) { - // Script does not run anymore... - TRACE("LUA standalone script exited: deleting window!"); - deleteLater(); - } - - // Kill global LUA LCD buffer - luaLcdBuffer = nullptr; -} +} \ No newline at end of file diff --git a/radio/src/gui/colorlcd/standalone_lua.h b/radio/src/gui/colorlcd/standalone_lua.h index 064b00683..f2fe4b899 100644 --- a/radio/src/gui/colorlcd/standalone_lua.h +++ b/radio/src/gui/colorlcd/standalone_lua.h @@ -22,6 +22,7 @@ #pragma once #include "libopenui.h" +#include "lua/lua_api.h" struct LuaPopup { @@ -52,6 +53,12 @@ public: void onEvent(event_t evt) 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 + bool displayPopup(event_t event, uint8_t type, const char* text, const char* info, bool& result); @@ -65,4 +72,8 @@ protected: // run LUA code void runLua(event_t evt); event_t event = 0; +#if defined(HARDWARE_TOUCH) + static bool fingerDown; + LuaTouchData touch; +#endif }; diff --git a/radio/src/lua/interface.cpp b/radio/src/lua/interface.cpp index f032f1ca8..a638bc365 100644 --- a/radio/src/lua/interface.cpp +++ b/radio/src/lua/interface.cpp @@ -49,8 +49,18 @@ extern "C" { #define PERMANENT_SCRIPTS_MAX_INSTRUCTIONS 100 #define LUA_TASK_PERIOD_TICKS 5 // 50 ms -// Since we may not run FG every time, keep the first two events in a buffer -event_t events[2] = {0, 0}; +#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 + +tmr10ms_t swipeTimeOut = 0; +LuaTouchData touches[EVENT_BUFFER_SIZE] = { 0 }; +#endif + +// Since we may not run FG every time, keep the events in a buffer +event_t events[EVENT_BUFFER_SIZE] = { 0 }; // The main thread - lsScripts is now a coroutine lua_State * L = nullptr; lua_State *lsScripts = nullptr; @@ -138,10 +148,26 @@ static void luaHook(lua_State * L, lua_Debug *ar) #endif // #if defined(LUA_ALLOCATOR_TRACER) } +static void l_pushtableint(const char * key, int value) +{ + lua_pushstring(lsScripts, key); + lua_pushinteger(lsScripts, value); + lua_settable(lsScripts, -3); +} + +static void l_pushtablebool(const char * key, bool value) +{ + lua_pushstring(lsScripts, key); + lua_pushboolean(lsScripts, value); + lua_settable(lsScripts, -3); +} + void luaEmptyEventBuffer() { - events[0] = 0; - events[1] = 0; + memclear(&events, sizeof(events)); +#if defined(HARDWARE_TOUCH) + memclear(&touches, sizeof(touches)); +#endif } #if defined(LUA_MODEL_SCRIPTS) @@ -423,8 +449,8 @@ int luaLoadScriptFileToState(lua_State * L, const char * filename, const char * bool scriptNeedsCompile = false; uint8_t loadFileType = 0; // 1=text, 2=binary - memset(&fnoLuaS, 0, sizeof(FILINFO)); - memset(&fnoLuaC, 0, sizeof(FILINFO)); + memclear(&fnoLuaS, sizeof(FILINFO)); + memclear(&fnoLuaC, sizeof(FILINFO)); fnamelen = strlen(filename); // check if file extension is already in the file name and strip it @@ -989,8 +1015,9 @@ static bool resumeLua(bool init, bool allowLcdUsage) if (ref == SCRIPT_STANDALONE) { // Pull a new event from the buffer evt = events[0]; - events[0] = events[1]; - events[1] = 0; + for (int i = 1; i < EVENT_BUFFER_SIZE; i++) + events[i - 1] = events[i]; + events[EVENT_BUFFER_SIZE - 1] = 0; if (evt == EVT_KEY_LONG(KEY_EXIT)) { killEvents(evt); @@ -1016,12 +1043,60 @@ static bool resumeLua(bool init, bool allowLcdUsage) #endif // Pull a new event from the buffer evt = events[0]; - events[0] = events[1]; - events[1] = 0; - + for (int i = 1; i < EVENT_BUFFER_SIZE; i++) + events[i - 1] = events[i]; + events[EVENT_BUFFER_SIZE - 1] = 0; +#if defined(HARDWARE_TOUCH) + LuaTouchData* touch = &touches[0]; +#endif lua_rawgeti(lsScripts, LUA_REGISTRYINDEX, sid.run); lua_pushunsigned(lsScripts, evt); inputsCount = 1; + +#if defined(HARDWARE_TOUCH) + if (IS_TOUCH_EVENT(evt)) { + lua_newtable(lsScripts); + l_pushtableint("x", touch->touchX); + l_pushtableint("y", touch->touchY); + l_pushtableint("tapCount", touch->tapCount); + + if (evt == EVT_TOUCH_SLIDE) { + l_pushtableint("startX", touch->startX); + l_pushtableint("startY", touch->startY); + l_pushtableint("slideX", touch->slideX); + l_pushtableint("slideY", touch->slideY); + + // Do we have a swipe? Only one at a time! + if (get_tmr10ms() > swipeTimeOut) { + coord_t absX = (touch->slideX < 0) ? -(touch->slideX) : touch->slideX; + coord_t absY = (touch->slideY < 0) ? -(touch->slideY) : touch->slideY; + bool swiped = false; + + if (absX > EVT_TOUCH_SWIPE_LOCK * absY) { + if ((swiped = (touch->slideX > EVT_TOUCH_SWIPE_SPEED))) + l_pushtablebool("swipeRight", true); + else if ((swiped = (touch->slideX < -EVT_TOUCH_SWIPE_SPEED))) + l_pushtablebool("swipeLeft", true); + } + else if (absY > EVT_TOUCH_SWIPE_LOCK * absX) { + if ((swiped = (touch->slideY > EVT_TOUCH_SWIPE_SPEED))) + l_pushtablebool("swipeDown", true); + else if ((swiped = (touch->slideY < -EVT_TOUCH_SWIPE_SPEED))) + l_pushtablebool("swipeUp", true); + } + + if (swiped) + swipeTimeOut = get_tmr10ms() + EVT_TOUCH_SWIPE_TIMEOUT; + } + } + inputsCount = 2; + } + + // Move the touch buffer forward + for (int i = 1; i < EVENT_BUFFER_SIZE; i++) + touches[i - 1] = touches[i]; + memclear(&touches[EVENT_BUFFER_SIZE - 1], sizeof(LuaTouchData)); +#endif } else continue; } @@ -1180,8 +1255,12 @@ bool luaTask(event_t evt, bool allowLcdUsage) // Add event to buffer if (evt != 0) { - if (events[0] == 0) events[0] = evt; - else if (events[1] == 0) events[1] = evt; + for (int i = 0; i < EVENT_BUFFER_SIZE; i++) { + if (events[i] == 0) { + events[i] = evt; + break; + } + } } // For preemption @@ -1254,7 +1333,7 @@ void luaInit() #if defined(USE_BIN_ALLOCATOR) L = lua_newstate(bin_l_alloc, nullptr); //we use our own allocator! #elif defined(LUA_ALLOCATOR_TRACER) - memset(&lsScriptsTrace, 0 , sizeof(lsScriptsTrace); + memclear(&lsScriptsTrace, sizeof(lsScriptsTrace); lsScriptsTrace.script = "lua_newstate(scripts)"; L = lua_newstate(tracer_alloc, &lsScriptsTrace); //we use tracer allocator #else @@ -1274,8 +1353,8 @@ void luaInit() lsScripts = lua_newthread(L); // Clear loaded scripts - memset(scriptInternalData, 0, sizeof(scriptInternalData)); - memset(scriptInputsOutputs, 0, sizeof(scriptInputsOutputs)); + memclear(scriptInternalData, sizeof(scriptInternalData)); + memclear(scriptInputsOutputs, sizeof(scriptInputsOutputs)); luaScriptsCount = 0; // protect libs and constants registration diff --git a/radio/src/lua/lua_api.h b/radio/src/lua/lua_api.h index 063714f68..612645afa 100644 --- a/radio/src/lua/lua_api.h +++ b/radio/src/lua/lua_api.h @@ -57,6 +57,9 @@ extern lua_State * lsScripts; extern bool luaLcdAllowed; +#define EVENT_BUFFER_SIZE 2 +extern event_t events[EVENT_BUFFER_SIZE]; + #if defined(COLORLCD) extern lua_State * lsWidgets; extern uint32_t luaExtraMemoryUsage; @@ -241,6 +244,21 @@ void * tracer_alloc(void * ud, void * ptr, size_t osize, size_t nsize); inline bool isLuaStandaloneRunning() { return scriptInternalData[0].reference == SCRIPT_STANDALONE; } + +#if defined(HARDWARE_TOUCH) +struct LuaTouchData { + coord_t touchX; + coord_t touchY; + coord_t startX; + coord_t startY; + coord_t slideX; + coord_t slideY; + short tapCount; +}; + +extern LuaTouchData touches[EVENT_BUFFER_SIZE]; +#endif + #else // defined(LUA) #define luaInit() diff --git a/radio/src/lua/widgets.cpp b/radio/src/lua/widgets.cpp index cfd51b934..8bdeccde7 100644 --- a/radio/src/lua/widgets.cpp +++ b/radio/src/lua/widgets.cpp @@ -295,14 +295,14 @@ eventData LuaWidget::events[EVENT_BUFFER_SIZE] = { 0 }; tmr10ms_t LuaWidget::swipeTimeOut = 0; #endif -void l_pushtableint(const char * key, int value) +static void l_pushtableint(const char * key, int value) { lua_pushstring(lsWidgets, key); lua_pushinteger(lsWidgets, value); lua_settable(lsWidgets, -3); } -void l_pushtablebool(const char * key, bool value) +static void l_pushtablebool(const char * key, bool value) { lua_pushstring(lsWidgets, key); lua_pushboolean(lsWidgets, value);