feat(color): telemetry queues for Lua, enhance default widget options (#5926)

This commit is contained in:
philmoz
2025-03-21 10:56:07 +10:00
committed by GitHub
parent 5a0c8dbff6
commit 4f18632505
30 changed files with 1053 additions and 712 deletions
+2 -3
View File
@@ -36,7 +36,6 @@
#define BITMAP_METATABLE "BITMAP*"
BitmapBuffer* luaLcdBuffer = nullptr;
LuaWidget *runningFS = nullptr;
/*luadoc
@function lcd.refresh()
@@ -1386,8 +1385,8 @@ Exit full screen widget mode.
*/
static int luaLcdExitFullScreen(lua_State *L)
{
if (runningFS)
runningFS->closeFullscreen();
if (luaScriptManager)
luaScriptManager->exitFullscreen();
return 0;
}
+45 -35
View File
@@ -28,14 +28,11 @@
#include "api_colorlcd.h"
LuaLvglManager *luaLvglManager = nullptr;
static int luaLvglObj(lua_State *L, std::function<LvglWidgetObject*()> create, bool fullscreenOnly = false)
{
if (luaLvglManager && (!fullscreenOnly || luaLvglManager->isFullscreen())) {
if (luaScriptManager && (!fullscreenOnly || luaScriptManager->isFullscreen())) {
auto obj = create();
obj->getParams(L, 1);
obj->build(L);
obj->create(L, 1);
obj->push(L);
} else {
lua_pushnil(L);
@@ -46,24 +43,23 @@ static int luaLvglObj(lua_State *L, std::function<LvglWidgetObject*()> create, b
static int luaLvglObjEx(lua_State *L, std::function<LvglWidgetObjectBase*()> create, bool fullscreenOnly = false)
{
if (luaLvglManager && (!fullscreenOnly || luaLvglManager->isFullscreen())) {
if (luaScriptManager && (!fullscreenOnly || luaScriptManager->isFullscreen())) {
LvglWidgetObjectBase* p = nullptr;
LvglWidgetObjectBase* prevParent = nullptr;
if (lua_gettop(L) == 2) {
p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
prevParent = luaLvglManager->getTempParent();
luaLvglManager->setTempParent(p);
prevParent = luaScriptManager->getTempParent();
luaScriptManager->setTempParent(p);
}
}
auto obj = create();
obj->getParams(L, -1);
obj->build(L);
obj->create(L, -1);
obj->push(L);
if (p)
luaLvglManager->setTempParent((prevParent));
luaScriptManager->setTempParent((prevParent));
} else {
lua_pushnil(L);
}
@@ -74,8 +70,7 @@ static int luaLvglObjEx(lua_State *L, std::function<LvglWidgetObjectBase*()> cre
static int luaLvglPopup(lua_State *L, std::function<LvglWidgetObjectBase*()> create)
{
auto obj = create();
obj->getParams(L, 1);
obj->build(L);
obj->create(L, 1);
return 0;
}
@@ -100,14 +95,14 @@ static int luaLvglSet(lua_State *L)
static int luaLvglClear(lua_State *L)
{
if (luaLvglManager) {
if (luaScriptManager) {
if (lua_gettop(L) == 1) {
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
p->clear();
}
} else {
luaLvglManager->clear();
luaScriptManager->clear();
}
}
@@ -150,6 +145,15 @@ static int luaLvglDisable(lua_State *L)
return 0;
}
static int luaLvglClose(lua_State *L)
{
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
p->close();
}
return 0;
}
class LvglWidgetParams
{
public:
@@ -177,6 +181,7 @@ static void buildLvgl(lua_State *L, int srcIndex, int refIndex)
{
luaL_checktype(L, srcIndex, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, srcIndex - 1); lua_pop(L, 1)) {
auto t = lua_gettop(L);
LvglWidgetParams p(L, -1);
LvglWidgetObjectBase *obj = nullptr;
if (strcasecmp(p.type, "label") == 0)
@@ -201,7 +206,7 @@ static void buildLvgl(lua_State *L, int srcIndex, int refIndex)
obj = new LvglWidgetQRCode();
else if (strcasecmp(p.type, "box") == 0)
obj = new LvglWidgetBox();
else if (luaLvglManager->isFullscreen()) {
else if (luaScriptManager->isFullscreen()) {
if (strcasecmp(p.type, "button") == 0)
obj = new LvglWidgetTextButton();
if (strcasecmp(p.type, "momentaryButton") == 0)
@@ -236,8 +241,7 @@ static void buildLvgl(lua_State *L, int srcIndex, int refIndex)
obj = new LvglWidgetSetting();
}
if (obj) {
obj->getParams(L, -1);
obj->build(L);
obj->create(L, -1);
auto ref = obj->getRef(L);
if (p.name) {
lua_pushstring(L, p.name);
@@ -246,26 +250,27 @@ static void buildLvgl(lua_State *L, int srcIndex, int refIndex)
}
if (p.hasChildren && obj->getWindow()) {
lua_getfield(L, -1, "children");
auto prevParent = luaLvglManager->getTempParent();
luaLvglManager->setTempParent(obj);
auto prevParent = luaScriptManager->getTempParent();
luaScriptManager->setTempParent(obj);
buildLvgl(L, -1, refIndex - 3);
lua_pop(L, 1);
luaLvglManager->setTempParent(prevParent);
luaScriptManager->setTempParent(prevParent);
}
}
lua_settop(L, t); // In case of errors in build functions
}
}
static int luaLvglBuild(lua_State *L)
{
if (luaLvglManager) {
if (luaScriptManager) {
LvglWidgetObjectBase* p = nullptr;
LvglWidgetObjectBase* prevParent = nullptr;
if (lua_gettop(L) == 2) {
p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
prevParent = luaLvglManager->getTempParent();
luaLvglManager->setTempParent(p);
prevParent = luaScriptManager->getTempParent();
luaScriptManager->setTempParent(p);
}
}
@@ -274,7 +279,7 @@ static int luaLvglBuild(lua_State *L)
buildLvgl(L, -2, -1);
if (p)
luaLvglManager->setTempParent((prevParent));
luaScriptManager->setTempParent((prevParent));
} else {
lua_pushnil(L);
}
@@ -283,8 +288,8 @@ static int luaLvglBuild(lua_State *L)
static int luaLvglIsAppMode(lua_State *L)
{
if (luaLvglManager) {
lua_pushboolean(L, luaLvglManager->isAppMode());
if (luaScriptManager) {
lua_pushboolean(L, luaScriptManager->isAppMode());
} else {
lua_pushboolean(L, false);
}
@@ -293,8 +298,8 @@ static int luaLvglIsAppMode(lua_State *L)
static int luaLvglIsFullscreen(lua_State *L)
{
if (luaLvglManager) {
lua_pushboolean(L, luaLvglManager->isFullscreen());
if (luaScriptManager) {
lua_pushboolean(L, luaScriptManager->isFullscreen());
} else {
lua_pushboolean(L, false);
}
@@ -303,16 +308,16 @@ static int luaLvglIsFullscreen(lua_State *L)
static int luaLvglExitFullscreen(lua_State *L)
{
if (luaLvglManager)
luaLvglManager->exitFullscreen();
if (luaScriptManager)
luaScriptManager->exitFullscreen();
return 0;
}
static int luaLvglGetContext(lua_State *L)
{
if (luaLvglManager && luaLvglManager->getContext() != LUA_REFNIL) {
if (luaScriptManager && luaScriptManager->getContext() != LUA_REFNIL) {
// Push context tanle onto Lua stack (return object)
lua_rawgeti(L, LUA_REGISTRYINDEX, luaLvglManager->getContext());
lua_rawgeti(L, LUA_REGISTRYINDEX, luaScriptManager->getContext());
} else {
lua_pushnil(L);
}
@@ -354,8 +359,8 @@ LROT_BEGIN(lvgllib, NULL, 0)
LROT_FUNCENTRY(switch, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSwitchPicker(); }, true); })
LROT_FUNCENTRY(source, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSourcePicker(); }, true); })
// Containers
LROT_FUNCENTRY(box, [](lua_State* L) { return luaLvglObj(L, []() { return new LvglWidgetBox(); }, true); })
LROT_FUNCENTRY(setting, [](lua_State* L) { return luaLvglObj(L, []() { return new LvglWidgetSetting(); }, true); })
LROT_FUNCENTRY(box, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetBox(); }); })
LROT_FUNCENTRY(setting, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSetting(); }, true); })
LROT_FUNCENTRY(page, [](lua_State* L) { return luaLvglObj(L, []() { return new LvglWidgetPage(); }, true); })
LROT_FUNCENTRY(dialog, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetDialog(); }, true); })
// Dialogs
@@ -367,6 +372,7 @@ LROT_BEGIN(lvgllib, NULL, 0)
LROT_FUNCENTRY(hide, luaLvglHide)
LROT_FUNCENTRY(enable, luaLvglEnable)
LROT_FUNCENTRY(disable, luaLvglDisable)
LROT_FUNCENTRY(close, luaLvglClose)
LROT_NUMENTRY(FLOW_ROW, LV_FLEX_FLOW_ROW)
LROT_NUMENTRY(FLOW_COLUMN, LV_FLEX_FLOW_COLUMN)
LROT_NUMENTRY(PAD_TINY, PAD_TINY)
@@ -440,12 +446,16 @@ LROT_BEGIN(lvgl_mt, NULL, LROT_MASK_GC_INDEX)
LROT_FUNCENTRY(timer, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetTimerPicker(); }, true); })
LROT_FUNCENTRY(switch, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSwitchPicker(); }, true); })
LROT_FUNCENTRY(source, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSourcePicker(); }, true); })
// Containers
LROT_FUNCENTRY(box, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetBox(); }); })
LROT_FUNCENTRY(setting, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSetting(); }, true); })
// Object manipulation functions
LROT_FUNCENTRY(set, luaLvglSet)
LROT_FUNCENTRY(show, luaLvglShow)
LROT_FUNCENTRY(hide, luaLvglHide)
LROT_FUNCENTRY(enable, luaLvglEnable)
LROT_FUNCENTRY(disable, luaLvglDisable)
LROT_FUNCENTRY(close, luaLvglClose)
LROT_END(lvgl_mt, NULL, LROT_MASK_GC_INDEX)
extern "C" {
+68 -92
View File
@@ -898,6 +898,24 @@ static int luaGetRotEncMode(lua_State * L)
return 1;
}
static TelemetryQueue* getTelemetryQueue()
{
#if defined(COLORLCD)
if (luaScriptManager) {
luaScriptManager->createTelemetryQueue();
return luaScriptManager->telemetryQueue();
} else {
if (!luaInputTelemetryFifo)
luaInputTelemetryFifo = new TelemetryQueue();
return luaInputTelemetryFifo;
}
#else
if (!luaInputTelemetryFifo)
luaInputTelemetryFifo = new TelemetryQueue();
return luaInputTelemetryFifo;
#endif
}
/*luadoc
@function sportTelemetryPop()
@@ -917,23 +935,20 @@ the LUA telemetry receive queue.
*/
static int luaSportTelemetryPop(lua_State * L)
{
if (!luaInputTelemetryFifo) {
luaInputTelemetryFifo = new Fifo<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE>();
if (!luaInputTelemetryFifo) {
return 0;
}
}
auto queue = getTelemetryQueue();
if (luaInputTelemetryFifo->size() >= sizeof(SportTelemetryPacket)) {
SportTelemetryPacket packet;
for (uint8_t i=0; i<sizeof(packet); i++) {
luaInputTelemetryFifo->pop(packet.raw[i]);
if (queue) {
if (queue->size() >= sizeof(SportTelemetryPacket)) {
SportTelemetryPacket packet;
for (uint8_t i=0; i<sizeof(packet); i++) {
queue->pop(packet.raw[i]);
}
lua_pushinteger(L, packet.physicalId);
lua_pushinteger(L, packet.primId);
lua_pushinteger(L, packet.dataId);
lua_pushinteger(L, packet.value);
return 4;
}
lua_pushinteger(L, packet.physicalId);
lua_pushinteger(L, packet.primId);
lua_pushinteger(L, packet.dataId);
lua_pushinteger(L, packet.value);
return 4;
}
return 0;
@@ -1144,27 +1159,24 @@ Pops a received Crossfire Telemetry packet from the queue.
*/
static int luaCrossfireTelemetryPop(lua_State * L)
{
if (!luaInputTelemetryFifo) {
luaInputTelemetryFifo = new Fifo<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE>();
if (!luaInputTelemetryFifo) {
return 0;
}
}
auto queue = getTelemetryQueue();
uint8_t length = 0, data = 0;
if (luaInputTelemetryFifo->probe(length) && luaInputTelemetryFifo->size() >= uint32_t(length)) {
// length value includes the length field
luaInputTelemetryFifo->pop(length);
luaInputTelemetryFifo->pop(data); // command
lua_pushinteger(L, data);
lua_newtable(L);
for (uint8_t i=1; i<length-1; i++) {
luaInputTelemetryFifo->pop(data);
lua_pushinteger(L, i);
if (queue) {
uint8_t length = 0, data = 0;
if (queue->probe(length) && queue->size() >= uint32_t(length)) {
// length value includes the length field
queue->pop(length);
queue->pop(data); // command
lua_pushinteger(L, data);
lua_settable(L, -3);
lua_newtable(L);
for (uint8_t i=1; i<length-1; i++) {
queue->pop(data);
lua_pushinteger(L, i);
lua_pushinteger(L, data);
lua_settable(L, -3);
}
return 2;
}
return 2;
}
return 0;
@@ -1268,27 +1280,24 @@ Pops a received Ghost Telemetry packet from the queue.
*/
static int luaGhostTelemetryPop(lua_State * L)
{
if (!luaInputTelemetryFifo) {
luaInputTelemetryFifo = new Fifo<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE>();
if (!luaInputTelemetryFifo) {
return 0;
}
}
auto queue = getTelemetryQueue();
uint8_t length = 0, data = 0;
if (luaInputTelemetryFifo->probe(length) && luaInputTelemetryFifo->size() >= uint32_t(length)) {
// length value includes type(1B), payload, crc(1B)
luaInputTelemetryFifo->pop(length);
luaInputTelemetryFifo->pop(data); // type
lua_pushinteger(L, data); // return type
lua_newtable(L);
for (uint8_t i=0; i<length-2; i++) {
luaInputTelemetryFifo->pop(data);
lua_pushinteger(L, i + 1);
lua_pushinteger(L, data);
lua_settable(L, -3);
if (queue) {
uint8_t length = 0, data = 0;
if (queue->probe(length) && queue->size() >= uint32_t(length)) {
// length value includes type(1B), payload, crc(1B)
queue->pop(length);
queue->pop(data); // type
lua_pushinteger(L, data); // return type
lua_newtable(L);
for (uint8_t i=0; i<length-2; i++) {
queue->pop(data);
lua_pushinteger(L, i + 1);
lua_pushinteger(L, data);
lua_settable(L, -3);
}
return 2;
}
return 2;
}
return 0;
@@ -2193,8 +2202,8 @@ Get percent of already used Lua instructions in current script execution cycle.
static int luaGetUsage(lua_State * L)
{
#if defined(COLORLCD)
if (luaLvglManager && luaLvglManager->useLvglLayout()) {
lua_pushinteger(L, luaLvglManager->refreshInstructionsPercent);
if (luaScriptManager && luaScriptManager->useLvglLayout()) {
lua_pushinteger(L, luaScriptManager->refreshInstructionsPercent);
} else {
lua_pushinteger(L, instructionsPercent);
}
@@ -2592,30 +2601,10 @@ to the fields in the table returned by `model.getLogicalSwitch(switch)` identify
static int luaGetSwitchIndex(lua_State * L)
{
const char * name = luaL_checkstring(L, 1);
bool negate = false;
bool found = false;
swsrc_t idx;
swsrc_t idx = getSwitchIndex(name, true);
if (name[0] == '!') {
name++;
negate = true;
}
for (idx = SWSRC_NONE; idx < SWSRC_COUNT; idx++) {
if (isSwitchAvailable(idx, ModelCustomFunctionsContext)) {
char* s = getSwitchPositionName(idx);
if (!strncasecmp(s, name, 31)) {
found = true;
break;
}
}
}
if (found) {
if (negate)
idx = -idx;
if (idx != SWSRC_INVERT)
lua_pushinteger(L, idx);
}
else
lua_pushnil(L);
@@ -2715,8 +2704,7 @@ static int luaSwitches(lua_State * L)
} else
last = SWSRC_LAST;
lua_pushcfunction(L, luaNextSwitch);
lua_pushinteger(L, last);
lua_pushcfunction(L, luaNextSwitch); lua_pushinteger(L, last);
lua_pushinteger(L, first);
return 3;
}
@@ -2737,21 +2725,9 @@ This function is rather time consuming, and should not be used repeatedly in a s
static int luaGetSourceIndex(lua_State* const L)
{
const char* const name = luaL_checkstring(L, 1);
bool found = false;
mixsrc_t idx;
mixsrc_t idx = getSourceIndex(name, true);
for (idx = MIXSRC_NONE; idx <= MIXSRC_LAST_TELEM; idx++) {
if (isSourceAvailable(idx)) {
char srcName[maxSourceNameLength];
getSourceString(srcName, idx);
if (!strncasecmp(srcName, name)) {
found = true;
break;
}
}
}
if (found)
if (idx >= 0)
lua_pushinteger(L, idx);
else
lua_pushnil(L);
-6
View File
@@ -61,12 +61,6 @@ extern bool luaLcdAllowed;
class BitmapBuffer;
extern BitmapBuffer* luaLcdBuffer;
class LuaWidget;
extern LuaWidget* runningFS;
class LuaLvglManager;
extern LuaLvglManager* luaLvglManager;
extern uint32_t luaExtraMemoryUsage;
void luaInitThemesAndWidgets();
#endif
File diff suppressed because it is too large Load Diff
+92 -68
View File
@@ -24,6 +24,30 @@
#define LVGL_METATABLE "LVGL*"
#define LVGL_SIMPLEMETATABLE "LVGLSIMPLE*"
class LuaScriptManager;
class LvglDialog;
//-----------------------------------------------------------------------------
struct LvglParamFuncOrValue
{
public:
enum ParamType {
PVALUE,
PTXT,
};
int function;
union {
LcdFlags flags;
coord_t coord;
const char* txt;
uint32_t value;
};
void parse(lua_State *L, ParamType typ = PVALUE);
};
//-----------------------------------------------------------------------------
class LvglWidgetObjectBase
@@ -36,9 +60,6 @@ class LvglWidgetObjectBase
void push(lua_State *L);
void saveLvglObjectRef(int ref);
void getParams(lua_State *L, int index);
virtual void build(lua_State *L);
virtual bool callRefs(lua_State *L);
virtual void clearRefs(lua_State *L);
void clearChildRefs(lua_State *L);
@@ -47,12 +68,14 @@ class LvglWidgetObjectBase
virtual void hide() = 0;
virtual void enable() {};
virtual void disable() {};
virtual void close() {};
virtual void setColor(LcdFlags newColor) {}
virtual void setOpacity(uint8_t newOpa) {}
virtual void setPos(coord_t x, coord_t y) {}
virtual void setSize(coord_t w, coord_t h) {}
void create(lua_State *L, int index);
void update(lua_State *L);
virtual Window *getWindow() const = 0;
@@ -66,21 +89,22 @@ class LvglWidgetObjectBase
std::vector<int> lvglObjectRefs;
const char* metatable = nullptr;
bool clearRequest = false;
LuaLvglManager *lvglManager = nullptr;
LuaScriptManager *lvglManager = nullptr;
coord_t x = 0, y = 0, w = LV_SIZE_CONTENT, h = LV_SIZE_CONTENT;
LcdFlags color = COLOR2FLAGS(COLOR_THEME_SECONDARY1_INDEX);
LcdFlags currentColor = -1;
uint8_t opacity = LV_OPA_COVER;
int getColorFunction = LUA_REFNIL;
int getOpacityFunction = LUA_REFNIL;
int getVisibleFunction = LUA_REFNIL;
int getSizeFunction = LUA_REFNIL;
int getPosFunction = LUA_REFNIL;
LvglParamFuncOrValue color = { .function = LUA_REFNIL, .flags = COLOR2FLAGS(COLOR_THEME_SECONDARY1_INDEX)};
LvglParamFuncOrValue opacity = { .function = LUA_REFNIL, .value = LV_OPA_COVER};
virtual void build(lua_State *L);
virtual void refresh();
virtual void parseParam(lua_State *L, const char *key);
void getParams(lua_State *L, int index);
bool colorChanged(LcdFlags newColor);
void clearRef(lua_State *L, int& ref);
@@ -128,26 +152,23 @@ class LvglWidgetLabel : public LvglSimpleWidgetObject
void setFont(LcdFlags font);
void setAlign(LcdFlags align);
void build(lua_State *L) override;
bool callRefs(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
uint32_t textHash = -1;
const char *txt = "";
LcdFlags font = FONT(STD);
LcdFlags align = LEFT;
int getTextFunction = LUA_REFNIL;
int getFontFunction = LUA_REFNIL;
int getAlignFunction = LUA_REFNIL;
LvglParamFuncOrValue font = { .function = LUA_REFNIL, .flags = FONT(STD)};
LvglParamFuncOrValue align = { .function = LUA_REFNIL, .flags = LEFT};
LvglParamFuncOrValue txt = { .function = LUA_REFNIL, .txt = ""};
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override
{
setText(txt);
setFont(font);
setAlign(align);
setText(txt.txt);
setFont(font.flags);
setAlign(align.flags);
LvglSimpleWidgetObject::refresh();
}
};
@@ -164,8 +185,6 @@ class LvglWidgetLineBase : public LvglSimpleWidgetObject
void setPos(coord_t x, coord_t y) override;
void setSize(coord_t w, coord_t h) override;
void build(lua_State *L) override;
protected:
bool rounded = false;
int dashGap = 0;
@@ -174,6 +193,7 @@ class LvglWidgetLineBase : public LvglSimpleWidgetObject
virtual void setLine() = 0;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override;
};
@@ -205,24 +225,30 @@ class LvglWidgetVLine : public LvglWidgetLineBase
class LvglWidgetLine : public LvglSimpleWidgetObject
{
public:
LvglWidgetLine() : LvglSimpleWidgetObject() {}
LvglWidgetLine();
~LvglWidgetLine();
void setColor(LcdFlags newColor) override;
void setOpacity(uint8_t newOpa) override;
void setPos(coord_t x, coord_t y) override;
void setSize(coord_t w, coord_t h) override;
void build(lua_State *L) override;
bool callRefs(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
coord_t thickness = 1;
bool rounded = false;
size_t ptCnt = 0;
lv_point_t* pts = nullptr;
uint32_t ptsHash = -1;
lv_obj_t* parent = nullptr;
int getPointsFunction = LUA_REFNIL;
void setLine();
void getPt(lua_State* L, int n);
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override;
};
@@ -232,22 +258,27 @@ class LvglWidgetLine : public LvglSimpleWidgetObject
class LvglWidgetTriangle : public LvglSimpleWidgetObject
{
public:
LvglWidgetTriangle() : LvglSimpleWidgetObject() {}
LvglWidgetTriangle();
~LvglWidgetTriangle();
void setColor(LcdFlags newColor) override;
void setSize(coord_t w, coord_t h) override;
void build(lua_State *L) override;
bool callRefs(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
coord_t px[3] = {0}, py[3] = {0};
lv_point_t pts[3] = {0};
uint32_t ptsHash = -1;
MaskBitmap* mask = nullptr;
lv_obj_t* parent = nullptr;
int getPointsFunction = LUA_REFNIL;
void fillTriangle();
void fillLine(coord_t x1, coord_t x2, coord_t y);
void getPt(lua_State* L, int n);
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override;
};
@@ -290,9 +321,8 @@ class LvglWidgetBox : public LvglWidgetObject
public:
LvglWidgetBox() : LvglWidgetObject() {}
void build(lua_State *L) override;
protected:
void build(lua_State *L) override;
};
//-----------------------------------------------------------------------------
@@ -302,11 +332,10 @@ class LvglWidgetSetting : public LvglWidgetObject
public:
LvglWidgetSetting() : LvglWidgetObject() {}
void build(lua_State *L) override;
protected:
const char *txt = "";
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -320,12 +349,11 @@ class LvglWidgetBorderedObject : public LvglWidgetObject
void setColor(LcdFlags newColor) override;
void setOpacity(uint8_t newOpa) override;
void build(lua_State *L) override;
protected:
coord_t thickness = 1;
bool filled = false;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -343,14 +371,12 @@ class LvglWidgetRoundObject : public LvglWidgetBorderedObject
void clearRefs(lua_State *L) override;
protected:
coord_t radius = 0;
int getRadiusFunction = LUA_REFNIL;
LvglParamFuncOrValue radius = { .function = LUA_REFNIL, .coord = 0};
void parseParam(lua_State *L, const char *key) override;
void refresh() override
{
setRadius(radius);
setRadius(radius.coord);
LvglWidgetObject::refresh();
}
};
@@ -362,11 +388,10 @@ class LvglWidgetRectangle : public LvglWidgetBorderedObject
public:
LvglWidgetRectangle() : LvglWidgetBorderedObject() {}
void build(lua_State *L) override;
protected:
coord_t rounded = 0;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -377,9 +402,8 @@ class LvglWidgetCircle : public LvglWidgetRoundObject
public:
LvglWidgetCircle() : LvglWidgetRoundObject() {}
void build(lua_State *L) override;
protected:
void build(lua_State *L) override;
};
//-----------------------------------------------------------------------------
@@ -394,21 +418,19 @@ class LvglWidgetArc : public LvglWidgetRoundObject
void setStartAngle(coord_t angle);
void setEndAngle(coord_t angle);
void build(lua_State *L) override;
bool callRefs(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
coord_t startAngle = 0, endAngle = 0;
int getStartAngleFunction = LUA_REFNIL;
int getEndAngleFunction = LUA_REFNIL;
LvglParamFuncOrValue startAngle = { .function = LUA_REFNIL, .coord = 0};
LvglParamFuncOrValue endAngle = { .function = LUA_REFNIL, .coord = 0};
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override
{
setStartAngle(startAngle);
setEndAngle(endAngle);
setStartAngle(startAngle.coord);
setEndAngle(endAngle.coord);
LvglWidgetRoundObject::refresh();
}
};
@@ -420,12 +442,11 @@ class LvglWidgetImage : public LvglWidgetObject
public:
LvglWidgetImage() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
protected:
std::string filename;
bool fillFrame = false;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -436,12 +457,11 @@ class LvglWidgetQRCode : public LvglWidgetObject
public:
LvglWidgetQRCode() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
protected:
std::string data;
LcdFlags bgColor = COLOR2FLAGS(COLOR_THEME_SECONDARY3_INDEX);
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -452,7 +472,7 @@ class LvglWidgetTextButtonBase : public LvglWidgetObject
public:
LvglWidgetTextButtonBase() : LvglWidgetObject(LVGL_SIMPLEMETATABLE)
{
color = -1; // ignore unless overridden
color.flags = -1; // ignore unless overridden
}
void setText(const char *s);
@@ -485,13 +505,13 @@ class LvglWidgetTextButton : public LvglWidgetTextButtonBase
void setFont(LcdFlags font);
void setChecked(bool check);
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
bool checked = false;
int longPressFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override
{
@@ -509,12 +529,12 @@ class LvglWidgetMomentaryButton : public LvglWidgetTextButtonBase
void setFont(LcdFlags font);
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
int releaseFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -525,13 +545,13 @@ class LvglWidgetToggleSwitch : public LvglWidgetObject
public:
LvglWidgetToggleSwitch() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
int getStateFunction = LUA_REFNIL;
int setStateFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -542,7 +562,6 @@ class LvglWidgetTextEdit : public LvglWidgetObject
public:
LvglWidgetTextEdit() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
@@ -552,6 +571,7 @@ class LvglWidgetTextEdit : public LvglWidgetObject
int setFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -562,7 +582,6 @@ class LvglWidgetNumberEdit : public LvglWidgetObject
public:
LvglWidgetNumberEdit() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
@@ -572,6 +591,7 @@ class LvglWidgetNumberEdit : public LvglWidgetObject
int setFunction = LUA_REFNIL;
int dispFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -582,7 +602,7 @@ class LvglWidgetSliderBase : public LvglWidgetObject
public:
LvglWidgetSliderBase() : LvglWidgetObject(LVGL_SIMPLEMETATABLE)
{
color = -1;
color.flags = -1;
}
void setColor(LcdFlags newColor) override;
@@ -605,6 +625,7 @@ class LvglWidgetSlider : public LvglWidgetSliderBase
public:
LvglWidgetSlider() : LvglWidgetSliderBase() {}
protected:
void build(lua_State *L) override;
};
@@ -615,6 +636,7 @@ class LvglWidgetVerticalSlider : public LvglWidgetSliderBase
public:
LvglWidgetVerticalSlider() : LvglWidgetSliderBase() {}
protected:
void build(lua_State *L) override;
};
@@ -625,7 +647,6 @@ class LvglWidgetPage : public LvglWidgetObject
public:
LvglWidgetPage() : LvglWidgetObject() {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
@@ -635,6 +656,7 @@ class LvglWidgetPage : public LvglWidgetObject
int backActionFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -645,14 +667,16 @@ class LvglWidgetDialog : public LvglWidgetObject
public:
LvglWidgetDialog() : LvglWidgetObject() {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
void close() override;
protected:
const char *title = nullptr;
LvglDialog* dialog = nullptr;
int closeFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -663,7 +687,6 @@ class LvglWidgetConfirmDialog : public LvglWidgetObject
public:
LvglWidgetConfirmDialog() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
@@ -673,6 +696,7 @@ class LvglWidgetConfirmDialog : public LvglWidgetObject
int confirmFunction = LUA_REFNIL;
int cancelFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -683,13 +707,12 @@ class LvglWidgetMessageDialog : public LvglWidgetObject
public:
LvglWidgetMessageDialog() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
protected:
const char *title = nullptr;
const char *message = nullptr;
const char *details = nullptr;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -716,12 +739,11 @@ class LvglWidgetChoice : public LvglWidgetPicker
public:
LvglWidgetChoice() : LvglWidgetPicker() {}
void build(lua_State *L) override;
protected:
std::string title;
std::vector<std::string> values;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -732,6 +754,7 @@ class LvglWidgetFontPicker : public LvglWidgetPicker
public:
LvglWidgetFontPicker() : LvglWidgetPicker() {}
protected:
void build(lua_State *L) override;
};
@@ -742,6 +765,7 @@ class LvglWidgetAlignPicker : public LvglWidgetPicker
public:
LvglWidgetAlignPicker() : LvglWidgetPicker() {}
protected:
void build(lua_State *L) override;
};
@@ -752,6 +776,7 @@ class LvglWidgetColorPicker : public LvglWidgetPicker
public:
LvglWidgetColorPicker() : LvglWidgetPicker() {}
protected:
void build(lua_State *L) override;
};
@@ -762,6 +787,7 @@ class LvglWidgetTimerPicker : public LvglWidgetPicker
public:
LvglWidgetTimerPicker() : LvglWidgetPicker() {}
protected:
void build(lua_State *L) override;
};
@@ -772,11 +798,10 @@ class LvglWidgetSwitchPicker : public LvglWidgetPicker
public:
LvglWidgetSwitchPicker() : LvglWidgetPicker() {}
void build(lua_State *L) override;
protected:
uint32_t filter = 0xFFFFFFFF;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -787,11 +812,10 @@ class LvglWidgetSourcePicker : public LvglWidgetPicker
public:
LvglWidgetSourcePicker() : LvglWidgetPicker() {}
void build(lua_State *L) override;
protected:
uint32_t filter = 0xFFFFFFFF;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
+62 -20
View File
@@ -31,6 +31,8 @@
#define MAX_INSTRUCTIONS (20000 / 100)
LuaScriptManager *luaScriptManager = nullptr;
#if defined(HARDWARE_TOUCH)
uint32_t LuaEventHandler::downTime = 0;
uint32_t LuaEventHandler::tapTime = 0;
@@ -140,7 +142,7 @@ void LuaEventHandler::event_cb(lv_event_t* e)
#endif
}
void LuaEventHandler::onClicked()
void LuaEventHandler::onClickedEvent()
{
#if defined(HARDWARE_TOUCH)
auto click_source = lv_indev_get_act();
@@ -167,7 +169,7 @@ void LuaEventHandler::onClicked()
luaPushEvent(EVT_KEY_BREAK(KEY_ENTER));
}
void LuaEventHandler::onCancel() {
void LuaEventHandler::onCancelEvent() {
luaPushEvent(EVT_KEY_BREAK(KEY_EXIT));
}
@@ -217,18 +219,41 @@ void LuaWidget::redraw_cb(lv_event_t* e)
buf.setClippingRect(clipping.x1 - a.x1, clipping.x2 + 1 - a.x1,
clipping.y1 - a.y1, clipping.y2 + 1 - a.y1);
auto save = luaScriptManager;
luaScriptManager = widget;
widget->refresh(&buf);
luaScriptManager = save;
}
}
LuaWidget::LuaWidget(const WidgetFactory* factory, Window* parent,
const rect_t& rect, WidgetPersistentData* persistentData,
int luaScriptContextRef, int zoneRectDataRef, int optionsDataRef) :
int zoneRectDataRef, int optionsDataRef,
int createFunctionRef, std::string path) :
Widget(factory, parent, rect, persistentData),
zoneRectDataRef(zoneRectDataRef), optionsDataRef(optionsDataRef),
errorMessage(nullptr)
{
this->luaScriptContextRef = luaScriptContextRef;
// Push create function
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, createFunctionRef);
// Push stored zone for 'create' call
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, zoneRectDataRef);
// Push stored options for 'create' call
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, optionsDataRef);
// Push widget folder path
lua_pushstring(lsWidgets, path.c_str());
auto save = luaScriptManager;
luaScriptManager = this;
if (lua_pcall(lsWidgets, 3, 1, 0) == LUA_OK) {
luaScriptContextRef = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
} else {
luaScriptContextRef = LUA_NOREF;
setErrorMessage("create()");
}
luaScriptManager = save;
if (useLvglLayout()) {
update();
@@ -252,7 +277,7 @@ void LuaWidget::onClicked()
return;
}
LuaEventHandler::onClicked();
LuaScriptManager::onClickedEvent();
}
void LuaWidget::onCancel()
@@ -262,7 +287,7 @@ void LuaWidget::onCancel()
return;
}
LuaEventHandler::onCancel();
LuaScriptManager::onCancelEvent();
}
void LuaWidget::checkEvents()
@@ -286,8 +311,9 @@ void LuaWidget::checkEvents()
lv_obj_get_coords(lvobj, &a);
// Check widget is at least partially visible
if (a.x2 >= 0 && a.x1 < LCD_W) {
auto save = luaScriptManager;
PROTECT_LUA() {
luaLvglManager = this;
luaScriptManager = this;
refresh(nullptr);
if (!errorMessage) {
if (!callRefs(lsWidgets)) {
@@ -298,7 +324,7 @@ void LuaWidget::checkEvents()
} else {
// TODO: error handling
}
luaLvglManager = nullptr;
luaScriptManager = save;
UNPROTECT_LUA();
}
}
@@ -325,7 +351,7 @@ void LuaWidget::update()
// Get options table and update values
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, optionsDataRef);
int i = 0;
for (const ZoneOption* option = getOptions(); option->name; option++, i++) {
for (const ZoneOption* option = getOptionDefinitions(); option->name; option++, i++) {
auto optVal = getOptionValue(i);
switch (option->type) {
case ZoneOption::String:
@@ -347,7 +373,7 @@ void LuaWidget::update()
lua_setfield(lsWidgets, -2, option->name);
}
if (useLvglLayout()) luaLvglManager = this;
luaScriptManager = this;
if (lua_pcall(lsWidgets, 2, 0, 0) != 0)
setErrorMessage("update()");
@@ -370,7 +396,7 @@ void LuaWidget::update()
}
}
luaLvglManager = nullptr;
luaScriptManager = nullptr;
}
// Update table on top of Lua stack - set entry with name 'idx' to value 'val'
@@ -499,12 +525,10 @@ void LuaWidget::refresh(BitmapBuffer* dc)
// 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;
@@ -521,18 +545,19 @@ void LuaWidget::background()
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaFactory()->backgroundFunction);
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaScriptContextRef);
runningFS = this;
auto save = luaScriptManager;
luaScriptManager = this;
if (lua_pcall(lsWidgets, 1, 0, 0) != 0) {
setErrorMessage("background()");
}
runningFS = nullptr;
luaScriptManager = save;
}
}
void LuaWidget::onEvent(event_t event)
{
if (fullscreen) {
LuaEventHandler::onLuaEvent(event);
LuaScriptManager::onLuaEvent(event);
}
Widget::onEvent(event);
}
@@ -547,10 +572,10 @@ bool LuaWidget::useLvglLayout() const { return luaFactory()->useLvglLayout(); }
bool LuaWidget::isAppMode() const
{
return fullscreen && ViewMain::instance()->isAppMode();
return ((WidgetsContainer*)parent)->isAppMode();
}
void LuaLvglManager::saveLvglObjectRef(int ref)
void LuaScriptManager::saveLvglObjectRef(int ref)
{
if (tempParent)
tempParent->saveLvglObjectRef(ref);
@@ -558,7 +583,7 @@ void LuaLvglManager::saveLvglObjectRef(int ref)
lvglObjectRefs.push_back(ref);
}
void LuaLvglManager::clearRefs(lua_State *L)
void LuaScriptManager::clearRefs(lua_State *L)
{
for (size_t i = 0; i < lvglObjectRefs.size(); i += 1) {
lua_rawgeti(L, LUA_REGISTRYINDEX, lvglObjectRefs[i]);
@@ -569,7 +594,7 @@ void LuaLvglManager::clearRefs(lua_State *L)
lvglObjectRefs.clear();
}
bool LuaLvglManager::callRefs(lua_State *L)
bool LuaScriptManager::callRefs(lua_State *L)
{
for (size_t i = 0; i < lvglObjectRefs.size(); i += 1) {
lua_rawgeti(L, LUA_REGISTRYINDEX, lvglObjectRefs[i]);
@@ -579,3 +604,20 @@ bool LuaLvglManager::callRefs(lua_State *L)
}
return true;
}
void LuaScriptManager::createTelemetryQueue()
{
if (luaInputTelemetryFifo == nullptr) {
luaInputTelemetryFifo = new TelemetryQueue();
registerTelemetryQueue(luaInputTelemetryFifo);
}
}
LuaScriptManager::~LuaScriptManager()
{
if (luaInputTelemetryFifo == nullptr) {
deregisterTelemetryQueue(luaInputTelemetryFifo);
delete luaInputTelemetryFifo;
luaInputTelemetryFifo = nullptr;
}
}
+40 -30
View File
@@ -28,6 +28,7 @@
#include "lua_states.h"
#include "lua_api.h"
#include "lua_lvgl_widget.h"
#include "telemetry/telemetry.h"
#include "edgetx_types.h"
@@ -35,10 +36,37 @@
class LuaWidgetFactory;
class LuaLvglManager
class LuaEventHandler
{
public:
LuaEventHandler() = default;
void setupHandler(Window* w);
void removeHandler(Window* w);
protected:
#if defined(HARDWARE_TOUCH)
// "tap" handling
static uint32_t downTime;
static uint32_t tapTime;
static uint32_t tapCount;
// "swipe" / "slide" handling
static tmr10ms_t swipeTimeOut;
static bool _sliding;
static coord_t _startX;
static coord_t _startY;
#endif
static void event_cb(lv_event_t* e);
void onClickedEvent();
void onCancelEvent();
void onLuaEvent(event_t event);
};
class LuaScriptManager : public LuaEventHandler
{
public:
LuaLvglManager() = default;
LuaScriptManager() = default;
~LuaScriptManager();
std::vector<int> getLvglObjectRefs() const { return lvglObjectRefs; }
void saveLvglObjectRef(int ref);
@@ -62,46 +90,26 @@ class LuaLvglManager
uint8_t refreshInstructionsPercent;
void createTelemetryQueue();
TelemetryQueue* telemetryQueue() { return luaInputTelemetryFifo; }
protected:
int luaScriptContextRef = 0;
std::vector<int> lvglObjectRefs;
LvglWidgetObjectBase* tempParent = nullptr;
};
class LuaEventHandler
{
public:
LuaEventHandler() = default;
void setupHandler(Window* w);
void removeHandler(Window* w);
protected:
#if defined(HARDWARE_TOUCH)
// "tap" handling
static uint32_t downTime;
static uint32_t tapTime;
static uint32_t tapCount;
// "swipe" / "slide" handling
static tmr10ms_t swipeTimeOut;
static bool _sliding;
static coord_t _startX;
static coord_t _startY;
#if defined(LUA)
TelemetryQueue* luaInputTelemetryFifo = nullptr;
#endif
static void event_cb(lv_event_t* e);
void onClicked();
void onCancel();
void onLuaEvent(event_t event);
};
class LuaWidget : public Widget, public LuaEventHandler, public LuaLvglManager
class LuaWidget : public Widget, public LuaScriptManager
{
friend class LuaWidgetFactory;
public:
LuaWidget(const WidgetFactory* factory, Window* parent, const rect_t& rect,
WidgetPersistentData* persistentData, int luaScriptContextRef, int zoneRectDataRef,
int optionsDataRef);
WidgetPersistentData* persistentData, int zoneRectDataRef,
int optionsDataRef, int createFunctionRef, std::string path);
~LuaWidget() override;
#if defined(DEBUG_WINDOWS)
@@ -160,3 +168,5 @@ class LuaWidget : public Widget, public LuaEventHandler, public LuaLvglManager
static void redraw_cb(lv_event_t *e);
};
extern LuaScriptManager* luaScriptManager;
+220 -17
View File
@@ -24,18 +24,26 @@
#include "lua_api.h"
#include "lua_states.h"
#include "strhelpers.h"
#define MAX_INSTRUCTIONS (20000/100)
LuaWidgetFactory::LuaWidgetFactory(const char* name, ZoneOption* widgetOptions,
int createFunction) :
LuaWidgetFactory::LuaWidgetFactory(const char* name, ZoneOption* widgetOptions, int optionDefinitionsReference,
int createFunction, int updateFunction, int refreshFunction,
int backgroundFunction, int translateFunction, bool lvglLayout,
const char* filename) :
WidgetFactory(name, widgetOptions),
optionDefinitionsReference(optionDefinitionsReference),
createFunction(createFunction),
updateFunction(0),
refreshFunction(0),
backgroundFunction(0),
translateFunction(0)
updateFunction(updateFunction),
refreshFunction(refreshFunction),
backgroundFunction(backgroundFunction),
translateFunction(translateFunction),
lvglLayout(lvglLayout),
path(filename)
{
path = path.substr(0, path.rfind("/") + 1);
translateOptions(widgetOptions);
}
LuaWidgetFactory::~LuaWidgetFactory() {
@@ -45,7 +53,7 @@ LuaWidgetFactory::~LuaWidgetFactory() {
delete displayName;
}
auto option = getOptions();
auto option = getDefaultOptions();
while (option && option->name != nullptr) {
if (option->displayName) {
delete option->displayName;
@@ -62,7 +70,6 @@ Widget* LuaWidgetFactory::create(Window* parent, const rect_t& rect,
initPersistentData(persistentData, init);
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, createFunction);
// Make 'zone' table for 'create' call
lua_newtable(lsWidgets);
@@ -75,8 +82,6 @@ Widget* LuaWidgetFactory::create(Window* parent, const rect_t& rect,
// Store the zone data in registry for later updates
int zoneRectDataRef = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
// Push stored zone for 'create' call
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, zoneRectDataRef);
// Create options table
lua_newtable(lsWidgets);
@@ -99,14 +104,8 @@ Widget* LuaWidgetFactory::create(Window* parent, const rect_t& rect,
// Store the options data in registry for later updates
int optionsDataRef = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
// Push stored options for 'create' call
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, optionsDataRef);
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, zoneRectDataRef, optionsDataRef);
if (err) lw->setErrorMessage("create()");
return lw;
return new LuaWidget(this, parent, rect, persistentData, zoneRectDataRef, optionsDataRef, createFunction, path);
}
void LuaWidgetFactory::translateOptions(ZoneOption * options)
@@ -144,3 +143,207 @@ void LuaWidgetFactory::translateOptions(ZoneOption * options)
}
lua_pop(lsWidgets, 1);
}
static int switchValue()
{
int v = SWSRC_INVERT;
if (lua_istable(lsWidgets, -1)) {
// Find first available
int t = lua_gettop(lsWidgets);
for (lua_pushnil(lsWidgets); v == SWSRC_INVERT && lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
v = getSwitchIndex(luaL_checkstring(lsWidgets, -1), false);
}
lua_settop(lsWidgets, t);
} else if (lua_type(lsWidgets, -1) == LUA_TSTRING) {
v = getSwitchIndex(lua_tostring(lsWidgets, -1), true);
} else {
v = luaL_checkinteger(lsWidgets, -1);
}
if (v == SWSRC_INVERT) v = SWSRC_NONE;
return v;
}
static int sourceValue()
{
int v = -1;
if (lua_istable(lsWidgets, -1)) {
// Find first available
int t = lua_gettop(lsWidgets);
for (lua_pushnil(lsWidgets); v < 0 && lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
v = getSourceIndex(luaL_checkstring(lsWidgets, -1), false);
}
lua_settop(lsWidgets, t);
} else if (lua_type(lsWidgets, -1) == LUA_TSTRING) {
v = getSourceIndex(lua_tostring(lsWidgets, -1), true);
} else {
v = luaL_checkunsigned(lsWidgets, -1);
}
if (v == -1) v = MIXSRC_NONE;
return v;
}
// Parse the options table to get the default, min and max values
// Called when the widget settings dialog is opened to get values
// for current loaded model.
const void LuaWidgetFactory::parseOptionDefaults() const
{
if (optionDefinitionsReference == LUA_REFNIL) {
// TRACE("parseOptionDefaults() no options");
return;
}
PROTECT_LUA()
{
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, optionDefinitionsReference);
ZoneOption *option = (ZoneOption*)options;
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2), option->name;
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
uint8_t field = 0;
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2) && field < 5;
lua_pop(lsWidgets, 1), field++) {
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
switch (field) {
case 2:
if (option->type == ZoneOption::Switch) {
option->deflt.signedValue = switchValue();
} else if (option->type == ZoneOption::Source) {
option->deflt.unsignedValue = sourceValue();
} else if (option->type == ZoneOption::Integer) {
option->deflt.signedValue = luaL_checkinteger(lsWidgets, -1);
} else if (option->type == ZoneOption::Bool) {
option->deflt.boolValue = (luaL_checkunsigned(lsWidgets, -1) != 0);
} else if (option->type == ZoneOption::String || option->type == ZoneOption::File) {
strncpy(option->deflt.stringValue, luaL_checkstring(lsWidgets, -1),
LEN_ZONE_OPTION_STRING);
} else {
option->deflt.unsignedValue = luaL_checkunsigned(lsWidgets, -1);
}
break;
case 3:
if (option->type == ZoneOption::Switch) {
option->min.signedValue = switchValue();
} else if (option->type == ZoneOption::Source) {
option->min.unsignedValue = sourceValue();
} else if (option->type == ZoneOption::Integer || option->type == ZoneOption::Slider) {
option->min.signedValue = luaL_checkinteger(lsWidgets, -1);
} else if (option->type == ZoneOption::Choice) {
luaL_checktype(lsWidgets, -1, LUA_TTABLE); // value is a table
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
option->choiceValues.push_back(luaL_checkstring(lsWidgets, -1));
}
} else if (option->type == ZoneOption::File) {
option->fileSelectPath = luaL_checkstring(lsWidgets, -1);
}
break;
case 4:
if (option->type == ZoneOption::Switch) {
option->max.signedValue = switchValue();
} else if (option->type == ZoneOption::Source) {
option->max.unsignedValue = sourceValue();
} else if (option->type == ZoneOption::Integer || option->type == ZoneOption::Slider) {
option->max.signedValue = luaL_checkinteger(lsWidgets, -1);
}
break;
default:
break;
}
}
option++;
}
}
else
{
TRACE("error in theme/widget options");
}
UNPROTECT_LUA();
return;
}
// Parse options table to get name and type values.
// Called on radio startup to build base data for all widgtes.
ZoneOption* LuaWidgetFactory::parseOptionDefinitions(int reference)
{
if (reference == LUA_REFNIL) {
// TRACE("parseOptionDefinitions() no options");
return NULL;
}
int count = 0;
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference);
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
count++;
}
// TRACE("we have %d options", count);
if (count > MAX_WIDGET_OPTIONS) {
count = MAX_WIDGET_OPTIONS;
// TRACE("limited to %d options", count);
}
ZoneOption *options = new ZoneOption[count + 1];
if (!options) {
return NULL;
}
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)) {
// TRACE("parsing option %d", count);
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++) {
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
switch (field) {
case 0:
option->name = luaL_checkstring(lsWidgets, -1);
option->displayName = nullptr;
// TRACE("name = %s", option->name);
break;
case 1:
option->type = (ZoneOption::Type)luaL_checkinteger(lsWidgets, -1);
option->deflt.unsignedValue = 0;
// set some sensible defaults
if (option->type == ZoneOption::Integer) {
option->min.signedValue = -100;
option->max.signedValue = 100;
} else if (option->type == ZoneOption::Switch) {
option->min.signedValue = SWSRC_FIRST;
option->max.signedValue = SWSRC_LAST;
} else if (option->type == ZoneOption::Timer) {
option->min.unsignedValue = 0;
option->max.unsignedValue = MAX_TIMERS - 1;
} else if (option->type == ZoneOption::TextSize) {
option->min.unsignedValue = FONT_STD_INDEX;
option->max.unsignedValue = FONTS_COUNT - 1;
} else if (option->type == ZoneOption::String || option->type == ZoneOption::File) {
option->deflt.stringValue[0] = 0;
} else if (option->type == ZoneOption::Slider) {
option->min.unsignedValue = 0;
option->max.unsignedValue = 9;
}
break;
default:
break;
}
}
option++;
}
option->name = NULL; // sentinel
}
else
{
TRACE("error in theme/widget options");
delete[] options;
return NULL;
}
UNPROTECT_LUA();
return options;
}
+9 -4
View File
@@ -25,12 +25,13 @@
class LuaWidgetFactory : public WidgetFactory
{
friend void luaLoadWidgetCallback();
friend class LuaWidget;
public:
LuaWidgetFactory(const char* name, ZoneOption* widgetOptions,
int createFunction);
LuaWidgetFactory(const char* name, ZoneOption* widgetOptions, int optionDefinitionsReference,
int createFunction, int updateFunction, int refreshFunction,
int backgroundFunction, int translateFunction, bool lvgllayout,
const char* filename);
~LuaWidgetFactory();
Widget* create(Window* parent, const rect_t& rect,
@@ -41,14 +42,18 @@ class LuaWidgetFactory : public WidgetFactory
bool useLvglLayout() const { return lvglLayout; }
static ZoneOption* parseOptionDefinitions(int reference);
const void parseOptionDefaults() const override;
protected:
void translateOptions(ZoneOption * options);
int optionDefinitionsReference;
int createFunction;
int updateFunction;
int refreshFunction;
int backgroundFunction;
int translateFunction;
int settingsFunction;
bool lvglLayout;
std::string path;
};
+13 -133
View File
@@ -98,123 +98,12 @@ void luaSetInstructionsLimit(lua_State * L, int count)
#endif
}
ZoneOption *createOptionsArray(int reference, uint8_t maxOptions)
{
if (reference == 0) {
// TRACE("createOptionsArray() no options");
return NULL;
}
int count = 0;
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference);
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
count++;
}
// TRACE("we have %d options", count);
if (count > maxOptions) {
count = maxOptions;
// TRACE("limited to %d options", count);
}
ZoneOption *options = new ZoneOption[count + 1];
if (!options) {
return NULL;
}
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)) {
// TRACE("parsing option %d", count);
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++) {
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
switch (field) {
case 0:
option->name = luaL_checkstring(lsWidgets, -1);
option->displayName = nullptr;
// TRACE("name = %s", option->name);
break;
case 1:
option->type = (ZoneOption::Type)luaL_checkinteger(lsWidgets, -1);
option->deflt.unsignedValue = 0;
// set some sensible defaults
if (option->type == ZoneOption::Integer) {
option->min.signedValue = -100;
option->max.signedValue = 100;
} else if (option->type == ZoneOption::Switch) {
option->min.signedValue = SWSRC_FIRST;
option->max.signedValue = SWSRC_LAST;
} else if (option->type == ZoneOption::Timer) {
option->min.unsignedValue = 0;
option->max.unsignedValue = MAX_TIMERS - 1;
} else if (option->type == ZoneOption::TextSize) {
option->min.unsignedValue = FONT_STD_INDEX;
option->max.unsignedValue = FONTS_COUNT - 1;
} else if (option->type == ZoneOption::String || option->type == ZoneOption::File) {
option->deflt.stringValue[0] = 0;
} else if (option->type == ZoneOption::Slider) {
option->min.unsignedValue = 0;
option->max.unsignedValue = 9;
}
break;
case 2:
if (option->type == ZoneOption::Integer || option->type == ZoneOption::Switch) {
option->deflt.signedValue = luaL_checkinteger(lsWidgets, -1);
} else if (option->type == ZoneOption::Bool) {
option->deflt.boolValue = (luaL_checkunsigned(lsWidgets, -1) != 0);
} else if (option->type == ZoneOption::String || option->type == ZoneOption::File) {
strncpy(option->deflt.stringValue, luaL_checkstring(lsWidgets, -1),
LEN_ZONE_OPTION_STRING);
} else {
option->deflt.unsignedValue = luaL_checkunsigned(lsWidgets, -1);
}
break;
case 3:
if (option->type == ZoneOption::Integer || option->type == ZoneOption::Switch || option->type == ZoneOption::Slider) {
option->min.signedValue = luaL_checkinteger(lsWidgets, -1);
} else if (option->type == ZoneOption::Choice) {
luaL_checktype(lsWidgets, -1, LUA_TTABLE); // value is a table
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
option->choiceValues.push_back(luaL_checkstring(lsWidgets, -1));
}
} else if (option->type == ZoneOption::File) {
option->fileSelectPath = luaL_checkstring(lsWidgets, -1);
}
break;
case 4:
if (option->type == ZoneOption::Integer || option->type == ZoneOption::Switch || option->type == ZoneOption::Slider) {
option->max.signedValue = luaL_checkinteger(lsWidgets, -1);
}
break;
}
}
option++;
}
option->name = NULL; // sentinel
}
else
{
TRACE("error in theme/widget options");
delete[] options;
return NULL;
}
UNPROTECT_LUA();
return options;
}
void luaLoadWidgetCallback()
void luaLoadWidgetCallback(const char* filename)
{
TRACE("luaLoadWidgetCallback()");
const char * name=NULL;
int widgetOptions = 0, createFunction = 0, updateFunction = 0, settingsFunction = 0,
int optionDefinitionsReference = LUA_REFNIL, createFunction = 0, updateFunction = 0,
refreshFunction = 0, backgroundFunction = 0, translateFunction = 0;
bool lvglLayout = false;
@@ -226,7 +115,7 @@ void luaLoadWidgetCallback()
name = luaL_checkstring(lsWidgets, -1);
}
else if (!strcmp(key, "options")) {
widgetOptions = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
optionDefinitionsReference = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
lua_pushnil(lsWidgets);
}
else if (!strcmp(key, "create")) {
@@ -249,34 +138,25 @@ void luaLoadWidgetCallback()
translateFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
lua_pushnil(lsWidgets);
}
else if (!strcmp(key, "settings")) {
settingsFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
lua_pushnil(lsWidgets);
}
else if (!strcasecmp(key, "useLvgl")) {
lvglLayout = lua_toboolean(lsWidgets, -1);
}
}
if (name && createFunction) {
ZoneOption * options = createOptionsArray(widgetOptions, MAX_WIDGET_OPTIONS);
ZoneOption * options = LuaWidgetFactory::parseOptionDefinitions(optionDefinitionsReference);
if (options) {
LuaWidgetFactory * factory = new LuaWidgetFactory(name, options, createFunction);
factory->updateFunction = updateFunction;
factory->refreshFunction = refreshFunction;
factory->backgroundFunction = backgroundFunction;
factory->translateFunction = translateFunction;
factory->settingsFunction = settingsFunction;
factory->translateOptions(options);
factory->lvglLayout = lvglLayout;
new LuaWidgetFactory(name, options, optionDefinitionsReference,
createFunction, updateFunction, refreshFunction, backgroundFunction,
translateFunction, lvglLayout, filename);
TRACE("Loaded Lua widget %s", name);
}
}
}
void luaLoadFile(const char * filename, void (*callback)())
static void luaLoadFile(const char * filename, std::function<void()> callback)
{
if (lsWidgets == NULL || callback == NULL)
if (lsWidgets == NULL)
return;
TRACE("luaLoadFile(%s)", filename);
@@ -286,7 +166,7 @@ void luaLoadFile(const char * filename, void (*callback)())
PROTECT_LUA() {
if (luaLoadScriptFileToState(lsWidgets, filename, LUA_SCRIPT_LOAD_MODE) == SCRIPT_OK) {
if (lua_pcall(lsWidgets, 0, 1, 0) == LUA_OK && lua_istable(lsWidgets, -1)) {
(*callback)();
callback();
}
else {
TRACE("luaLoadFile(%s): Error parsing script: %s", filename, lua_tostring(lsWidgets, -1));
@@ -301,7 +181,7 @@ void luaLoadFile(const char * filename, void (*callback)())
UNPROTECT_LUA();
}
void luaLoadFiles(const char * directory, void (*callback)())
static void luaLoadFiles(const char * directory)
{
char path[LUA_FULLPATH_MAXLEN+1];
FILINFO fno;
@@ -324,7 +204,7 @@ void luaLoadFiles(const char * directory, void (*callback)())
strcpy(&path[pathlen], fno.fname);
strcat(&path[pathlen], LUA_WIDGET_FILENAME);
if (isFileAvailable(path)) {
luaLoadFile(path, callback);
luaLoadFile(path, [=]() { luaLoadWidgetCallback(path); });
}
}
}
@@ -374,7 +254,7 @@ void luaInitThemesAndWidgets()
}
UNPROTECT_LUA();
TRACE("lsWidgets %p", lsWidgets);
luaLoadFiles(WIDGETS_PATH, luaLoadWidgetCallback);
luaLoadFiles(WIDGETS_PATH);
luaDoGc(lsWidgets, true);
}
}