From 72a7409d10135f2ce776106592c518c2b0c1639e Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Sat, 24 Apr 2021 09:44:15 +0200 Subject: [PATCH] First working LUA widget: Timer2 --- radio/src/gui/colorlcd/widget.h | 12 +-- radio/src/lua/api_colorlcd.cpp | 15 ++-- radio/src/lua/api_colorlcd.h | 3 +- radio/src/lua/interface.cpp | 2 +- radio/src/lua/lua_api.h | 6 -- radio/src/lua/themes.cpp | 112 +++++++++++++++++++++++ radio/src/lua/widgets.cpp | 153 ++++++++------------------------ radio/src/opentx.cpp | 23 +---- 8 files changed, 171 insertions(+), 155 deletions(-) create mode 100644 radio/src/lua/themes.cpp diff --git a/radio/src/gui/colorlcd/widget.h b/radio/src/gui/colorlcd/widget.h index 279e662c4..5bfcb7b2c 100644 --- a/radio/src/gui/colorlcd/widget.h +++ b/radio/src/gui/colorlcd/widget.h @@ -48,10 +48,6 @@ class Widget : public Window ~Widget() override = default; - virtual void update() - { - } - inline const WidgetFactory * getFactory() const { return factory; @@ -81,7 +77,13 @@ class Widget : public Window { return persistentData; } - + + // Called when the widget options have changed + virtual void update() + { + } + + // Called at regular time interval, even if the widget cannot be seen virtual void background() { } diff --git a/radio/src/lua/api_colorlcd.cpp b/radio/src/lua/api_colorlcd.cpp index f1d173a84..93aa6f325 100644 --- a/radio/src/lua/api_colorlcd.cpp +++ b/radio/src/lua/api_colorlcd.cpp @@ -26,8 +26,8 @@ #include "api_colorlcd.h" -BitmapBuffer* luaLcdBuffer = nullptr; - +bool luaLcdAllowed = false; +BitmapBuffer* luaLcdBuffer = nullptr; /*luadoc @function lcd.refresh() @@ -252,17 +252,18 @@ static int luaLcdDrawTimer(lua_State *L) if (!luaLcdAllowed || !luaLcdBuffer) return 0; -#if 0 // TODO int x = luaL_checkinteger(L, 1); int y = luaL_checkinteger(L, 2); int seconds = luaL_checkinteger(L, 3); unsigned int att = luaL_optunsigned(L, 4, 0); - if (att & SHADOWED) { - luaLcdBuffer->drawTimer(x+1, y+1, seconds, (att & 0xFFFF) | LEFT); + bool shadowed = att & SHADOWED; + att = (att & 0xFFFF) | COLOR(COLOR_VAL(att)); + + if (shadowed) { + drawTimer(luaLcdBuffer, x+1, y+1, seconds, (att & 0xFFFF) | LEFT); } - luaLcdBuffer->drawTimer(x, y, seconds, att | LEFT); -#endif + drawTimer(luaLcdBuffer, x, y, seconds, att | LEFT); return 0; } diff --git a/radio/src/lua/api_colorlcd.h b/radio/src/lua/api_colorlcd.h index 8eb295f59..ae5f17109 100644 --- a/radio/src/lua/api_colorlcd.h +++ b/radio/src/lua/api_colorlcd.h @@ -33,4 +33,5 @@ constexpr coord_t INVERT_BOX_MARGIN = 2; -extern BitmapBuffer* luaLcdBuffer; +extern bool luaLcdAllowed; +extern BitmapBuffer * luaLcdBuffer; diff --git a/radio/src/lua/interface.cpp b/radio/src/lua/interface.cpp index 42fbfd849..a0100e29a 100644 --- a/radio/src/lua/interface.cpp +++ b/radio/src/lua/interface.cpp @@ -29,6 +29,7 @@ #include "sdcard.h" #if defined(LIBOPENUI) + #include "api_colorlcd.h" #include "libopenui.h" #else #include "libopenui/src/libopenui_file.h" @@ -50,7 +51,6 @@ ScriptInputsOutputs scriptInputsOutputs[MAX_SCRIPTS]; ScriptInternalData standaloneScript; uint16_t maxLuaInterval = 0; uint16_t maxLuaDuration = 0; -bool luaLcdAllowed; uint8_t instructionsPercent = 0; char lua_warning_info[LUA_WARNING_INFO_LEN+1]; struct our_longjmp * global_lj = 0; diff --git a/radio/src/lua/lua_api.h b/radio/src/lua/lua_api.h index 4457794ee..944a37507 100644 --- a/radio/src/lua/lua_api.h +++ b/radio/src/lua/lua_api.h @@ -55,12 +55,6 @@ extern uint32_t luaExtraMemoryUsage; void luaInit(); void luaInitThemesAndWidgets(); -//TODO FIXME -#if 1 -#define LUA_INIT_THEMES_AND_WIDGETS() -#else -#define LUA_INIT_THEMES_AND_WIDGETS() luaInitThemesAndWidgets() -#endif #define lua_registernumber(L, n, i) (lua_pushnumber(L, (i)), lua_setglobal(L, (n))) #define lua_registerint(L, n, i) (lua_pushinteger(L, (i)), lua_setglobal(L, (n))) diff --git a/radio/src/lua/themes.cpp b/radio/src/lua/themes.cpp new file mode 100644 index 000000000..3ea68f2e9 --- /dev/null +++ b/radio/src/lua/themes.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "libopenui.h" +#include "lua_api.h" + +class LuaTheme: public Theme +{ + friend void luaLoadThemeCallback(); + + public: + LuaTheme(const char * name, ZoneOption * options): + Theme(name, options), + loadFunction(0), + drawBackgroundFunction(0), + drawTopbarBackgroundFunction(0), + drawAlertBoxFunction(0) + { + } + + virtual void load() const + { + luaLcdAllowed = true; + exec(loadFunction); + } + + virtual void drawBackground() const + { + exec(drawBackgroundFunction); + } + + void drawTopbarBackground(uint8_t icon) const override + { + exec(drawTopbarBackgroundFunction); + } + +#if 0 + virtual void drawAlertBox(const char * title, const char * text, const char * action) const + { + exec(drawAlertBoxFunction); + } +#endif + + protected: + int loadFunction; + int drawBackgroundFunction; + int drawTopbarBackgroundFunction; + int drawAlertBoxFunction; +}; + +void luaLoadThemeCallback() +{ + TRACE("luaLoadThemeCallback()"); + const char * name=NULL; + int themeOptions=0, loadFunction=0, drawBackgroundFunction=0, drawTopbarBackgroundFunction=0; + + luaL_checktype(lsWidgets, -1, LUA_TTABLE); + + for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) { + const char * key = lua_tostring(lsWidgets, -2); + if (!strcmp(key, "name")) { + name = luaL_checkstring(lsWidgets, -1); + } + else if (!strcmp(key, "options")) { + themeOptions = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + else if (!strcmp(key, "load")) { + loadFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + else if (!strcmp(key, "drawBackground")) { + drawBackgroundFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + else if (!strcmp(key, "drawTopbarBackground")) { + drawTopbarBackgroundFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + } + + if (name) { + ZoneOption * options = NULL; + if (themeOptions) { + options = createOptionsArray(themeOptions, MAX_THEME_OPTIONS); + if (!options) + return; + } + LuaTheme * theme = new LuaTheme(name, options); + theme->loadFunction = loadFunction; + theme->drawBackgroundFunction = drawBackgroundFunction; + theme->drawTopbarBackgroundFunction = drawTopbarBackgroundFunction; // NOSONAR + TRACE("Loaded Lua theme %s", name); + } +} diff --git a/radio/src/lua/widgets.cpp b/radio/src/lua/widgets.cpp index 3e902a8a1..afb0f27da 100644 --- a/radio/src/lua/widgets.cpp +++ b/radio/src/lua/widgets.cpp @@ -23,6 +23,9 @@ #include "opentx.h" #include "bin_allocator.h" #include "lua_api.h" +#include "widget.h" +#include "libopenui_file.h" +#include "api_colorlcd.h" #define WIDGET_SCRIPTS_MAX_INSTRUCTIONS (10000/100) #define MANUAL_SCRIPTS_MAX_INSTRUCTIONS (20000/100) @@ -30,7 +33,6 @@ lua_State * lsWidgets = NULL; -#if 0 extern int custom_lua_atpanic(lua_State *L); #define LUA_WIDGET_FILENAME "/main.lua" @@ -159,122 +161,35 @@ ZoneOption * createOptionsArray(int reference, uint8_t maxOptions) return options; } -class LuaTheme: public Theme -{ - friend void luaLoadThemeCallback(); - - public: - LuaTheme(const char * name, ZoneOption * options): - Theme(name, options), - loadFunction(0), - drawBackgroundFunction(0), - drawTopbarBackgroundFunction(0), - drawAlertBoxFunction(0) - { - } - - virtual void load() const - { - luaLcdAllowed = true; - exec(loadFunction); - } - - virtual void drawBackground() const - { - exec(drawBackgroundFunction); - } - - void drawTopbarBackground(uint8_t icon) const override - { - exec(drawTopbarBackgroundFunction); - } - -#if 0 - virtual void drawAlertBox(const char * title, const char * text, const char * action) const - { - exec(drawAlertBoxFunction); - } -#endif - - protected: - int loadFunction; - int drawBackgroundFunction; - int drawTopbarBackgroundFunction; - int drawAlertBoxFunction; -}; - -void luaLoadThemeCallback() -{ - TRACE("luaLoadThemeCallback()"); - const char * name=NULL; - int themeOptions=0, loadFunction=0, drawBackgroundFunction=0, drawTopbarBackgroundFunction=0; - - luaL_checktype(lsWidgets, -1, LUA_TTABLE); - - for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) { - const char * key = lua_tostring(lsWidgets, -2); - if (!strcmp(key, "name")) { - name = luaL_checkstring(lsWidgets, -1); - } - else if (!strcmp(key, "options")) { - themeOptions = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); - lua_pushnil(lsWidgets); - } - else if (!strcmp(key, "load")) { - loadFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); - lua_pushnil(lsWidgets); - } - else if (!strcmp(key, "drawBackground")) { - drawBackgroundFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); - lua_pushnil(lsWidgets); - } - else if (!strcmp(key, "drawTopbarBackground")) { - drawTopbarBackgroundFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); - lua_pushnil(lsWidgets); - } - } - - if (name) { - ZoneOption * options = NULL; - if (themeOptions) { - options = createOptionsArray(themeOptions, MAX_THEME_OPTIONS); - if (!options) - return; - } - LuaTheme * theme = new LuaTheme(name, options); - theme->loadFunction = loadFunction; - theme->drawBackgroundFunction = drawBackgroundFunction; - theme->drawTopbarBackgroundFunction = drawTopbarBackgroundFunction; // NOSONAR - TRACE("Loaded Lua theme %s", name); - } -} - class LuaWidget: public Widget { public: - LuaWidget(const WidgetFactory * factory, const Zone & zone, Widget::PersistentData * persistentData, int widgetData): - Widget(factory, zone, persistentData), - widgetData(widgetData), + LuaWidget(const WidgetFactory * factory, FormGroup * 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, widgetData); + luaL_unref(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef); free(errorMessage); } + // Window interface + void paint(BitmapBuffer * dc) override; + + // Widget interface + const char * getErrorMessage() const override; void update() override; - - void refresh() override; - void background() override; - const char * getErrorMessage() const override; + // Calls LUA widget 'refresh' method + void refresh(BitmapBuffer* dc); protected: - int widgetData; + int luaWidgetDataRef; char * errorMessage; void setErrorMessage(const char * funcName); @@ -302,7 +217,7 @@ class LuaWidgetFactory: public WidgetFactory { } - Widget * create(const Zone & zone, Widget::PersistentData * persistentData, bool init=true) const override + Widget * create(FormGroup * parent, const rect_t & rect, Widget::PersistentData * persistentData, bool init=true) const override { if (lsWidgets == 0) return 0; if (init) { @@ -313,10 +228,10 @@ class LuaWidgetFactory: public WidgetFactory lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, createFunction); lua_newtable(lsWidgets); - l_pushtableint("x", zone.x); - l_pushtableint("y", zone.y); - l_pushtableint("w", zone.w); - l_pushtableint("h", zone.h); + l_pushtableint("x", 0); + l_pushtableint("y", 0); + l_pushtableint("w", rect.w); + l_pushtableint("h", rect.h); lua_newtable(lsWidgets); int i = 0; @@ -328,8 +243,7 @@ class LuaWidgetFactory: public WidgetFactory TRACE("Error in widget %s create() function: %s", getName(), lua_tostring(lsWidgets, -1)); } int widgetData = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); - Widget * widget = new LuaWidget(this, zone, persistentData, widgetData); - return widget; + return new LuaWidget(this, parent, rect, persistentData, widgetData); } protected: @@ -339,6 +253,11 @@ class LuaWidgetFactory: public WidgetFactory int backgroundFunction; }; +void LuaWidget::paint(BitmapBuffer * dc) +{ + refresh(dc); +} + void LuaWidget::update() { if (lsWidgets == 0 || errorMessage) return; @@ -346,7 +265,7 @@ void LuaWidget::update() luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->updateFunction); - lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, widgetData); + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef); lua_newtable(lsWidgets); int i = 0; @@ -375,23 +294,30 @@ const char * LuaWidget::getErrorMessage() const return errorMessage; } -void LuaWidget::refresh() +void LuaWidget::refresh(BitmapBuffer* dc) { if (lsWidgets == 0) return; if (errorMessage) { lcdSetColor(RED); - lcdDrawText(zone.x, zone.y, "Disabled", SMLSIZE|CUSTOM_COLOR); + dc->drawText(0, 0, "Disabled", FONT(XS) | CUSTOM_COLOR); return; } luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->refreshFunction); - lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, widgetData); + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef); + + // Enable drawing into the current LCD buffer + luaLcdBuffer = dc; + luaLcdAllowed = true; if (lua_pcall(lsWidgets, 1, 0, 0) != 0) { setErrorMessage("refresh()"); } + // Remove LCD + luaLcdAllowed = false; + luaLcdBuffer = nullptr; } void LuaWidget::background() @@ -402,7 +328,7 @@ void LuaWidget::background() LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; if (factory->backgroundFunction) { lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->backgroundFunction); - lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, widgetData); + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef); if (lua_pcall(lsWidgets, 1, 0, 0) != 0) { setErrorMessage("background()"); } @@ -556,9 +482,8 @@ void luaInitThemesAndWidgets() } UNPROTECT_LUA(); TRACE("lsWidgets %p", lsWidgets); - luaLoadFiles(THEMES_PATH, luaLoadThemeCallback); + //luaLoadFiles(THEMES_PATH, luaLoadThemeCallback); luaLoadFiles(WIDGETS_PATH, luaLoadWidgetCallback); luaDoGc(lsWidgets, true); } } -#endif \ No newline at end of file diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 88fb202d6..6e66e889f 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -1833,27 +1833,8 @@ void opentxInit() #if defined(COLORLCD) if (!globalData.unexpectedShutdown) { - // g_model.topbarData is still zero here (because it was not yet read from SDCARD), - // but we only remember the pointer to in in constructor. - // The storageReadAll() needs topbar object, so it must be created here - - // TODO topbar removed from new UI for now - // topbar = new Topbar(&g_model.topbarData); - -// #if __clang__ -// // clang does not like this at all, turn into a warning so that -Werror does not stop here -// // taking address of packed member 'topbarData' of class or structure 'ModelData' may result in an unaligned pointer value [-Werror,-Waddress-of-packed-member] -// #pragma clang diagnostic push -// #pragma clang diagnostic warning "-Waddress-of-packed-member" -// #endif -// topbar = new Topbar((Topbar::PersistentData*)(((uint8_t*)&g_model) + offsetof(ModelData,topbarData))); -// #if __clang__ -// // Restore warnings -// #pragma clang diagnostic pop -// #endif - - // lua widget state must also be prepared before the call to storageReadAll() - LUA_INIT_THEMES_AND_WIDGETS(); + // ??? lua widget state must be prepared before the call to storageReadAll() + luaInitThemesAndWidgets(); } #endif