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
+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;
}