feat(color): enhancements and fixes for Lua LVGL API (#5558)

New:
line and triangle primitives
message popup dialog
expose buttons for for font, alignment, color, timer, switch and source pickers
generic popup dialog that can be filled with other things
lvgl.isAppMode() function to let widgets know when app mode is active
additional containers for creating layouts (box and setting)
flex layouts

Fixes:
colors are updated when theme changes
fix memory leaks when stand alone scripts close
run stand alone scripts in a separate Lua state and use lua_pcallk() to prevent cross boundary errors (color only)
This commit is contained in:
philmoz
2024-09-30 09:41:48 +10:00
committed by GitHub
parent 471f87fc2a
commit c1c600cf35
63 changed files with 2124 additions and 1181 deletions
@@ -61,9 +61,9 @@ class ColorEditorPopup : public BaseDialog
}
public:
ColorEditorPopup(Window* parent, uint32_t color,
ColorEditorPopup(uint32_t color,
std::function<void(uint32_t)> _setValue) :
BaseDialog(parent, STR_COLOR_PICKER, false, COLOR_EDIT_WIDTH,
BaseDialog(STR_COLOR_PICKER, false, COLOR_EDIT_WIDTH,
LV_SIZE_CONTENT)
{
FlexGridLayout grid(col_dsc, row_dsc);
@@ -170,7 +170,7 @@ ColorPicker::ColorPicker(Window* parent, const rect_t& rect,
void ColorPicker::onClicked()
{
new ColorEditorPopup(this, getColor(), [=](uint32_t c) { setColor(c); });
new ColorEditorPopup(getColor(), [=](uint32_t c) { setColor(c); });
}
void ColorPicker::setColor(uint32_t c)
@@ -186,7 +186,7 @@ void SourceChoice::openMenu()
inverted = getIntValue() < 0;
inMenu = true;
auto menu = new Menu(this);
auto menu = new Menu();
if (menuTitle) menu->setTitle(menuTitle);
auto tb = new SourceChoiceMenuToolbar(this, menu);
@@ -131,7 +131,7 @@ void SwitchChoice::openMenu()
{
setEditMode(true); // this needs to be done first before menu is created.
auto menu = new Menu(this);
auto menu = new Menu();
if (menuTitle) menu->setTitle(menuTitle);
inverted = _getValue() < 0;
+1 -1
View File
@@ -215,7 +215,7 @@ void Choice::openMenu()
{
setEditMode(true); // this needs to be done first before menu is created.
auto menu = new Menu(this);
auto menu = new Menu();
if (menuTitle) menu->setTitle(menuTitle);
fillMenu(menu);
+18 -17
View File
@@ -28,21 +28,22 @@
class BaseDialogForm : public Window
{
public:
BaseDialogForm(Window* parent, lv_coord_t width) : Window(parent, rect_t{})
BaseDialogForm(Window* parent, lv_coord_t width, bool flexLayout) : Window(parent, rect_t{})
{
etx_scrollbar(lvobj);
padAll(PAD_MEDIUM);
setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_MEDIUM, width, LV_SIZE_CONTENT);
padAll(PAD_TINY);
if (flexLayout)
setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO, width, LV_SIZE_CONTENT);
}
protected:
void onClicked() override { Keyboard::hide(false); }
};
BaseDialog::BaseDialog(Window* parent, const char* title,
BaseDialog::BaseDialog(const char* title,
bool closeIfClickedOutside, lv_coord_t width,
lv_coord_t maxHeight) :
ModalWindow(parent, closeIfClickedOutside)
lv_coord_t maxHeight, bool flexLayout) :
ModalWindow(closeIfClickedOutside)
{
auto content = new Window(this, rect_t{});
content->setWindowFlag(OPAQUE);
@@ -56,7 +57,7 @@ BaseDialog::BaseDialog(Window* parent, const char* title,
header->padAll(PAD_SMALL);
header->show(title != nullptr);
form = new BaseDialogForm(content, width);
form = new BaseDialogForm(content, width, flexLayout);
if (maxHeight != LV_SIZE_CONTENT)
lv_obj_set_style_max_height(form->getLvObj(), maxHeight - EdgeTxStyles::UI_ELEMENT_HEIGHT, LV_PART_MAIN);
}
@@ -68,9 +69,9 @@ void BaseDialog::setTitle(const char* title)
//-----------------------------------------------------------------------------
ProgressDialog::ProgressDialog(Window* parent, const char* title,
ProgressDialog::ProgressDialog(const char* title,
std::function<void()> onClose) :
BaseDialog(parent, title, false), onClose(std::move(onClose))
BaseDialog(title, false), onClose(std::move(onClose))
{
progress = new Progress(form, rect_t{0, 0, LV_PCT(100), 32});
updateProgress(0);
@@ -96,10 +97,10 @@ void ProgressDialog::closeDialog()
//-----------------------------------------------------------------------------
MessageDialog::MessageDialog(Window* parent, const char* title,
MessageDialog::MessageDialog(const char* title,
const char* message, const char* info,
LcdFlags messageFlags, LcdFlags infoFlags) :
BaseDialog(parent, title, true)
BaseDialog(title, true)
{
messageWidget = new StaticText(form, {0, 0, LV_PCT(100), LV_SIZE_CONTENT},
message, COLOR_THEME_PRIMARY1_INDEX, messageFlags);
@@ -115,9 +116,9 @@ void MessageDialog::onClicked() { deleteLater(); }
//-----------------------------------------------------------------------------
DynamicMessageDialog::DynamicMessageDialog(
Window* parent, const char* title, std::function<std::string()> textHandler,
const char* title, std::function<std::string()> textHandler,
const char* message, const int lineHeight, LcdColorIndex color, LcdFlags textFlags) :
BaseDialog(parent, title, true)
BaseDialog(title, true)
{
messageWidget = new StaticText(form, {0, 0, LV_PCT(100), LV_SIZE_CONTENT},
message, COLOR_THEME_PRIMARY1_INDEX, CENTERED);
@@ -130,11 +131,11 @@ void DynamicMessageDialog::onClicked() { deleteLater(); }
//-----------------------------------------------------------------------------
ConfirmDialog::ConfirmDialog(Window* parent, const char* title,
ConfirmDialog::ConfirmDialog(const char* title,
const char* message,
std::function<void(void)> confirmHandler,
std::function<void(void)> cancelHandler) :
BaseDialog(parent, title, false),
BaseDialog(title, false),
confirmHandler(std::move(confirmHandler)),
cancelHandler(std::move(cancelHandler))
{
@@ -168,9 +169,9 @@ void ConfirmDialog::onCancel()
//-----------------------------------------------------------------------------
LabelDialog::LabelDialog(Window *parent, const char *label, int length, const char* title,
LabelDialog::LabelDialog(const char *label, int length, const char* title,
std::function<void(std::string)> _saveHandler) :
ModalWindow(parent, false), saveHandler(std::move(_saveHandler))
ModalWindow(false), saveHandler(std::move(_saveHandler))
{
assert(length <= MAX_LABEL_LENGTH);
+8 -8
View File
@@ -33,9 +33,10 @@ class Progress;
class BaseDialog : public ModalWindow
{
public:
BaseDialog(Window* parent, const char* title, bool closeIfClickedOutside,
BaseDialog(const char* title, bool closeIfClickedOutside,
lv_coord_t width = DIALOG_DEFAULT_WIDTH,
lv_coord_t maxHeight = DIALOG_DEFAULT_HEIGHT);
lv_coord_t maxHeight = DIALOG_DEFAULT_HEIGHT,
bool flexLayout = true);
void setTitle(const char* title);
@@ -52,8 +53,7 @@ class BaseDialog : public ModalWindow
class ProgressDialog : public BaseDialog
{
public:
ProgressDialog(Window* parent, const char* title,
std::function<void()> onClose);
ProgressDialog(const char* title, std::function<void()> onClose);
void updateProgress(int percentage);
void setTitle(std::string title);
@@ -74,7 +74,7 @@ class ProgressDialog : public BaseDialog
class MessageDialog : public BaseDialog
{
public:
MessageDialog(Window* parent, const char* title, const char* message,
MessageDialog(const char* title, const char* message,
const char* info = nullptr, LcdFlags messageFlags = CENTERED,
LcdFlags infoFlags = CENTERED);
@@ -94,7 +94,7 @@ class MessageDialog : public BaseDialog
class DynamicMessageDialog : public BaseDialog
{
public:
DynamicMessageDialog(Window* parent, const char* title,
DynamicMessageDialog(const char* title,
std::function<std::string()> textHandler,
const char* message = "",
const int lineHeight = EdgeTxStyles::PAGE_LINE_HEIGHT,
@@ -117,7 +117,7 @@ class DynamicMessageDialog : public BaseDialog
class ConfirmDialog : public BaseDialog
{
public:
ConfirmDialog(Window* parent, const char* title, const char* message,
ConfirmDialog(const char* title, const char* message,
std::function<void(void)> confirmHandler,
std::function<void(void)> cancelHandler = nullptr);
@@ -133,7 +133,7 @@ class ConfirmDialog : public BaseDialog
class LabelDialog : public ModalWindow
{
public:
LabelDialog(Window *parent, const char *label, int length, const char* title,
LabelDialog(const char *label, int length, const char* title,
std::function<void(std::string)> _saveHandler = nullptr);
static constexpr int MAX_LABEL_LENGTH = 255;
+25 -2
View File
@@ -236,6 +236,7 @@ EdgeTxStyles::EdgeTxStyles()
lv_style_set_img_recolor_opa(&img_color[i], LV_OPA_COVER);
lv_style_init(&border_color[i]);
lv_style_init(&arc_color[i]);
lv_style_init(&line_color[i]);
}
lv_style_init(&outline_color_light);
lv_style_init(&outline_color_normal);
@@ -310,6 +311,7 @@ void EdgeTxStyles::applyColors()
lv_style_set_img_recolor(&img_color[i], c);
lv_style_set_border_color(&border_color[i], c);
lv_style_set_arc_color(&arc_color[i], c);
lv_style_set_line_color(&line_color[i], c);
}
lv_style_set_line_color(&graph_border, makeLvColor(COLOR_THEME_SECONDARY2));
@@ -466,12 +468,33 @@ void etx_arc_color(lv_obj_t* obj, LcdColorIndex colorIdx,
etx_obj_add_style(obj, styles->arc_color[colorIdx], selector);
}
void etx_remove_line_color(lv_obj_t* obj, lv_style_selector_t selector)
{
// Remove styles
for (int i = 0; i < TOTAL_COLOR_COUNT; i += 1)
lv_obj_remove_style(obj, &styles->line_color[i], selector);
}
void etx_line_color(lv_obj_t* obj, LcdColorIndex colorIdx,
lv_style_selector_t selector)
{
// Remove old style first
etx_remove_line_color(obj, selector);
etx_obj_add_style(obj, styles->line_color[colorIdx], selector);
}
void etx_remove_img_color(lv_obj_t* obj, lv_style_selector_t selector)
{
// Remove styles
for (int i = 0; i < TOTAL_COLOR_COUNT; i += 1)
lv_obj_remove_style(obj, &styles->img_color[i], selector);
}
void etx_img_color(lv_obj_t* obj, LcdColorIndex colorIdx,
lv_style_selector_t selector)
{
// Remove old style first
for (int i = 0; i < TOTAL_COLOR_COUNT; i += 1)
lv_obj_remove_style(obj, &styles->img_color[i], selector);
etx_remove_img_color(obj, selector);
etx_obj_add_style(obj, styles->img_color[colorIdx], selector);
}
@@ -111,6 +111,11 @@ void etx_remove_arc_color(lv_obj_t* obj, lv_style_selector_t selector = LV_PART_
void etx_arc_color(lv_obj_t* obj, LcdColorIndex colorIdx,
lv_style_selector_t selector = LV_PART_MAIN);
void etx_remove_line_color(lv_obj_t* obj, lv_style_selector_t selector = LV_PART_MAIN);
void etx_line_color(lv_obj_t* obj, LcdColorIndex colorIdx,
lv_style_selector_t selector = LV_PART_MAIN);
void etx_remove_img_color(lv_obj_t* obj, lv_style_selector_t selector = LV_PART_MAIN);
void etx_img_color(lv_obj_t* obj, LcdColorIndex colorIdx,
lv_style_selector_t selector = LV_PART_MAIN);
@@ -145,6 +150,7 @@ class EdgeTxStyles
lv_style_t img_color[TOTAL_COLOR_COUNT];
lv_style_t border_color[TOTAL_COLOR_COUNT];
lv_style_t arc_color[TOTAL_COLOR_COUNT];
lv_style_t line_color[TOTAL_COLOR_COUNT];
lv_style_t outline_color_light;
lv_style_t outline_color_normal;
lv_style_t outline_color_focus;
+2 -2
View File
@@ -182,7 +182,7 @@ void FileChoice::openMenu()
if (fileCount > 0) {
setEditMode(true); // this needs to be done first before menu is created.
auto menu = new Menu(this);
auto menu = new Menu();
if (menuTitle) menu->setTitle(menuTitle);
auto tb = new FileChoiceMenuToolbar(this, menu);
@@ -192,6 +192,6 @@ void FileChoice::openMenu()
menu->setCloseHandler([=]() { setEditMode(false); });
} else {
new MessageDialog(this, STR_SDCARD, STR_NO_FILES_ON_SD);
new MessageDialog(STR_SDCARD, STR_NO_FILES_ON_SD);
}
}
+2 -2
View File
@@ -364,8 +364,8 @@ class MenuWindowContent : public Window
//-----------------------------------------------------------------------------
Menu::Menu(Window* parent, bool multiple) :
ModalWindow(parent, true),
Menu::Menu(bool multiple) :
ModalWindow(true),
multiple(multiple),
content(new MenuWindowContent(this))
{
+1 -1
View File
@@ -29,7 +29,7 @@ class Menu : public ModalWindow
friend class MenuBody;
public:
explicit Menu(Window *parent, bool multiple = false);
explicit Menu(bool multiple = false);
#if defined(DEBUG_WINDOWS)
std::string getName() const override { return "Menu"; }
@@ -20,6 +20,7 @@
#include "layer.h"
#include "etx_lv_theme.h"
#include "mainwindow.h"
// Modal overlay style (for dimming background)
void modal_window_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
@@ -45,8 +46,8 @@ static lv_obj_t* modal_create(lv_obj_t* parent)
return etx_create(&modal_window_class, parent);
}
ModalWindow::ModalWindow(Window* parent, bool closeWhenClickOutside) :
Window(parent->getFullScreenWindow(), {0, 0, LCD_W, LCD_H}, modal_create),
ModalWindow::ModalWindow(bool closeWhenClickOutside) :
Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}, modal_create),
closeWhenClickOutside(closeWhenClickOutside)
{
Layer::push(this);
+1 -1
View File
@@ -23,7 +23,7 @@
class ModalWindow : public Window
{
public:
explicit ModalWindow(Window* parent, bool closeWhenClickOutside = false);
explicit ModalWindow(bool closeWhenClickOutside = false);
#if defined(DEBUG_WINDOWS)
std::string getName() const override { return "ModalWindow"; }
+1 -1
View File
@@ -38,7 +38,7 @@ static void _run_popup_dialog(const char* title, const char* msg,
// RELEASED/CLICKED to be called in a loop
lv_indev_reset(nullptr, nullptr);
auto md = new MessageDialog(MainWindow::instance(), title, msg, info);
auto md = new MessageDialog(title, msg, info);
md->setCloseHandler([&]() { running = false; });
while (running) {
// Allow power off while showing popup
@@ -56,7 +56,7 @@ class LayoutChoice : public Button
void onPress() override
{
auto menu = new Menu(parent);
auto menu = new Menu();
for (auto layout : LayoutFactory::getRegisteredLayouts()) {
menu->addLine(layout->getBitmap(), layout->getName(),
[=]() { setValue(layout); });
@@ -39,7 +39,7 @@ const std::string copyright_str = "Copyright (C) " BUILD_YEAR " EdgeTX";
const std::string edgetx_url = "https://edgetx.org";
AboutUs::AboutUs() :
BaseDialog(MainWindow::instance(), STR_ABOUT_US, true, 220, LV_SIZE_CONTENT)
BaseDialog(STR_ABOUT_US, true, 220, LV_SIZE_CONTENT)
{
new StaticText(form, {0, 0, LV_PCT(100), LV_SIZE_CONTENT},
about_str + "\n" + copyright_str,
@@ -128,7 +128,7 @@ ViewMainMenu::ViewMainMenu(Window* parent, std::function<void()> closeHandler) :
carousel->addButton(
ICON_MODEL_TELEMETRY, STR_MAIN_MENU_RESET_TELEMETRY, [=]() -> uint8_t {
deleteLater();
Menu* resetMenu = new Menu(parent);
Menu* resetMenu = new Menu();
resetMenu->addLine(STR_RESET_FLIGHT, []() { flightReset(); });
resetMenu->addLine(STR_RESET_TIMER1, []() { timerReset(0); });
resetMenu->addLine(STR_RESET_TIMER2, []() { timerReset(1); });
+1 -5
View File
@@ -58,11 +58,7 @@ void Widget::openMenu()
}
if (getOptions() || fsAllowed) {
// Widgets are placed on a full screen window which is underneath the main
// view menu bar Find the parent of this so that when the popup loads it
// covers the main view menu
Window* w = parent->getFullScreenWindow()->getParent();
Menu* menu = new Menu(w ? w : this);
Menu* menu = new Menu();
menu->setTitle(getFactory()->getDisplayName());
if (fsAllowed) {
menu->addLine(STR_WIDGET_FULLSCREEN, [&]() { setFullscreen(true); });
@@ -43,11 +43,9 @@ static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT,
LV_GRID_TEMPLATE_LAST};
WidgetSettings::WidgetSettings(Widget* w) :
BaseDialog(ViewMain::instance(), w->getFactory()->getDisplayName(), true), widget(w)
BaseDialog(w->getFactory()->getDisplayName(), true), widget(w)
{
FlexGridLayout grid(line_col_dsc, line_row_dsc);
form->padAll(PAD_SMALL);
form->padRow(PAD_ZERO);
FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY);
uint8_t optIdx = 0;
auto opt = widget->getOptions();
@@ -37,7 +37,7 @@ SetupWidgetsPageSlot::SetupWidgetsPageSlot(Window* parent, const rect_t& rect,
{
setPressHandler([=]() -> uint8_t {
if (container->getWidget(slotIndex)) {
Menu* menu = new Menu(parent);
Menu* menu = new Menu();
menu->addLine(STR_SELECT_WIDGET,
[=]() { addNewWidget(container, slotIndex); });
auto widget = container->getWidget(slotIndex);
@@ -95,7 +95,7 @@ void SetupWidgetsPageSlot::addNewWidget(WidgetsContainer* container,
auto w = container->getWidget((slotIndex));
if (w) cur = w->getFactory()->getDisplayName();
Menu* menu = new Menu(parent);
Menu* menu = new Menu();
menu->setTitle(STR_SELECT_WIDGET);
int selected = -1;
int index = 0;
@@ -40,12 +40,13 @@ class SetupWidgetsPage : public Window
void onClicked() override;
void onCancel() override;
void deleteLater(bool detach = true, bool trash = true) override;
protected:
uint8_t customScreenIdx;
unsigned savedView = 0;
void onEvent(event_t event) override;
void deleteLater(bool detach = true, bool trash = true) override;
};
class SetupWidgetsPageSlot : public ButtonBase
@@ -55,6 +56,9 @@ class SetupWidgetsPageSlot : public ButtonBase
WidgetsContainer* container, uint8_t slotIndex);
protected:
WidgetsContainer* container = nullptr;
uint8_t slotIndex = 0;
bool openSettings = false;
lv_style_t borderStyle;
lv_point_t borderPts[5];
lv_obj_t* border;
@@ -142,7 +142,7 @@ void ModelCurvesPage::editCurve(Window *window, uint8_t curve)
void ModelCurvesPage::presetMenu(Window *window, uint8_t index)
{
Menu *menu = new Menu(window);
Menu *menu = new Menu();
menu->setTitle(STR_CURVE_PRESET);
for (int angle = -45; angle <= 45; angle += 15) {
char label[16];
@@ -169,7 +169,7 @@ void ModelCurvesPage::presetMenu(Window *window, uint8_t index)
void ModelCurvesPage::newCV(Window *window, bool presetCV)
{
Menu *menu = new Menu(Layer::back());
Menu *menu = new Menu();
menu->setTitle(STR_CURVE);
char s[6] = "CVxx";
@@ -195,7 +195,7 @@ void ModelCurvesPage::newCV(Window *window, bool presetCV)
void ModelCurvesPage::plusPopup(Window *window)
{
Menu *menu = new Menu(window);
Menu *menu = new Menu();
menu->setTitle(STR_NEW);
menu->addLine(STR_EDIT, [=]() { newCV(window, false); });
menu->addLine(STR_CURVE_PRESET, [=]() { newCV(window, true); });
@@ -235,7 +235,7 @@ void ModelCurvesPage::build(Window *window)
auto button =
new CurveButton(line, rect_t{0, 0, CurveButton::CURVE_BTN_W, CurveButton::CURVE_BTH_H}, index);
button->setPressHandler([=]() -> uint8_t {
Menu *menu = new Menu(window);
Menu *menu = new Menu();
menu->setTitle(STR_CURVE);
menu->addLine(STR_EDIT, [=]() { editCurve(window, index); });
menu->addLine(STR_CURVE_PRESET, [=]() { presetMenu(window, index); });
+1 -1
View File
@@ -561,7 +561,7 @@ void ModelGVarsPage::build(Window* window)
auto button = new GVarButton(window, index);
lv_obj_set_pos(button->getLvObj(), 0, yo + index * (GVarButton::BTN_H + PAD_TINY));
button->setPressHandler([=]() {
Menu* menu = new Menu(window);
Menu* menu = new Menu();
menu->addLine(STR_EDIT, [=]() {
Window* editWindow = new GVarEditWindow(index);
editWindow->setCloseHandler([=]() { rebuild(window); });
@@ -202,7 +202,7 @@ ModelInputsPage::ModelInputsPage() : InputMixPageBase(STR_MENUINPUTS, ICON_MODEL
bool ModelInputsPage::reachExposLimit()
{
if (getExposCount() >= MAX_EXPOS) {
new MessageDialog(form, STR_WARNING, STR_NOFREEEXPO);
new MessageDialog(STR_WARNING, STR_NOFREEEXPO);
return true;
}
return false;
@@ -233,7 +233,7 @@ InputMixButtonBase* ModelInputsPage::createLineButton(InputMixGroupBase* group,
uint8_t input = group->getMixSrc() - MIXSRC_FIRST_INPUT;
button->setPressHandler([=]() -> uint8_t {
Menu* menu = new Menu(form);
Menu* menu = new Menu();
menu->addLine(STR_EDIT, [=]() {
uint8_t idx = button->getIndex();
editInput(input, idx);
@@ -287,7 +287,7 @@ void ModelInputsPage::addLineButton(uint8_t index)
void ModelInputsPage::newInput()
{
Menu* menu = new Menu(Layer::back());
Menu* menu = new Menu();
menu->setTitle(STR_MENU_INPUTS);
uint8_t chn = 0;
@@ -560,7 +560,7 @@ void ModelLogicalSwitchesPage::rebuild(Window* window)
void ModelLogicalSwitchesPage::newLS(Window* window, bool pasteLS)
{
Menu* menu = new Menu(Layer::back());
Menu* menu = new Menu();
menu->setTitle(STR_MENU_LOGICAL_SWITCHES);
// search for unused switches
@@ -593,7 +593,7 @@ void ModelLogicalSwitchesPage::newLS(Window* window, bool pasteLS)
void ModelLogicalSwitchesPage::plusPopup(Window* window)
{
if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_SWITCH) {
Menu* menu = new Menu(window);
Menu* menu = new Menu();
menu->addLine(STR_NEW, [=]() { newLS(window, false); });
menu->addLine(STR_PASTE, [=]() { newLS(window, true); });
} else {
@@ -619,7 +619,7 @@ void ModelLogicalSwitchesPage::build(Window* window)
auto button = new LogicalSwitchButton(window, i);
button->setPressHandler([=]() {
Menu* menu = new Menu(window);
Menu* menu = new Menu();
menu->addLine(STR_EDIT, [=]() {
Window* lsWindow = new LogicalSwitchEditPage(i);
lsWindow->setCloseHandler([=]() {
@@ -301,7 +301,7 @@ void ModelMixerScriptsPage::build(Window* window, int8_t focusIdx)
auto button = new ScriptLineButton(window, *sd, runtimeData, idx);
button->setPressHandler([=]() -> uint8_t {
Menu* const menu = new Menu(window);
Menu* const menu = new Menu();
menu->addLine(STR_EDIT, [=]() { editLine(window, idx); });
if (runtimeData != nullptr) {
+3 -3
View File
@@ -231,7 +231,7 @@ ModelMixesPage::ModelMixesPage() : InputMixPageBase(STR_MIXES, ICON_MODEL_MIXER)
bool ModelMixesPage::reachMixesLimit()
{
if (getMixCount() >= MAX_MIXERS) {
new MessageDialog(form, STR_WARNING, STR_NOFREEMIXER);
new MessageDialog(STR_WARNING, STR_NOFREEMIXER);
return true;
}
return false;
@@ -264,7 +264,7 @@ InputMixButtonBase* ModelMixesPage::createLineButton(InputMixGroupBase *group, u
uint8_t ch = group->getMixSrc() - MIXSRC_FIRST_CH;
button->setPressHandler([=]() -> uint8_t {
Menu *menu = new Menu(form);
Menu *menu = new Menu();
menu->addLine(STR_EDIT, [=]() {
uint8_t idx = button->getIndex();
editMix(ch, idx);
@@ -318,7 +318,7 @@ void ModelMixesPage::addLineButton(uint8_t index)
void ModelMixesPage::newMix()
{
Menu* menu = new Menu(Layer::back());
Menu* menu = new Menu();
menu->setTitle(STR_MENU_CHANNELS);
uint8_t index = 0;
@@ -240,7 +240,7 @@ void ModelOutputsPage::build(Window* window)
new TextButton(window, {ADD_TRIMS_X, ADD_TRIMS_Y, ADD_TRIMS_W, ADD_TRIMS_H}, STR_ADD_ALL_TRIMS_TO_SUBTRIMS, [=]() {
new ConfirmDialog(
window, STR_TRIMS2OFFSETS, STR_ADD_ALL_TRIMS_TO_SUBTRIMS,
STR_TRIMS2OFFSETS, STR_ADD_ALL_TRIMS_TO_SUBTRIMS,
[=] {
moveTrimsToOffsets();
});
@@ -258,7 +258,7 @@ void ModelOutputsPage::build(Window* window)
LimitData* output = limitAddress(ch);
btn->setPressHandler([=]() -> uint8_t {
Menu* menu = new Menu(window);
Menu* menu = new Menu();
menu->addLine(STR_EDIT, [=]() { editOutput(ch, btn); });
menu->addLine(STR_RESET, [=]() {
output->min = 0;
+13 -13
View File
@@ -334,7 +334,7 @@ class ModelsPageBody : public Window
void openMenu()
{
Menu *menu = new Menu(this);
Menu *menu = new Menu();
menu->setTitle(focusedModel->modelName);
if (g_eeGeneral.modelQuickSelect ||
focusedModel != modelslist.getCurrentModel()) {
@@ -393,7 +393,7 @@ class ModelsPageBody : public Window
void duplicateModel(ModelCell *model)
{
new ConfirmDialog(
parent, STR_DUPLICATE_MODEL,
STR_DUPLICATE_MODEL,
std::string(model->modelName, sizeof(model->modelName)).c_str(), [=] {
storageFlushCurrentModel();
storageCheck(true);
@@ -422,7 +422,7 @@ class ModelsPageBody : public Window
void deleteModel(ModelCell *model)
{
new ConfirmDialog(
parent, STR_DELETE_MODEL,
STR_DELETE_MODEL,
std::string(model->modelName, sizeof(model->modelName)).c_str(), [=] {
modelslist.removeModel(model);
if (refreshLabels != nullptr) refreshLabels();
@@ -437,7 +437,7 @@ class ModelsPageBody : public Window
// dont display menu if there will be no labels
if (labels.size()) {
auto menu = new Menu(getParent(), true);
auto menu = new Menu(true);
menu->setTitle(model->modelName);
menu->setCloseHandler([=]() {
if (isDirty) {
@@ -466,7 +466,7 @@ class ModelsPageBody : public Window
void saveAsTemplate(ModelCell *model)
{
new ConfirmDialog(
parent, STR_SAVE_TEMPLATE,
STR_SAVE_TEMPLATE,
std::string(model->modelName, sizeof(model->modelName)).c_str(), [=] {
storageDirty(EE_MODEL);
storageCheck(true);
@@ -487,7 +487,7 @@ class ModelsPageBody : public Window
snprintf(templatePath, FF_MAX_LFN, "%s%c%s", persFolder, '/',
modelName);
if (isFileAvailable(templatePath)) {
new ConfirmDialog(parent, STR_FILE_EXISTS, STR_ASK_OVERWRITE, [=] {
new ConfirmDialog(STR_FILE_EXISTS, STR_ASK_OVERWRITE, [=] {
sdCopyFile(model->modelFilename, MODELS_PATH, modelName,
persFolder);
});
@@ -668,7 +668,7 @@ void ModelLabelsWindow::newModel()
void ModelLabelsWindow::newLabel()
{
tmpLabel[0] = '\0';
new LabelDialog(this, tmpLabel, LABEL_LENGTH, STR_ENTER_LABEL, [=](std::string label) {
new LabelDialog(tmpLabel, LABEL_LENGTH, STR_ENTER_LABEL, [=](std::string label) {
int newlabindex = modelslabels.addLabel(label);
if (newlabindex >= 0) {
std::set<uint32_t> newset;
@@ -690,7 +690,7 @@ void ModelLabelsWindow::buildHead(Window *hdr)
// new model button
new TextButton(hdr, {LCD_W - NEW_BTN_W - PAD_LARGE, PAD_MEDIUM, NEW_BTN_W, EdgeTxStyles::UI_ELEMENT_HEIGHT}, STR_NEW, [=]() {
auto menu = new Menu(this);
auto menu = new Menu();
menu->setTitle(STR_CREATE_NEW);
menu->addLine(STR_NEW_MODEL, [=]() { newModel(); });
menu->addLine(STR_NEW_LABEL, [=]() { newLabel(); });
@@ -811,16 +811,16 @@ void ModelLabelsWindow::buildBody(Window *window)
std::string selectedLabel = labels.at(selected);
if (selectedLabel != STR_UNLABELEDMODEL) {
Menu *menu = new Menu(window);
Menu *menu = new Menu();
menu->setTitle(selectedLabel);
menu->addLine(STR_RENAME_LABEL, [=]() {
auto oldLabel = labels[selected];
strncpy(tmpLabel, oldLabel.c_str(), LABEL_LENGTH);
tmpLabel[LABEL_LENGTH] = '\0';
new LabelDialog(this, tmpLabel, LABEL_LENGTH, STR_ENTER_LABEL, [=](std::string newLabel) {
new LabelDialog(tmpLabel, LABEL_LENGTH, STR_ENTER_LABEL, [=](std::string newLabel) {
if (newLabel.size() > 0) {
auto rndialog =
new ProgressDialog(this, STR_RENAME_LABEL, [=]() {});
new ProgressDialog(STR_RENAME_LABEL, [=]() {});
modelslabels.renameLabel(
oldLabel, newLabel, [=](const char *name, int percentage) {
rndialog->setTitle(std::string(STR_RENAME_LABEL) + " " +
@@ -838,9 +838,9 @@ void ModelLabelsWindow::buildBody(Window *window)
menu->addLine(STR_DELETE_LABEL, [=]() {
auto labelToDelete = labels[selected];
new ConfirmDialog(
parent, STR_DELETE_LABEL, labelToDelete.c_str(), [=]() {
STR_DELETE_LABEL, labelToDelete.c_str(), [=]() {
auto deldialog =
new ProgressDialog(this, STR_DELETE_LABEL, [=]() {});
new ProgressDialog(STR_DELETE_LABEL, [=]() {});
modelslabels.removeLabel(
labelToDelete, [=](const char *name, int percentage) {
deldialog->setTitle(std::string(STR_DELETE_LABEL) + " " +
+1 -1
View File
@@ -300,7 +300,7 @@ static SetupLineDef setupLines[] = {
auto curmod = modelslist.getCurrentModel();
TextButton* btn = new TextButton(parent, {x, y, 0, 0}, modelslabels.getBulletLabelString(curmod, STR_UNLABELEDMODEL));
btn->setPressHandler([=]() {
Menu *menu = new Menu(MainWindow::instance(), true);
Menu *menu = new Menu(true);
menu->setTitle(STR_LABELS);
for (auto &label : modelslabels.getLabels()) {
menu->addLineBuffered(
@@ -836,7 +836,7 @@ void ModelTelemetryPage::buildSensorList(int8_t focusSensorIndex)
if (!first) first = button;
button->setPressHandler([=]() -> uint8_t {
Menu* menu = new Menu(window);
Menu* menu = new Menu();
menu->addLine(STR_EDIT, [=]() { editSensor(window, idx); });
menu->addLine(STR_COPY, [=]() {
auto newIndex = availableTelemetryIndex();
@@ -944,7 +944,7 @@ void ModelTelemetryPage::build(Window* window)
// Delete all sensors button
deleteAll =
new TextButton(line, rect_t{}, STR_DELETE_ALL_SENSORS, [=]() -> uint8_t {
new ConfirmDialog(window, STR_DELETE_ALL_SENSORS, STR_CONFIRMDELETE,
new ConfirmDialog(STR_DELETE_ALL_SENSORS, STR_CONFIRMDELETE,
[=]() {
for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) {
delTelemetryIndex(i);
@@ -562,7 +562,7 @@ ModelUSBJoystickPage::ModelUSBJoystickPage() : Page(ICON_MODEL_USB)
if (cch->mode == USBJOYS_CH_NONE) {
editChannel(ch, btn);
} else {
Menu* menu = new Menu(parent);
Menu* menu = new Menu();
menu->addLine(STR_EDIT, [=]() { editChannel(ch, btn); });
menu->addLine(STR_CLEAR, [=]() {
memset(cch, 0, sizeof(USBJoystickChData));
@@ -720,7 +720,7 @@ void FunctionsPage::rebuild(Window *window)
void FunctionsPage::newSF(Window *window, bool pasteSF)
{
Menu *menu = new Menu(Layer::back());
Menu *menu = new Menu();
menu->setTitle(title);
// search for unused switches
@@ -769,7 +769,7 @@ void FunctionsPage::editSpecialFunction(Window *window, uint8_t index,
void FunctionsPage::plusPopup(Window *window)
{
if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_FUNCTION) {
Menu *menu = new Menu(window);
Menu *menu = new Menu();
menu->addLine(STR_NEW, [=]() { newSF(window, false); });
menu->addLine(STR_PASTE, [=]() { newSF(window, true); });
} else {
@@ -810,7 +810,7 @@ void FunctionsPage::build(Window *window)
});
button->setPressHandler([=]() {
Menu *menu = new Menu(window);
Menu *menu = new Menu();
menu->addLine(STR_EDIT,
[=]() { editSpecialFunction(window, i, button); });
if (isActive) {
@@ -42,7 +42,7 @@ public:
};
BTDiscoverMenu::BTDiscoverMenu() :
Menu(Layer::back())
Menu()
{
setTitle(STR_BT_SELECT_DEVICE);
// TODO: set minimum height
@@ -132,7 +132,7 @@ void BluetoothTrainerWindow::refresh()
}
} else if (bluetooth.state == BLUETOOTH_STATE_DISCOVER_END) {
if(reusableBuffer.moduleSetup.bt.devicesCount == 0) {
new MessageDialog(this, STR_BLUETOOTH, STR_BLUETOOTH_NODEVICES);
new MessageDialog(STR_BLUETOOTH, STR_BLUETOOTH_NODEVICES);
bluetooth.state = BLUETOOTH_STATE_OFF;
}
} else if (bluetooth.distantAddr[0]) {
+1 -1
View File
@@ -46,7 +46,7 @@ static SetupLineDef setupLines[] = {
new Choice(parent, {x, y, TrimsSetup::HATSMODE_W, 0}, STR_HATSOPT, HATSMODE_TRIMS_ONLY, HATSMODE_GLOBAL,
GET_SET_DEFAULT(g_model.hatsMode));
new TextButton(parent, {x + TrimsSetup::HATSMODE_W + PAD_SMALL, y, 0, 0}, "?", [=]() {
new MessageDialog(parent, STR_HATSMODE_KEYS, STR_HATSMODE_KEYS_HELP, "",
new MessageDialog(STR_HATSMODE_KEYS, STR_HATSMODE_KEYS_HELP, "",
LEFT);
return 0;
});
+91 -104
View File
@@ -34,7 +34,7 @@ namespace pxx2
class BindRxChoiceMenu : public Menu
{
public:
BindRxChoiceMenu(Window* parent, uint8_t moduleIdx, uint8_t receiverIdx);
BindRxChoiceMenu(uint8_t moduleIdx, uint8_t receiverIdx);
protected:
uint8_t moduleIdx;
@@ -44,11 +44,71 @@ class BindRxChoiceMenu : public Menu
class BindWaitDialog : public BaseDialog
{
public:
BindWaitDialog(Window* parent, uint8_t moduleIdx, uint8_t receiverIdx);
BindWaitDialog(uint8_t moduleIdx, uint8_t receiverIdx) :
BaseDialog(STR_BIND, true),
moduleIdx(moduleIdx),
receiverIdx(receiverIdx)
{
new StaticText(form, rect_t{}, STR_WAITING_FOR_RX);
void checkEvents() override;
setCloseHandler([=]() { moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; });
}
void deleteLater(bool detach = true, bool trash = true) override;
void checkEvents() override
{
auto& bindInfo = getPXX2BindInformationBuffer();
if (moduleState[moduleIdx].mode == MODULE_MODE_NORMAL) {
// returned to normal after bind
if (bindInfo.step > BIND_INIT) {
removePXX2ReceiverIfEmpty(moduleIdx, receiverIdx);
deleteLater();
if (bindInfo.step == BIND_OK) {
POPUP_INFORMATION(STR_REG_OK);
setPXX2ReceiverUsed(moduleIdx, receiverIdx);
}
return;
}
// pre-bind phase: fetching info for R9M
auto& modSetup = getPXX2ModuleSetupBuffer();
switch (bindInfo.step) {
case BIND_MODULE_TX_INFORMATION_REQUEST:
if (modSetup.moduleInformation.information.variant == PXX2_VARIANT_EU) {
// In EU mode we will need the power of the module to know if
// telemetry can be proposed
bindInfo.step = BIND_MODULE_TX_SETTINGS_REQUEST;
#if defined(SIMU)
modSetup.moduleSettings.txPower = 14;
#else
moduleState[moduleIdx].readModuleSettings(&modSetup.moduleSettings);
#endif
} else {
bindInfo.step = 0;
moduleState[moduleIdx].startBind(&bindInfo);
}
break;
case BIND_MODULE_TX_SETTINGS_REQUEST:
// We just receive the module settings (for TX power)
bindInfo.step = 0;
moduleState[moduleIdx].startBind(&bindInfo);
break;
}
return;
}
if (bindInfo.step == BIND_INIT && bindInfo.candidateReceiversCount > 0) {
// prevent module mode being reset to NORMAL before exiting
setCloseHandler(nullptr);
deleteLater();
// ... and create RX choice dialog
new BindRxChoiceMenu(moduleIdx, receiverIdx);
return;
}
BaseDialog::checkEvents();
}
protected:
uint8_t moduleIdx;
@@ -58,7 +118,7 @@ class BindWaitDialog : public BaseDialog
class RxOptions : public BaseDialog
{
public:
RxOptions(Window* parent, uint8_t moduleIdx, uint8_t rxIdx);
RxOptions(uint8_t moduleIdx, uint8_t rxIdx);
void checkEvents() override;
protected:
@@ -84,8 +144,7 @@ class RxOptions : public BaseDialog
void writeSettings();
};
static void startBindWaitDialog(Window* parent, uint8_t moduleIdx,
uint8_t receiverIdx)
static void startBindWaitDialog(uint8_t moduleIdx, uint8_t receiverIdx)
{
auto& bindInfo = getPXX2BindInformationBuffer();
#if defined(SIMU)
@@ -96,32 +155,32 @@ static void startBindWaitDialog(Window* parent, uint8_t moduleIdx,
bindInfo.step = BIND_OK;
setPXX2ReceiverUsed(moduleIdx, receiverIdx);
moduleState[moduleIdx].mode = MODULE_MODE_NORMAL;
new MessageDialog(parent, STR_BIND, STR_BIND_OK);
new MessageDialog(STR_BIND, STR_BIND_OK);
#else
bindInfo.step = BIND_START;
new BindWaitDialog(parent, moduleIdx, receiverIdx);
new BindWaitDialog(moduleIdx, receiverIdx);
#endif
}
static void startFlexBindWaitDialog(Window* parent, uint8_t moduleIdx,
static void startFlexBindWaitDialog(uint8_t moduleIdx,
uint8_t receiverIdx, uint8_t flex)
{
auto& bindInfo = getPXX2BindInformationBuffer();
bindInfo.flexMode = flex;
startBindWaitDialog(parent, moduleIdx, receiverIdx);
startBindWaitDialog(moduleIdx, receiverIdx);
}
static void startLBTBindWaitDialog(Window* parent, uint8_t moduleIdx,
static void startLBTBindWaitDialog(uint8_t moduleIdx,
uint8_t receiverIdx, uint8_t lbt)
{
auto& bindInfo = getPXX2BindInformationBuffer();
bindInfo.lbtMode = lbt;
startBindWaitDialog(parent, moduleIdx, receiverIdx);
startBindWaitDialog(moduleIdx, receiverIdx);
}
BindRxChoiceMenu::BindRxChoiceMenu(Window* parent, uint8_t moduleIdx,
BindRxChoiceMenu::BindRxChoiceMenu(uint8_t moduleIdx,
uint8_t receiverIdx) :
Menu(parent), moduleIdx(moduleIdx), receiverIdx(receiverIdx)
Menu(), moduleIdx(moduleIdx), receiverIdx(receiverIdx)
{
const auto& bindInfo = getPXX2BindInformationBuffer();
auto receiversCount = min<uint8_t>(bindInfo.candidateReceiversCount,
@@ -138,26 +197,26 @@ BindRxChoiceMenu::BindRxChoiceMenu(Window* parent, uint8_t moduleIdx,
auto& modSetup = getPXX2ModuleSetupBuffer();
if (modSetup.moduleSettings.txPower <= 14) {
// with telemetry
startLBTBindWaitDialog(parent, moduleIdx, receiverIdx, 1);
startLBTBindWaitDialog(moduleIdx, receiverIdx, 1);
} else {
// without telemetry
startLBTBindWaitDialog(parent, moduleIdx, receiverIdx, 2);
startLBTBindWaitDialog(moduleIdx, receiverIdx, 2);
}
return;
} else if (isModuleR9MAccess(moduleIdx) &&
modInfo.information.variant == PXX2_VARIANT_FLEX) {
bindInfo.step = BIND_RX_NAME_SELECTED;
auto flexMenu = new Menu(parent);
auto flexMenu = new Menu();
flexMenu->addLine(STR_FLEX_868, [=]() {
startFlexBindWaitDialog(parent, moduleIdx, receiverIdx, 0);
startFlexBindWaitDialog(moduleIdx, receiverIdx, 0);
});
flexMenu->addLine(STR_FLEX_915, [=]() {
startFlexBindWaitDialog(parent, moduleIdx, receiverIdx, 1);
startFlexBindWaitDialog(moduleIdx, receiverIdx, 1);
});
return;
}
startBindWaitDialog(parent, moduleIdx, receiverIdx);
startBindWaitDialog(moduleIdx, receiverIdx);
});
}
@@ -170,78 +229,6 @@ static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT,
LV_GRID_TEMPLATE_LAST};
BindWaitDialog::BindWaitDialog(Window* parent, uint8_t moduleIdx,
uint8_t receiverIdx) :
BaseDialog(parent, STR_BIND, true),
moduleIdx(moduleIdx),
receiverIdx(receiverIdx)
{
new StaticText(form, rect_t{}, STR_WAITING_FOR_RX);
setCloseHandler([=]() { moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; });
}
void BindWaitDialog::deleteLater(bool detach, bool trash)
{
BaseDialog::deleteLater(detach, trash);
}
void BindWaitDialog::checkEvents()
{
auto& bindInfo = getPXX2BindInformationBuffer();
if (moduleState[moduleIdx].mode == MODULE_MODE_NORMAL) {
// returned to normal after bind
if (bindInfo.step > BIND_INIT) {
removePXX2ReceiverIfEmpty(moduleIdx, receiverIdx);
deleteLater();
if (bindInfo.step == BIND_OK) {
POPUP_INFORMATION(STR_REG_OK);
setPXX2ReceiverUsed(moduleIdx, receiverIdx);
}
return;
}
// pre-bind phase: fetching info for R9M
auto& modSetup = getPXX2ModuleSetupBuffer();
switch (bindInfo.step) {
case BIND_MODULE_TX_INFORMATION_REQUEST:
if (modSetup.moduleInformation.information.variant == PXX2_VARIANT_EU) {
// In EU mode we will need the power of the module to know if
// telemetry can be proposed
bindInfo.step = BIND_MODULE_TX_SETTINGS_REQUEST;
#if defined(SIMU)
modSetup.moduleSettings.txPower = 14;
#else
moduleState[moduleIdx].readModuleSettings(&modSetup.moduleSettings);
#endif
} else {
bindInfo.step = 0;
moduleState[moduleIdx].startBind(&bindInfo);
}
break;
case BIND_MODULE_TX_SETTINGS_REQUEST:
// We just receive the module settings (for TX power)
bindInfo.step = 0;
moduleState[moduleIdx].startBind(&bindInfo);
break;
}
return;
}
if (bindInfo.step == BIND_INIT && bindInfo.candidateReceiversCount > 0) {
// prevent module mode being reset to NORMAL before exiting
setCloseHandler(nullptr);
deleteLater();
// ... and create RX choice dialog
new BindRxChoiceMenu(Layer::back(), moduleIdx, receiverIdx);
return;
}
BaseDialog::checkEvents();
}
ReceiverButton::ReceiverButton(Window* parent, rect_t rect, uint8_t moduleIdx,
uint8_t receiverIdx) :
TextButton(parent, rect, STR_BIND,
@@ -256,13 +243,13 @@ uint8_t ReceiverButton::pressBind()
if (g_model.moduleData[moduleIdx].pxx2.receiverName[receiverIdx][0] == '\0') {
startBind();
} else {
auto menu = new Menu(parent);
auto menu = new Menu();
menu->addLine(STR_BIND, [=]() {
startBind();
return 0;
});
menu->addLine(STR_OPTIONS, [=]() {
new RxOptions(this, moduleIdx, receiverIdx);
new RxOptions(moduleIdx, receiverIdx);
return 0;
});
menu->addLine(STR_SHARE, [=]() {
@@ -276,7 +263,7 @@ uint8_t ReceiverButton::pressBind()
memclear(&modSetup, sizeof(modSetup));
modSetup.resetReceiverIndex = receiverIdx;
modSetup.resetReceiverFlags = 0x01;
new ConfirmDialog(parent, STR_RECEIVER, STR_RECEIVER_DELETE, [=]() {
new ConfirmDialog(STR_RECEIVER, STR_RECEIVER_DELETE, [=]() {
moduleState[moduleIdx].mode = MODULE_MODE_RESET;
removePXX2Receiver(moduleIdx, receiverIdx);
});
@@ -287,7 +274,7 @@ uint8_t ReceiverButton::pressBind()
memclear(&modSetup, sizeof(modSetup));
modSetup.resetReceiverIndex = receiverIdx;
modSetup.resetReceiverFlags = 0xFF;
new ConfirmDialog(parent, STR_RECEIVER, STR_RECEIVER_RESET, [=]() {
new ConfirmDialog(STR_RECEIVER, STR_RECEIVER_RESET, [=]() {
moduleState[moduleIdx].mode = MODULE_MODE_RESET;
removePXX2Receiver(moduleIdx, receiverIdx);
});
@@ -321,7 +308,7 @@ void ReceiverButton::startBind()
moduleState[moduleIdx].startBind(&bindInfo);
}
new BindWaitDialog(parent, moduleIdx, receiverIdx);
new BindWaitDialog(moduleIdx, receiverIdx);
}
void ReceiverButton::checkEvents()
@@ -342,8 +329,8 @@ void ReceiverButton::checkEvents()
TextButton::checkEvents();
}
RegisterDialog::RegisterDialog(Window* parent, uint8_t moduleIdx) :
BaseDialog(parent, STR_REGISTER, true, DIALOG_DEFAULT_WIDTH,
RegisterDialog::RegisterDialog(uint8_t moduleIdx) :
BaseDialog(STR_REGISTER, true, DIALOG_DEFAULT_WIDTH,
LV_SIZE_CONTENT),
moduleIdx(moduleIdx)
{
@@ -439,8 +426,8 @@ void RegisterDialog::checkEvents()
BaseDialog::checkEvents();
}
ModuleOptions::ModuleOptions(Window* parent, uint8_t moduleIdx) :
BaseDialog(parent, STR_MODULE_OPTIONS, true), moduleIdx(moduleIdx)
ModuleOptions::ModuleOptions(uint8_t moduleIdx) :
BaseDialog(STR_MODULE_OPTIONS, true), moduleIdx(moduleIdx)
{
new StaticText(form, rect_t{}, STR_WAITING_FOR_MODULE);
@@ -632,8 +619,8 @@ void ModuleOptions::writeSettings()
}
}
RxOptions::RxOptions(Window* parent, uint8_t moduleIdx, uint8_t rxIdx) :
BaseDialog(parent, STR_RECEIVER_OPTIONS, true),
RxOptions::RxOptions(uint8_t moduleIdx, uint8_t rxIdx) :
BaseDialog(STR_RECEIVER_OPTIONS, true),
moduleIdx(moduleIdx),
receiverIdx(rxIdx)
{
@@ -47,7 +47,7 @@ class ReceiverButton : public TextButton
class RegisterDialog : public BaseDialog
{
public:
RegisterDialog(Window* parent, uint8_t moduleIdx);
RegisterDialog(uint8_t moduleIdx);
void start();
void checkEvents() override;
@@ -65,7 +65,7 @@ class RegisterDialog : public BaseDialog
class ModuleOptions : public BaseDialog
{
public:
ModuleOptions(Window* parent, uint8_t moduleIdx);
ModuleOptions(uint8_t moduleIdx);
void checkEvents() override;
protected:
@@ -26,10 +26,10 @@
#include "telemetry/multi.h"
#endif
BindChoiceMenu::BindChoiceMenu(Window *parent, uint8_t moduleIdx,
BindChoiceMenu::BindChoiceMenu(uint8_t moduleIdx,
std::function<void()> onPress,
std::function<void()> onCancelFn) :
Menu(parent), moduleIdx(moduleIdx), onPressHandler(std::move(onPress))
Menu(), moduleIdx(moduleIdx), onPressHandler(std::move(onPress))
{
if (isTelemAllowedOnBind(moduleIdx)) {
addLine(STR_BINDING_1_8_TELEM_ON, [=]() { onSelect(Bind_1_8_TELEM_ON); });
@@ -38,6 +38,6 @@ class BindChoiceMenu : public Menu
void onSelect(BindChanMode mode);
public:
BindChoiceMenu(Window *parent, uint8_t moduleIdx,
BindChoiceMenu(uint8_t moduleIdx,
std::function<void()> onPress, std::function<void()> onCancel);
};
@@ -246,7 +246,7 @@ class ModuleWindow : public Window
if (isModuleR9MNonAccess(moduleIdx) || isModuleD16(moduleIdx) ||
IS_R9_MULTI(moduleIdx)) {
new BindChoiceMenu(
Layer::back(), moduleIdx, [=]() { bindButton->check(true); },
moduleIdx, [=]() { bindButton->check(true); },
[=]() { bindButton->check(false); });
return 0;
}
@@ -316,7 +316,7 @@ class ModuleWindow : public Window
if (isModuleISRM(moduleIdx)) {
auto options = new TextButton(box, rect_t{}, LV_SYMBOL_SETTINGS);
options->setPressHandler([=]() {
new pxx2::ModuleOptions(Layer::back(), moduleIdx);
new pxx2::ModuleOptions(moduleIdx);
return 0;
});
}
@@ -336,7 +336,7 @@ class ModuleWindow : public Window
registerButton = new TextButton(box, rect_t{}, STR_REGISTER);
registerButton->setPressHandler([=]() -> uint8_t {
new pxx2::RegisterDialog(Layer::back(), moduleIdx);
new pxx2::RegisterDialog(moduleIdx);
return 0;
});
@@ -354,7 +354,7 @@ class ModuleWindow : public Window
auto options = new TextButton(box, rect_t{}, LV_SYMBOL_SETTINGS);
options->setPressHandler([=]() {
new pxx2::ModuleOptions(Layer::back(), moduleIdx);
new pxx2::ModuleOptions(moduleIdx);
return 0;
});
@@ -506,7 +506,7 @@ class ModuleWindow : public Window
void startRSSIDialog(std::function<void()> closeHandler = nullptr)
{
auto rssiDialog = new DynamicMessageDialog(
parent, STR_RANGE_TEST,
STR_RANGE_TEST,
[=]() {
return std::to_string((int)TELEMETRY_RSSI()) + getRxStatLabels()->unit;
},
@@ -664,7 +664,7 @@ class ModuleSubTypeChoice : public Choice
protos->triggerScan();
if (protos->isScanning()) {
new RfScanDialog(parent, protos, [=]() { updateLayout(); });
new RfScanDialog(protos, [=]() { updateLayout(); });
} else {
TRACE("!protos->isScanning()");
}
@@ -685,7 +685,7 @@ class ModuleSubTypeChoice : public Choice
{
#if defined(MULTIMODULE)
if (isModuleMultimodule(moduleIdx)) {
auto menu = new Menu(this);
auto menu = new Menu();
if (menuTitle) menu->setTitle(menuTitle);
menu->setCloseHandler([=]() { setEditMode(false); });
@@ -28,9 +28,9 @@
// TODO: translation
const char* const RFSCAN_TITLE = "MPM: Scanning protocols...";
RfScanDialog::RfScanDialog(Window* parent, MultiRfProtocols* protos,
RfScanDialog::RfScanDialog(MultiRfProtocols* protos,
std::function<void()> onClose) :
ProgressDialog(parent, RFSCAN_TITLE, onClose),
ProgressDialog(RFSCAN_TITLE, onClose),
protos(protos)
{
}
@@ -31,7 +31,7 @@ class RfScanDialog : public ProgressDialog
uint32_t lastUpdate = 0;
public:
RfScanDialog(Window* parent, MultiRfProtocols* protos,
RfScanDialog(MultiRfProtocols* protos,
std::function<void()> onClose);
void showProgress();
@@ -33,7 +33,7 @@ static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
class BTDetailsDialog : public BaseDialog
{
public:
BTDetailsDialog(Window* parent) : BaseDialog(parent, STR_BLUETOOTH, true)
BTDetailsDialog() : BaseDialog(STR_BLUETOOTH, true)
{
FlexGridLayout grid(col_dsc, row_dsc);
@@ -86,7 +86,7 @@ BluetoothConfigWindow::BluetoothConfigWindow(Window* parent, FlexGridLayout& gri
settingsBtn =
new TextButton(box, rect_t{}, LV_SYMBOL_SETTINGS, [=]() -> uint8_t {
new BTDetailsDialog(parent);
new BTDetailsDialog();
return 0;
});
settingsBtn->show(g_eeGeneral.bluetoothMode != BLUETOOTH_OFF);
+1 -1
View File
@@ -267,7 +267,7 @@ HWSwitches::HWSwitches(Window* parent) :
template <class T>
HWInputDialog<T>::HWInputDialog(const char* title) :
BaseDialog(Layer::back(), title, true)
BaseDialog(title, true)
{
new T(form);
}
@@ -95,8 +95,8 @@ ModuleCallback onUpdateStateChangedCallbackFor(FrskyOtaFlashDialog* dialog);
class FrskyOtaFlashDialog : public BaseDialog
{
public:
explicit FrskyOtaFlashDialog(Window* parent, const char* title) :
BaseDialog(parent, title, true)
explicit FrskyOtaFlashDialog(const char* title) :
BaseDialog(title, true)
{
new StaticText(form, rect_t{}, STR_WAITING_FOR_RX);
}
@@ -137,8 +137,7 @@ class FrskyOtaFlashDialog : public BaseDialog
*tmp++ = '.';
tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.revision);
updateConfirmDialog = new ConfirmDialog(Layer::back(),
getPXX2ReceiverName(modelId),
updateConfirmDialog = new ConfirmDialog(getPXX2ReceiverName(modelId),
std::string(reusableBuffer.sdManager.otaReceiverVersion).c_str(),
[=]() { onUpdateConfirmation(); },
[=]() { deleteLater(); });
@@ -156,7 +155,7 @@ class FrskyOtaFlashDialog : public BaseDialog
if (reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount > 0) {
if (reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount != popupReceiversCount) {
if (rxChoiceMenu == nullptr) {
rxChoiceMenu = new Menu(Layer::back());
rxChoiceMenu = new Menu();
rxChoiceMenu->setTitle(STR_PXX2_SELECT_RX);
rxChoiceMenu->setCancelHandler([=]() {
// Seems menu didn't delete itself before call cancelHandler().
@@ -293,8 +292,7 @@ void RadioSdManagerPage::dirAction(const char* path, const char* name,
{
if (strcmp(name, "..") == 0) return;
auto window = Layer::back();
auto menu = new Menu(window);
auto menu = new Menu();
menu->addLine(STR_RENAME_FILE, [=]() {
uint8_t nameLength;
uint8_t extLength;
@@ -308,7 +306,7 @@ void RadioSdManagerPage::dirAction(const char* path, const char* name,
std::string extension("");
if (ext) extension = ext;
new LabelDialog(Layer::back(), fname.c_str(), maxNameLength, STR_RENAME_FILE, [=](std::string label) {
new LabelDialog(fname.c_str(), maxNameLength, STR_RENAME_FILE, [=](std::string label) {
label += extension;
f_rename((const TCHAR *)name, (const TCHAR *)label.c_str());
browser->refresh();
@@ -316,7 +314,7 @@ void RadioSdManagerPage::dirAction(const char* path, const char* name,
});
menu->addLine(STR_DELETE_FILE, [=]() {
if (f_unlink(fullpath) != FR_OK) {
new MessageDialog(window, STR_DELETE_FILE, STR_DEL_DIR_NOT_EMPTY);
new MessageDialog(STR_DELETE_FILE, STR_DEL_DIR_NOT_EMPTY);
}
browser->refresh();
});
@@ -325,8 +323,7 @@ void RadioSdManagerPage::dirAction(const char* path, const char* name,
void RadioSdManagerPage::fileAction(const char* path, const char* name,
const char* fullpath)
{
auto window = Layer::back();
auto menu = new Menu(window);
auto menu = new Menu();
const char* ext = getFileExtension(name);
if (ext) {
if (!strcasecmp(ext, SOUNDS_EXT)) {
@@ -376,7 +373,7 @@ void RadioSdManagerPage::fileAction(const char* path, const char* name,
char buf[64];
sprintf(buf, " %s %dkB. %s", STR_FILE_SIZE, fileLength / 1024,
STR_FILE_OPEN);
new ConfirmDialog(window, STR_WARNING, buf,
new ConfirmDialog(STR_WARNING, buf,
[=] { new ViewTextWindow(path, name, ICON_RADIO_SD_MANAGER); });
} else {
new ViewTextWindow(path, name, ICON_RADIO_SD_MANAGER);
@@ -434,7 +431,6 @@ void RadioSdManagerPage::fileAction(const char* path, const char* name,
information.productId))
menu->addLine(STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA, [=]() {
auto dialog = new FrskyOtaFlashDialog(
Layer::back(),
STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA);
dialog->flash(fullpath, INTERNAL_MODULE);
});
@@ -443,7 +439,6 @@ void RadioSdManagerPage::fileAction(const char* path, const char* name,
information.productId))
menu->addLine(STR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA, [=]() {
auto dialog = new FrskyOtaFlashDialog(
Layer::back(),
STR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA);
dialog->flash(fullpath, EXTERNAL_MODULE);
});
@@ -453,7 +448,6 @@ void RadioSdManagerPage::fileAction(const char* path, const char* name,
menu->addLine(STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA,
[=]() {
auto dialog = new FrskyOtaFlashDialog(
Layer::back(),
STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA);
dialog->flash(fullpath, INTERNAL_MODULE);
});
@@ -461,7 +455,6 @@ void RadioSdManagerPage::fileAction(const char* path, const char* name,
menu->addLine(STR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA,
[=]() {
auto dialog = new FrskyOtaFlashDialog(
Layer::back(),
STR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA);
dialog->flash(fullpath, EXTERNAL_MODULE);
});
@@ -527,7 +520,7 @@ void RadioSdManagerPage::fileAction(const char* path, const char* name,
std::string extension("");
if (ext) extension = ext;
new LabelDialog(Layer::back(), fname.c_str(), maxNameLength, STR_RENAME_FILE, [=](std::string label) {
new LabelDialog(fname.c_str(), maxNameLength, STR_RENAME_FILE, [=](std::string label) {
label += extension;
f_rename((const TCHAR *)name, (const TCHAR *)label.c_str());
browser->refresh();
+1 -1
View File
@@ -877,7 +877,7 @@ static SetupLineDef setupLines[] = {
new Choice(parent, {x, y, 120, 0}, STR_HATSOPT, HATSMODE_TRIMS_ONLY,
HATSMODE_SWITCHABLE, GET_SET_DEFAULT(g_eeGeneral.hatsMode));
new TextButton(parent, {x + 120 + PAD_MEDIUM, y, 0, 0}, "?", [=]() {
new MessageDialog(parent, STR_HATSMODE_KEYS, STR_HATSMODE_KEYS_HELP, "",
new MessageDialog(STR_HATSMODE_KEYS, STR_HATSMODE_KEYS_HELP, "",
LEFT);
return 0;
});
+7 -9
View File
@@ -99,9 +99,9 @@ class ThemeDetailsDialog : public BaseDialog
{
public:
ThemeDetailsDialog(
Window *parent, ThemeFile theme,
ThemeFile theme,
std::function<bool(ThemeFile theme)> saveHandler = nullptr) :
BaseDialog(parent, STR_EDIT_THEME_DETAILS, false, DIALOG_DEFAULT_WIDTH,
BaseDialog(STR_EDIT_THEME_DETAILS, false, DIALOG_DEFAULT_WIDTH,
LV_SIZE_CONTENT),
theme(theme),
saveHandler(saveHandler)
@@ -346,8 +346,7 @@ class ThemeEditPage : public Page
void onCancel() override
{
if (_dirty) {
new ConfirmDialog(
this, STR_SAVE_THEME, _theme.getName().c_str(),
new ConfirmDialog(STR_SAVE_THEME, _theme.getName().c_str(),
[=]() {
if (saveHandler != nullptr) {
saveHandler(_theme);
@@ -391,7 +390,7 @@ class ThemeEditPage : public Page
// save and cancel
rect_t r = {LCD_W - (ColorEditPage::BUTTON_WIDTH + 5), PAD_MEDIUM, ColorEditPage::BUTTON_WIDTH, 0};
new TextButton(window, r, STR_DETAILS, [=]() {
new ThemeDetailsDialog(page, _theme, [=](ThemeFile t) {
new ThemeDetailsDialog(_theme, [=](ThemeFile t) {
_theme.setAuthor(t.getAuthor());
_theme.setInfo(t.getInfo());
_theme.setName(t.getName());
@@ -480,7 +479,7 @@ void ThemeSetupPage::checkEvents()
void ThemeSetupPage::displayThemeMenu(Window *window, ThemePersistance *tp)
{
auto menu = new Menu(listBox, false);
auto menu = new Menu(false);
// you can't activate the active theme
if (listBox->getSelected() != tp->getThemeIndex()) {
@@ -529,7 +528,7 @@ void ThemeSetupPage::displayThemeMenu(Window *window, ThemePersistance *tp)
menu->addLine(STR_DUPLICATE, [=]() {
ThemeFile newTheme;
new ThemeDetailsDialog(window, newTheme, [=](ThemeFile theme) {
new ThemeDetailsDialog(newTheme, [=](ThemeFile theme) {
if (!theme.getName().empty()) {
char name[SELECTED_THEME_NAME_LEN + 1];
int n = 0;
@@ -565,8 +564,7 @@ void ThemeSetupPage::displayThemeMenu(Window *window, ThemePersistance *tp)
if (listBox->getSelected() != 0 &&
listBox->getSelected() != tp->getThemeIndex()) {
menu->addLine(STR_DELETE, [=]() {
new ConfirmDialog(
window, STR_DELETE_THEME,
new ConfirmDialog(STR_DELETE_THEME,
tp->getThemeByIndex(listBox->getSelected())->getName().c_str(), [=] {
tp->deleteThemeByIndex(listBox->getSelected());
listBox->setNames(tp->getNames());
+1 -1
View File
@@ -101,7 +101,7 @@ static void run_lua_tool(Window* parent, const std::string& path)
*((char*)getBasename(toolPath) - 1) = '\0';
f_chdir(toolPath);
luaExec(path.c_str());
luaExecStandalone(path.c_str());
}
// LUA scripts in TOOLS
@@ -73,8 +73,8 @@ class VersionDialog : public BaseDialog
StaticText* ext_rx_status;
public:
VersionDialog(Window* parent) :
BaseDialog(parent, STR_MODULES_RX_VERSION, true)
VersionDialog() :
BaseDialog(STR_MODULES_RX_VERSION, true)
{
#if defined(PXX2)
memclear(&reusableBuffer.hardwareAndSettings.modules,
@@ -378,7 +378,7 @@ void RadioVersionPage::build(Window* window)
// Module and receivers versions
auto btn = new TextButton(window, rect_t{}, STR_MODULES_RX_VERSION);
btn->setPressHandler([=]() -> uint8_t {
new VersionDialog(window);
new VersionDialog();
return 0;
});
lv_obj_set_width(btn->getLvObj(), lv_pct(100));
+190 -28
View File
@@ -24,13 +24,110 @@
#include "translations.h"
#include "view_main.h"
#include "dma2d.h"
#include "lua/lua_event.h"
lua_State *lsStandalone = nullptr;
#if defined(LUA_ALLOCATOR_TRACER)
LuaMemTracer lsStandaloneTrace;
static void luaStandaloneHook(lua_State * L, lua_Debug *ar)
{
else if (ar->event == LUA_HOOKLINE) {
lua_getinfo(L, "nSl", ar);
LuaMemTracer * tracer = &lsStandaloneTrace;
if (tracer->alloc || tracer->free) {
TRACE("LT: [+%u,-%u] %s:%d", tracer->alloc, tracer->free, tracer->script, tracer->lineno);
}
tracer->script = ar->source;
tracer->lineno = ar->currentline;
tracer->alloc = 0;
tracer->free = 0;
}
}
#endif // #if defined(LUA_ALLOCATOR_TRACER)
static void luaStandaloneInit()
{
luaClose(&lsStandalone);
#if defined(USE_BIN_ALLOCATOR)
lsStandalone = lua_newstate(bin_l_alloc, nullptr); //we use our own allocator!
#elif defined(LUA_ALLOCATOR_TRACER)
memclear(&lsStandaloneTrace, sizeof(lsStandaloneTrace));
lsStandaloneTrace.script = "lua_newstate(scripts)";
lsStandalone = lua_newstate(tracer_alloc, &lsStandaloneTrace); //we use tracer allocator
#else
lsStandalone = lua_newstate(l_alloc, nullptr); //we use Lua default allocator
#endif
if (lsStandalone) {
// install our panic handler
extern int custom_lua_atpanic(lua_State *L);
lua_atpanic(lsStandalone, &custom_lua_atpanic);
#if defined(LUA_ALLOCATOR_TRACER)
lua_sethook(L, luaStandaloneHook, LUA_MASKLINE);
#endif
// protect libs and constants registration
PROTECT_LUA() {
luaRegisterLibraries(lsStandalone);
}
else {
// if we got panic during registration
// we disable Lua for this session
luaClose(&lsStandalone);
lsStandalone = 0;
}
UNPROTECT_LUA();
}
}
void luaExecStandalone(const char * filename)
{
if (lsStandalone == NULL)
luaStandaloneInit();
PROTECT_LUA() {
if (luaLoadScriptFileToState(lsStandalone, filename, LUA_SCRIPT_LOAD_MODE) == SCRIPT_OK) {
if (lua_pcall(lsStandalone, 0, 1, 0) == LUA_OK && lua_istable(lsStandalone, -1)) {
int initFunction = LUA_REFNIL, runFunction = LUA_REFNIL;
bool lvglLayout = false;
for (lua_pushnil(lsStandalone); lua_next(lsStandalone, -2); lua_pop(lsStandalone, 1)) {
const char * key = lua_tostring(lsStandalone, -2);
if (!strcmp(key, "init")) {
initFunction = luaL_ref(lsStandalone, LUA_REGISTRYINDEX);
lua_pushnil(lsStandalone);
} else if (!strcmp(key, "run")) {
runFunction = luaL_ref(lsStandalone, LUA_REGISTRYINDEX);
lua_pushnil(lsStandalone);
} else if (!strcasecmp(key, "useLvgl")) {
lvglLayout = lua_toboolean(lsStandalone, -1);
}
}
StandaloneLuaWindow::setup(lvglLayout, initFunction, runFunction);
}
else {
TRACE("luaLoadFile(%s): Error parsing script: %s", filename, lua_tostring(lsStandalone, -1));
}
}
}
else {
// error while loading Lua widget/theme,
// do not disable whole Lua state, just ingnore bad script
return;
}
UNPROTECT_LUA();
}
// singleton instance
StandaloneLuaWindow* StandaloneLuaWindow::_instance;
StandaloneLuaWindow::StandaloneLuaWindow(bool useLvgl) :
StandaloneLuaWindow::StandaloneLuaWindow(bool useLvgl, int initFn, int runFn) :
Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}),
useLvgl(useLvgl)
useLvgl(useLvgl), initFunction(initFn), runFunction(runFn)
{
setWindowFlag(OPAQUE);
@@ -45,6 +142,7 @@ StandaloneLuaWindow::StandaloneLuaWindow(bool useLvgl) :
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);
etx_font(lbl, FONT_XL_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);
@@ -69,12 +167,22 @@ StandaloneLuaWindow::StandaloneLuaWindow(bool useLvgl) :
setupHandler(this);
attach();
lua_gc(lsStandalone, LUA_GCCOLLECT, 0);
// Pause function and mixer scripts
prevLuaState = luaState;
luaState = INTERPRETER_PAUSED;
#if defined(USE_HATS_AS_KEYS)
setTransposeHatsForLUA(true);
#endif
}
void StandaloneLuaWindow::setup(bool useLvgl)
void StandaloneLuaWindow::setup(bool useLvgl, int initFn, int runFn)
{
if (_instance == nullptr)
_instance = new StandaloneLuaWindow(useLvgl);
_instance = new StandaloneLuaWindow(useLvgl, initFn, runFn);
}
StandaloneLuaWindow* StandaloneLuaWindow::instance()
@@ -102,6 +210,11 @@ void StandaloneLuaWindow::deleteLater(bool detach, bool trash)
{
if (_deleted) return;
if (initFunction != LUA_REFNIL) luaL_unref(lsStandalone, LUA_REGISTRYINDEX, initFunction);
if (runFunction != LUA_REFNIL) luaL_unref(lsStandalone, LUA_REGISTRYINDEX, runFunction);
lua_settop(lsStandalone, 0);
luaLcdBuffer = nullptr;
if (lcdBuffer) delete lcdBuffer;
lcdBuffer = nullptr;
@@ -118,6 +231,12 @@ void StandaloneLuaWindow::deleteLater(bool detach, bool trash)
_instance = nullptr;
}
#if defined(USE_HATS_AS_KEYS)
setTransposeHatsForLUA(false);
#endif
luaState = prevLuaState;
Window::deleteLater(detach, trash);
}
@@ -125,38 +244,78 @@ void StandaloneLuaWindow::checkEvents()
{
Window::checkEvents();
if (initFunction != LUA_REFNIL) {
lua_rawgeti(lsStandalone, LUA_REGISTRYINDEX, initFunction);
if (lua_pcall(lsStandalone, 0, 0, 0) != LUA_OK) {
luaShowError();
}
luaL_unref(lsStandalone, LUA_REGISTRYINDEX, initFunction);
initFunction = LUA_REFNIL;
return;
}
// Set global LUA LCD buffer
luaLcdBuffer = lcdBuffer;
luaLcdAllowed = !useLvglLayout();
if (luaState != INTERPRETER_RELOAD_PERMANENT_SCRIPTS) {
if (luaTask(true)) {
if (useLvglLayout() && !hasError) {
// if LUA finished a full cycle,
// call update functions
PROTECT_LUA() {
if (!callRefs(lsScripts)) {
luaShowError();
}
} else {
luaShowError();
}
UNPROTECT_LUA();
LuaEventData evt;
// Pull a new event from the buffer
luaNextEvent(&evt);
if (evt.event == EVT_KEY_LONG(KEY_EXIT)) {
killEvents(evt.event);
deleteLater();
} else {
if (runFunction != LUA_REFNIL) {
lua_rawgeti(lsStandalone, LUA_REGISTRYINDEX, runFunction);
lua_pushunsigned(lsStandalone, evt.event);
int inputsCount = 1;
#if defined(HARDWARE_TOUCH)
if (IS_TOUCH_EVENT(evt.event)) {
luaPushTouchEventTable(lsStandalone, &evt);
inputsCount += 1;
}
#endif
if (lua_pcall(lsStandalone, inputsCount, 1, 0) != LUA_OK) {
luaShowError();
} else {
// if LUA finished a full cycle,
// invalidate to display the screen buffer
invalidate();
if (lua_isnumber(lsStandalone, -1)) {
int scriptResult = lua_tointeger(lsStandalone, -1);
lua_pop(lsStandalone, 1); /* pop returned value */
if (scriptResult != 0) {
deleteLater();
} else {
if (useLvglLayout() && !hasError) {
PROTECT_LUA() {
if (!callRefs(lsStandalone)) {
luaShowError();
}
} else {
luaShowError();
}
UNPROTECT_LUA();
} else {
invalidate();
}
}
} else if (lua_isstring(lsStandalone, -1)) {
char nextScript[FF_MAX_LFN+1];
strncpy(nextScript, lua_tostring(lsStandalone, -1), FF_MAX_LFN);
nextScript[FF_MAX_LFN] = '\0';
_instance = nullptr;
lua_settop(lsStandalone, 0);
deleteLater();
luaExecStandalone(nextScript);
}
}
}
}
if (luaState == INTERPRETER_RELOAD_PERMANENT_SCRIPTS) {
// Script does not run anymore...
TRACE("LUA standalone script exited: deleting window!");
deleteLater();
}
// Kill global LUA LCD buffer
luaLcdBuffer = nullptr;
luaLcdAllowed = false;
}
void StandaloneLuaWindow::onClicked() { Keyboard::hide(false); LuaEventHandler::onClicked(); }
@@ -212,19 +371,22 @@ bool StandaloneLuaWindow::displayPopup(event_t event, uint8_t type,
void StandaloneLuaWindow::clear()
{
clearRefs(lsScripts);
clearRefs(lsStandalone);
Window::clear();
}
void StandaloneLuaWindow::luaShowError()
{
if (runFunction != LUA_REFNIL) luaL_unref(lsStandalone, LUA_REGISTRYINDEX, runFunction);
runFunction = LUA_REFNIL;
hasError = true;
extern void luaError(lua_State *L, uint8_t error);
luaError(lsScripts, SCRIPT_SYNTAX_ERROR);
luaError(lsStandalone, SCRIPT_SYNTAX_ERROR);
}
void StandaloneLuaWindow::showError(bool firstCall, const char* title, const char* msg)
{
runFunction = LUA_REFNIL;
hasError = true;
if (!errorModal) {
lv_obj_set_scroll_dir(lvobj, LV_DIR_NONE);
+9 -6
View File
@@ -26,15 +26,17 @@
#include "lua/lua_api.h"
#include "lua/lua_widget.h"
extern void luaExecStandalone(const char * filename);
class StandaloneLuaWindow : public Window, public LuaEventHandler, public LuaLvglManager
{
static StandaloneLuaWindow* _instance;
explicit StandaloneLuaWindow(bool useLvgl);
explicit StandaloneLuaWindow(bool useLvgl, int initFn, int runFn);
public:
static StandaloneLuaWindow* instance();
static void setup(bool useLvgl);
static void setup(bool useLvgl, int initFn, int runFn);
void attach();
void deleteLater(bool detach = true, bool trash = true) override;
@@ -46,10 +48,11 @@ 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; }
Window* getCurrentParent() const override { return (tempParent && tempParent->getWindow()) ? tempParent->getWindow() : (Window*)this; }
void clear() override;
bool useLvglLayout() const override { return useLvgl; }
bool isAppMode() const override { return false; }
void luaShowError() override;
@@ -68,6 +71,9 @@ protected:
lv_obj_t* errorMsg = nullptr;
bool hasError = false;
bool useLvgl = false;
int initFunction = LUA_REFNIL;
int runFunction = LUA_REFNIL;
uint8_t prevLuaState;
// GFX
BitmapBuffer *lcdBuffer = nullptr;
@@ -76,9 +82,6 @@ protected:
void popupPaint(BitmapBuffer* dc, coord_t x, coord_t y, coord_t w, coord_t h,
const char* text, const char* info);
// run LUA code
void runLua(event_t evt);
void onEvent(event_t evt) override;
void checkEvents() override;
void onClicked() override;
+1 -1
View File
@@ -648,7 +648,7 @@ class AntennaSelectionMenu : public Menu
bool& done;
public:
AntennaSelectionMenu(bool& done) : Menu(MainWindow::instance()), done(done) {
AntennaSelectionMenu(bool& done) : Menu(), done(done) {
setTitle(STR_ANTENNA);
addLine(STR_USE_INTERNAL_ANTENNA,
[] { globalData.externalAntennaEnabled = false; });
-1
View File
@@ -200,7 +200,6 @@ bool rotaryEncoderPollingCycle();
void setHatsAsKeys(bool val);
bool getHatsAsKeys();
void setTransposeHatsForLUA(bool val);
bool getTransposeHatsForLUA();
#endif
struct InactivityData
+173 -79
View File
@@ -44,16 +44,16 @@ static int luaLvglObj(lua_State *L, std::function<LvglWidgetObject*()> create, b
return 1;
}
static int luaLvglObjEx(lua_State *L, std::function<LvglWidgetObject*()> create, bool standalone = false)
static int luaLvglObjEx(lua_State *L, std::function<LvglWidgetObjectBase*()> create, bool standalone = false)
{
if (luaLvglManager && (!standalone || !luaLvglManager->isWidget())) {
LvglWidgetObject* p = nullptr;
Window* prevParent = nullptr;
LvglWidgetObjectBase* p = nullptr;
LvglWidgetObjectBase* prevParent = nullptr;
if (lua_gettop(L) == 2) {
p = LvglWidgetObject::checkLvgl(L, 1);
p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
prevParent = luaLvglManager->getTempParent();
luaLvglManager->setTempParent(p->getWindow());
luaLvglManager->setTempParent(p);
}
}
@@ -71,32 +71,27 @@ static int luaLvglObjEx(lua_State *L, std::function<LvglWidgetObject*()> create,
return 1;
}
static int luaLvglConfirm(lua_State *L)
static int luaLvglPopup(lua_State *L, std::function<LvglWidgetObjectBase*()> create)
{
auto obj = new LvglWidgetConfirmDialog();
auto obj = create();
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 int luaDestroyLvglWidget(lua_State *L)
{
auto p = LvglWidgetObject::checkLvgl(L, 1);
if (p) delete p;
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
p->clearRefs(L);
delete p;
}
return 0;
}
static int luaLvglSet(lua_State *L)
{
auto p = LvglWidgetObject::checkLvgl(L, 1);
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
p->update(L);
}
@@ -107,9 +102,10 @@ static int luaLvglClear(lua_State *L)
{
if (luaLvglManager) {
if (lua_gettop(L) == 1) {
auto p = LvglWidgetObject::checkLvgl(L, 1);
if (p)
p->getWindow()->clear();
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
p->clear();
}
} else {
luaLvglManager->clear();
}
@@ -120,7 +116,7 @@ static int luaLvglClear(lua_State *L)
static int luaLvglShow(lua_State *L)
{
auto p = LvglWidgetObject::checkLvgl(L, 1);
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
p->show();
}
@@ -129,7 +125,7 @@ static int luaLvglShow(lua_State *L)
static int luaLvglHide(lua_State *L)
{
auto p = LvglWidgetObject::checkLvgl(L, 1);
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
p->hide();
}
@@ -164,50 +160,72 @@ 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;
LvglWidgetObjectBase *obj = nullptr;
if (strcasecmp(p.type, "label") == 0)
lvobj = new LvglWidgetLabel();
obj = new LvglWidgetLabel();
else if (strcasecmp(p.type, "rectangle") == 0)
lvobj = new LvglWidgetRectangle();
obj = new LvglWidgetRectangle();
else if (strcasecmp(p.type, "circle") == 0)
lvobj = new LvglWidgetCircle();
obj = new LvglWidgetCircle();
else if (strcasecmp(p.type, "arc") == 0)
lvobj = new LvglWidgetArc();
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)
lvobj = new LvglWidgetImage();
obj = new LvglWidgetImage();
else if (strcasecmp(p.type, "qrcode") == 0)
lvobj = new LvglWidgetQRCode();
// else if (strcasecmp(p.type, "meter") == 0)
// lvobj = new LvglWidgetMeter();
obj = new LvglWidgetQRCode();
else if (strcasecmp(p.type, "box") == 0)
obj = new LvglWidgetBox();
else if (strcasecmp(p.type, "setting") == 0)
obj = new LvglWidgetSetting();
else if (!luaLvglManager->isWidget()) {
if (strcasecmp(p.type, "button") == 0)
lvobj = new LvglWidgetTextButton();
obj = new LvglWidgetTextButton();
else if (strcasecmp(p.type, "toggle") == 0)
lvobj = new LvglWidgetToggleSwitch();
obj = new LvglWidgetToggleSwitch();
else if (strcasecmp(p.type, "textEdit") == 0)
lvobj = new LvglWidgetTextEdit();
obj = new LvglWidgetTextEdit();
else if (strcasecmp(p.type, "numberEdit") == 0)
lvobj = new LvglWidgetNumberEdit();
obj = new LvglWidgetNumberEdit();
else if (strcasecmp(p.type, "choice") == 0)
lvobj = new LvglWidgetChoice();
obj = new LvglWidgetChoice();
else if (strcasecmp(p.type, "slider") == 0)
lvobj = new LvglWidgetSlider();
obj = new LvglWidgetSlider();
else if (strcasecmp(p.type, "page") == 0)
lvobj = new LvglWidgetPage();
obj = new LvglWidgetPage();
else if (strcasecmp(p.type, "font") == 0)
obj = new LvglWidgetFontPicker();
else if (strcasecmp(p.type, "align") == 0)
obj = new LvglWidgetAlignPicker();
else if (strcasecmp(p.type, "color") == 0)
obj = new LvglWidgetColorPicker();
else if (strcasecmp(p.type, "timer") == 0)
obj = new LvglWidgetTimerPicker();
else if (strcasecmp(p.type, "switch") == 0)
obj = new LvglWidgetSwitchPicker();
else if (strcasecmp(p.type, "source") == 0)
obj = new LvglWidgetSourcePicker();
}
if (lvobj) {
lvobj->getParams(L, -1);
lvobj->build(L);
auto ref = lvobj->getRef(L);
if (obj) {
obj->getParams(L, -1);
obj->build(L);
auto ref = obj->getRef(L);
if (p.name) {
lua_pushstring(L, p.name);
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
lua_settable(L, refIndex - 4);
}
if (p.hasChildren) {
if (p.hasChildren && obj->getWindow()) {
lua_getfield(L, -1, "children");
auto prevParent = luaLvglManager->getTempParent();
luaLvglManager->setTempParent(lvobj->getWindow());
luaLvglManager->setTempParent(obj);
buildLvgl(L, -1, refIndex - 3);
lua_pop(L, 1);
luaLvglManager->setTempParent(prevParent);
@@ -219,13 +237,13 @@ static void buildLvgl(lua_State *L, int srcIndex, int refIndex)
static int luaLvglBuild(lua_State *L)
{
if (luaLvglManager) {
LvglWidgetObject* p = nullptr;
Window* prevParent = nullptr;
LvglWidgetObjectBase* p = nullptr;
LvglWidgetObjectBase* prevParent = nullptr;
if (lua_gettop(L) == 2) {
p = LvglWidgetObject::checkLvgl(L, 1);
p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
prevParent = luaLvglManager->getTempParent();
luaLvglManager->setTempParent(p->getWindow());
luaLvglManager->setTempParent(p);
}
}
@@ -241,40 +259,116 @@ static int luaLvglBuild(lua_State *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)
// Objects - widgets and standalone
LROT_FUNCENTRY(label, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetLabel(); }); })
LROT_FUNCENTRY(rectangle, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetRectangle(); }); })
LROT_FUNCENTRY(circle, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetCircle(); }); })
LROT_FUNCENTRY(arc, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetArc(); }); })
LROT_FUNCENTRY(image, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetImage(); }); })
LROT_FUNCENTRY(qrcode, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetQRCode(); }); })
// LROT_FUNCENTRY(meter, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetMeter(); }); })
// Objects - standalone scripts only
LROT_FUNCENTRY(button, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetTextButton(); }, true); })
LROT_FUNCENTRY(toggle, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetToggleSwitch(); }, true); })
LROT_FUNCENTRY(textEdit, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetTextEdit(); }, true); })
LROT_FUNCENTRY(numberEdit, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetNumberEdit(); }, true); })
LROT_FUNCENTRY(choice, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetChoice(); }, true); })
LROT_FUNCENTRY(slider, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSlider(); }, true); })
// Containers
LROT_FUNCENTRY(page, [](lua_State* L) { return luaLvglObj(L, []() { return new LvglWidgetPage(); }, true); })
// Dialogs
LROT_FUNCENTRY(confirm, luaLvglConfirm)
// Manipulation functions
LROT_FUNCENTRY(set, luaLvglSet)
LROT_FUNCENTRY(show, luaLvglShow)
LROT_FUNCENTRY(hide, luaLvglHide)
LROT_END(lvgllib, NULL, LROT_MASK_GC_INDEX)
static int luaLvglIsAppMode(lua_State *L)
{
if (luaLvglManager) {
lua_pushboolean(L, luaLvglManager->isAppMode());
} else {
lua_pushboolean(L, false);
}
return 1;
}
// lvgl functions
LROT_BEGIN(lvgllib, NULL, 0)
LROT_FUNCENTRY(clear, luaLvglClear)
LROT_FUNCENTRY(build, luaLvglBuild)
LROT_FUNCENTRY(isAppMode, luaLvglIsAppMode)
// Objects - widgets and standalone
LROT_FUNCENTRY(label, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetLabel(); }); })
LROT_FUNCENTRY(rectangle, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetRectangle(); }); })
LROT_FUNCENTRY(hline, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetHLine(); }); })
LROT_FUNCENTRY(vline, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetVLine(); }); })
LROT_FUNCENTRY(line, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetLine(); }); })
LROT_FUNCENTRY(triangle, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetTriangle(); }); })
LROT_FUNCENTRY(circle, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetCircle(); }); })
LROT_FUNCENTRY(arc, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetArc(); }); })
LROT_FUNCENTRY(image, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetImage(); }); })
LROT_FUNCENTRY(qrcode, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetQRCode(); }); })
// Objects - standalone scripts only
LROT_FUNCENTRY(button, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetTextButton(); }, true); })
LROT_FUNCENTRY(toggle, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetToggleSwitch(); }, true); })
LROT_FUNCENTRY(textEdit, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetTextEdit(); }, true); })
LROT_FUNCENTRY(numberEdit, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetNumberEdit(); }, true); })
LROT_FUNCENTRY(choice, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetChoice(); }, true); })
LROT_FUNCENTRY(slider, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSlider(); }, true); })
LROT_FUNCENTRY(font, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetFontPicker(); }, true); })
LROT_FUNCENTRY(align, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetAlignPicker(); }, true); })
LROT_FUNCENTRY(color, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetColorPicker(); }, true); })
LROT_FUNCENTRY(timer, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetTimerPicker(); }, true); })
LROT_FUNCENTRY(switch, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSwitchPicker(); }, true); })
LROT_FUNCENTRY(source, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSourcePicker(); }, true); })
// Containers
LROT_FUNCENTRY(box, [](lua_State* L) { return luaLvglObj(L, []() { return new LvglWidgetBox(); }, true); })
LROT_FUNCENTRY(setting, [](lua_State* L) { return luaLvglObj(L, []() { return new LvglWidgetSetting(); }, true); })
LROT_FUNCENTRY(page, [](lua_State* L) { return luaLvglObj(L, []() { return new LvglWidgetPage(); }, true); })
LROT_FUNCENTRY(dialog, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetDialog(); }, true); })
// Dialogs
LROT_FUNCENTRY(confirm, [](lua_State* L) { return luaLvglPopup(L, []() { return new LvglWidgetConfirmDialog(); }); })
LROT_FUNCENTRY(message, [](lua_State* L) { return luaLvglPopup(L, []() { return new LvglWidgetMessageDialog(); }); })
// Object manipulation functions
LROT_FUNCENTRY(set, luaLvglSet)
LROT_FUNCENTRY(show, luaLvglShow)
LROT_FUNCENTRY(hide, luaLvglHide)
LROT_NUMENTRY(FLOW_ROW, LV_FLEX_FLOW_ROW)
LROT_NUMENTRY(FLOW_COLUMN, LV_FLEX_FLOW_COLUMN)
LROT_NUMENTRY(PAD_TINY, PAD_TINY)
LROT_NUMENTRY(PAD_SMALL, PAD_SMALL)
LROT_NUMENTRY(PAD_MEDIUM, PAD_MEDIUM)
LROT_NUMENTRY(PAD_LARGE, PAD_LARGE)
LROT_END(lvgllib, NULL, 0)
// Metatable for simple objects (line, arc, label)
LROT_BEGIN(lvgl_base_mt, NULL, LROT_MASK_GC_INDEX)
LROT_FUNCENTRY(__gc, luaDestroyLvglWidget)
LROT_TABENTRY(__index, lvgl_base_mt)
// Object manipulation functions
LROT_FUNCENTRY(set, luaLvglSet)
LROT_FUNCENTRY(show, luaLvglShow)
LROT_FUNCENTRY(hide, luaLvglHide)
LROT_END(lvgl_base_mt, NULL, LROT_MASK_GC_INDEX)
// Metatable for complex objects
LROT_BEGIN(lvgl_mt, NULL, LROT_MASK_GC_INDEX)
LROT_FUNCENTRY(__gc, luaDestroyLvglWidget)
LROT_TABENTRY(__index, lvgl_mt)
LROT_FUNCENTRY(clear, luaLvglClear)
LROT_FUNCENTRY(build, luaLvglBuild)
// Objects - widgets and standalone
LROT_FUNCENTRY(label, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetLabel(); }); })
LROT_FUNCENTRY(rectangle, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetRectangle(); }); })
LROT_FUNCENTRY(hline, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetHLine(); }); })
LROT_FUNCENTRY(vline, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetVLine(); }); })
LROT_FUNCENTRY(line, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetLine(); }); })
LROT_FUNCENTRY(triangle, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetTriangle(); }); })
LROT_FUNCENTRY(circle, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetCircle(); }); })
LROT_FUNCENTRY(arc, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetArc(); }); })
LROT_FUNCENTRY(image, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetImage(); }); })
LROT_FUNCENTRY(qrcode, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetQRCode(); }); })
// Objects - standalone scripts only
LROT_FUNCENTRY(button, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetTextButton(); }, true); })
LROT_FUNCENTRY(toggle, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetToggleSwitch(); }, true); })
LROT_FUNCENTRY(textEdit, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetTextEdit(); }, true); })
LROT_FUNCENTRY(numberEdit, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetNumberEdit(); }, true); })
LROT_FUNCENTRY(choice, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetChoice(); }, true); })
LROT_FUNCENTRY(slider, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSlider(); }, true); })
LROT_FUNCENTRY(font, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetFontPicker(); }, true); })
LROT_FUNCENTRY(align, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetAlignPicker(); }, true); })
LROT_FUNCENTRY(color, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetColorPicker(); }, true); })
LROT_FUNCENTRY(timer, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetTimerPicker(); }, true); })
LROT_FUNCENTRY(switch, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSwitchPicker(); }, true); })
LROT_FUNCENTRY(source, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSourcePicker(); }, true); })
// Object manipulation functions
LROT_FUNCENTRY(set, luaLvglSet)
LROT_FUNCENTRY(show, luaLvglShow)
LROT_FUNCENTRY(hide, luaLvglHide)
LROT_END(lvgl_mt, NULL, LROT_MASK_GC_INDEX)
extern "C" {
LUALIB_API int luaopen_lvgl(lua_State *L)
{
luaL_rometatable(L, LVGL_METATABLE, LROT_TABLEREF(lvgllib));
luaL_rometatable(L, LVGL_SIMPLEMETATABLE, LROT_TABLEREF(lvgl_base_mt));
luaL_rometatable(L, LVGL_METATABLE, LROT_TABLEREF(lvgl_mt));
return 0;
}
}
+8 -36
View File
@@ -83,13 +83,6 @@ struct our_longjmp * global_lj = nullptr;
uint32_t luaExtraMemoryUsage = 0;
#endif
#if defined(USE_HATS_AS_KEYS)
static bool _is_standalone_script()
{
return scriptInternalData[0].reference == SCRIPT_STANDALONE;
}
#endif
#if defined(LUA_ALLOCATOR_TRACER)
LuaMemTracer lsScriptsTrace;
@@ -257,10 +250,6 @@ void luaDisable()
{
POPUP_WARNING("Lua disabled!");
luaState = INTERPRETER_PANIC;
#if defined(USE_HATS_AS_KEYS)
if (_is_standalone_script()) setTransposeHatsForLUA(false);
#endif
}
void luaClose(lua_State ** L)
@@ -893,9 +882,6 @@ static void luaLoadScripts(bool init, const char * filename = nullptr)
ScriptInternalData & sid = scriptInternalData[luaScriptsCount++];
sid.reference = SCRIPT_STANDALONE;
if (luaLoad(filename, sid)) {
#if defined(COLORLCD)
StandaloneLuaWindow::setup(true);
#endif
luaError(lsScripts, sid.state);
break;
}
@@ -933,14 +919,6 @@ 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);
StandaloneLuaWindow::setup(sid.useLvgl);
}
#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;
@@ -962,10 +940,6 @@ static void luaLoadScripts(bool init, const char * filename = nullptr)
else {
snprintf(lua_warning_info, LUA_WARNING_INFO_LEN, "luaLoadScripts(%.*s): The script did not return a table\n", LEN_SCRIPT_FILENAME, getScriptName(idx));
sid.state = SCRIPT_SYNTAX_ERROR;
#if defined(COLORLCD)
if (sid.reference == SCRIPT_STANDALONE)
StandaloneLuaWindow::setup(true);
#endif
initFunction = LUA_NOREF;
}
@@ -1187,8 +1161,7 @@ static bool resumeLua(bool init, bool allowLcdUsage)
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
else if (luaDisplayStatistics) {
#if defined(COLORLCD)
#else
#if !defined(COLORLCD)
lcdDrawSolidHorizontalLine(0, 7*FH-1, lcdLastRightPos+6, ERASE);
lcdDrawText(0, 7*FH, "GV Use: ");
lcdDrawNumber(lcdLastRightPos, 7*FH, luaGetMemUsed(lsScripts), LEFT);
@@ -1264,10 +1237,6 @@ bool luaTask(bool allowLcdUsage)
case INTERPRETER_RELOAD_PERMANENT_SCRIPTS:
init = true;
luaState = INTERPRETER_LOADING;
#if defined(USE_HATS_AS_KEYS)
if (_is_standalone_script()) setTransposeHatsForLUA(false);
#endif
case INTERPRETER_LOADING:
PROTECT_LUA() {
@@ -1280,10 +1249,6 @@ bool luaTask(bool allowLcdUsage)
case INTERPRETER_START_RUNNING:
init = true;
luaState = INTERPRETER_RUNNING;
#if defined(USE_HATS_AS_KEYS)
if (_is_standalone_script()) setTransposeHatsForLUA(true);
#endif
case INTERPRETER_RUNNING:
PROTECT_LUA() {
@@ -1291,6 +1256,13 @@ bool luaTask(bool allowLcdUsage)
}
else luaDisable();
UNPROTECT_LUA();
break;
#if defined(COLORLCD)
case INTERPRETER_PAUSED:
// stand alone script running
break;
#endif
}
return scriptWasRun;
}
+3
View File
@@ -169,6 +169,9 @@ enum InterpreterState {
INTERPRETER_LOADING,
INTERPRETER_START_RUNNING,
INTERPRETER_RUNNING,
#if defined(COLORLCD)
INTERPRETER_PAUSED,
#endif
INTERPRETER_PANIC = 255
};
File diff suppressed because it is too large Load Diff
+379 -123
View File
@@ -22,29 +22,64 @@
#pragma once
#define LVGL_METATABLE "LVGL*"
#define LVGL_SIMPLEMETATABLE "LVGLSIMPLE*"
//-----------------------------------------------------------------------------
class LvglWidgetObjectBase
{
public:
LvglWidgetObjectBase() { lvglManager = luaLvglManager; }
LvglWidgetObjectBase(const char* meta);
virtual ~LvglWidgetObjectBase() {}
int getRef(lua_State *L);
void push(lua_State *L);
void saveLvglObjectRef(int ref);
void getParams(lua_State *L, int index);
virtual void build(lua_State *L);
virtual bool callRefs(lua_State *L) = 0;
virtual void clearRefs(lua_State *L) = 0;
virtual bool callRefs(lua_State *L);
virtual void clearRefs(lua_State *L);
void clearChildRefs(lua_State *L);
virtual void show() = 0;
virtual void hide() = 0;
virtual void setColor(LcdFlags newColor) {}
virtual void setPos(coord_t x, coord_t y) {}
virtual void setSize(coord_t w, coord_t h) {}
void update(lua_State *L);
virtual Window *getWindow() const = 0;
static LvglWidgetObjectBase *checkLvgl(lua_State *L, int index);
void clear() { clearRequest = true; }
protected:
int luaRef = LUA_REFNIL;
std::vector<int> lvglObjectRefs;
const char* metatable = nullptr;
bool clearRequest = false;
LuaLvglManager *lvglManager = nullptr;
coord_t x = 0, y = 0, w = LV_SIZE_CONTENT, h = LV_SIZE_CONTENT;
LcdFlags color = COLOR2FLAGS(COLOR_THEME_SECONDARY1_INDEX);
LcdFlags currentColor = -1;
int getColorFunction = LUA_REFNIL;
int getVisibleFunction = LUA_REFNIL;
int getSizeFunction = LUA_REFNIL;
int getPosFunction = LUA_REFNIL;
virtual void parseParam(lua_State *L, const char *key) = 0;
virtual void refresh();
void clearRef(lua_State *L, int ref);
virtual void parseParam(lua_State *L, const char *key);
bool colorChanged(LcdFlags newColor);
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);
@@ -58,54 +93,32 @@ class LvglWidgetObjectBase
//-----------------------------------------------------------------------------
class LvglWidgetObject : public LvglWidgetObjectBase
class LvglSimpleWidgetObject : public LvglWidgetObjectBase
{
public:
LvglWidgetObject() : LvglWidgetObjectBase() {}
LvglSimpleWidgetObject() : LvglWidgetObjectBase(LVGL_SIMPLEMETATABLE) {}
int getRef(lua_State *L);
void push(lua_State *L);
void show() override;
void hide() override;
void update(lua_State *L);
void setPos(coord_t x, coord_t y) override;
void setSize(coord_t w, coord_t h) override;
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;
Window *getWindow() const override { return nullptr; }
protected:
Window *window = nullptr;
LcdFlags currentColor = -1;
coord_t x = 0, y = 0, w = LV_SIZE_CONTENT, h = LV_SIZE_CONTENT;
LcdFlags color = COLOR2FLAGS(COLOR_THEME_SECONDARY1_INDEX);
int getColorFunction = 0;
int getVisibleFunction = 0;
int getSizeFunction = 0;
int getPosFunction = 0;
void parseParam(lua_State *L, const char *key) override;
virtual void refresh();
lv_obj_t* lvobj = nullptr;
};
//-----------------------------------------------------------------------------
class LvglWidgetLabel : public LvglWidgetObject
class LvglWidgetLabel : public LvglSimpleWidgetObject
{
public:
LvglWidgetLabel() : LvglWidgetObject() {}
LvglWidgetLabel() : LvglSimpleWidgetObject() {}
void setText(const char *s);
void setColor(LcdFlags color) override;
void setColor(LcdFlags newColor) override;
void setFont(LcdFlags font);
void build(lua_State *L) override;
@@ -117,26 +130,174 @@ class LvglWidgetLabel : public LvglWidgetObject
const char *txt = "";
LcdFlags font = FONT(STD);
int getTextFunction = 0;
int getFontFunction = 0;
int getTextFunction = LUA_REFNIL;
int getFontFunction = LUA_REFNIL;
void parseParam(lua_State *L, const char *key) override;
void refresh() override
{
setText(txt);
setFont(font);
LvglWidgetObject::refresh();
LvglSimpleWidgetObject::refresh();
}
};
//-----------------------------------------------------------------------------
class LvglWidgetLineBase : public LvglSimpleWidgetObject
{
public:
LvglWidgetLineBase() : LvglSimpleWidgetObject() {}
void setColor(LcdFlags newColor) override;
void setPos(coord_t x, coord_t y) override;
void setSize(coord_t w, coord_t h) override;
void build(lua_State *L) override;
protected:
bool rounded = false;
lv_point_t pts[2];
virtual void setLine() = 0;
void parseParam(lua_State *L, const char *key) override;
void refresh() override;
};
//-----------------------------------------------------------------------------
class LvglWidgetHLine : public LvglWidgetLineBase
{
public:
LvglWidgetHLine() : LvglWidgetLineBase() {}
protected:
void setLine() override;
};
//-----------------------------------------------------------------------------
class LvglWidgetVLine : public LvglWidgetLineBase
{
public:
LvglWidgetVLine() : LvglWidgetLineBase() {}
protected:
void setLine() override;
};
//-----------------------------------------------------------------------------
class LvglWidgetLine : public LvglSimpleWidgetObject
{
public:
LvglWidgetLine() : LvglSimpleWidgetObject() {}
void setColor(LcdFlags newColor) override;
void setPos(coord_t x, coord_t y) override;
void setSize(coord_t w, coord_t h) override;
void build(lua_State *L) override;
protected:
coord_t thickness = 1;
bool rounded = false;
size_t ptCnt = 0;
lv_point_t* pts = nullptr;
void setLine();
void getPt(lua_State* L, int n);
void parseParam(lua_State *L, const char *key) override;
void refresh() override;
};
//-----------------------------------------------------------------------------
class LvglWidgetTriangle : public LvglSimpleWidgetObject
{
public:
LvglWidgetTriangle() : LvglSimpleWidgetObject() {}
~LvglWidgetTriangle();
void setColor(LcdFlags newColor) override;
void setSize(coord_t w, coord_t h) override;
void build(lua_State *L) override;
protected:
coord_t px[3] = {0}, py[3] = {0};
MaskBitmap* mask = nullptr;
void fillTriangle();
void fillLine(coord_t x1, coord_t x2, coord_t y);
void getPt(lua_State* L, int n);
void parseParam(lua_State *L, const char *key) override;
void refresh() override;
};
//-----------------------------------------------------------------------------
class LvglWidgetObject : public LvglWidgetObjectBase
{
public:
LvglWidgetObject(const char* meta = LVGL_METATABLE) : LvglWidgetObjectBase(meta) {}
void show() override { window->show(); }
void hide() override { window->hide(); }
void setPos(coord_t x, coord_t y) override;
void setSize(coord_t w, coord_t h) override;
Window *getWindow() const override { return window; }
protected:
Window *window = nullptr;
int8_t flexFlow = -1;
int8_t flexPad = PAD_TINY;
void parseParam(lua_State *L, const char *key) override;
bool setFlex();
};
//-----------------------------------------------------------------------------
class LvglWidgetBox : public LvglWidgetObject
{
public:
LvglWidgetBox() : LvglWidgetObject() {}
void build(lua_State *L) override;
protected:
};
//-----------------------------------------------------------------------------
class LvglWidgetSetting : public LvglWidgetObject
{
public:
LvglWidgetSetting() : LvglWidgetObject() {}
void build(lua_State *L) override;
protected:
const char *txt = "";
void parseParam(lua_State *L, const char *key) override;
};
//-----------------------------------------------------------------------------
class LvglWidgetBorderedObject : public LvglWidgetObject
{
public:
LvglWidgetBorderedObject() : LvglWidgetObject() {}
void setColor(LcdFlags color) override;
void setColor(LcdFlags newColor) override;
void build(lua_State *L) override;
@@ -163,7 +324,7 @@ class LvglWidgetRoundObject : public LvglWidgetBorderedObject
protected:
coord_t radius = 0;
int getRadiusFunction = 0;
int getRadiusFunction = LUA_REFNIL;
void parseParam(lua_State *L, const char *key) override;
void refresh() override
@@ -207,7 +368,7 @@ class LvglWidgetArc : public LvglWidgetRoundObject
public:
LvglWidgetArc() : LvglWidgetRoundObject() {}
void setColor(LcdFlags color) override;
void setColor(LcdFlags newColor) override;
void setStartAngle(coord_t angle);
void setEndAngle(coord_t angle);
@@ -218,8 +379,8 @@ class LvglWidgetArc : public LvglWidgetRoundObject
protected:
coord_t startAngle = 0, endAngle = 0;
int getStartAngleFunction = 0;
int getEndAngleFunction = 0;
int getStartAngleFunction = LUA_REFNIL;
int getEndAngleFunction = LUA_REFNIL;
void parseParam(lua_State *L, const char *key) override;
void refresh() override
@@ -235,7 +396,7 @@ class LvglWidgetArc : public LvglWidgetRoundObject
class LvglWidgetImage : public LvglWidgetObject
{
public:
LvglWidgetImage() : LvglWidgetObject() {}
LvglWidgetImage() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
@@ -251,7 +412,7 @@ class LvglWidgetImage : public LvglWidgetObject
class LvglWidgetQRCode : public LvglWidgetObject
{
public:
LvglWidgetQRCode() : LvglWidgetObject() {}
LvglWidgetQRCode() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
@@ -264,29 +425,10 @@ class LvglWidgetQRCode : public LvglWidgetObject
//-----------------------------------------------------------------------------
// 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() {}
LvglWidgetTextButton() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void setText(const char *s);
@@ -297,7 +439,7 @@ class LvglWidgetTextButton : public LvglWidgetObject
uint32_t textHash = -1;
const char *txt = "";
int pressFunction = 0;
int pressFunction = LUA_REFNIL;
void parseParam(lua_State *L, const char *key) override;
};
@@ -307,34 +449,14 @@ class LvglWidgetTextButton : public LvglWidgetObject
class LvglWidgetToggleSwitch : public LvglWidgetObject
{
public:
LvglWidgetToggleSwitch() : LvglWidgetObject() {}
LvglWidgetToggleSwitch() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
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;
int getStateFunction = LUA_REFNIL;
int setStateFunction = LUA_REFNIL;
void parseParam(lua_State *L, const char *key) override;
};
@@ -344,7 +466,7 @@ class LvglWidgetConfirmDialog : public LvglWidgetObject
class LvglWidgetTextEdit : public LvglWidgetObject
{
public:
LvglWidgetTextEdit() : LvglWidgetObject() {}
LvglWidgetTextEdit() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
@@ -354,7 +476,7 @@ class LvglWidgetTextEdit : public LvglWidgetObject
char value[129];
int maxLen = 32;
int setFunction = 0;
int setFunction = LUA_REFNIL;
void parseParam(lua_State *L, const char *key) override;
};
@@ -364,7 +486,7 @@ class LvglWidgetTextEdit : public LvglWidgetObject
class LvglWidgetNumberEdit : public LvglWidgetObject
{
public:
LvglWidgetNumberEdit() : LvglWidgetObject() {}
LvglWidgetNumberEdit() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
@@ -372,29 +494,9 @@ class LvglWidgetNumberEdit : public LvglWidgetObject
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;
int getFunction = LUA_REFNIL;
int setFunction = LUA_REFNIL;
int dispFunction = LUA_REFNIL;
void parseParam(lua_State *L, const char *key) override;
};
@@ -404,7 +506,7 @@ class LvglWidgetChoice : public LvglWidgetObject
class LvglWidgetSlider : public LvglWidgetObject
{
public:
LvglWidgetSlider() : LvglWidgetObject() {}
LvglWidgetSlider() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
@@ -412,8 +514,8 @@ class LvglWidgetSlider : public LvglWidgetObject
protected:
int32_t vmin = 0;
int32_t vmax = 100;
int getValueFunction = 0;
int setValueFunction = 0;
int getValueFunction = LUA_REFNIL;
int setValueFunction = LUA_REFNIL;
void parseParam(lua_State *L, const char *key) override;
};
@@ -429,12 +531,166 @@ class LvglWidgetPage : public LvglWidgetObject
void clearRefs(lua_State *L) override;
protected:
int backActionFunction = 0;
std::string title;
std::string subtitle;
std::string iconFile;
int backActionFunction = LUA_REFNIL;
void parseParam(lua_State *L, const char *key) override;
};
//-----------------------------------------------------------------------------
class LvglWidgetDialog : public LvglWidgetObject
{
public:
LvglWidgetDialog() : LvglWidgetObject() {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
const char *title = nullptr;
int closeFunction = LUA_REFNIL;
void parseParam(lua_State *L, const char *key) override;
};
//-----------------------------------------------------------------------------
class LvglWidgetConfirmDialog : public LvglWidgetObject
{
public:
LvglWidgetConfirmDialog() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
const char *title = nullptr;
const char *message = nullptr;
int confirmFunction = LUA_REFNIL;
int cancelFunction = LUA_REFNIL;
void parseParam(lua_State *L, const char *key) override;
};
//-----------------------------------------------------------------------------
class LvglWidgetMessageDialog : public LvglWidgetObject
{
public:
LvglWidgetMessageDialog() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
protected:
const char *title = nullptr;
const char *message = nullptr;
const char *details = nullptr;
void parseParam(lua_State *L, const char *key) override;
};
//-----------------------------------------------------------------------------
class LvglWidgetPicker : public LvglWidgetObject
{
public:
LvglWidgetPicker() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void clearRefs(lua_State *L) override;
protected:
int getFunction = LUA_REFNIL;
int setFunction = LUA_REFNIL;
void parseParam(lua_State *L, const char *key) override;
};
//-----------------------------------------------------------------------------
class LvglWidgetChoice : public LvglWidgetPicker
{
public:
LvglWidgetChoice() : LvglWidgetPicker() {}
void build(lua_State *L) override;
protected:
std::string title;
std::vector<std::string> values;
void parseParam(lua_State *L, const char *key) override;
};
//-----------------------------------------------------------------------------
class LvglWidgetFontPicker : public LvglWidgetPicker
{
public:
LvglWidgetFontPicker() : LvglWidgetPicker() {}
void build(lua_State *L) override;
};
//-----------------------------------------------------------------------------
class LvglWidgetAlignPicker : public LvglWidgetPicker
{
public:
LvglWidgetAlignPicker() : LvglWidgetPicker() {}
void build(lua_State *L) override;
};
//-----------------------------------------------------------------------------
class LvglWidgetColorPicker : public LvglWidgetPicker
{
public:
LvglWidgetColorPicker() : LvglWidgetPicker() {}
void build(lua_State *L) override;
};
//-----------------------------------------------------------------------------
class LvglWidgetTimerPicker : public LvglWidgetPicker
{
public:
LvglWidgetTimerPicker() : LvglWidgetPicker() {}
void build(lua_State *L) override;
};
//-----------------------------------------------------------------------------
class LvglWidgetSwitchPicker : public LvglWidgetPicker
{
public:
LvglWidgetSwitchPicker() : LvglWidgetPicker() {}
void build(lua_State *L) override;
protected:
int16_t vmin = SWSRC_FIRST;
int16_t vmax = SWSRC_LAST;
void parseParam(lua_State *L, const char *key) override;
};
//-----------------------------------------------------------------------------
class LvglWidgetSourcePicker : public LvglWidgetPicker
{
public:
LvglWidgetSourcePicker() : LvglWidgetPicker() {}
void build(lua_State *L) override;
};
//-----------------------------------------------------------------------------
+46 -20
View File
@@ -221,12 +221,15 @@ LuaWidget::LuaWidget(const WidgetFactory* factory, Window* parent,
const rect_t& rect, WidgetPersistentData* persistentData,
int luaWidgetDataRef, int zoneRectDataRef, int optionsDataRef) :
Widget(factory, parent, rect, persistentData),
zoneRectDataRef(zoneRectDataRef), optionsDataRef(optionsDataRef),
zoneRectDataRef(zoneRectDataRef), optionsDataRef(optionsDataRef), luaWidgetDataRef(luaWidgetDataRef),
errorMessage(nullptr)
{
this->luaWidgetDataRef = luaWidgetDataRef;
lv_obj_add_event_cb(lvobj, LuaWidget::redraw_cb, LV_EVENT_DRAW_MAIN,
nullptr);
if (useLvglLayout()) {
update();
} else {
lv_obj_add_event_cb(lvobj, LuaWidget::redraw_cb, LV_EVENT_DRAW_MAIN,
nullptr);
}
}
LuaWidget::~LuaWidget()
@@ -265,12 +268,6 @@ void LuaWidget::checkEvents()
setFullscreen(false);
}
// Call update once after widget first created
if (!created) {
created = true;
update();
}
// refresh() has not been called
if (!refreshed)
background();
@@ -348,6 +345,24 @@ void LuaWidget::update()
if (lua_pcall(lsWidgets, 2, 0, 0) != 0)
setErrorMessage("update()");
if (useLvglLayout()) {
if (!lv_obj_has_flag(lvobj, LV_OBJ_FLAG_HIDDEN)) {
lv_area_t a;
lv_obj_get_coords(lvobj, &a);
// Check widget is at least partially visible
if (a.x2 >= 0 && a.x1 < LCD_W) {
PROTECT_LUA() {
if (!callRefs(lsWidgets)) {
setErrorMessage("callRefs()");
}
} else {
// TODO: error handling
}
UNPROTECT_LUA();
}
}
}
luaLvglManager = nullptr;
}
@@ -495,9 +510,8 @@ void LuaWidget::background()
{
if (lsWidgets == 0 || errorMessage) return;
// TRACE("LuaWidget::background()");
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
if (luaFactory()->backgroundFunction) {
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaFactory()->backgroundFunction);
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef);
runningFS = this;
@@ -524,25 +538,37 @@ void LuaWidget::clear()
bool LuaWidget::useLvglLayout() const { return luaFactory()->useLvglLayout(); }
bool LuaWidget::isAppMode() const
{
return fullscreen && ViewMain::instance()->isAppMode();
}
void LuaLvglManager::saveLvglObjectRef(int ref)
{
if (tempParent)
tempParent->saveLvglObjectRef(ref);
else
lvglObjectRefs.push_back(ref);
}
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]);
auto p = LvglWidgetObjectBase::checkLvgl(L, -1);
lua_pop(L, 1);
if (p) p->clearRefs(L);
}
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);
auto p = LvglWidgetObjectBase::checkLvgl(L, -1);
lua_pop(L, 1);
if (p) if (!p->callRefs(L)) return false;
}
return rv;
return true;
}
+30 -29
View File
@@ -40,16 +40,17 @@ class LuaLvglManager
LuaLvglManager() = default;
std::vector<int> getLvglObjectRefs() const { return lvglObjectRefs; }
void saveLvglObjectRef(int ref) { lvglObjectRefs.push_back(ref); }
void saveLvglObjectRef(int ref);
void clearRefs(lua_State *L);
bool callRefs(lua_State *L);
void setTempParent(Window *p) { tempParent = p; }
Window* getTempParent() const { return tempParent; }
void setTempParent(LvglWidgetObjectBase *p) { tempParent = p; }
LvglWidgetObjectBase* getTempParent() const { return tempParent; }
virtual Window* getCurrentParent() const = 0;
virtual void clear() = 0;
virtual bool useLvglLayout() const = 0;
virtual bool isAppMode() const = 0;
virtual void luaShowError() = 0;
@@ -59,7 +60,7 @@ class LuaLvglManager
protected:
std::vector<int> lvglObjectRefs;
Window* tempParent = nullptr;
LvglWidgetObjectBase* tempParent = nullptr;
};
class LuaEventHandler
@@ -92,25 +93,6 @@ class LuaWidget : public Widget, public LuaEventHandler, public LuaLvglManager
{
friend class LuaWidgetFactory;
int zoneRectDataRef;
int optionsDataRef;
char* errorMessage;
bool refreshed = false;
// Window interface
void onClicked() override;
void onCancel() override;
void checkEvents() override;
// Widget interface
void onFullscreen(bool enable) override;
void setErrorMessage(const char* funcName);
// Update 'zone' data
void updateZoneRect(rect_t rect, bool updateUI = true) override;
bool updateTable(const char* idx, int val);
public:
LuaWidget(const WidgetFactory* factory, Window* parent, const rect_t& rect,
WidgetPersistentData* persistentData, int luaWidgetDataRef, int zoneRectDataRef,
@@ -121,6 +103,8 @@ class LuaWidget : public Widget, public LuaEventHandler, public LuaLvglManager
std::string getName() const override { return "LuaWidget"; }
#endif
void setErrorMessage(const char* funcName);
// Widget interface
const char* getErrorMessage() const override;
void update() override;
@@ -130,24 +114,41 @@ class LuaWidget : public Widget, public LuaEventHandler, public LuaLvglManager
LuaWidgetFactory* luaFactory() const { return (LuaWidgetFactory*)factory; }
Window* getCurrentParent() const override { return tempParent ? tempParent : (Window*)this; }
Window* getCurrentParent() const override { return (tempParent && tempParent->getWindow()) ? tempParent->getWindow() : (Window*)this; }
bool useLvglLayout() const override;
bool isAppMode() const override;
void luaShowError() override {}
bool isWidget() override { return true; }
void pushOptionsTable();
bool isWidget() override { return !inSettings; }
protected:
bool created = false;
bool inSettings = false;
lv_obj_t* errorLabel = nullptr;
int zoneRectDataRef;
int optionsDataRef;
int luaWidgetDataRef = 0;
char* errorMessage;
bool refreshed = false;
// Window interface
void onClicked() override;
void onCancel() override;
void checkEvents() override;
void onEvent(event_t event) override;
// Widget interface
void onFullscreen(bool enable) override;
// Update 'zone' data
void updateZoneRect(rect_t rect, bool updateUI = true) override;
bool updateTable(const char* idx, int val);
// Calls LUA widget 'refresh' method
void refresh(BitmapBuffer* dc);
// Window interface
void onEvent(event_t event) override;
static void redraw_cb(lv_event_t *e);
};
+1
View File
@@ -49,5 +49,6 @@ class LuaWidgetFactory : public WidgetFactory
int refreshFunction;
int backgroundFunction;
int translateFunction;
int settingsFunction;
bool lvglLayout;
};
+9 -4
View File
@@ -217,7 +217,7 @@ void luaLoadWidgetCallback()
TRACE("luaLoadWidgetCallback()");
const char * name=NULL;
int widgetOptions = 0, createFunction = 0, updateFunction = 0,
int widgetOptions = 0, createFunction = 0, updateFunction = 0, settingsFunction = 0,
refreshFunction = 0, backgroundFunction = 0, translateFunction = 0;
bool lvglLayout = false;
@@ -252,7 +252,11 @@ void luaLoadWidgetCallback()
translateFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
lua_pushnil(lsWidgets);
}
else if (!strcasecmp(key, "uselvgl")) {
else if (!strcmp(key, "settings")) {
settingsFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
lua_pushnil(lsWidgets);
}
else if (!strcasecmp(key, "useLvgl")) {
lvglLayout = lua_toboolean(lsWidgets, -1);
}
}
@@ -263,10 +267,11 @@ void luaLoadWidgetCallback()
LuaWidgetFactory * factory = new LuaWidgetFactory(name, options, createFunction);
factory->updateFunction = updateFunction;
factory->refreshFunction = refreshFunction;
factory->backgroundFunction = backgroundFunction; // NOSONAR
factory->lvglLayout = lvglLayout;
factory->backgroundFunction = backgroundFunction;
factory->translateFunction = translateFunction;
factory->settingsFunction = settingsFunction;
factory->translateOptions(options);
factory->lvglLayout = lvglLayout;
TRACE("Loaded Lua widget %s", name);
}
}
+1 -1
View File
@@ -68,7 +68,7 @@ void openUsbMenu()
{
if (_usbMenu || _usbDisabled) return;
_usbMenu = new Menu(MainWindow::instance());
_usbMenu = new Menu();
_usbMenu->setCloseHandler([]() { _usbMenu = nullptr; });