First working LUA widget: Timer2

This commit is contained in:
Raphael Coeffic
2021-05-06 12:55:59 +02:00
committed by Raphael Coeffic
parent ca36c9595e
commit 72a7409d10
8 changed files with 171 additions and 155 deletions
+7 -5
View File
@@ -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()
{
}
+8 -7
View File
@@ -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;
}
+2 -1
View File
@@ -33,4 +33,5 @@
constexpr coord_t INVERT_BOX_MARGIN = 2;
extern BitmapBuffer* luaLcdBuffer;
extern bool luaLcdAllowed;
extern BitmapBuffer * luaLcdBuffer;
+1 -1
View File
@@ -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;
-6
View File
@@ -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)))
+112
View File
@@ -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);
}
}
+39 -114
View File
@@ -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
+2 -21
View File
@@ -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