feat(color): telemetry queues for Lua, enhance default widget options (#5926)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user