First working LUA widget: Timer2
This commit is contained in:
committed by
Raphael Coeffic
parent
ca36c9595e
commit
72a7409d10
@@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -33,4 +33,5 @@
|
||||
|
||||
constexpr coord_t INVERT_BOX_MARGIN = 2;
|
||||
|
||||
extern BitmapBuffer* luaLcdBuffer;
|
||||
extern bool luaLcdAllowed;
|
||||
extern BitmapBuffer * luaLcdBuffer;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user