From a3424d5bc0d62077d279430680971e6276ea0023 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Fri, 10 Jun 2022 14:23:35 +0200 Subject: [PATCH] Support for touch/key events in LUA widgets --- radio/src/CMakeLists.txt | 1 + radio/src/debug.h | 2 +- radio/src/gui/colorlcd/CMakeLists.txt | 6 +- radio/src/gui/colorlcd/LvglWrapper.cpp | 7 +- radio/src/gui/colorlcd/radio_tools.cpp | 1 - radio/src/gui/colorlcd/standalone_lua.cpp | 92 +-- radio/src/gui/colorlcd/standalone_lua.h | 27 +- radio/src/gui/colorlcd/widget.cpp | 50 +- radio/src/gui/colorlcd/widget.h | 4 +- radio/src/lua/interface.cpp | 123 +--- radio/src/lua/lua_api.h | 27 +- radio/src/lua/lua_event.cpp | 131 ++++ radio/src/lua/lua_event.h | 53 ++ radio/src/lua/lua_touch.h | 37 ++ radio/src/lua/lua_widget.cpp | 358 +++++++++++ radio/src/lua/lua_widget.h | 88 +++ radio/src/lua/lua_widget_factory.cpp | 92 +++ radio/src/lua/lua_widget_factory.h | 45 ++ radio/src/lua/widgets.cpp | 568 +++--------------- .../targets/common/arm/stm32/timers_driver.h | 2 +- radio/src/targets/simu/simulcd.cpp | 4 +- 21 files changed, 965 insertions(+), 753 deletions(-) create mode 100644 radio/src/lua/lua_event.cpp create mode 100644 radio/src/lua/lua_event.h create mode 100644 radio/src/lua/lua_touch.h create mode 100644 radio/src/lua/lua_widget.cpp create mode 100644 radio/src/lua/lua_widget.h create mode 100644 radio/src/lua/lua_widget_factory.cpp create mode 100644 radio/src/lua/lua_widget_factory.h diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index abcb3fca1..62a5fe694 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -218,6 +218,7 @@ if(LUA) lua/api_general.cpp lua/api_model.cpp lua/api_filesystem.cpp + lua/lua_event.cpp ) if(GUI_DIR STREQUAL colorlcd) diff --git a/radio/src/debug.h b/radio/src/debug.h index e635d79c2..d7074ba69 100644 --- a/radio/src/debug.h +++ b/radio/src/debug.h @@ -31,7 +31,7 @@ #include "serial.h" -extern volatile uint32_t g_tmr10ms; +EXTERN_C(extern volatile uint32_t g_tmr10ms); #if defined(SIMU) typedef void (*traceCallbackFunc)(const char * text); diff --git a/radio/src/gui/colorlcd/CMakeLists.txt b/radio/src/gui/colorlcd/CMakeLists.txt index 3515a5a00..9d8a2ea53 100644 --- a/radio/src/gui/colorlcd/CMakeLists.txt +++ b/radio/src/gui/colorlcd/CMakeLists.txt @@ -104,7 +104,11 @@ endmacro(add_gui_src) if(LUA) add_gui_src(standalone_lua.cpp) - set(SRC ${SRC} lua/widgets.cpp) + set(SRC ${SRC} + lua/lua_widget.cpp + lua/lua_widget_factory.cpp + lua/widgets.cpp + ) endif() if(LUA_MIXER) diff --git a/radio/src/gui/colorlcd/LvglWrapper.cpp b/radio/src/gui/colorlcd/LvglWrapper.cpp index eb29fb087..210330d93 100644 --- a/radio/src/gui/colorlcd/LvglWrapper.cpp +++ b/radio/src/gui/colorlcd/LvglWrapper.cpp @@ -69,7 +69,12 @@ static bool evt_to_indev_data(event_t evt, lv_indev_data_t *data) case KEY_EXIT: if (evt != EVT_KEY_LONG(KEY_EXIT)) { data->key = LV_KEY_ESC; - } else { return false; } + } else { + // prevent subsequent RELEASE event + lv_indev_wait_release(lv_indev_get_act()); + data->state = LV_INDEV_STATE_PRESSED; + return false; + } break; default: diff --git a/radio/src/gui/colorlcd/radio_tools.cpp b/radio/src/gui/colorlcd/radio_tools.cpp index 18c859139..23252f771 100644 --- a/radio/src/gui/colorlcd/radio_tools.cpp +++ b/radio/src/gui/colorlcd/radio_tools.cpp @@ -185,7 +185,6 @@ struct ToolButton : public TextButton { void RadioToolsPage::rebuild(FormWindow * window) { window->clear(); - // Window::clearFocus(); std::list tools; diff --git a/radio/src/gui/colorlcd/standalone_lua.cpp b/radio/src/gui/colorlcd/standalone_lua.cpp index 4d19da248..cd6c36248 100644 --- a/radio/src/gui/colorlcd/standalone_lua.cpp +++ b/radio/src/gui/colorlcd/standalone_lua.cpp @@ -21,7 +21,7 @@ #include "standalone_lua.h" #include "view_main.h" -#include "touch.h" +// #include "touch.h" using std::string; extern BitmapBuffer* luaLcdBuffer; @@ -51,15 +51,13 @@ 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 - StandaloneLuaWindow::StandaloneLuaWindow() : Window(nullptr, {0, 0, LCD_W, LCD_H}, OPAQUE), lcdBuffer(BMP_RGB565, LCD_W, LCD_H), popup({50, 73, LCD_W - 100, LCD_H - 146}) { + // setup LUA event handler + setupHandler(this); } StandaloneLuaWindow* StandaloneLuaWindow::instance() @@ -82,8 +80,10 @@ void StandaloneLuaWindow::attach() lv_scr_load(lvobj); Layer::push(this); + + lv_group_add_obj(lv_group_get_default(), lvobj); + lv_group_set_editing(lv_group_get_default(), true); } - // setFocus(); } void StandaloneLuaWindow::deleteLater(bool detach, bool trash) @@ -119,30 +119,11 @@ void StandaloneLuaWindow::checkEvents() 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(); - } + // if LUA finished a full cycle, + // invalidate to display the screen buffer + if (luaTask(0, true)) { 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!"); @@ -153,61 +134,20 @@ void StandaloneLuaWindow::checkEvents() luaLcdBuffer = nullptr; } +void StandaloneLuaWindow::onClicked() +{ + LuaEventHandler::onClicked(); +} + void StandaloneLuaWindow::onCancel() { - // do nothing: wait for long press to kill - // the script + LuaEventHandler::onCancel(); } -#if defined(HARDWARE_KEYS) void StandaloneLuaWindow::onEvent(event_t evt) { - event = evt; + LuaEventHandler::onEvent(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) diff --git a/radio/src/gui/colorlcd/standalone_lua.h b/radio/src/gui/colorlcd/standalone_lua.h index ea2a596ae..90e7c0812 100644 --- a/radio/src/gui/colorlcd/standalone_lua.h +++ b/radio/src/gui/colorlcd/standalone_lua.h @@ -24,6 +24,7 @@ #if defined(LUA) #include "libopenui.h" #include "lua/lua_api.h" +#include "lua/lua_widget.h" struct LuaPopup { @@ -32,7 +33,7 @@ struct LuaPopup void paint(BitmapBuffer* dc, uint8_t type, const char* text, const char* info); }; -class StandaloneLuaWindow : public Window +class StandaloneLuaWindow : public Window, public LuaEventHandler { static StandaloneLuaWindow* _instance; @@ -43,24 +44,11 @@ public: void attach(); void deleteLater(bool detach = true, bool trash = true) override; - void paint(BitmapBuffer* dc) override; - void checkEvents() override; - void onCancel() override; #if defined(DEBUG_WINDOWS) std::string getName() const override { return "StandaloneLuaWindow"; } #endif -#if defined(HARDWARE_KEYS) - 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); @@ -75,10 +63,11 @@ protected: // run LUA code void runLua(event_t evt); - event_t event = 0; -#if defined(HARDWARE_TOUCH) - static bool fingerDown; - LuaTouchData touch; -#endif + + void paint(BitmapBuffer* dc) override; + void onEvent(event_t evt) override; + void checkEvents() override; + void onClicked() override; + void onCancel() override; }; #endif diff --git a/radio/src/gui/colorlcd/widget.cpp b/radio/src/gui/colorlcd/widget.cpp index 56b6f1b21..8b7edb05f 100644 --- a/radio/src/gui/colorlcd/widget.cpp +++ b/radio/src/gui/colorlcd/widget.cpp @@ -30,8 +30,6 @@ #include "touch.h" #endif -// constexpr uint32_t WIDGET_FOCUS_TIMEOUT = 10*1000; // 10 seconds - static void openWidgetMenu(Widget * parent) { Menu *menu = new Menu(parent); @@ -64,17 +62,6 @@ Widget::Widget(const WidgetFactory* factory, Window* parent, }); } -void Widget::checkEvents() -{ - Button::checkEvents(); - - // Give the focus back to ViewMain after WIDGET_FOCUS_TIMEOUT milliseconds - // if (!fullscreen && hasFocus() && (RTOS_GET_MS() - focusGainedTS >= WIDGET_FOCUS_TIMEOUT)) { - // ViewMain::instance()->setFocus(); - // } -} - - void Widget::paint(BitmapBuffer * dc) { if (fullscreen) { @@ -86,12 +73,6 @@ void Widget::paint(BitmapBuffer * dc) refresh(dc); if (hasFocus() && !fullscreen) { - - // // Blink from haft-time before expiring (5s) - // if ((RTOS_GET_MS() - focusGainedTS >= WIDGET_FOCUS_TIMEOUT / 2) - // && !FAST_BLINK_ON_PHASE) { - // return; - // } dc->drawRect(0, 0, width(), height(), 2, STASHED, COLOR_THEME_FOCUS); } } @@ -99,21 +80,7 @@ void Widget::paint(BitmapBuffer * dc) #if defined(HARDWARE_KEYS) void Widget::onEvent(event_t event) { - TRACE("### event = 0x%x ###", event); - if (!fullscreen) { - if (event == EVT_KEY_BREAK(KEY_EXIT)) { - // [EXIT] -> exit focus mode (if not fullscreen) - // killEvents(event); - // ViewMain::instance()->setFocus(); - return; - } - // Forward the rest to the parent class - Button::onEvent(event); - } - // In fullscreen mode, we react only to that one key: - // [RTN / EXIT LONG] -> exit fullscreen mode - else if (EVT_KEY_LONG(KEY_EXIT) == event) { - // killEvents(event); + if (fullscreen && (EVT_KEY_LONG(KEY_EXIT) == event)) { setFullscreen(false); } } @@ -148,6 +115,11 @@ void Widget::setFullscreen(bool enable) // re-enable scroll chaining (sliding main view) lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_CHAIN_HOR); lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_CHAIN_VER); + + // exit editing mode + lv_group_set_editing(lv_group_get_default(), false); + + onFullscreen(enable); } // Enter Fullscreen Mode else { @@ -167,9 +139,19 @@ void Widget::setFullscreen(bool enable) // disable scroll chaining (sliding main view) lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_SCROLL_CHAIN_HOR); lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_SCROLL_CHAIN_VER); + + // set group in editing mode (keys LEFT / RIGHT) + lv_group_set_editing(lv_group_get_default(), true); + + onFullscreen(enable); } } +void Widget::onLongPress() +{ + if (!fullscreen) Button::onLongPress(); +} + std::list & getRegisteredWidgets() { static std::list widgets; diff --git a/radio/src/gui/colorlcd/widget.h b/radio/src/gui/colorlcd/widget.h index 21c4961a1..81fa43e96 100644 --- a/radio/src/gui/colorlcd/widget.h +++ b/radio/src/gui/colorlcd/widget.h @@ -83,7 +83,6 @@ class Widget : public Button #endif // Window interface - void checkEvents() override; #if defined(HARDWARE_KEYS) void onEvent(event_t event) override; #endif @@ -108,6 +107,9 @@ class Widget : public Button PersistentData * persistentData; uint32_t focusGainedTS = 0; bool fullscreen = false; + + void onLongPress() override; + virtual void onFullscreen(bool enable) {} }; void registerWidget(const WidgetFactory * factory); diff --git a/radio/src/lua/interface.cpp b/radio/src/lua/interface.cpp index 3ae5c9d21..d05f06ca4 100644 --- a/radio/src/lua/interface.cpp +++ b/radio/src/lua/interface.cpp @@ -24,9 +24,13 @@ #include #include #include + #include "opentx.h" #include "bin_allocator.h" + #include "lua_api.h" +#include "lua_event.h" + #include "sdcard.h" #include "api_filesystem.h" @@ -49,15 +53,9 @@ extern "C" { #define PERMANENT_SCRIPTS_MAX_INSTRUCTIONS 100 #define LUA_TASK_PERIOD_TICKS 5 // 50 ms -#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 +// #if defined(HARDWARE_TOUCH) +// #include "touch.h" +// #endif // Since we may not run FG every time, keep the events in a buffer event_t events[EVENT_BUFFER_SIZE] = { 0 }; @@ -148,30 +146,6 @@ static void luaHook(lua_State * L, lua_Debug *ar) #endif // #if defined(LUA_ALLOCATOR_TRACER) } -#if defined(COLORLCD) -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); -} -#endif - -void luaEmptyEventBuffer() -{ - memclear(&events, sizeof(events)); -#if defined(HARDWARE_TOUCH) - memclear(&touches, sizeof(touches)); -#endif -} - #if defined(LUA_MODEL_SCRIPTS) void luaGetInputs(ScriptInputsOutputs & sid) { @@ -988,7 +962,7 @@ void luaExec(const char * filename) static bool resumeLua(bool init, bool allowLcdUsage) { static uint8_t idx; - static event_t evt = 0; + static LuaEventData evt; if (init) idx = 0; bool scriptWasRun = false; @@ -1021,13 +995,8 @@ static bool resumeLua(bool init, bool allowLcdUsage) if (ref == SCRIPT_STANDALONE) { // Pull a new event from the buffer - evt = events[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); + luaNextEvent(&evt); + if (evt.event == EVT_KEY_LONG(KEY_EXIT)) { luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS; } } @@ -1044,65 +1013,24 @@ static bool resumeLua(bool init, bool allowLcdUsage) if (allowLcdUsage) { #if defined(PCBTARANIS) - if ((menuHandlers[menuLevel] == menuViewTelemetry && ref == SCRIPT_TELEMETRY_FIRST + s_frsky_view) || ref == SCRIPT_STANDALONE) { + if ((menuHandlers[menuLevel] == menuViewTelemetry && + ref == SCRIPT_TELEMETRY_FIRST + s_frsky_view) || + ref == SCRIPT_STANDALONE) { #else if (ref == SCRIPT_STANDALONE) { #endif // Pull a new event from the buffer - evt = events[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 + luaNextEvent(&evt); + lua_rawgeti(lsScripts, LUA_REGISTRYINDEX, sid.run); - lua_pushunsigned(lsScripts, evt); + lua_pushunsigned(lsScripts, evt.event); 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; - } - } + if (IS_TOUCH_EVENT(evt.event)) { + luaPushTouchEventTable(lsScripts, &evt); 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; @@ -1218,7 +1146,7 @@ static bool resumeLua(bool init, bool allowLcdUsage) luaError(lsScripts, sid.state); } - if (evt == EVT_KEY_LONG(KEY_EXIT)) { + if (evt.event == EVT_KEY_LONG(KEY_EXIT)) { TRACE("Script force exit"); // killEvents(evt); luaEmptyEventBuffer(); @@ -1226,8 +1154,8 @@ static bool resumeLua(bool init, bool allowLcdUsage) } #if defined(KEYS_GPIO_REG_MENU) // TODO find another key and add a #define - else if (evt == EVT_KEY_LONG(KEY_MENU)) { - killEvents(evt); + else if (evt.event == EVT_KEY_LONG(KEY_MENU)) { + killEvents(evt.event); luaEmptyEventBuffer(); luaDisplayStatistics = !luaDisplayStatistics; } @@ -1262,14 +1190,7 @@ bool luaTask(event_t evt, bool allowLcdUsage) bool scriptWasRun = false; // Add event to buffer - if (evt != 0) { - for (int i = 0; i < EVENT_BUFFER_SIZE; i++) { - if (events[i] == 0) { - events[i] = evt; - break; - } - } - } + if (evt != 0) { luaPushEvent(evt); } // For preemption luaCycleStart = get_tmr10ms(); diff --git a/radio/src/lua/lua_api.h b/radio/src/lua/lua_api.h index 38ffe4e74..77d05f6f2 100644 --- a/radio/src/lua/lua_api.h +++ b/radio/src/lua/lua_api.h @@ -61,9 +61,6 @@ extern lua_State * lsScripts; extern bool luaLcdAllowed; -#define EVENT_BUFFER_SIZE 4 -extern event_t events[EVENT_BUFFER_SIZE]; - #if defined(COLORLCD) extern lua_State * lsWidgets; extern uint32_t luaExtraMemoryUsage; @@ -251,19 +248,19 @@ 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; -}; +// #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 +// extern LuaTouchData touches[EVENT_BUFFER_SIZE]; +// #endif #else // defined(LUA) diff --git a/radio/src/lua/lua_event.cpp b/radio/src/lua/lua_event.cpp new file mode 100644 index 000000000..5e7991570 --- /dev/null +++ b/radio/src/lua/lua_event.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "lua_event.h" +#include "opentx_helpers.h" +#include "timers_driver.h" +#include "keys.h" + +extern "C" { + #include "lua.h" +}; + +#define EVT_TOUCH_SWIPE_LOCK 4 +#define EVT_TOUCH_SWIPE_SPEED 60 +#define EVT_TOUCH_SWIPE_TIMEOUT 50 + +static tmr10ms_t _swipeTimeOut = 0; + +static LuaEventData _lua_event_buffer[EVENT_BUFFER_SIZE]; + +LuaEventData::LuaEventData() +{ + memclear(this, sizeof(LuaEventData)); +} + +void luaPushEvent(event_t evt) +{ + for (int i = 0; i < EVENT_BUFFER_SIZE; i++) { + if (_lua_event_buffer[i].event == 0) { + _lua_event_buffer[i].event = evt; + return; + } + } +} + +void luaNextEvent(LuaEventData* evt) +{ + if (!evt) return; + *evt = _lua_event_buffer[0]; + + if (evt->event != 0) { + size_t len = sizeof(_lua_event_buffer) - sizeof(LuaEventData); + memmove(_lua_event_buffer, _lua_event_buffer + 1, len); + memclear(_lua_event_buffer + (EVENT_BUFFER_SIZE - 1), + sizeof(EVENT_BUFFER_SIZE)); + } +} + +void luaEmptyEventBuffer() +{ + memclear(_lua_event_buffer, sizeof(_lua_event_buffer)); +} + +// Look for a slot in the event buffer that is either unused (zero) or matches event +LuaEventData* luaGetEventSlot(event_t event) +{ + for (int i = 0; i < EVENT_BUFFER_SIZE; i++) { + if (_lua_event_buffer[i].event == event || _lua_event_buffer[i].event == 0) + return &_lua_event_buffer[i]; + } + + return nullptr; +} + +static void l_pushtableint(lua_State* ls, const char * key, int value) +{ + lua_pushstring(ls, key); + lua_pushinteger(ls, value); + lua_settable(ls, -3); +} + +static void l_pushtablebool(lua_State* ls, const char * key, bool value) +{ + lua_pushstring(ls, key); + lua_pushboolean(ls, value); + lua_settable(ls, -3); +} + +void luaPushTouchEventTable(lua_State* ls, LuaEventData* evt) +{ + lua_newtable(ls); + l_pushtableint(ls, "x", evt->touchX); + l_pushtableint(ls, "y", evt->touchY); + l_pushtableint(ls, "tapCount", evt->tapCount); + + if (evt->event == EVT_TOUCH_SLIDE) { + l_pushtableint(ls, "startX", evt->startX); + l_pushtableint(ls, "startY", evt->startY); + l_pushtableint(ls, "slideX", evt->slideX); + l_pushtableint(ls, "slideY", evt->slideY); + + // Do we have a swipe? Only one at a time! + if (get_tmr10ms() > _swipeTimeOut) { + coord_t absX = (evt->slideX < 0) ? -(evt->slideX) : evt->slideX; + coord_t absY = (evt->slideY < 0) ? -(evt->slideY) : evt->slideY; + bool swiped = false; + + if (absX > EVT_TOUCH_SWIPE_LOCK * absY) { + if ((swiped = (evt->slideX > EVT_TOUCH_SWIPE_SPEED))) + l_pushtablebool(ls, "swipeRight", true); + else if ((swiped = (evt->slideX < -EVT_TOUCH_SWIPE_SPEED))) + l_pushtablebool(ls, "swipeLeft", true); + } else if (absY > EVT_TOUCH_SWIPE_LOCK * absX) { + if ((swiped = (evt->slideY > EVT_TOUCH_SWIPE_SPEED))) + l_pushtablebool(ls, "swipeDown", true); + else if ((swiped = (evt->slideY < -EVT_TOUCH_SWIPE_SPEED))) + l_pushtablebool(ls, "swipeUp", true); + } + + if (swiped) _swipeTimeOut = get_tmr10ms() + EVT_TOUCH_SWIPE_TIMEOUT; + } + } +} diff --git a/radio/src/lua/lua_event.h b/radio/src/lua/lua_event.h new file mode 100644 index 000000000..f3cb40d60 --- /dev/null +++ b/radio/src/lua/lua_event.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "opentx_types.h" + +#define EVENT_BUFFER_SIZE 4 + +struct LuaEventData { + 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 + LuaEventData(); +}; + +void luaPushEvent(event_t evt); +void luaNextEvent(LuaEventData* evt); +void luaEmptyEventBuffer(); + +// Look for a slot in the event buffer that is either unused (zero) or matches event +LuaEventData* luaGetEventSlot(event_t event = 0); + +struct lua_State; +typedef struct lua_State lua_State; + +void luaPushTouchEventTable(lua_State* ls, LuaEventData* evt); + diff --git a/radio/src/lua/lua_touch.h b/radio/src/lua/lua_touch.h new file mode 100644 index 000000000..5b3dc432a --- /dev/null +++ b/radio/src/lua/lua_touch.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +struct LuaEventData { + 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 + EventData(); +}; + diff --git a/radio/src/lua/lua_widget.cpp b/radio/src/lua/lua_widget.cpp new file mode 100644 index 000000000..f771f57a2 --- /dev/null +++ b/radio/src/lua/lua_widget.cpp @@ -0,0 +1,358 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "lua_widget.h" +#include "lua_widget_factory.h" + +#include "lua_api.h" +#include "lua_event.h" +#include "api_colorlcd.h" +#include "draw_functions.h" + +#define MAX_INSTRUCTIONS (20000/100) + +#if defined(HARDWARE_TOUCH) +tmr10ms_t LuaEventHandler::swipeTimeOut = 0; +coord_t LuaEventHandler::_startX; +coord_t LuaEventHandler::_startY; +bool LuaEventHandler::_sliding = false; +#endif + +void LuaEventHandler::event_cb(lv_event_t* e) +{ + auto obj = lv_event_get_target(e); + auto win = (Window*)lv_obj_get_user_data(obj); + if (!win) return; + + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_PRESSED || code == LV_EVENT_PRESSING) { + + lv_area_t obj_coords; + lv_obj_get_coords(obj, &obj_coords); + + lv_point_t point_act; + lv_indev_t* click_source = (lv_indev_t*)lv_event_get_param(e); + lv_indev_get_point(click_source, &point_act); + + // Ignore event from keypad + if (point_act.x < 0 || point_act.y < 0) return; + + lv_point_t rel_pos; + rel_pos.x = point_act.x - obj_coords.x1; + rel_pos.y = point_act.y - obj_coords.y1; + + if (code == LV_EVENT_PRESSING) { + lv_point_t vect_act; + lv_indev_get_vect(click_source, &vect_act); + + if ((abs(vect_act.x) >= SLIDE_RANGE) || (abs(vect_act.y) >= SLIDE_RANGE)) + _sliding = true; + + if (!_sliding) return; + TRACE_WINDOWS("LuaWidget touch slide"); + + // If we already have a SLIDE going, then accumulate slide values instead + // of allocating an empty slot + LuaEventData* es = luaGetEventSlot(EVT_TOUCH_SLIDE); + + if (es) { + es->event = EVT_TOUCH_SLIDE; + es->touchX = rel_pos.x; + es->touchY = rel_pos.y; + es->startX = _startX; + es->startY = _startY; + es->slideX += vect_act.x; + es->slideY += vect_act.y; + TRACE("EVT_TOUCH_SLIDE [%d,%d]", rel_pos.x, rel_pos.y); + } + } else { + LuaEventData* es = luaGetEventSlot(); + if (es) { + es->event = EVT_TOUCH_FIRST; + es->touchX = rel_pos.x; + es->touchY = rel_pos.y; + TRACE("EVT_TOUCH_FIRST [%d,%d]", rel_pos.x, rel_pos.y); + } + + _startX = rel_pos.x; + _startY = rel_pos.y; + } + } else if (code == LV_EVENT_KEY) { + uint32_t key = *(uint32_t*)lv_event_get_param(e); + if (key == LV_KEY_LEFT) { + win->onEvent(EVT_ROTARY_LEFT); + } else if (key == LV_KEY_RIGHT) { + win->onEvent(EVT_ROTARY_RIGHT); + } + } +} + +void LuaEventHandler::onClicked() +{ + auto click_source = lv_indev_get_act(); + bool is_pointer = lv_indev_get_type(click_source) == LV_INDEV_TYPE_POINTER; + if (is_pointer) { + + lv_point_t point_act; + lv_indev_get_point(click_source, &point_act); + + LuaEventData* es = luaGetEventSlot(); + if (!es) return; + + es->event = EVT_TOUCH_TAP; + es->touchX = point_act.x; + es->touchY = point_act.y; + es->tapCount = 1; + _sliding = false; + } else { + luaPushEvent(EVT_KEY_BREAK(KEY_ENTER)); + } +} + +void LuaEventHandler::onCancel() +{ + luaPushEvent(EVT_KEY_BREAK(KEY_EXIT)); +} + +void LuaEventHandler::onEvent(event_t event) +{ + // if (event == EVT_KEY_LONG(KEY_EXIT)) { + // // Exits widget fullscreen / standalone LUA + // lv_indev_wait_release(lv_indev_get_act()); + // } + + luaPushEvent(event); +} + +void LuaEventHandler::setupHandler(Window* w) +{ + lv_obj_t* obj = w->getLvObj(); + lv_obj_add_event_cb(obj, LuaEventHandler::event_cb, LV_EVENT_ALL, nullptr); +} + +void LuaEventHandler::removeHandler(Window* w) +{ + lv_obj_t* obj = w->getLvObj(); + lv_obj_remove_event_cb(obj, LuaEventHandler::event_cb); +} + +LuaWidget::LuaWidget(const WidgetFactory* factory, Window* parent, + const rect_t& rect, WidgetPersistentData* persistentData, + int luaWidgetDataRef) : + Widget(factory, parent, rect, persistentData), + luaWidgetDataRef(luaWidgetDataRef), + errorMessage(nullptr) +{ +} + +LuaWidget::~LuaWidget() +{ + luaL_unref(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef); + free(errorMessage); +} + +void LuaWidget::onClicked() +{ + if (!fullscreen) { + Button::onClicked(); + return; + } + + LuaEventHandler::onClicked(); +} + +void LuaWidget::onCancel() +{ + if (!fullscreen) { + Button::onCancel(); + return; + } + + LuaEventHandler::onCancel(); +} + +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 +} + +static void l_pushtableint(const char * key, int value) +{ + lua_pushstring(lsWidgets, key); + lua_pushinteger(lsWidgets, value); + lua_settable(lsWidgets, -3); +} + +void LuaWidget::update() +{ + Widget::update(); + + if (lsWidgets == 0 || errorMessage) return; + LuaWidgetFactory * lua_factory = (LuaWidgetFactory *)factory; + + luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS); + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, lua_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::onFullscreen(bool enable) +{ + if (enable) { + setupHandler(this); + } else { + removeHandler(this); + luaEmptyEventBuffer(); + } +} + +void LuaWidget::setErrorMessage(const char * funcName) +{ + const char* lua_err = lua_tostring(lsWidgets, -1); + TRACE("Error in widget %s %s function: %s", factory->getName(), funcName, lua_err); + TRACE("Widget disabled"); + + size_t err_len = snprintf(NULL, 0, "ERROR in %s: %s", funcName, lua_err); + errorMessage = (char*)malloc(err_len + 1); + + if (errorMessage) { + snprintf(errorMessage, err_len, "ERROR in %s: %s", funcName, lua_err); + errorMessage[err_len] = '\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 + LuaEventData evt; + luaNextEvent(&evt); + + if (fullscreen) { + lua_pushinteger(lsWidgets, evt.event); + } + else + lua_pushnil(lsWidgets); + +#if defined(HARDWARE_TOUCH) + if (fullscreen && IS_TOUCH_EVENT(evt.event)) { + luaPushTouchEventTable(lsWidgets, &evt); + } else +#endif + lua_pushnil(lsWidgets); + + // 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; + } +} + +void LuaWidget::onEvent(event_t event) +{ + if (fullscreen) { + LuaEventHandler::onEvent(event); + } + Widget::onEvent(event); +} diff --git a/radio/src/lua/lua_widget.h b/radio/src/lua/lua_widget.h new file mode 100644 index 000000000..e5e54026c --- /dev/null +++ b/radio/src/lua/lua_widget.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "window.h" +#include "widget.h" +#include "lua_api.h" + +#include "opentx_types.h" + +class LuaEventHandler +{ +#if defined(HARDWARE_TOUCH) + static tmr10ms_t swipeTimeOut; + static bool _sliding; + static coord_t _startX; + static coord_t _startY; +#endif + static void event_cb(lv_event_t* e); + +protected: + void onClicked(); + void onCancel(); + void onEvent(event_t event); + +public: + LuaEventHandler() = default; + void setupHandler(Window* w); + void removeHandler(Window* w); +}; + +class LuaWidget : public Widget, public LuaEventHandler +{ + friend class LuaWidgetFactory; + + int luaWidgetDataRef; + char* errorMessage; + bool refreshed = false; + + // Window interface + void onClicked() override; + void onCancel() override; + void checkEvents() override; + + // Widget interface + void onFullscreen(bool enable) override; + + void setErrorMessage(const char* funcName); + + public: + LuaWidget(const WidgetFactory* factory, Window* parent, const rect_t& rect, + WidgetPersistentData* persistentData, int luaWidgetDataRef); + ~LuaWidget() override; + +#if defined(DEBUG_WINDOWS) + std::string getName() const override { return "LuaWidget"; } +#endif + + // Window interface + void onEvent(event_t event) override; + + // Widget interface + const char* getErrorMessage() const override; + void update() override; + void background() override; + + // Calls LUA widget 'refresh' method + void refresh(BitmapBuffer* dc) override; +}; diff --git a/radio/src/lua/lua_widget_factory.cpp b/radio/src/lua/lua_widget_factory.cpp new file mode 100644 index 000000000..f2bf4bb80 --- /dev/null +++ b/radio/src/lua/lua_widget_factory.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "lua_widget_factory.h" +#include "lua_widget.h" + +#include "lua_api.h" +#include "api_colorlcd.h" + +#define MAX_INSTRUCTIONS (20000/100) + +static void l_pushtableint(const char * key, int value) +{ + lua_pushstring(lsWidgets, key); + lua_pushinteger(lsWidgets, value); + lua_settable(lsWidgets, -3); +} + +LuaWidgetFactory::LuaWidgetFactory(const char* name, ZoneOption* widgetOptions, + int createFunction) : + WidgetFactory(name, widgetOptions), + createFunction(createFunction), + updateFunction(0), + refreshFunction(0), + backgroundFunction(0) +{ +} + +LuaWidgetFactory::~LuaWidgetFactory() { unregisterWidget(this); } + +Widget* LuaWidgetFactory::create(Window* parent, const rect_t& rect, + Widget::PersistentData* persistentData, + bool init) const +{ + 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); + // Zero-terminated string for Lua + char str[LEN_ZONE_OPTION_STRING + 1] = {0}; + 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; +} diff --git a/radio/src/lua/lua_widget_factory.h b/radio/src/lua/lua_widget_factory.h new file mode 100644 index 000000000..5a646194b --- /dev/null +++ b/radio/src/lua/lua_widget_factory.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "gui/colorlcd/widget.h" + +class LuaWidgetFactory : public WidgetFactory +{ + friend void luaLoadWidgetCallback(); + friend class LuaWidget; + + public: + LuaWidgetFactory(const char* name, ZoneOption* widgetOptions, + int createFunction); + ~LuaWidgetFactory(); + + Widget* create(Window* parent, const rect_t& rect, + Widget::PersistentData* persistentData, + bool init = true) const override; + + protected: + int createFunction; + int updateFunction; + int refreshFunction; + int backgroundFunction; +}; diff --git a/radio/src/lua/widgets.cpp b/radio/src/lua/widgets.cpp index 5ede3d0ba..5f1e56e27 100644 --- a/radio/src/lua/widgets.cpp +++ b/radio/src/lua/widgets.cpp @@ -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); } diff --git a/radio/src/targets/common/arm/stm32/timers_driver.h b/radio/src/targets/common/arm/stm32/timers_driver.h index 2c39eb9cc..638dff109 100644 --- a/radio/src/targets/common/arm/stm32/timers_driver.h +++ b/radio/src/targets/common/arm/stm32/timers_driver.h @@ -42,7 +42,7 @@ void watchdogSuspend(uint32_t timeout); #include "opentx_types.h" -extern volatile tmr10ms_t g_tmr10ms; +extern "C" volatile tmr10ms_t g_tmr10ms; static inline tmr10ms_t get_tmr10ms() { diff --git a/radio/src/targets/simu/simulcd.cpp b/radio/src/targets/simu/simulcd.cpp index f87c85c9c..b49f7f6fe 100644 --- a/radio/src/targets/simu/simulcd.cpp +++ b/radio/src/targets/simu/simulcd.cpp @@ -178,8 +178,8 @@ static void simuRefreshLcd(lv_disp_drv_t * disp_drv, uint16_t *buffer, const rec lv_area_t refr_area; lv_area_copy(&refr_area, &disp->inv_areas[i]); - TRACE("{%d,%d,%d,%d}", refr_area.x1, - refr_area.y1, refr_area.x2, refr_area.y2); + // TRACE("{%d,%d,%d,%d}", refr_area.x1, + // refr_area.y1, refr_area.x2, refr_area.y2); // _rotate_area_180(refr_area); _copy_screen_area(dst, src, refr_area);