chore(color): improvements to Lua API (#6846)

This commit is contained in:
philmoz
2025-12-05 11:47:25 +10:00
committed by GitHub
parent cf5ab821ee
commit b57f735945
6 changed files with 493 additions and 138 deletions
@@ -58,13 +58,16 @@ class Window;
#if LANDSCAPE
#if LCD_W == 320
#define LAYOUT_SCALE(x) (((x) * 8 + 5) / 10)
#define LUA_LCD_SCALE 0.8
#elif LCD_W == 800
#define LAYOUT_SCALE(x) (((x) * 11 + 4) / 8)
#define LUA_LCD_SCALE 1.375
#endif
#endif
#if !defined(LAYOUT_SCALE)
#define LAYOUT_SCALE(x) (x)
#define LUA_LCD_SCALE 1.0
#endif
// Macros for setting up layout values
@@ -26,6 +26,8 @@
#define INVERS 0x01u
#define BLINK 0x1000u
#define TIMEHOUR 0x2000u
#define VTOP 0x00u
#define VBOTTOM 0x200u
/* drawText flags */
#define LEFT 0x00u /* align left */
+226 -98
View File
@@ -27,44 +27,69 @@
#include "api_colorlcd.h"
static int luaLvglObj(lua_State *L, std::function<LvglWidgetObject*()> create, bool fullscreenOnly = false)
class LvglWidgetParams
{
if (luaScriptManager && (!fullscreenOnly || luaScriptManager->isFullscreen())) {
auto obj = create();
obj->create(L, 1);
obj->push(L);
} else {
lua_pushnil(L);
}
return 1;
}
static int luaLvglObjEx(lua_State *L, std::function<LvglWidgetObjectBase*()> create, bool fullscreenOnly = false)
{
if (luaScriptManager && (!fullscreenOnly || luaScriptManager->isFullscreen())) {
LvglWidgetObjectBase* p = nullptr;
LvglWidgetObjectBase* prevParent = nullptr;
if (lua_gettop(L) == 2) {
p = LvglWidgetObjectBase::checkLvgl(L, 1, true);
if (p) {
prevParent = luaScriptManager->getTempParent();
luaScriptManager->setTempParent(p);
public:
LvglWidgetParams(lua_State *L, int index = 1)
{
luaL_checktype(L, index, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
const char *key = lua_tostring(L, -2);
if (!strcmp(key, "type")) {
if (lua_isinteger(L, -1)) {
int n = lua_tointeger(L, -1);
if (n > ETX_UNDEF && n < ETX_LAST)
type = (LuaLvglType)n;
else
type = ETX_UNDEF;
} else {
type = getType(luaL_checkstring(L, -1));
}
} else if (!strcmp(key, "name")) {
name = luaL_checkstring(L, -1);
} else if (!strcmp(key, "children")) {
hasChildren = true;
}
}
auto obj = create();
obj->create(L, -1);
obj->push(L);
if (p)
luaScriptManager->setTempParent((prevParent));
} else {
lua_pushnil(L);
}
return 1;
}
LuaLvglType getType(const char* s)
{
if (strcasecmp(s, "label") == 0) return ETX_LABEL;
if (strcasecmp(s, "rectangle") == 0) return ETX_RECTANGLE;
if (strcasecmp(s, "circle") == 0) return ETX_CIRCLE;
if (strcasecmp(s, "arc") == 0) return ETX_ARC;
if (strcasecmp(s, "hline") == 0) return ETX_HLINE;
if (strcasecmp(s, "vline") == 0) return ETX_VLINE;
if (strcasecmp(s, "line") == 0) return ETX_LINE;
if (strcasecmp(s, "triangle") == 0) return ETX_TRIANGLE;
if (strcasecmp(s, "image") == 0) return ETX_IMAGE;
if (strcasecmp(s, "qrcode") == 0) return ETX_QRCODE;
if (strcasecmp(s, "box") == 0) return ETX_BOX;
if (strcasecmp(s, "button") == 0) return ETX_BUTTON;
if (strcasecmp(s, "momentaryButton") == 0) return ETX_MOMENTARY_BUTTON;
if (strcasecmp(s, "toggle") == 0) return ETX_TOGGLE;
if (strcasecmp(s, "textEdit") == 0) return ETX_TEXTEDIT;
if (strcasecmp(s, "numberEdit") == 0) return ETX_NUMBEREDIT;
if (strcasecmp(s, "choice") == 0) return ETX_CHOICE;
if (strcasecmp(s, "slider") == 0) return ETX_SLIDER;
if (strcasecmp(s, "verticalSlider") == 0) return ETX_VERTICAL_SLIDER;
if (strcasecmp(s, "page") == 0) return ETX_PAGE;
if (strcasecmp(s, "font") == 0) return ETX_FONT;
if (strcasecmp(s, "align") == 0) return ETX_ALIGN;
if (strcasecmp(s, "color") == 0) return ETX_COLOR;
if (strcasecmp(s, "timer") == 0) return ETX_TIMER;
if (strcasecmp(s, "switch") == 0) return ETX_SWITCH;
if (strcasecmp(s, "source") == 0) return ETX_SOURCE;
if (strcasecmp(s, "file") == 0) return ETX_FILE;
if (strcasecmp(s, "setting") == 0) return ETX_SETTING;
return ETX_UNDEF;
}
LuaLvglType type = ETX_UNDEF;
const char *name = nullptr;
bool hasChildren = false;
};
static int luaLvglPopup(lua_State *L, std::function<LvglWidgetObjectBase*()> create)
{
@@ -153,98 +178,107 @@ static int luaLvglClose(lua_State *L)
return 0;
}
class LvglWidgetParams
{
public:
LvglWidgetParams(lua_State *L, int index = 1)
{
luaL_checktype(L, index, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
const char *key = lua_tostring(L, -2);
if (!strcmp(key, "type")) {
type = luaL_checkstring(L, -1);
} else if (!strcmp(key, "name")) {
name = luaL_checkstring(L, -1);
} else if (!strcmp(key, "children")) {
hasChildren = true;
}
}
}
const char *type = nullptr;
const char *name = nullptr;
bool hasChildren = false;
};
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);
if (p.type >= ETX_FIRST_CONTROL && !luaScriptManager->isFullscreen())
continue;
LvglWidgetObjectBase *obj = nullptr;
if (strcasecmp(p.type, "label") == 0)
obj = new LvglWidgetLabel();
else if (strcasecmp(p.type, "rectangle") == 0)
obj = new LvglWidgetRectangle();
else if (strcasecmp(p.type, "circle") == 0)
obj = new LvglWidgetCircle();
else if (strcasecmp(p.type, "arc") == 0)
obj = new LvglWidgetArc();
else if (strcasecmp(p.type, "hline") == 0)
obj = new LvglWidgetHLine();
else if (strcasecmp(p.type, "vline") == 0)
obj = new LvglWidgetVLine();
else if (strcasecmp(p.type, "line") == 0)
obj = new LvglWidgetLine();
else if (strcasecmp(p.type, "triangle") == 0)
obj = new LvglWidgetTriangle();
else if (strcasecmp(p.type, "image") == 0)
obj = new LvglWidgetImage();
else if (strcasecmp(p.type, "qrcode") == 0)
obj = new LvglWidgetQRCode();
else if (strcasecmp(p.type, "box") == 0)
obj = new LvglWidgetBox();
else if (luaScriptManager->isFullscreen()) {
if (strcasecmp(p.type, "button") == 0)
switch (p.type) {
case ETX_LABEL:
obj = new LvglWidgetLabel();
break;
case ETX_RECTANGLE:
obj = new LvglWidgetRectangle();
break;
case ETX_CIRCLE:
obj = new LvglWidgetCircle();
break;
case ETX_ARC:
obj = new LvglWidgetArc();
break;
case ETX_HLINE:
obj = new LvglWidgetHLine();
break;
case ETX_VLINE:
obj = new LvglWidgetVLine();
break;
case ETX_LINE:
obj = new LvglWidgetLine();
break;
case ETX_TRIANGLE:
obj = new LvglWidgetTriangle();
break;
case ETX_IMAGE:
obj = new LvglWidgetImage();
break;
case ETX_QRCODE:
obj = new LvglWidgetQRCode();
break;
case ETX_BOX:
obj = new LvglWidgetBox();
break;
case ETX_BUTTON:
obj = new LvglWidgetTextButton();
if (strcasecmp(p.type, "momentaryButton") == 0)
break;
case ETX_MOMENTARY_BUTTON:
obj = new LvglWidgetMomentaryButton();
else if (strcasecmp(p.type, "toggle") == 0)
break;
case ETX_TOGGLE:
obj = new LvglWidgetToggleSwitch();
else if (strcasecmp(p.type, "textEdit") == 0)
break;
case ETX_TEXTEDIT:
obj = new LvglWidgetTextEdit();
else if (strcasecmp(p.type, "numberEdit") == 0)
break;
case ETX_NUMBEREDIT:
obj = new LvglWidgetNumberEdit();
else if (strcasecmp(p.type, "choice") == 0)
break;
case ETX_CHOICE:
obj = new LvglWidgetChoice();
else if (strcasecmp(p.type, "slider") == 0)
break;
case ETX_SLIDER:
obj = new LvglWidgetSlider();
else if (strcasecmp(p.type, "verticalSlider") == 0)
break;
case ETX_VERTICAL_SLIDER:
obj = new LvglWidgetVerticalSlider();
else if (strcasecmp(p.type, "page") == 0)
break;
case ETX_PAGE:
obj = new LvglWidgetPage();
else if (strcasecmp(p.type, "font") == 0)
break;
case ETX_FONT:
obj = new LvglWidgetFontPicker();
else if (strcasecmp(p.type, "align") == 0)
break;
case ETX_ALIGN:
obj = new LvglWidgetAlignPicker();
else if (strcasecmp(p.type, "color") == 0)
break;
case ETX_COLOR:
obj = new LvglWidgetColorPicker();
else if (strcasecmp(p.type, "timer") == 0)
break;
case ETX_TIMER:
obj = new LvglWidgetTimerPicker();
else if (strcasecmp(p.type, "switch") == 0)
break;
case ETX_SWITCH:
obj = new LvglWidgetSwitchPicker();
else if (strcasecmp(p.type, "source") == 0)
break;
case ETX_SOURCE:
obj = new LvglWidgetSourcePicker();
else if (strcasecmp(p.type, "file") == 0)
break;
case ETX_FILE:
obj = new LvglWidgetFilePicker();
else if (strcasecmp(p.type, "setting") == 0)
break;
case ETX_SETTING:
obj = new LvglWidgetSetting();
break;
default:
continue;
}
if (obj) {
obj->create(L, -1);
auto ref = obj->getRef(L);
if (p.name) {
if (p.name && refIndex != LUA_REFNIL) {
lua_pushstring(L, p.name);
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
lua_settable(L, refIndex - 4);
@@ -253,7 +287,7 @@ static void buildLvgl(lua_State *L, int srcIndex, int refIndex)
lua_getfield(L, -1, "children");
auto prevParent = luaScriptManager->getTempParent();
luaScriptManager->setTempParent(obj);
buildLvgl(L, -1, refIndex - 3);
buildLvgl(L, -1, (refIndex != LUA_REFNIL) ? refIndex - 3 : LUA_REFNIL);
lua_pop(L, 1);
luaScriptManager->setTempParent(prevParent);
}
@@ -262,6 +296,67 @@ static void buildLvgl(lua_State *L, int srcIndex, int refIndex)
}
}
static void addChildren(lua_State *L, LvglWidgetObjectBase* obj)
{
if (obj->getWindow()) {
lua_getfield(L, -1, "children");
auto prevParent = luaScriptManager->getTempParent();
luaScriptManager->setTempParent(obj);
buildLvgl(L, -1, LUA_REFNIL);
lua_pop(L, 1);
luaScriptManager->setTempParent(prevParent);
}
}
static int luaLvglObj(lua_State *L, std::function<LvglWidgetObject*()> create, bool fullscreenOnly = false)
{
if (luaScriptManager && (!fullscreenOnly || luaScriptManager->isFullscreen())) {
LvglWidgetParams params(L, 1);
auto obj = create();
obj->create(L, 1);
if (params.hasChildren) addChildren(L, obj);
obj->push(L);
} else {
lua_pushnil(L);
}
return 1;
}
static int luaLvglObjEx(lua_State *L, std::function<LvglWidgetObjectBase*()> create, bool fullscreenOnly = false)
{
if (luaScriptManager && (!fullscreenOnly || luaScriptManager->isFullscreen())) {
LvglWidgetObjectBase* p = nullptr;
LvglWidgetObjectBase* prevParent = nullptr;
if (lua_gettop(L) == 2) {
p = LvglWidgetObjectBase::checkLvgl(L, 1, true);
if (p) {
prevParent = luaScriptManager->getTempParent();
luaScriptManager->setTempParent(p);
}
}
LvglWidgetParams params(L, -1);
auto obj = create();
obj->create(L, -1);
if (params.hasChildren) addChildren(L, obj);
obj->push(L);
if (p)
luaScriptManager->setTempParent((prevParent));
} else {
lua_pushnil(L);
}
return 1;
}
static int luaLvglBuild(lua_State *L)
{
if (luaScriptManager) {
@@ -396,6 +491,7 @@ LROT_BEGIN(lvgllib, NULL, 0)
LROT_NUMENTRY(PAD_MEDIUM, PAD_MEDIUM)
LROT_NUMENTRY(PAD_LARGE, PAD_LARGE)
LROT_NUMENTRY(PAD_OUTLINE, PAD_OUTLINE)
LROT_NUMENTRY(PAD_BORDER, PAD_BORDER)
LROT_NUMENTRY(SRC_ALL, 0xFFFFFFFF)
LROT_NUMENTRY(SRC_INPUT, SRC_INPUT)
LROT_NUMENTRY(SRC_LUA, SRC_LUA)
@@ -423,6 +519,38 @@ LROT_BEGIN(lvgllib, NULL, 0)
LROT_NUMENTRY(SCROLL_HOR, LV_DIR_HOR)
LROT_NUMENTRY(SCROLL_VER, LV_DIR_VER)
LROT_NUMENTRY(SCROLL_ALL, LV_DIR_ALL)
LROT_NUMENTRY(PERCENT_SIZE, LV_PCT(0))
LROT_NUMENTRY(PAGE_BODY_HEIGHT, LCD_H - EdgeTxStyles::MENU_HEADER_HEIGHT)
LROT_NUMENTRY(UI_ELEMENT_HEIGHT, EdgeTxStyles::UI_ELEMENT_HEIGHT)
LROT_FLOATENTRY(LCD_SCALE, LUA_LCD_SCALE)
LROT_NUMENTRY(LABEL, ETX_LABEL)
LROT_NUMENTRY(RECTANGLE, ETX_RECTANGLE)
LROT_NUMENTRY(CIRCLE, ETX_CIRCLE)
LROT_NUMENTRY(ARC, ETX_ARC)
LROT_NUMENTRY(HLINE, ETX_HLINE)
LROT_NUMENTRY(VLINE, ETX_VLINE)
LROT_NUMENTRY(LINE, ETX_LINE)
LROT_NUMENTRY(TRIANGLE, ETX_TRIANGLE)
LROT_NUMENTRY(IMAGE, ETX_IMAGE)
LROT_NUMENTRY(QRCODE, ETX_QRCODE)
LROT_NUMENTRY(BOX, ETX_BOX)
LROT_NUMENTRY(BUTTON, ETX_BUTTON)
LROT_NUMENTRY(MOMENTARY_BUTTON, ETX_MOMENTARY_BUTTON)
LROT_NUMENTRY(TOGGLE, ETX_TOGGLE)
LROT_NUMENTRY(TEXT_EDIT, ETX_TEXTEDIT)
LROT_NUMENTRY(NUMBER_EDIT, ETX_NUMBEREDIT)
LROT_NUMENTRY(CHOIDE, ETX_CHOICE)
LROT_NUMENTRY(SLIDER, ETX_SLIDER)
LROT_NUMENTRY(VERTICAL_SLIDER, ETX_VERTICAL_SLIDER)
LROT_NUMENTRY(PAGE, ETX_PAGE)
LROT_NUMENTRY(FONT, ETX_FONT)
LROT_NUMENTRY(ALIGN, ETX_ALIGN)
LROT_NUMENTRY(COLOR, ETX_COLOR)
LROT_NUMENTRY(TIMER, ETX_TIMER)
LROT_NUMENTRY(SWITCH, ETX_SWITCH)
LROT_NUMENTRY(SOURCE, ETX_SOURCE)
LROT_NUMENTRY(FILE, ETX_FILE)
LROT_NUMENTRY(SETTING, ETX_SETTING)
LROT_END(lvgllib, NULL, 0)
// Metatable for simple objects (line, arc, label)
+2
View File
@@ -3165,6 +3165,8 @@ LROT_BEGIN(etxcst, NULL, 0)
LROT_NUMENTRY( BLINK, BLINK )
LROT_NUMENTRY( INVERS, INVERS )
LROT_NUMENTRY( VCENTER, VCENTERED )
LROT_NUMENTRY( VTOP, VTOP )
LROT_NUMENTRY( VBOTTOM, VBOTTOM )
#else
LROT_NUMENTRY( XXLSIZE, XXLSIZE )
LROT_NUMENTRY( DBLSIZE, DBLSIZE )
+179 -33
View File
@@ -30,6 +30,8 @@
#include "toggleswitch.h"
#include "filechoice.h"
#include "keyboard_base.h"
#include "theme_manager.h"
#include "pagegroup.h"
//-----------------------------------------------------------------------------
@@ -40,6 +42,13 @@ static void clearRef(lua_State *L, int& ref)
ref = LUA_REFNIL;
}
static bool getLuaBool(lua_State *L)
{
if (lua_isboolean(L, -1))
return lua_toboolean(L, -1);
return luaL_checkunsigned(L, -1);
}
//-----------------------------------------------------------------------------
void LvglParamFuncOrValue::parse(lua_State *L)
@@ -164,6 +173,11 @@ bool LvglTitleParam::parseTitleParam(lua_State *L, const char *key)
return false;
}
void LvglTitleParam::clearTitleRefs(lua_State *L)
{
title.clearRef(L);
}
bool LvglMessageParam::parseMessageParam(lua_State *L, const char *key)
{
if (!strcmp(key, "message")) {
@@ -176,12 +190,26 @@ bool LvglMessageParam::parseMessageParam(lua_State *L, const char *key)
bool LvglRoundedParam::parseRoundedParam(lua_State *L, const char *key)
{
if (!strcmp(key, "rounded")) {
rounded = lua_toboolean(L, -1);
rounded = getLuaBool(L);
return true;
}
return false;
}
bool LvglAlignParam::parseAlignParam(lua_State *L, const char *key)
{
if (!strcmp(key, "align")) {
align.parse(L);
return true;
}
return false;
}
void LvglAlignParam::clearAlignRefs(lua_State *L)
{
align.clearRef(L);
}
bool LvglThicknessParam::parseThicknessParam(lua_State *L, const char *key)
{
if (!strcmp(key, "thickness")) {
@@ -206,7 +234,7 @@ bool LvglValuesParam::parseValuesParam(lua_State *L, const char *key)
bool LvglScrollableParams::parseScrollableParam(lua_State *L, const char *key)
{
if (!strcmp(key, "scrollBar")) {
showScrollBar = lua_toboolean(L, -1);
showScrollBar = getLuaBool(L);
return true;
}
if (!strcmp(key, "scrollDir")) {
@@ -487,7 +515,7 @@ int LvglWidgetObjectBase::pcallGetIntVal(lua_State *L, int getFuncRef)
int LvglWidgetObjectBase::pcallGetOptIntVal(lua_State *L, int getFuncRef, int defVal)
{
int val = 0;
int val = defVal;
if (getFuncRef != LUA_REFNIL) {
auto save = luaScriptManager;
luaScriptManager = lvglManager;
@@ -740,11 +768,9 @@ bool LvglSimpleWidgetObject::isVisible()
void LvglWidgetLabel::parseParam(lua_State *L, const char *key)
{
if (!strcmp(key, "align")) {
align.parse(L);
} else if (!parseTextParam(L, key)) {
LvglSimpleWidgetObject::parseParam(L, key);
}
if (parseAlignParam(L, key)) return;
if (parseTextParam(L, key)) return;
LvglSimpleWidgetObject::parseParam(L, key);
}
bool LvglWidgetLabel::callRefs(lua_State *L)
@@ -765,7 +791,7 @@ bool LvglWidgetLabel::callRefs(lua_State *L)
void LvglWidgetLabel::clearRefs(lua_State *L)
{
align.clearRef(L);
clearAlignRefs(L);
clearTextRefs(L);
LvglSimpleWidgetObject::clearRefs(L);
}
@@ -1067,6 +1093,11 @@ void LvglWidgetLine::refresh()
build(nullptr);
}
bool LvglWidgetLine::isVisible()
{
return !lvobj || !lv_obj_has_flag(lvobj, LV_OBJ_FLAG_HIDDEN);
}
//-----------------------------------------------------------------------------
LvglWidgetTriangle::LvglWidgetTriangle() : LvglSimpleWidgetObject()
@@ -1424,6 +1455,7 @@ void LvglWidgetObject::clearRefs(lua_State *L)
void LvglWidgetBox::parseParam(lua_State *L, const char *key)
{
if (parseAlignParam(L, key)) return;
if (parseScrollableParam(L, key)) return;
LvglWidgetObject::parseParam(L, key);
}
@@ -1454,6 +1486,7 @@ bool LvglWidgetBox::callRefs(lua_State *L)
void LvglWidgetBox::clearRefs(lua_State *L)
{
clearAlignRefs(L);
clearRef(L, scrollToFunction);
LvglWidgetObject::clearRefs(L);
}
@@ -1472,8 +1505,16 @@ void LvglWidgetBox::build(lua_State *L)
if (showScrollBar)
etx_scrollbar(window->getLvObj());
}
if (setFlex())
lv_obj_set_flex_align(window->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
if (setFlex()) {
lv_flex_align_t align1 = (align.flags & RIGHT) ? LV_FLEX_ALIGN_END : (align.flags & CENTERED) ? LV_FLEX_ALIGN_CENTER : LV_FLEX_ALIGN_START;
lv_flex_align_t align2 = (align.flags & VCENTERED) ? LV_FLEX_ALIGN_CENTER : (align.flags & VBOTTOM) ? LV_FLEX_ALIGN_END : LV_FLEX_ALIGN_START;
if (flexFlow & LV_FLEX_FLOW_COLUMN)
lv_obj_set_flex_align(window->getLvObj(), align2, align2, align1);
else
lv_obj_set_flex_align(window->getLvObj(), align1, align1, align2);
}
setColor(color.flags);
setOpacity(opacity.value);
}
//-----------------------------------------------------------------------------
@@ -1484,6 +1525,12 @@ void LvglWidgetSetting::parseParam(lua_State *L, const char *key)
LvglWidgetObject::parseParam(L, key);
}
void LvglWidgetSetting::clearRefs(lua_State *L)
{
clearTitleRefs(L);
LvglWidgetObjectBase::clearRefs(L);
}
void LvglWidgetSetting::build(lua_State *L)
{
window =
@@ -1801,7 +1848,7 @@ void LvglWidgetImage::parseParam(lua_State *L, const char *key)
if (!strcmp(key, "file")) {
filename.parse(L);
} else if (!strcmp(key, "fill")) {
fillFrame = lua_toboolean(L, -1);
fillFrame = getLuaBool(L);
} else {
LvglWidgetObject::parseParam(L, key);
}
@@ -1931,7 +1978,7 @@ void LvglWidgetTextButtonBase::setRounded()
void LvglWidgetTextButton::parseParam(lua_State *L, const char *key)
{
if (!strcmp(key, "checked")) {
checked = lua_toboolean(L, -1);
checked = getLuaBool(L);
} else if (!strcmp(key, "longpress")) {
longPressFunction = luaL_ref(L, LUA_REGISTRYINDEX);
} else {
@@ -2203,10 +2250,21 @@ void LvglWidgetVerticalSlider::build(lua_State *L)
class WidgetPage : public NavWindow, public LuaEventHandler
{
public:
WidgetPage(Window *parent, std::function<void()> backAction,
WidgetPage(Window *parent,
std::function<void()> backAction,
std::function<void()> menuAction,
std::function<void()> prevAction,
std::function<void()> nextAction,
std::function<bool()> prevActive,
std::function<bool()> nextActive,
std::string title, std::string subtitle, std::string iconFile,
lv_dir_t scrollDir, bool showScrollBar) :
NavWindow(parent, {0, 0, LCD_W, LCD_H}), backAction(std::move(backAction))
lv_dir_t scrollDir, bool showScrollBar,
bool showBackBtn, bool showPrevBtn, bool showNextBtn) :
NavWindow(parent, {0, 0, LCD_W, LCD_H}),
backAction(std::move(backAction)), menuAction(menuAction),
prevAction(std::move(prevAction)), nextAction(std::move(nextAction)),
prevActive(std::move(prevActive)), nextActive(std::move(nextActive)),
showPrev(showPrevBtn), showNext(showNextBtn)
{
if (iconFile.empty())
header = new PageHeader(this, ICON_EDGETX);
@@ -2214,9 +2272,15 @@ class WidgetPage : public NavWindow, public LuaEventHandler
header = new PageHeader(this, iconFile.c_str());
#if defined(HARDWARE_TOUCH)
addCustomButton(0, 0, [=]() { onCancel(); });
if (showBackBtn) {
new HeaderBackIcon(header);
addCustomButton(0, 0, this->menuAction);
addCustomButton(LCD_W - EdgeTxStyles::MENU_HEADER_HEIGHT, 0, this->backAction);
} else {
addCustomButton(0, 0, this->backAction);
}
#endif
body = new Window(
this, {0, EdgeTxStyles::MENU_HEADER_HEIGHT, LCD_W, LCD_H - EdgeTxStyles::MENU_HEADER_HEIGHT});
body->setWindowFlag(NO_FOCUS);
@@ -2230,6 +2294,26 @@ class WidgetPage : public NavWindow, public LuaEventHandler
lv_obj_set_scroll_dir(body->getLvObj(), scrollDir);
if (showScrollBar)
etx_scrollbar(body->getLvObj());
delayLoad();
}
void delayedInit() override
{
#if defined(HARDWARE_TOUCH)
if (showPrev) {
prevBtn = new IconButton(this, ICON_BTN_PREV, LCD_W - PageGroup::PAGE_GROUP_BACK_BTN_W * 3, PAD_MEDIUM, [=]() {
prevAction();
return 0;
});
}
if (showNext) {
nextBtn = new IconButton(this, ICON_BTN_NEXT, LCD_W - PageGroup::PAGE_GROUP_BACK_BTN_W * 2, PAD_MEDIUM, [=]() {
nextAction();
return 0;
});
}
#endif
}
Window *getBody() { return body; }
@@ -2239,8 +2323,17 @@ class WidgetPage : public NavWindow, public LuaEventHandler
protected:
std::function<void()> backAction;
std::function<void()> menuAction;
std::function<void()> prevAction;
std::function<void()> nextAction;
std::function<bool()> prevActive;
std::function<bool()> nextActive;
bool showPrev = false;
bool showNext = false;
PageHeader *header = nullptr;
Window *body = nullptr;
IconButton* prevBtn = nullptr;
IconButton* nextBtn = nullptr;
void onClicked() override { Keyboard::hide(false); LuaEventHandler::onClickedEvent(); }
@@ -2251,14 +2344,49 @@ class WidgetPage : public NavWindow, public LuaEventHandler
LuaEventHandler::onLuaEvent(evt);
parent->onEvent(evt);
}
void checkEvents() override
{
if (prevBtn) prevBtn->enable(prevActive());
if (nextBtn) nextBtn->enable(nextActive());
}
};
void LvglWidgetPage::parseParam(lua_State *L, const char *key)
{
if (parseAlignParam(L, key)) return;
if (parseTitleParam(L, key)) return;
if (parseScrollableParam(L, key)) return;
if (!strcmp(key, "back")) {
backActionFunction = luaL_ref(L, LUA_REGISTRYINDEX);
} else if (!strcmp(key, "menu")) {
menuActionFunction = luaL_ref(L, LUA_REGISTRYINDEX);
} else if (!strcmp(key, "prevButton")) {
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
const char *key = lua_tostring(L, -2);
if (!strcmp(key, "press")) {
prevActionFunction = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
} else if (!strcmp(key, "active")) {
prevActiveFunction = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
}
}
} else if (!strcmp(key, "nextButton")) {
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
const char *key = lua_tostring(L, -2);
if (!strcmp(key, "press")) {
nextActionFunction = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
} else if (!strcmp(key, "active")) {
nextActiveFunction = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
}
}
} else if (!strcmp(key, "backButton")) {
showBackButton = getLuaBool(L);
} else if (!strcmp(key, "subtitle")) {
subtitle.parse(L);
} else if (!strcmp(key, "icon")) {
@@ -2310,23 +2438,44 @@ bool LvglWidgetPage::callRefs(lua_State *L)
void LvglWidgetPage::clearRefs(lua_State *L)
{
title.clearRef(L);
clearAlignRefs(L);
clearTitleRefs(L);
subtitle.clearRef(L);
clearRef(L, backActionFunction);
clearRef(L, menuActionFunction);
clearRef(L, prevActionFunction);
clearRef(L, nextActionFunction);
clearRef(L, prevActiveFunction);
clearRef(L, nextActiveFunction);
LvglWidgetObject::clearRefs(L);
}
void LvglWidgetPage::build(lua_State *L)
{
w = LCD_W;
h = LCD_H;
page = new WidgetPage(
lvglManager->getCurrentParent(),
[=]() { pcallSimpleFunc(L, backActionFunction); }, title.txt, subtitle.txt, iconFile, scrollDir, showScrollBar);
[=]() { pcallSimpleFunc(L, backActionFunction); },
[=]() { pcallSimpleFunc(L, menuActionFunction); },
[=]() { pcallSimpleFunc(L, prevActionFunction); },
[=]() { pcallSimpleFunc(L, nextActionFunction); },
[=]() { return pcallGetOptIntVal(L, prevActiveFunction, true); },
[=]() { return pcallGetOptIntVal(L, nextActiveFunction, true); },
title.txt, subtitle.txt, iconFile, scrollDir, showScrollBar,
showBackButton, prevActionFunction != LUA_REFNIL, nextActionFunction != LUA_REFNIL);
window = page->getBody();
window->disableForcedScroll();
window->setScrollHandler([=](coord_t x, coord_t y) { pcallFuncWith2Int(L, scrolledFunction, 0, x, y); });
if (setFlex())
lv_obj_set_flex_align(window->getLvObj(), LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
if (setFlex()) {
lv_flex_align_t align1 = (align.flags & RIGHT) ? LV_FLEX_ALIGN_END : (align.flags & CENTERED) ? LV_FLEX_ALIGN_CENTER : LV_FLEX_ALIGN_START;
lv_flex_align_t align2 = (align.flags & VCENTERED) ? LV_FLEX_ALIGN_CENTER : (align.flags & VBOTTOM) ? LV_FLEX_ALIGN_END : LV_FLEX_ALIGN_START;
if (flexFlow & LV_FLEX_FLOW_COLUMN)
lv_obj_set_flex_align(window->getLvObj(), align2, align2, align1);
else
lv_obj_set_flex_align(window->getLvObj(), align1, align1, align2);
}
}
//-----------------------------------------------------------------------------
@@ -2365,7 +2514,7 @@ void LvglWidgetDialog::parseParam(lua_State *L, const char *key)
void LvglWidgetDialog::clearRefs(lua_State *L)
{
title.clearRef(L);
clearTitleRefs(L);
clearRef(L, closeFunction);
LvglWidgetObject::clearRefs(L);
}
@@ -2405,7 +2554,7 @@ void LvglWidgetConfirmDialog::parseParam(lua_State *L, const char *key)
void LvglWidgetConfirmDialog::clearRefs(lua_State *L)
{
title.clearRef(L);
clearTitleRefs(L);
clearRef(L, confirmFunction);
clearRef(L, cancelFunction);
LvglWidgetObject::clearRefs(L);
@@ -2433,7 +2582,7 @@ void LvglWidgetMessageDialog::parseParam(lua_State *L, const char *key)
void LvglWidgetMessageDialog::clearRefs(lua_State *L)
{
title.clearRef(L);
clearTitleRefs(L);
LvglWidgetObject::clearRefs(L);
}
@@ -2474,7 +2623,7 @@ void LvglWidgetChoice::parseParam(lua_State *L, const char *key)
void LvglWidgetChoice::clearRefs(lua_State *L)
{
title.clearRef(L);
clearTitleRefs(L);
clearRef(L, filterFunction);
LvglWidgetPicker::clearRefs(L);
}
@@ -2496,10 +2645,7 @@ void LvglWidgetChoice::build(lua_State *L)
PROTECT_LUA()
{
if (pcallFuncWithInt(L, filterFunction, 1, n + 1)) {
if (lua_isboolean(L, -1))
rv = lua_toboolean(L, -1);
else
rv = luaL_checkinteger(L, -1) != 0;
rv = getLuaBool(L);
} else {
lvglManager->luaShowError();
}
@@ -2527,7 +2673,7 @@ void LvglWidgetMenu::parseParam(lua_State *L, const char *key)
void LvglWidgetMenu::clearRefs(lua_State *L)
{
title.clearRef(L);
clearTitleRefs(L);
LvglWidgetPicker::clearRefs(L);
}
@@ -2669,7 +2815,7 @@ void LvglWidgetFilePicker::parseParam(lua_State *L, const char *key)
} else if (!strcmp(key, "maxLen")) {
maxLen = luaL_checkunsigned(L, -1);
} else if (!strcmp(key, "hideExtension")) {
hideExtension = lua_toboolean(L, -1);
hideExtension = getLuaBool(L);
} else {
LvglWidgetPicker::parseParam(L, key);
}
@@ -2677,7 +2823,7 @@ void LvglWidgetFilePicker::parseParam(lua_State *L, const char *key)
void LvglWidgetFilePicker::clearRefs(lua_State *L)
{
title.clearRef(L);
clearTitleRefs(L);
LvglWidgetPicker::clearRefs(L);
}
+81 -7
View File
@@ -29,6 +29,52 @@ class LvglDialog;
//-----------------------------------------------------------------------------
enum LuaLvglType
{
ETX_UNDEF,
// Drawing primitives
ETX_LABEL,
ETX_RECTANGLE,
ETX_CIRCLE,
ETX_ARC,
ETX_HLINE,
ETX_VLINE,
ETX_LINE,
ETX_TRIANGLE,
ETX_IMAGE,
ETX_QRCODE,
// Contianers
ETX_BOX,
// Controls - tools / fullscreen widgets only
ETX_FIRST_CONTROL,
ETX_BUTTON = ETX_FIRST_CONTROL,
ETX_MOMENTARY_BUTTON,
ETX_TOGGLE,
ETX_TEXTEDIT,
ETX_NUMBEREDIT,
ETX_CHOICE,
ETX_SLIDER,
ETX_VERTICAL_SLIDER,
// Containers
ETX_PAGE,
// Value selectors
ETX_FONT,
ETX_ALIGN,
ETX_COLOR,
ETX_TIMER,
ETX_SWITCH,
ETX_SOURCE,
ETX_FILE,
ETX_SETTING,
ETX_LAST
};
//-----------------------------------------------------------------------------
struct LvglParamFuncOrValue
{
public:
@@ -114,6 +160,7 @@ class LvglTitleParam
LvglParamFuncOrString title = { .function = LUA_REFNIL, .txt = ""};
bool parseTitleParam(lua_State *L, const char *key);
void clearTitleRefs(lua_State *L);
};
class LvglMessageParam
@@ -138,6 +185,18 @@ class LvglRoundedParam
bool parseRoundedParam(lua_State *L, const char *key);
};
class LvglAlignParam
{
public:
LvglAlignParam() {}
protected:
LvglParamFuncOrValue align = { .function = LUA_REFNIL, .flags = LEFT};
bool parseAlignParam(lua_State *L, const char *key);
void clearAlignRefs(lua_State *L);
};
class LvglThicknessParam
{
public:
@@ -271,7 +330,7 @@ class LvglSimpleWidgetObject : public LvglWidgetObjectBase
//-----------------------------------------------------------------------------
class LvglWidgetLabel : public LvglSimpleWidgetObject, public LvglTextParams
class LvglWidgetLabel : public LvglSimpleWidgetObject, public LvglTextParams, public LvglAlignParam
{
public:
LvglWidgetLabel() : LvglSimpleWidgetObject() {}
@@ -285,8 +344,6 @@ class LvglWidgetLabel : public LvglSimpleWidgetObject, public LvglTextParams
void clearRefs(lua_State *L) override;
protected:
LvglParamFuncOrValue align = { .function = LUA_REFNIL, .flags = LEFT};
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override
@@ -360,6 +417,8 @@ class LvglWidgetLine : public LvglSimpleWidgetObject, public LvglRoundedParam, p
bool callRefs(lua_State *L) override;
void clearRefs(lua_State *L) override;
bool isVisible() override;
protected:
size_t ptCnt = 0;
size_t ptAlloc = 0;
@@ -441,10 +500,13 @@ class LvglWidgetObject : public LvglWidgetObjectBase
//-----------------------------------------------------------------------------
class LvglWidgetBox : public LvglWidgetObject, public LvglScrollableParams
class LvglWidgetBox : public LvglWidgetObject, public LvglScrollableParams, public LvglAlignParam
{
public:
LvglWidgetBox() : LvglWidgetObject() {}
LvglWidgetBox() : LvglWidgetObject(), LvglScrollableParams(), LvglAlignParam()
{
align.flags = CENTERED;
}
coord_t getScrollX() override;
coord_t getScrollY() override;
@@ -464,6 +526,8 @@ class LvglWidgetSetting : public LvglWidgetObject, public LvglTitleParam
public:
LvglWidgetSetting() : LvglWidgetObject() {}
void clearRefs(lua_State *L) override;
protected:
void build(lua_State *L) override;
@@ -787,10 +851,13 @@ class LvglWidgetVerticalSlider : public LvglWidgetSliderBase
class WidgetPage;
class LvglWidgetPage : public LvglWidgetObject, public LvglTitleParam, public LvglScrollableParams
class LvglWidgetPage : public LvglWidgetObject, public LvglTitleParam, public LvglScrollableParams, public LvglAlignParam
{
public:
LvglWidgetPage() : LvglWidgetObject() {}
LvglWidgetPage() : LvglWidgetObject()
{
align.flags = CENTERED;
}
bool callRefs(lua_State *L) override;
void clearRefs(lua_State *L) override;
@@ -805,8 +872,15 @@ class LvglWidgetPage : public LvglWidgetObject, public LvglTitleParam, public Lv
LvglParamFuncOrString subtitle = { .function = LUA_REFNIL, .txt = ""};
std::string iconFile;
WidgetPage* page = nullptr;
bool showBackButton = false;
bool showNavButtons = false;
int backActionFunction = LUA_REFNIL;
int menuActionFunction = LUA_REFNIL;
int prevActionFunction = LUA_REFNIL;
int nextActionFunction = LUA_REFNIL;
int prevActiveFunction = LUA_REFNIL;
int nextActiveFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;