feat(lua): support for using LVGL objects on colorlcd (#4887)
This commit is contained in:
@@ -134,6 +134,7 @@ if(LUA)
|
||||
lua/lua_widget.cpp
|
||||
lua/lua_widget_factory.cpp
|
||||
lua/widgets.cpp
|
||||
lua/lua_lvgl_widget.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -68,9 +68,6 @@ void Layout::adjustLayout()
|
||||
|
||||
// Save settings
|
||||
decorationSettings = checkSettings;
|
||||
|
||||
// Set visible decoration
|
||||
show();
|
||||
}
|
||||
|
||||
void Layout::show(bool visible)
|
||||
|
||||
@@ -142,7 +142,7 @@ class ModelButton : public Button
|
||||
if (modelLayouts[layout].hasImage) {
|
||||
if (modelCell->modelBitmap[0]) {
|
||||
GET_FILENAME(filename, BITMAPS_PATH, modelCell->modelBitmap, "");
|
||||
auto bitmap = new StaticImage(this, {PAD_TINY, PAD_TINY, w, h}, filename, true);
|
||||
auto bitmap = new StaticImage(this, {PAD_TINY, PAD_TINY, w, h}, filename, false, true);
|
||||
lv_obj_move_background(bitmap->getLvObj());
|
||||
bitmap->show(bitmap->hasImage());
|
||||
if (bitmap->hasImage()) {
|
||||
@@ -626,7 +626,6 @@ void ModelLabelsWindow::newModel()
|
||||
snprintf(path + len, LEN_BUFFER - len, "/%s%s", name.c_str(), SCRIPT_EXT);
|
||||
if (f_stat(path, 0) == FR_OK) {
|
||||
luaExec(path);
|
||||
StandaloneLuaWindow::instance()->attach();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -417,7 +417,6 @@ void RadioSdManagerPage::fileAction(const char* path, const char* name,
|
||||
else if (isExtensionMatching(ext, SCRIPTS_EXT)) {
|
||||
menu->addLine(STR_EXECUTE_FILE, [=]() {
|
||||
luaExec(fullpath);
|
||||
StandaloneLuaWindow::instance()->attach();
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -102,8 +102,6 @@ static void run_lua_tool(Window* parent, const std::string& path)
|
||||
f_chdir(toolPath);
|
||||
|
||||
luaExec(path.c_str());
|
||||
auto lua_win = StandaloneLuaWindow::instance();
|
||||
lua_win->attach();
|
||||
}
|
||||
|
||||
// LUA scripts in TOOLS
|
||||
|
||||
@@ -85,8 +85,9 @@ void StandaloneLuaWindow::redraw_cb(lv_event_t* e)
|
||||
// singleton instance
|
||||
StandaloneLuaWindow* StandaloneLuaWindow::_instance;
|
||||
|
||||
StandaloneLuaWindow::StandaloneLuaWindow() :
|
||||
Window(nullptr, {0, 0, LCD_W, LCD_H}),
|
||||
StandaloneLuaWindow::StandaloneLuaWindow(bool useLvgl) :
|
||||
Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}),
|
||||
useLvgl(useLvgl),
|
||||
lcdBuffer(BMP_RGB565, LCD_W, LCD_H),
|
||||
popup({50, 73, LCD_W - 100, LCD_H - 146})
|
||||
{
|
||||
@@ -94,24 +95,42 @@ StandaloneLuaWindow::StandaloneLuaWindow() :
|
||||
|
||||
etx_solid_bg(lvobj);
|
||||
|
||||
lcdBuffer.clear();
|
||||
lcdBuffer.drawText(LCD_W / 2, LCD_H / 2 - 20, STR_LOADING,
|
||||
FONT(L) | COLOR_THEME_PRIMARY2 | CENTERED);
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE);
|
||||
if (useLvglLayout()) {
|
||||
padAll(PAD_ZERO);
|
||||
etx_scrollbar(lvobj);
|
||||
lv_obj_t* lbl = lv_label_create(lvobj);
|
||||
lv_obj_set_pos(lbl, 0, 0);
|
||||
lv_obj_set_size(lbl, LCD_W, LCD_H);
|
||||
etx_solid_bg(lbl, COLOR_THEME_PRIMARY1_INDEX);
|
||||
etx_txt_color(lbl, COLOR_THEME_PRIMARY2_INDEX);
|
||||
lv_obj_set_style_text_align(lbl, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_top(lbl, (LCD_H - EdgeTxStyles::PAGE_LINE_HEIGHT) / 2, LV_PART_MAIN);
|
||||
lv_label_set_text(lbl, STR_LOADING);
|
||||
|
||||
luaLvglManager = this;
|
||||
} else {
|
||||
lcdBuffer.clear();
|
||||
lcdBuffer.drawText(LCD_W / 2, LCD_H / 2 - 20, STR_LOADING,
|
||||
FONT(L) | COLOR_THEME_PRIMARY2 | CENTERED);
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE);
|
||||
|
||||
lv_obj_add_event_cb(lvobj, StandaloneLuaWindow::redraw_cb, LV_EVENT_DRAW_MAIN, nullptr);
|
||||
}
|
||||
|
||||
// setup LUA event handler
|
||||
setupHandler(this);
|
||||
|
||||
lv_obj_add_event_cb(lvobj, StandaloneLuaWindow::redraw_cb, LV_EVENT_DRAW_MAIN, nullptr);
|
||||
attach();
|
||||
}
|
||||
|
||||
void StandaloneLuaWindow::setup(bool useLvgl)
|
||||
{
|
||||
_instance = new StandaloneLuaWindow(useLvgl);
|
||||
}
|
||||
|
||||
StandaloneLuaWindow* StandaloneLuaWindow::instance()
|
||||
{
|
||||
if (!_instance) {
|
||||
_instance = new StandaloneLuaWindow();
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
@@ -121,13 +140,13 @@ void StandaloneLuaWindow::attach()
|
||||
// backup previous screen
|
||||
prevScreen = lv_scr_act();
|
||||
|
||||
// and load new one
|
||||
lv_scr_load(lvobj);
|
||||
|
||||
Layer::back()->hide();
|
||||
Layer::push(this);
|
||||
|
||||
lv_group_add_obj(lv_group_get_default(), lvobj);
|
||||
lv_group_set_editing(lv_group_get_default(), true);
|
||||
if (!useLvglLayout()) {
|
||||
lv_group_add_obj(lv_group_get_default(), lvobj);
|
||||
lv_group_set_editing(lv_group_get_default(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,10 +154,12 @@ void StandaloneLuaWindow::deleteLater(bool detach, bool trash)
|
||||
{
|
||||
if (_deleted) return;
|
||||
|
||||
luaLvglManager = nullptr;
|
||||
|
||||
Layer::pop(this);
|
||||
Layer::back()->show();
|
||||
|
||||
if (prevScreen) {
|
||||
lv_scr_load(prevScreen);
|
||||
prevScreen = nullptr;
|
||||
}
|
||||
|
||||
@@ -159,8 +180,20 @@ void StandaloneLuaWindow::checkEvents()
|
||||
if (luaState != INTERPRETER_RELOAD_PERMANENT_SCRIPTS) {
|
||||
// if LUA finished a full cycle,
|
||||
// invalidate to display the screen buffer
|
||||
bool useLvgl = useLvglLayout();
|
||||
if (luaTask(true)) {
|
||||
invalidate();
|
||||
if (useLvgl && !hasError) {
|
||||
PROTECT_LUA() {
|
||||
if (!callRefs(lsScripts)) {
|
||||
luaShowError();
|
||||
}
|
||||
} else {
|
||||
luaShowError();
|
||||
}
|
||||
UNPROTECT_LUA();
|
||||
} else {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +207,7 @@ void StandaloneLuaWindow::checkEvents()
|
||||
luaLcdBuffer = nullptr;
|
||||
}
|
||||
|
||||
void StandaloneLuaWindow::onClicked() { LuaEventHandler::onClicked(); }
|
||||
void StandaloneLuaWindow::onClicked() { Keyboard::hide(false); LuaEventHandler::onClicked(); }
|
||||
|
||||
void StandaloneLuaWindow::onCancel() { LuaEventHandler::onCancel(); }
|
||||
|
||||
@@ -210,3 +243,47 @@ bool StandaloneLuaWindow::displayPopup(event_t event, uint8_t type,
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void StandaloneLuaWindow::clear()
|
||||
{
|
||||
clearRefs(lsScripts);
|
||||
Window::clear();
|
||||
}
|
||||
|
||||
void StandaloneLuaWindow::luaShowError()
|
||||
{
|
||||
hasError = true;
|
||||
extern void luaError(lua_State *L, uint8_t error);
|
||||
luaError(lsScripts, SCRIPT_SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
void StandaloneLuaWindow::showError(bool firstCall, const char* title, const char* msg)
|
||||
{
|
||||
hasError = true;
|
||||
if (!errorModal) {
|
||||
lv_obj_set_scroll_dir(lvobj, LV_DIR_NONE);
|
||||
errorModal = lv_obj_create(lvobj);
|
||||
lv_obj_set_pos(errorModal, lv_obj_get_scroll_x(lvobj), lv_obj_get_scroll_y(lvobj));
|
||||
lv_obj_set_size(errorModal, LCD_W, LCD_H);
|
||||
etx_bg_color(errorModal, COLOR_BLACK_INDEX);
|
||||
etx_obj_add_style(errorModal, styles->bg_opacity_75, LV_PART_MAIN);
|
||||
errorTitle = lv_label_create(errorModal);
|
||||
lv_obj_set_pos(errorTitle, 50, 30);
|
||||
lv_obj_set_size(errorTitle, LCD_W - 100, 32);
|
||||
etx_txt_color(errorTitle, COLOR_THEME_PRIMARY2_INDEX);
|
||||
etx_solid_bg(errorTitle, COLOR_THEME_SECONDARY1_INDEX);
|
||||
etx_font(errorTitle, FONT_L_INDEX);
|
||||
etx_obj_add_style(errorTitle, styles->text_align_center, LV_PART_MAIN);
|
||||
errorMsg = lv_label_create(errorModal);
|
||||
lv_obj_set_pos(errorMsg, 50, 62);
|
||||
lv_obj_set_size(errorMsg, LCD_W - 100, LCD_H - 92);
|
||||
lv_obj_set_style_pad_all(errorMsg, 4, LV_PART_MAIN);
|
||||
etx_txt_color(errorMsg, COLOR_THEME_PRIMARY1_INDEX);
|
||||
etx_solid_bg(errorMsg, COLOR_THEME_SECONDARY3_INDEX);
|
||||
etx_font(errorMsg, FONT_STD_INDEX);
|
||||
etx_obj_add_style(errorMsg, styles->text_align_center, LV_PART_MAIN);
|
||||
}
|
||||
|
||||
lv_label_set_text(errorTitle, title);
|
||||
lv_label_set_text(errorMsg, msg);
|
||||
}
|
||||
|
||||
@@ -33,14 +33,15 @@ struct LuaPopup
|
||||
void paint(BitmapBuffer* dc, uint8_t type, const char* text, const char* info);
|
||||
};
|
||||
|
||||
class StandaloneLuaWindow : public Window, public LuaEventHandler
|
||||
class StandaloneLuaWindow : public Window, public LuaEventHandler, public LuaLvglManager
|
||||
{
|
||||
static StandaloneLuaWindow* _instance;
|
||||
|
||||
explicit StandaloneLuaWindow();
|
||||
explicit StandaloneLuaWindow(bool useLvgl);
|
||||
|
||||
public:
|
||||
static StandaloneLuaWindow* instance();
|
||||
static void setup(bool useLvgl);
|
||||
|
||||
void attach();
|
||||
void deleteLater(bool detach = true, bool trash = true) override;
|
||||
@@ -52,8 +53,24 @@ public:
|
||||
bool displayPopup(event_t event, uint8_t type, const char* text,
|
||||
const char* info, bool& result);
|
||||
|
||||
Window* getCurrentParent() const override { return tempParent ? tempParent : (Window*)this; }
|
||||
|
||||
void clear() override;
|
||||
bool useLvglLayout() const override { return useLvgl; }
|
||||
|
||||
void luaShowError() override;
|
||||
|
||||
void showError(bool firstCall, const char* title, const char* msg);
|
||||
|
||||
bool isWidget() override { return false; }
|
||||
|
||||
protected:
|
||||
lv_obj_t* prevScreen = nullptr;
|
||||
lv_obj_t* errorModal = nullptr;
|
||||
lv_obj_t* errorTitle = nullptr;
|
||||
lv_obj_t* errorMsg = nullptr;
|
||||
bool hasError = false;
|
||||
bool useLvgl = false;
|
||||
|
||||
// GFX
|
||||
BitmapBuffer lcdBuffer;
|
||||
|
||||
@@ -75,6 +75,7 @@ class ViewMain : public NavWindow
|
||||
bool onLongPress() override;
|
||||
|
||||
void show(bool visible = true) override;
|
||||
bool viewIsVisible() const { return isVisible; }
|
||||
void showTopBarEdgeTxButton();
|
||||
void hideTopBarEdgeTxButton();
|
||||
|
||||
|
||||
@@ -115,16 +115,17 @@ void Widget::setFullscreen(bool enable)
|
||||
}
|
||||
// Enter Fullscreen Mode
|
||||
else {
|
||||
ViewMain::instance()->enableWidgetSelect(false);
|
||||
|
||||
// ViewMain hidden - re-show this widget
|
||||
show();
|
||||
|
||||
// Set window opaque (inhibits redraw from windows below)
|
||||
setWindowFlag(OPAQUE);
|
||||
|
||||
updateZoneRect(parent->getRect());
|
||||
updateZoneRect(parent->getRect(), false);
|
||||
setRect(parent->getRect());
|
||||
|
||||
ViewMain::instance()->enableWidgetSelect(false);
|
||||
bringToTop();
|
||||
|
||||
if (!lv_obj_get_group(lvobj)) {
|
||||
|
||||
@@ -83,7 +83,7 @@ class Widget : public ButtonBase
|
||||
virtual void background() {}
|
||||
|
||||
// Update widget 'zone' data (for Lua widgets)
|
||||
virtual void updateZoneRect(rect_t rect) {}
|
||||
virtual void updateZoneRect(rect_t rect, bool updateUI = true) {}
|
||||
|
||||
void enableFocus(bool enable);
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ class TimerWidget : public Widget
|
||||
|
||||
int val = lastValue;
|
||||
if (lastStartValue && timerData.showElapsed &&
|
||||
lastStartValue != lastValue)
|
||||
(int)lastStartValue != lastValue)
|
||||
val = (int)lastStartValue - lastValue;
|
||||
|
||||
if (isLarge) {
|
||||
|
||||
@@ -43,7 +43,7 @@ add_custom_target(lua_mixsrc DEPENDS ${HW_DESC_JSON} lua_mixsrc.inc)
|
||||
add_custom_target(lua_keys DEPENDS ${HW_DESC_JSON} lua_keys.inc)
|
||||
|
||||
if(GUI_DIR STREQUAL colorlcd)
|
||||
set(SRC ${SRC} lua/api_colorlcd.cpp lua/widgets.cpp)
|
||||
set(SRC ${SRC} lua/api_colorlcd.cpp lua/api_colorlcd_lvgl.cpp lua/widgets.cpp)
|
||||
else()
|
||||
set(SRC ${SRC} lua/api_stdlcd.cpp)
|
||||
endif()
|
||||
|
||||
@@ -30,17 +30,18 @@
|
||||
#include "theme.h"
|
||||
|
||||
#include "lua_api.h"
|
||||
#include "lua_widget.h"
|
||||
#include "api_colorlcd.h"
|
||||
|
||||
#define BITMAP_METATABLE "BITMAP*"
|
||||
|
||||
constexpr coord_t INVERT_BOX_MARGIN = 2;
|
||||
constexpr int8_t text_horizontal_offset[7] {-2,-1,-2,-2,-2,-2,-2};
|
||||
constexpr int8_t text_vertical_offset[7] {0,0,0,0,0,-1,7};
|
||||
constexpr int8_t text_horizontal_offset[7] = {-2,-1,-2,-2,-2,-2,-2};
|
||||
constexpr int8_t text_vertical_offset[7] = {0,0,0,0,0,-1,7};
|
||||
|
||||
BitmapBuffer* luaLcdBuffer = nullptr;
|
||||
Widget* runningFS = nullptr;
|
||||
|
||||
LuaWidget *runningFS = nullptr;
|
||||
|
||||
static int8_t getTextHorizontalOffset(LcdFlags flags)
|
||||
{
|
||||
// no need to adjust if not right aligned
|
||||
@@ -1413,7 +1414,7 @@ Exit full screen widget mode.
|
||||
static int luaLcdExitFullScreen(lua_State *L)
|
||||
{
|
||||
if (runningFS) {
|
||||
Widget* rfs = runningFS;
|
||||
auto rfs = runningFS;
|
||||
runningFS = nullptr;
|
||||
rfs->setFullscreen(false);
|
||||
}
|
||||
|
||||
@@ -22,3 +22,4 @@
|
||||
#include "definitions.h"
|
||||
|
||||
EXTERN_C(LUALIB_API int luaopen_bitmap(lua_State * L));
|
||||
EXTERN_C(LUALIB_API int luaopen_lvgl(lua_State * L));
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define LUA_LIB
|
||||
|
||||
#include "libopenui.h"
|
||||
#include "lua_api.h"
|
||||
#include "lua_widget.h"
|
||||
#include "opentx.h"
|
||||
|
||||
#include "api_colorlcd.h"
|
||||
|
||||
LuaLvglManager *luaLvglManager = nullptr;
|
||||
|
||||
static int luaLvglObj(lua_State *L, std::function<LvglWidgetObject*()> create, bool standalone = false)
|
||||
{
|
||||
if (luaLvglManager && (!standalone || !luaLvglManager->isWidget())) {
|
||||
auto obj = create();
|
||||
obj->getParams(L, 1);
|
||||
obj->build(L);
|
||||
obj->push(L);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaLvglLabel(lua_State *L)
|
||||
{
|
||||
return luaLvglObj(L, [=]() { return new LvglWidgetLabel(); });
|
||||
}
|
||||
|
||||
static int luaLvglRectangle(lua_State *L)
|
||||
{
|
||||
return luaLvglObj(L, [=]() { return new LvglWidgetRectangle(); });
|
||||
}
|
||||
|
||||
static int luaLvglCircle(lua_State *L)
|
||||
{
|
||||
return luaLvglObj(L, [=]() { return new LvglWidgetCircle(); });
|
||||
}
|
||||
|
||||
static int luaLvglArc(lua_State *L)
|
||||
{
|
||||
return luaLvglObj(L, [=]() { return new LvglWidgetArc(); });
|
||||
}
|
||||
|
||||
static int luaLvglImage(lua_State *L)
|
||||
{
|
||||
return luaLvglObj(L, [=]() { return new LvglWidgetImage(); });
|
||||
}
|
||||
|
||||
static int luaLvglMeter(lua_State *L)
|
||||
{
|
||||
return luaLvglObj(L, [=]() { return new LvglWidgetMeter(); });
|
||||
}
|
||||
|
||||
static int luaLvglButton(lua_State *L)
|
||||
{
|
||||
return luaLvglObj(L, [=]() { return new LvglWidgetTextButton(); }, true);
|
||||
}
|
||||
|
||||
static int luaLvglToggle(lua_State *L)
|
||||
{
|
||||
return luaLvglObj(L, [=]() { return new LvglWidgetToggleSwitch(); }, true);
|
||||
}
|
||||
|
||||
static int luaLvglTextEdit(lua_State *L)
|
||||
{
|
||||
return luaLvglObj(L, [=]() { return new LvglWidgetTextEdit(); }, true);
|
||||
}
|
||||
|
||||
static int luaLvglNumberEdit(lua_State *L)
|
||||
{
|
||||
return luaLvglObj(L, [=]() { return new LvglWidgetNumberEdit(); }, true);
|
||||
}
|
||||
|
||||
static int luaLvglChoice(lua_State *L)
|
||||
{
|
||||
return luaLvglObj(L, [=]() { return new LvglWidgetChoice(); }, true);
|
||||
}
|
||||
|
||||
static int luaLvglSlider(lua_State *L)
|
||||
{
|
||||
return luaLvglObj(L, [=]() { return new LvglWidgetSlider(); }, true);
|
||||
}
|
||||
|
||||
static int luaLvglConfirm(lua_State *L)
|
||||
{
|
||||
auto obj = new LvglWidgetConfirmDialog();
|
||||
obj->getParams(L, 1);
|
||||
obj->build(L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LvglWidgetObject *LvglWidgetObject::checkLvgl(lua_State *L, int index)
|
||||
{
|
||||
LvglWidgetObject **p =
|
||||
(LvglWidgetObject **)luaL_checkudata(L, index, LVGL_METATABLE);
|
||||
if (p) return *p;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static LvglWidgetObject *optLvgl(lua_State *L, int index)
|
||||
{
|
||||
LvglWidgetObject **p =
|
||||
(LvglWidgetObject **)luaL_testudata(L, index, LVGL_METATABLE);
|
||||
if (p) return *p;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static int luaDestroyLvglWidget(lua_State *L)
|
||||
{
|
||||
auto p = LvglWidgetObject::checkLvgl(L, 1);
|
||||
if (p) delete p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaLvglSet(lua_State *L)
|
||||
{
|
||||
auto p = LvglWidgetObject::checkLvgl(L, 1);
|
||||
if (p) {
|
||||
p->update(L);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaLvglClear(lua_State *L)
|
||||
{
|
||||
if (luaLvglManager) luaLvglManager->clear();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaLvglSetParent(lua_State *L)
|
||||
{
|
||||
if (luaLvglManager) {
|
||||
auto p = optLvgl(L, 1);
|
||||
luaLvglManager->setTempParent(p ? p->getWindow() : nullptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaLvglShow(lua_State *L)
|
||||
{
|
||||
auto p = LvglWidgetObject::checkLvgl(L, 1);
|
||||
if (p) {
|
||||
p->show();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaLvglHide(lua_State *L)
|
||||
{
|
||||
auto p = LvglWidgetObject::checkLvgl(L, 1);
|
||||
if (p) {
|
||||
p->hide();
|
||||
}
|
||||
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)) {
|
||||
LvglWidgetParams p(L, -1);
|
||||
LvglWidgetObject *lvobj = nullptr;
|
||||
if (strcasecmp(p.type, "label") == 0)
|
||||
lvobj = new LvglWidgetLabel();
|
||||
else if (strcasecmp(p.type, "rectangle") == 0)
|
||||
lvobj = new LvglWidgetRectangle();
|
||||
else if (strcasecmp(p.type, "circle") == 0)
|
||||
lvobj = new LvglWidgetCircle();
|
||||
else if (strcasecmp(p.type, "arc") == 0)
|
||||
lvobj = new LvglWidgetArc();
|
||||
else if (strcasecmp(p.type, "image") == 0)
|
||||
lvobj = new LvglWidgetImage();
|
||||
else if (strcasecmp(p.type, "meter") == 0)
|
||||
lvobj = new LvglWidgetMeter();
|
||||
else if (!luaLvglManager->isWidget()) {
|
||||
if (strcasecmp(p.type, "button") == 0)
|
||||
lvobj = new LvglWidgetTextButton();
|
||||
else if (strcasecmp(p.type, "toggle") == 0)
|
||||
lvobj = new LvglWidgetToggleSwitch();
|
||||
else if (strcasecmp(p.type, "textEdit") == 0)
|
||||
lvobj = new LvglWidgetTextEdit();
|
||||
else if (strcasecmp(p.type, "numberEdit") == 0)
|
||||
lvobj = new LvglWidgetNumberEdit();
|
||||
else if (strcasecmp(p.type, "choice") == 0)
|
||||
lvobj = new LvglWidgetChoice();
|
||||
else if (strcasecmp(p.type, "slider") == 0)
|
||||
lvobj = new LvglWidgetSlider();
|
||||
}
|
||||
if (lvobj) {
|
||||
lvobj->getParams(L, -1);
|
||||
lvobj->build(L);
|
||||
auto ref = lvobj->getRef(L);
|
||||
if (p.name) {
|
||||
lua_pushstring(L, p.name);
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
lua_settable(L, refIndex - 4);
|
||||
}
|
||||
if (p.hasChildren) {
|
||||
lua_getfield(L, -1, "children");
|
||||
auto prevParent = luaLvglManager->getTempParent();
|
||||
luaLvglManager->setTempParent(lvobj->getWindow());
|
||||
buildLvgl(L, -1, refIndex - 3);
|
||||
lua_pop(L, 1);
|
||||
luaLvglManager->setTempParent(prevParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int luaLvglBuild(lua_State *L)
|
||||
{
|
||||
if (luaLvglManager) {
|
||||
// Return array of lvgl object references
|
||||
lua_newtable(L);
|
||||
buildLvgl(L, -2, -1);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
LROT_BEGIN(lvgllib, NULL, LROT_MASK_GC_INDEX)
|
||||
LROT_FUNCENTRY(__gc, luaDestroyLvglWidget)
|
||||
LROT_TABENTRY(__index, lvgllib)
|
||||
LROT_FUNCENTRY(clear, luaLvglClear)
|
||||
LROT_FUNCENTRY(build, luaLvglBuild)
|
||||
LROT_FUNCENTRY(setParent, luaLvglSetParent)
|
||||
// Objects
|
||||
LROT_FUNCENTRY(label, luaLvglLabel)
|
||||
LROT_FUNCENTRY(rectangle, luaLvglRectangle)
|
||||
LROT_FUNCENTRY(circle, luaLvglCircle)
|
||||
LROT_FUNCENTRY(arc, luaLvglArc)
|
||||
LROT_FUNCENTRY(image, luaLvglImage)
|
||||
LROT_FUNCENTRY(meter, luaLvglMeter)
|
||||
LROT_FUNCENTRY(button, luaLvglButton)
|
||||
LROT_FUNCENTRY(toggle, luaLvglToggle)
|
||||
LROT_FUNCENTRY(confirm, luaLvglConfirm)
|
||||
LROT_FUNCENTRY(textEdit, luaLvglTextEdit)
|
||||
LROT_FUNCENTRY(numberEdit, luaLvglNumberEdit)
|
||||
LROT_FUNCENTRY(choice, luaLvglChoice)
|
||||
LROT_FUNCENTRY(slider, luaLvglSlider)
|
||||
// Manipulation functions
|
||||
LROT_FUNCENTRY(set, luaLvglSet)
|
||||
LROT_FUNCENTRY(show, luaLvglShow)
|
||||
LROT_FUNCENTRY(hide, luaLvglHide)
|
||||
LROT_END(lvgllib, NULL, LROT_MASK_GC_INDEX)
|
||||
|
||||
extern "C" {
|
||||
LUALIB_API int luaopen_lvgl(lua_State *L)
|
||||
{
|
||||
luaL_rometatable(L, LVGL_METATABLE, LROT_TABLEREF(lvgllib));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -2165,7 +2165,15 @@ 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);
|
||||
} else {
|
||||
lua_pushinteger(L, instructionsPercent);
|
||||
}
|
||||
#else
|
||||
lua_pushinteger(L, instructionsPercent);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+19
-34
@@ -35,6 +35,10 @@
|
||||
#include "api_filesystem.h"
|
||||
#include "switches.h"
|
||||
|
||||
#if defined(COLORLCD)
|
||||
#include "standalone_lua.h"
|
||||
#endif
|
||||
|
||||
#if defined(LIBOPENUI)
|
||||
#include "libopenui.h"
|
||||
#else
|
||||
@@ -725,42 +729,11 @@ void displayLuaError(bool firstCall = false)
|
||||
}
|
||||
|
||||
#if defined(COLORLCD)
|
||||
static bool drewBackground = false;
|
||||
|
||||
if (firstCall)
|
||||
drewBackground = false;
|
||||
|
||||
if (!luaLcdAllowed || luaLcdBuffer == nullptr)
|
||||
return;
|
||||
|
||||
coord_t w = 0.75 * LCD_W;
|
||||
coord_t left = (LCD_W - w) / 2;
|
||||
#if (!PORTRAIT_LCD)
|
||||
coord_t hh = getFontHeight(FONT(XL)) + 4;
|
||||
#else
|
||||
coord_t hh = getFontHeight(FONT(L)) + 4;
|
||||
#endif
|
||||
coord_t h = 0.75 * LCD_H - hh;
|
||||
coord_t top = (LCD_H - h + hh / 2) / 2;
|
||||
|
||||
if (!drewBackground) {
|
||||
drewBackground = true;
|
||||
luaLcdBuffer->drawFilledRect(0, 0, LCD_W, LCD_H, SOLID, COLOR_BLACK, OPACITY(6));
|
||||
}
|
||||
|
||||
luaLcdBuffer->drawSolidFilledRect(left, top - hh, w, hh, COLOR_THEME_SECONDARY1);
|
||||
luaLcdBuffer->drawSolidFilledRect(left, top, w, h, COLOR_THEME_SECONDARY3);
|
||||
#if (!PORTRAIT_LCD)
|
||||
luaLcdBuffer->drawText(left + 10, top - hh + 2, title, FONT(XL) | COLOR_THEME_PRIMARY2);
|
||||
luaLcdBuffer->drawTextLines(left + 10, top + 5, w - 20, h - 10, lua_warning_info, FONT(L) | COLOR_THEME_PRIMARY1);
|
||||
#else
|
||||
luaLcdBuffer->drawText(left + 10, top - hh + 2, title, FONT(L) | COLOR_THEME_PRIMARY2);
|
||||
luaLcdBuffer->drawTextLines(left + 10, top + 5, w - 20, h - 10, lua_warning_info, FONT(STD) | COLOR_THEME_PRIMARY1);
|
||||
#endif
|
||||
StandaloneLuaWindow::instance()->showError(firstCall, title, lua_warning_info);
|
||||
#else
|
||||
if (!luaLcdAllowed)
|
||||
return;
|
||||
|
||||
|
||||
drawMessageBox(title);
|
||||
coord_t y = WARNING_LINE_Y + FH + 4;
|
||||
|
||||
@@ -955,6 +928,13 @@ static void luaLoadScripts(bool init, const char * filename = nullptr)
|
||||
sid.run = luaRegisterFunction("run");
|
||||
sid.background = luaRegisterFunction("background");
|
||||
initFunction = luaRegisterFunction("init");
|
||||
#if defined(COLORLCD)
|
||||
if (sid.reference == SCRIPT_STANDALONE) {
|
||||
lua_getfield(lsScripts, -1, "useLvgl");
|
||||
sid.useLvgl = lua_toboolean(lsScripts, -1);
|
||||
lua_pop(lsScripts, 1);
|
||||
}
|
||||
#endif
|
||||
if (sid.run == LUA_NOREF) {
|
||||
snprintf(lua_warning_info, LUA_WARNING_INFO_LEN, "luaLoadScripts(%.*s): No run function\n", LEN_SCRIPT_FILENAME, getScriptName(idx));
|
||||
sid.state = SCRIPT_SYNTAX_ERROR;
|
||||
@@ -985,7 +965,12 @@ static void luaLoadScripts(bool init, const char * filename = nullptr)
|
||||
// If init(), push it on the stack
|
||||
if (initFunction != LUA_NOREF) {
|
||||
lua_rawgeti(lsScripts, LUA_REGISTRYINDEX, initFunction);
|
||||
if (ref == SCRIPT_STANDALONE) luaLcdAllowed = true;
|
||||
if (ref == SCRIPT_STANDALONE) {
|
||||
luaLcdAllowed = true;
|
||||
#if defined(COLORLCD)
|
||||
StandaloneLuaWindow::setup(sid.useLvgl);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _LUA_API_H_
|
||||
#define _LUA_API_H_
|
||||
#pragma once
|
||||
|
||||
#if defined(LUA)
|
||||
|
||||
@@ -66,8 +65,11 @@ extern bool luaLcdAllowed;
|
||||
class BitmapBuffer;
|
||||
extern BitmapBuffer* luaLcdBuffer;
|
||||
|
||||
class Widget;
|
||||
extern Widget* runningFS;
|
||||
class LuaWidget;
|
||||
extern LuaWidget* runningFS;
|
||||
|
||||
class LuaLvglManager;
|
||||
extern LuaLvglManager* luaLvglManager;
|
||||
|
||||
LcdFlags flagsRGB(LcdFlags flags);
|
||||
|
||||
@@ -149,6 +151,9 @@ struct ScriptInternalData {
|
||||
int run;
|
||||
int background;
|
||||
uint8_t instructions;
|
||||
#if defined(COLORLCD)
|
||||
bool useLvgl;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ScriptInputsOutputs {
|
||||
@@ -252,5 +257,3 @@ void * tracer_alloc(void * ud, void * ptr, size_t osize, size_t nsize);
|
||||
#define LUA_LOAD_MODEL_SCRIPTS()
|
||||
|
||||
#endif // defined(LUA)
|
||||
|
||||
#endif // _LUA_API_H_
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define LVGL_METATABLE "LVGL*"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetObjectBase
|
||||
{
|
||||
public:
|
||||
LvglWidgetObjectBase() { lvglManager = luaLvglManager; }
|
||||
virtual ~LvglWidgetObjectBase() {}
|
||||
|
||||
void getParams(lua_State *L, int index);
|
||||
|
||||
virtual void build(lua_State *L);
|
||||
virtual bool callRefs(lua_State *L) = 0;
|
||||
virtual void clearRefs(lua_State *L) = 0;
|
||||
|
||||
protected:
|
||||
LuaLvglManager *lvglManager = nullptr;
|
||||
|
||||
virtual void parseParam(lua_State *L, const char *key) = 0;
|
||||
|
||||
void clearRef(lua_State *L, int ref);
|
||||
|
||||
bool pcallFunc(lua_State *L, int getFuncRef, int nret);
|
||||
void pcallSimpleFunc(lua_State *L, int funcRef);
|
||||
bool pcallUpdateBool(lua_State *L, int getFuncRef,
|
||||
std::function<void(bool)> update);
|
||||
bool pcallUpdate1Int(lua_State *L, int getFuncRef,
|
||||
std::function<void(int)> update);
|
||||
bool pcallUpdate2Int(lua_State *L, int getFuncRef,
|
||||
std::function<void(int, int)> update);
|
||||
int pcallGetIntVal(lua_State *L, int getFuncRef);
|
||||
void pcallSetIntVal(lua_State *L, int setFuncRef, int val);
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetObject : public LvglWidgetObjectBase
|
||||
{
|
||||
public:
|
||||
LvglWidgetObject() : LvglWidgetObjectBase() {}
|
||||
|
||||
int getRef(lua_State *L);
|
||||
void push(lua_State *L);
|
||||
|
||||
void update(lua_State *L);
|
||||
|
||||
virtual void setColor(LcdFlags color) {}
|
||||
virtual void setPos(coord_t x, coord_t y);
|
||||
void setSize(coord_t w, coord_t h);
|
||||
|
||||
void show() { window->show(); }
|
||||
void hide() { window->hide(); }
|
||||
|
||||
Window *getWindow() const { return window; }
|
||||
|
||||
static LvglWidgetObject *checkLvgl(lua_State *L, int index);
|
||||
|
||||
bool callRefs(lua_State *L) override;
|
||||
void clearRefs(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
Window *window = nullptr;
|
||||
LcdFlags currentColor = -1;
|
||||
|
||||
coord_t x = 0, y = 0, w = LV_SIZE_CONTENT, h = LV_SIZE_CONTENT;
|
||||
LcdFlags color = COLOR_THEME_SECONDARY1;
|
||||
int getColorFunction = 0;
|
||||
int getVisibleFunction = 0;
|
||||
int getSizeFunction = 0;
|
||||
int getPosFunction = 0;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
virtual void refresh();
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetLabel : public LvglWidgetObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetLabel() : LvglWidgetObject() {}
|
||||
|
||||
void setText(const char *s);
|
||||
void setColor(LcdFlags color) override;
|
||||
void setFont(LcdFlags font);
|
||||
|
||||
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);
|
||||
int getTextFunction = 0;
|
||||
int getFontFunction = 0;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
void refresh() override
|
||||
{
|
||||
setText(txt);
|
||||
setFont(font);
|
||||
LvglWidgetObject::refresh();
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetBorderedObject : public LvglWidgetObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetBorderedObject() : LvglWidgetObject() {}
|
||||
|
||||
void setColor(LcdFlags color) override;
|
||||
|
||||
void build(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
coord_t thickness = 1;
|
||||
bool filled = false;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetRoundObject : public LvglWidgetBorderedObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetRoundObject() : LvglWidgetBorderedObject() {}
|
||||
|
||||
void setPos(coord_t x, coord_t y) override;
|
||||
void setRadius(coord_t r);
|
||||
|
||||
bool callRefs(lua_State *L) override;
|
||||
void clearRefs(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
coord_t radius = 0;
|
||||
|
||||
int getRadiusFunction = 0;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
void refresh() override
|
||||
{
|
||||
setRadius(radius);
|
||||
LvglWidgetObject::refresh();
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetRectangle : public LvglWidgetBorderedObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetRectangle() : LvglWidgetBorderedObject() {}
|
||||
|
||||
void build(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
coord_t rounded = 0;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetCircle : public LvglWidgetRoundObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetCircle() : LvglWidgetRoundObject() {}
|
||||
|
||||
void build(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetArc : public LvglWidgetRoundObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetArc() : LvglWidgetRoundObject() {}
|
||||
|
||||
void setColor(LcdFlags color) override;
|
||||
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 = 0;
|
||||
int getEndAngleFunction = 0;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
void refresh() override
|
||||
{
|
||||
setStartAngle(startAngle);
|
||||
setEndAngle(endAngle);
|
||||
LvglWidgetRoundObject::refresh();
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetImage : public LvglWidgetObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetImage() : LvglWidgetObject() {}
|
||||
|
||||
void build(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
std::string filename;
|
||||
bool fillFrame = false;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetMeterScale;
|
||||
|
||||
class LvglWidgetMeter : public LvglWidgetRoundObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetMeter() : LvglWidgetRoundObject() {}
|
||||
|
||||
void build(lua_State *L) override;
|
||||
bool callRefs(lua_State *L) override;
|
||||
void clearRefs(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
std::vector<LvglWidgetMeterScale*> scales;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetTextButton : public LvglWidgetObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetTextButton() : LvglWidgetObject() {}
|
||||
|
||||
void setText(const char *s);
|
||||
|
||||
void build(lua_State *L) override;
|
||||
void clearRefs(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
uint32_t textHash = -1;
|
||||
|
||||
const char *txt = "";
|
||||
int pressFunction = 0;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetToggleSwitch : public LvglWidgetObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetToggleSwitch() : LvglWidgetObject() {}
|
||||
|
||||
void build(lua_State *L) override;
|
||||
void clearRefs(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
int getStateFunction = 0;
|
||||
int setStateFunction = 0;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetConfirmDialog : public LvglWidgetObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetConfirmDialog() : LvglWidgetObject() {}
|
||||
|
||||
void build(lua_State *L) override;
|
||||
void clearRefs(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
const char *title = nullptr;
|
||||
const char *message = nullptr;
|
||||
|
||||
int confirmFunction = 0;
|
||||
int cancelFunction = 0;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetTextEdit : public LvglWidgetObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetTextEdit() : LvglWidgetObject() {}
|
||||
|
||||
void build(lua_State *L) override;
|
||||
void clearRefs(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
const char *txt = "";
|
||||
char value[129];
|
||||
int maxLen = 32;
|
||||
|
||||
int setFunction = 0;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetNumberEdit : public LvglWidgetObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetNumberEdit() : LvglWidgetObject() {}
|
||||
|
||||
void build(lua_State *L) override;
|
||||
void clearRefs(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
int min = -1024, max = 1024;
|
||||
|
||||
int getFunction = 0;
|
||||
int setFunction = 0;
|
||||
int dispFunction = 0;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetChoice : public LvglWidgetObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetChoice() : LvglWidgetObject() {}
|
||||
|
||||
void build(lua_State *L) override;
|
||||
void clearRefs(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
std::string title;
|
||||
std::vector<std::string> values;
|
||||
|
||||
int getFunction = 0;
|
||||
int setFunction = 0;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LvglWidgetSlider : public LvglWidgetObject
|
||||
{
|
||||
public:
|
||||
LvglWidgetSlider() : LvglWidgetObject() {}
|
||||
|
||||
void build(lua_State *L) override;
|
||||
void clearRefs(lua_State *L) override;
|
||||
|
||||
protected:
|
||||
int32_t vmin = 0;
|
||||
int32_t vmax = 100;
|
||||
int getValueFunction = 0;
|
||||
int setValueFunction = 0;
|
||||
|
||||
void parseParam(lua_State *L, const char *key) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
+111
-34
@@ -25,6 +25,7 @@
|
||||
#include "lua_event.h"
|
||||
#include "lua_widget_factory.h"
|
||||
#include "touch.h"
|
||||
#include "view_main.h"
|
||||
|
||||
#define MAX_INSTRUCTIONS (20000 / 100)
|
||||
|
||||
@@ -162,7 +163,9 @@ void LuaEventHandler::onClicked()
|
||||
luaPushEvent(EVT_KEY_BREAK(KEY_ENTER));
|
||||
}
|
||||
|
||||
void LuaEventHandler::onCancel() { luaPushEvent(EVT_KEY_BREAK(KEY_EXIT)); }
|
||||
void LuaEventHandler::onCancel() {
|
||||
luaPushEvent(EVT_KEY_BREAK(KEY_EXIT));
|
||||
}
|
||||
|
||||
void LuaEventHandler::onEvent(event_t event)
|
||||
{
|
||||
@@ -189,28 +192,35 @@ void LuaWidget::redraw_cb(lv_event_t* e)
|
||||
LuaWidget* widget = (LuaWidget*)lv_obj_get_user_data(target);
|
||||
|
||||
if (widget) {
|
||||
lv_draw_ctx_t* draw_ctx = lv_event_get_draw_ctx(e);
|
||||
if (widget->useLvglLayout()) {
|
||||
if (!widget->isCreated()) {
|
||||
widget->update();
|
||||
widget->setCreated();
|
||||
}
|
||||
} else {
|
||||
lv_draw_ctx_t* draw_ctx = lv_event_get_draw_ctx(e);
|
||||
|
||||
lv_area_t a, clipping, obj_coords;
|
||||
lv_area_copy(&a, draw_ctx->buf_area);
|
||||
lv_area_copy(&clipping, draw_ctx->clip_area);
|
||||
lv_obj_get_coords(target, &obj_coords);
|
||||
lv_area_t a, clipping, obj_coords;
|
||||
lv_area_copy(&a, draw_ctx->buf_area);
|
||||
lv_area_copy(&clipping, draw_ctx->clip_area);
|
||||
lv_obj_get_coords(target, &obj_coords);
|
||||
|
||||
auto w = a.x2 - a.x1 + 1;
|
||||
auto h = a.y2 - a.y1 + 1;
|
||||
auto w = a.x2 - a.x1 + 1;
|
||||
auto h = a.y2 - a.y1 + 1;
|
||||
|
||||
TRACE_WINDOWS("Draw %s", widget->getWindowDebugString().c_str());
|
||||
TRACE_WINDOWS("Draw %s", widget->getWindowDebugString().c_str());
|
||||
|
||||
BitmapBuffer buf = {BMP_RGB565, (uint16_t)w, (uint16_t)h,
|
||||
(uint16_t*)draw_ctx->buf};
|
||||
BitmapBuffer buf = {BMP_RGB565, (uint16_t)w, (uint16_t)h,
|
||||
(uint16_t*)draw_ctx->buf};
|
||||
|
||||
buf.setDrawCtx(draw_ctx);
|
||||
buf.setDrawCtx(draw_ctx);
|
||||
|
||||
buf.setOffset(obj_coords.x1 - a.x1, obj_coords.y1 - a.y1);
|
||||
buf.setClippingRect(clipping.x1 - a.x1, clipping.x2 + 1 - a.x1,
|
||||
clipping.y1 - a.y1, clipping.y2 + 1 - a.y1);
|
||||
buf.setOffset(obj_coords.x1 - a.x1, obj_coords.y1 - a.y1);
|
||||
buf.setClippingRect(clipping.x1 - a.x1, clipping.x2 + 1 - a.x1,
|
||||
clipping.y1 - a.y1, clipping.y2 + 1 - a.y1);
|
||||
|
||||
widget->refresh(&buf);
|
||||
widget->refresh(&buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,11 +228,12 @@ LuaWidget::LuaWidget(const WidgetFactory* factory, Window* parent,
|
||||
const rect_t& rect, WidgetPersistentData* persistentData,
|
||||
int luaWidgetDataRef, int zoneRectDataRef) :
|
||||
Widget(factory, parent, rect, persistentData),
|
||||
luaWidgetDataRef(luaWidgetDataRef),
|
||||
zoneRectDataRef(zoneRectDataRef),
|
||||
errorMessage(nullptr)
|
||||
{
|
||||
lv_obj_add_event_cb(lvobj, LuaWidget::redraw_cb, LV_EVENT_DRAW_MAIN, nullptr);
|
||||
this->luaWidgetDataRef = luaWidgetDataRef;
|
||||
lv_obj_add_event_cb(lvobj, LuaWidget::redraw_cb, LV_EVENT_DRAW_MAIN,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
LuaWidget::~LuaWidget()
|
||||
@@ -258,12 +269,32 @@ void LuaWidget::checkEvents()
|
||||
|
||||
// paint has not been called
|
||||
if (!refreshed) {
|
||||
background();
|
||||
if (isCreated())
|
||||
background();
|
||||
refreshed = true;
|
||||
}
|
||||
|
||||
refreshed = false;
|
||||
invalidate();
|
||||
if (useLvglLayout()) {
|
||||
if (!lv_obj_has_flag(lvobj, LV_OBJ_FLAG_HIDDEN) && isCreated()) {
|
||||
PROTECT_LUA() {
|
||||
luaLvglManager = this;
|
||||
refresh(nullptr);
|
||||
if (!errorMessage) {
|
||||
if (!callRefs(lsWidgets)) {
|
||||
setErrorMessage("callRefs()");
|
||||
}
|
||||
}
|
||||
refreshInstructionsPercent = instructionsPercent;
|
||||
} else {
|
||||
// TODO: error handling
|
||||
}
|
||||
luaLvglManager = nullptr;
|
||||
UNPROTECT_LUA();
|
||||
}
|
||||
} else {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
TRACE_WINDOWS("# refresh: %s", getWindowDebugString().c_str());
|
||||
@@ -282,10 +313,9 @@ void LuaWidget::update()
|
||||
Widget::update();
|
||||
|
||||
if (lsWidgets == 0 || errorMessage) return;
|
||||
LuaWidgetFactory* lua_factory = (LuaWidgetFactory*)factory;
|
||||
|
||||
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, lua_factory->updateFunction);
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaFactory()->updateFunction);
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef);
|
||||
|
||||
lua_newtable(lsWidgets);
|
||||
@@ -308,9 +338,12 @@ void LuaWidget::update()
|
||||
}
|
||||
}
|
||||
|
||||
if (lua_pcall(lsWidgets, 2, 0, 0) != 0) {
|
||||
if (useLvglLayout()) luaLvglManager = this;
|
||||
|
||||
if (lua_pcall(lsWidgets, 2, 0, 0) != 0)
|
||||
setErrorMessage("update()");
|
||||
}
|
||||
|
||||
luaLvglManager = nullptr;
|
||||
}
|
||||
|
||||
// Update table on top of Lua stack - set entry with name 'idx' to value 'val'
|
||||
@@ -338,7 +371,7 @@ bool LuaWidget::updateTable(const char* idx, int val)
|
||||
return update;
|
||||
}
|
||||
|
||||
void LuaWidget::updateZoneRect(rect_t rect)
|
||||
void LuaWidget::updateZoneRect(rect_t rect, bool updateUI)
|
||||
{
|
||||
if (lsWidgets) {
|
||||
// Update widget zone with current size and position
|
||||
@@ -354,7 +387,8 @@ void LuaWidget::updateZoneRect(rect_t rect)
|
||||
|
||||
lua_pop(lsWidgets, 1);
|
||||
|
||||
if (changed) update();
|
||||
if (changed && updateUI)
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,15 +425,28 @@ void LuaWidget::refresh(BitmapBuffer* dc)
|
||||
if (lsWidgets == 0) return;
|
||||
|
||||
if (errorMessage) {
|
||||
dc->drawTextLines(0, 0, fullscreen ? LCD_W : rect.w,
|
||||
fullscreen ? LCD_H : rect.h, errorMessage,
|
||||
FONT(XS) | COLOR_THEME_WARNING);
|
||||
if (dc) {
|
||||
dc->drawTextLines(0, 0, fullscreen ? LCD_W : rect.w,
|
||||
fullscreen ? LCD_H : rect.h, errorMessage,
|
||||
FONT(XS) | COLOR_THEME_WARNING);
|
||||
} else {
|
||||
if (errorLabel == nullptr) {
|
||||
errorLabel = lv_label_create(lvobj);
|
||||
lv_obj_set_pos(errorLabel, 0, 0);
|
||||
lv_obj_set_size(errorLabel, width(), height());
|
||||
lv_label_set_long_mode(errorLabel, LV_LABEL_LONG_WRAP);
|
||||
etx_txt_color(errorLabel, COLOR_THEME_WARNING_INDEX);
|
||||
etx_font(errorLabel, FONT_XS_INDEX);
|
||||
etx_bg_color(errorLabel, COLOR_THEME_SECONDARY3_INDEX);
|
||||
etx_obj_add_style(errorLabel, styles->bg_opacity_75, LV_PART_MAIN);
|
||||
}
|
||||
lv_label_set_text(errorLabel, errorMessage);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
|
||||
LuaWidgetFactory* factory = (LuaWidgetFactory*)this->factory;
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->refreshFunction);
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaFactory()->refreshFunction);
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef);
|
||||
|
||||
// Pass key event to fullscreen Lua widget
|
||||
@@ -445,9 +492,8 @@ void LuaWidget::background()
|
||||
|
||||
// TRACE("LuaWidget::background()");
|
||||
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
|
||||
LuaWidgetFactory* factory = (LuaWidgetFactory*)this->factory;
|
||||
if (factory->backgroundFunction) {
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->backgroundFunction);
|
||||
if (luaFactory()->backgroundFunction) {
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaFactory()->backgroundFunction);
|
||||
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef);
|
||||
runningFS = this;
|
||||
if (lua_pcall(lsWidgets, 1, 0, 0) != 0) {
|
||||
@@ -464,3 +510,34 @@ void LuaWidget::onEvent(event_t event)
|
||||
}
|
||||
Widget::onEvent(event);
|
||||
}
|
||||
|
||||
void LuaWidget::clear()
|
||||
{
|
||||
clearRefs(lsWidgets);
|
||||
Widget::clear();
|
||||
}
|
||||
|
||||
bool LuaWidget::useLvglLayout() const { return luaFactory()->useLvglLayout(); }
|
||||
|
||||
void LuaLvglManager::clearRefs(lua_State *L)
|
||||
{
|
||||
for (size_t i = 0; i < lvglObjectRefs.size(); i += 1) {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, lvglObjectRefs[i]);
|
||||
auto lvobj = LvglWidgetObject::checkLvgl(L, -1);
|
||||
lvobj->clearRefs(L);
|
||||
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, lvglObjectRefs[i]);
|
||||
}
|
||||
lvglObjectRefs.clear();
|
||||
}
|
||||
|
||||
bool LuaLvglManager::callRefs(lua_State *L)
|
||||
{
|
||||
bool rv = true;
|
||||
for (size_t i = 0; i < lvglObjectRefs.size(); i += 1) {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, lvglObjectRefs[i]);
|
||||
auto lvobj = LvglWidgetObject::checkLvgl(L, -1);
|
||||
lvobj->callRefs(L);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -21,14 +21,47 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "window.h"
|
||||
#include "widget.h"
|
||||
#include "lua_api.h"
|
||||
#include "lua_lvgl_widget.h"
|
||||
|
||||
#include "opentx_types.h"
|
||||
|
||||
#define LUA_TAP_TIME 250 // 250 ms
|
||||
|
||||
class LuaWidgetFactory;
|
||||
|
||||
class LuaLvglManager
|
||||
{
|
||||
public:
|
||||
LuaLvglManager() = default;
|
||||
|
||||
std::vector<int> getLvglObjectRefs() const { return lvglObjectRefs; }
|
||||
void saveLvglObjectRef(int ref) { lvglObjectRefs.push_back(ref); }
|
||||
void clearRefs(lua_State *L);
|
||||
bool callRefs(lua_State *L);
|
||||
|
||||
void setTempParent(Window *p) { tempParent = p; }
|
||||
Window* getTempParent() const { return tempParent; }
|
||||
|
||||
virtual Window* getCurrentParent() const = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual bool useLvglLayout() const = 0;
|
||||
|
||||
virtual void luaShowError() = 0;
|
||||
|
||||
virtual bool isWidget() = 0;
|
||||
|
||||
uint8_t refreshInstructionsPercent;
|
||||
|
||||
protected:
|
||||
std::vector<int> lvglObjectRefs;
|
||||
Window* tempParent = nullptr;
|
||||
};
|
||||
|
||||
class LuaEventHandler
|
||||
{
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
@@ -55,11 +88,10 @@ public:
|
||||
void removeHandler(Window* w);
|
||||
};
|
||||
|
||||
class LuaWidget : public Widget, public LuaEventHandler
|
||||
class LuaWidget : public Widget, public LuaEventHandler, public LuaLvglManager
|
||||
{
|
||||
friend class LuaWidgetFactory;
|
||||
|
||||
int luaWidgetDataRef;
|
||||
int zoneRectDataRef;
|
||||
char* errorMessage;
|
||||
bool refreshed = false;
|
||||
@@ -75,7 +107,7 @@ class LuaWidget : public Widget, public LuaEventHandler
|
||||
void setErrorMessage(const char* funcName);
|
||||
|
||||
// Update 'zone' data
|
||||
void updateZoneRect(rect_t rect) override;
|
||||
void updateZoneRect(rect_t rect, bool updateUI = true) override;
|
||||
bool updateTable(const char* idx, int val);
|
||||
|
||||
public:
|
||||
@@ -92,9 +124,26 @@ class LuaWidget : public Widget, public LuaEventHandler
|
||||
void update() override;
|
||||
void background() override;
|
||||
|
||||
void clear() override;
|
||||
|
||||
LuaWidgetFactory* luaFactory() const { return (LuaWidgetFactory*)factory; }
|
||||
bool isCreated() const { return created; }
|
||||
void setCreated() { created = true; }
|
||||
|
||||
Window* getCurrentParent() const override { return tempParent ? tempParent : (Window*)this; }
|
||||
|
||||
bool useLvglLayout() const override;
|
||||
|
||||
void luaShowError() override {}
|
||||
|
||||
bool isWidget() override { return true; }
|
||||
|
||||
protected:
|
||||
bool created = false;
|
||||
lv_obj_t* errorLabel = nullptr;
|
||||
// Calls LUA widget 'refresh' method
|
||||
void refresh(BitmapBuffer* dc);
|
||||
int luaWidgetDataRef = 0;
|
||||
|
||||
// Window interface
|
||||
void onEvent(event_t event) override;
|
||||
|
||||
@@ -39,6 +39,8 @@ class LuaWidgetFactory : public WidgetFactory
|
||||
|
||||
bool isLuaWidgetFactory() const override { return true; }
|
||||
|
||||
bool useLvglLayout() const { return lvglLayout; }
|
||||
|
||||
protected:
|
||||
void translateOptions(ZoneOption * options);
|
||||
|
||||
@@ -47,4 +49,5 @@ class LuaWidgetFactory : public WidgetFactory
|
||||
int refreshFunction;
|
||||
int backgroundFunction;
|
||||
int translateFunction;
|
||||
bool lvglLayout;
|
||||
};
|
||||
|
||||
@@ -235,6 +235,7 @@ void luaLoadWidgetCallback()
|
||||
|
||||
int widgetOptions = 0, createFunction = 0, updateFunction = 0,
|
||||
refreshFunction = 0, backgroundFunction = 0, translateFunction = 0;
|
||||
bool lvglLayout = false;
|
||||
|
||||
luaL_checktype(lsWidgets, -1, LUA_TTABLE);
|
||||
|
||||
@@ -267,6 +268,9 @@ void luaLoadWidgetCallback()
|
||||
translateFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
|
||||
lua_pushnil(lsWidgets);
|
||||
}
|
||||
else if (!strcasecmp(key, "uselvgl")) {
|
||||
lvglLayout = lua_toboolean(lsWidgets, -1);
|
||||
}
|
||||
}
|
||||
|
||||
if (name && createFunction) {
|
||||
@@ -276,6 +280,7 @@ void luaLoadWidgetCallback()
|
||||
factory->updateFunction = updateFunction;
|
||||
factory->refreshFunction = refreshFunction;
|
||||
factory->backgroundFunction = backgroundFunction; // NOSONAR
|
||||
factory->lvglLayout = lvglLayout;
|
||||
factory->translateFunction = translateFunction;
|
||||
factory->translateOptions(options);
|
||||
TRACE("Loaded Lua widget %s", name);
|
||||
|
||||
+1
-1
@@ -601,7 +601,7 @@
|
||||
|
||||
#define LV_USE_MENU 0
|
||||
|
||||
#define LV_USE_METER 0
|
||||
#define LV_USE_METER 1
|
||||
|
||||
#define LV_USE_MSGBOX 0
|
||||
|
||||
|
||||
@@ -375,6 +375,8 @@ void guiMain(event_t evt)
|
||||
maxLuaInterval = interval;
|
||||
}
|
||||
|
||||
luaDoGc(lsWidgets, true);
|
||||
|
||||
DEBUG_TIMER_START(debugTimerLua);
|
||||
luaTask(false);
|
||||
DEBUG_TIMER_STOP(debugTimerLua);
|
||||
|
||||
Vendored
+3
@@ -43,6 +43,7 @@ extern LROT_TABLE(modellib);
|
||||
extern LROT_TABLE(bitmaplib);
|
||||
|
||||
#if defined(COLORLCD)
|
||||
extern LROT_TABLE(lvgllib);
|
||||
extern LROT_TABLE(tablib);
|
||||
#endif
|
||||
|
||||
@@ -99,6 +100,7 @@ LROT_BEGIN(rotables, LROT_TABLEREF(rotables_meta), 0)
|
||||
LROT_TABENTRY( bitmap, bitmaplib )
|
||||
LROT_TABENTRY( Bitmap, bitmaplib ) /* TODO: obsolete after 2.9 */
|
||||
#if defined(COLORLCD)
|
||||
LROT_TABENTRY( lvgl, lvgllib )
|
||||
LROT_TABENTRY( table, tablib )
|
||||
#endif
|
||||
LROT_TABENTRY( ROM, rotables )
|
||||
@@ -110,6 +112,7 @@ LROT_BEGIN(lua_libs, NULL, 0)
|
||||
LROT_FUNCENTRY( dir, luaopen_etxdir )
|
||||
LROT_FUNCENTRY( bitmap_mt, luaopen_bitmap )
|
||||
#if defined(COLORLCD)
|
||||
LROT_FUNCENTRY( lvgl_mt, luaopen_lvgl )
|
||||
LROT_FUNCENTRY( package, luaopen_package )
|
||||
#endif
|
||||
#if defined(LUA_ENABLE_STRLIB_MT)
|
||||
|
||||
+3
-3
@@ -183,8 +183,8 @@ void StaticIcon::center(coord_t w, coord_t h)
|
||||
// Display image from file system using LVGL with LVGL scaling
|
||||
// - LVGL scaling is slow so don't use this if there are many images
|
||||
StaticImage::StaticImage(Window* parent, const rect_t& rect,
|
||||
const char* filename, bool dontEnlarge) :
|
||||
Window(parent, rect), dontEnlarge(dontEnlarge)
|
||||
const char* filename, bool fillFrame, bool dontEnlarge) :
|
||||
Window(parent, rect), fillFrame(fillFrame), dontEnlarge(dontEnlarge)
|
||||
{
|
||||
setWindowFlag(NO_FOCUS);
|
||||
|
||||
@@ -234,7 +234,7 @@ void StaticImage::setZoom()
|
||||
if (img && img->w && img->h) {
|
||||
uint16_t zw = (width() * 256) / img->w;
|
||||
uint16_t zh = (height() * 256) / img->h;
|
||||
uint16_t z = min(zw, zh);
|
||||
uint16_t z = fillFrame ? max(zw, zh) : min(zw, zh);
|
||||
if (dontEnlarge) z = min(z, (uint16_t)256);
|
||||
lv_img_set_zoom(image, z);
|
||||
}
|
||||
|
||||
+2
-1
@@ -142,7 +142,7 @@ class StaticImage : public Window
|
||||
{
|
||||
public:
|
||||
StaticImage(Window *parent, const rect_t &rect,
|
||||
const char *filename = nullptr, bool dontEnlarge = false);
|
||||
const char *filename = nullptr, bool fillFrame = false, bool dontEnlarge = false);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "StaticImage"; }
|
||||
@@ -154,6 +154,7 @@ class StaticImage : public Window
|
||||
bool hasImage() const;
|
||||
|
||||
protected:
|
||||
bool fillFrame;
|
||||
bool dontEnlarge = false;
|
||||
lv_obj_t *image = nullptr;
|
||||
};
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ class Window
|
||||
typedef std::function<void(bool)> FocusHandler;
|
||||
void setFocusHandler(FocusHandler h) { focusHandler = std::move(h); }
|
||||
|
||||
void clear();
|
||||
virtual void clear();
|
||||
virtual void deleteLater(bool detach = true, bool trash = true);
|
||||
|
||||
bool hasFocus() const;
|
||||
|
||||
Reference in New Issue
Block a user