diff --git a/companion/.ci-trigger b/companion/.ci-trigger
new file mode 100644
index 000000000..1e6063a86
--- /dev/null
+++ b/companion/.ci-trigger
@@ -0,0 +1 @@
+Mon Jan 26 18:05:25 AEST 2026
diff --git a/radio/.gitignore b/radio/.gitignore
deleted file mode 100644
index 7091e5b78..000000000
--- a/radio/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/gtest-1.6.0
diff --git a/radio/src/bitmaps/320x240/mask_ui_bg_tile_top_left.png b/radio/src/bitmaps/320x240/mask_ui_bg_tile_top_left.png
deleted file mode 100644
index c140846ff..000000000
Binary files a/radio/src/bitmaps/320x240/mask_ui_bg_tile_top_left.png and /dev/null differ
diff --git a/radio/src/bitmaps/320x240/mask_ui_bg_tile_top_right.png b/radio/src/bitmaps/320x240/mask_ui_bg_tile_top_right.png
deleted file mode 100644
index e6bba8164..000000000
Binary files a/radio/src/bitmaps/320x240/mask_ui_bg_tile_top_right.png and /dev/null differ
diff --git a/radio/src/bitmaps/480x272/mask_ui_bg_tile_top_left.png b/radio/src/bitmaps/480x272/mask_ui_bg_tile_top_left.png
deleted file mode 100644
index 5f4f8ca27..000000000
Binary files a/radio/src/bitmaps/480x272/mask_ui_bg_tile_top_left.png and /dev/null differ
diff --git a/radio/src/bitmaps/480x272/mask_ui_bg_tile_top_right.png b/radio/src/bitmaps/480x272/mask_ui_bg_tile_top_right.png
deleted file mode 100644
index ee33ffdc2..000000000
Binary files a/radio/src/bitmaps/480x272/mask_ui_bg_tile_top_right.png and /dev/null differ
diff --git a/radio/src/bitmaps/800x480/mask_ui_bg_tile_top_left.png b/radio/src/bitmaps/800x480/mask_ui_bg_tile_top_left.png
deleted file mode 100644
index 99a5474a4..000000000
Binary files a/radio/src/bitmaps/800x480/mask_ui_bg_tile_top_left.png and /dev/null differ
diff --git a/radio/src/bitmaps/800x480/mask_ui_bg_tile_top_right.png b/radio/src/bitmaps/800x480/mask_ui_bg_tile_top_right.png
deleted file mode 100644
index 18e414d6c..000000000
Binary files a/radio/src/bitmaps/800x480/mask_ui_bg_tile_top_right.png and /dev/null differ
diff --git a/radio/src/bitmaps/img-src/mask_ui_bg_tile_top_left.svg b/radio/src/bitmaps/img-src/mask_ui_bg_tile_top_left.svg
deleted file mode 100644
index e35aee7ca..000000000
--- a/radio/src/bitmaps/img-src/mask_ui_bg_tile_top_left.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/radio/src/bitmaps/img-src/mask_ui_bg_tile_top_right.svg b/radio/src/bitmaps/img-src/mask_ui_bg_tile_top_right.svg
deleted file mode 100644
index 1459a5fff..000000000
--- a/radio/src/bitmaps/img-src/mask_ui_bg_tile_top_right.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/radio/src/edgetx.cpp b/radio/src/edgetx.cpp
index 847ca0354..2e40816c8 100644
--- a/radio/src/edgetx.cpp
+++ b/radio/src/edgetx.cpp
@@ -167,10 +167,6 @@ void checkValidMCU(void)
#endif
}
-#if defined(SIMU)
-static bool evalFSok = false;
-#endif
-
void per10ms()
{
DEBUG_TIMER_START(debugTimerPer10ms);
@@ -215,13 +211,8 @@ void per10ms()
}
#if defined(FUNCTION_SWITCHES)
-#if defined(SIMU)
- if (evalFSok)
- evalFunctionSwitches();
-#else
evalFunctionSwitches();
#endif
-#endif
#if defined(ROTARY_ENCODER_NAVIGATION) && !defined(COLORLCD)
if (rotaryEncoderPollingCycle()) {
@@ -766,14 +757,14 @@ void checkAll(bool isBootCheck)
}
dlg->setMessage(strKeys.c_str());
- dlg->setCloseCondition([tgtime]() {
- if (tgtime >= get_tmr10ms() && keyDown()) {
- return false;
- } else {
+ MainWindow::instance()->blockUntilClose(true, [=]() {
+ if (dlg->deleted()) return true;
+ if ((tgtime < get_tmr10ms()) || !keyDown()) {
+ dlg->deleteLater();
return true;
}
+ return false;
});
- dlg->runForever();
LED_ERROR_END();
}
#else
@@ -846,9 +837,11 @@ void checkThrottleStick()
}
LED_ERROR_BEGIN();
auto dialog = new ThrottleWarnDialog(throttleNotIdle);
- dialog->runForever();
+ MainWindow::instance()->blockUntilClose(true, [=]() {
+ return dialog->deleted();
+ });
+ LED_ERROR_END();
}
- LED_ERROR_END();
}
#else
void checkThrottleStick()
@@ -917,6 +910,7 @@ void checkAlarm() // added by Gohst
}
}
+#if !defined(COLORLCD)
void alert(const char * title, const char * msg , uint8_t sound)
{
LED_ERROR_BEGIN();
@@ -958,6 +952,7 @@ void alert(const char * title, const char * msg , uint8_t sound)
LED_ERROR_END();
}
+#endif
#if defined(GVARS)
#if MAX_TRIMS == 8
@@ -1585,9 +1580,6 @@ void edgeTxInit()
#if defined(FUNCTION_SWITCHES)
setFSStartupPosition();
-#if defined(SIMU)
- evalFSok = true;
-#endif
#endif
#if defined(GUI)
@@ -1619,6 +1611,8 @@ void edgeTxInit()
resetBacklightTimeout();
+ LED_ERROR_END();
+
pulsesStart();
WDG_ENABLE(WDG_DURATION);
}
@@ -1660,6 +1654,12 @@ int main()
modulePortInit();
pulsesInit();
+#if defined(COLORLCD)
+ // Do all lvgl init in case of fatal error on startup
+ extern void initLvgl();
+ initLvgl();
+#endif
+
#if !defined(DISABLE_MCUCHECK)
checkValidMCU();
#endif
diff --git a/radio/src/gui/colorlcd/CMakeLists.txt b/radio/src/gui/colorlcd/CMakeLists.txt
index 935aa10e2..e03c060f2 100644
--- a/radio/src/gui/colorlcd/CMakeLists.txt
+++ b/radio/src/gui/colorlcd/CMakeLists.txt
@@ -74,10 +74,8 @@ set(GUI_SRC
model/output_edit.cpp
model/preflight_checks.cpp
model/special_functions.cpp
- model/throttle_params.cpp
model/timer_setup.cpp
model/trainer_setup.cpp
- model/trims_setup.cpp
module/bind_menu_d16.cpp
module/custom_failsafe.cpp
diff --git a/radio/src/gui/colorlcd/LvglWrapper.cpp b/radio/src/gui/colorlcd/LvglWrapper.cpp
index 348d359cc..8f0f0d3b0 100644
--- a/radio/src/gui/colorlcd/LvglWrapper.cpp
+++ b/radio/src/gui/colorlcd/LvglWrapper.cpp
@@ -380,3 +380,8 @@ void LvglWrapper::run()
}
}
}
+
+void initLvgl()
+{
+ LvglWrapper::instance();
+}
diff --git a/radio/src/gui/colorlcd/bitmaps.cpp b/radio/src/gui/colorlcd/bitmaps.cpp
index c03525bf7..b00c7804f 100644
--- a/radio/src/gui/colorlcd/bitmaps.cpp
+++ b/radio/src/gui/colorlcd/bitmaps.cpp
@@ -294,13 +294,6 @@ static const uint8_t mask_info_usb_plugged[] __FLASH = {
// gfx for ui elements
-
-const uint8_t mask_round_title_left[]{
-#include "mask_ui_bg_tile_top_left.lbm"
-};
-const uint8_t mask_round_title_right[]{
-#include "mask_ui_bg_tile_top_right.lbm"
-};
const uint8_t mask_topleft_bg[] __FLASH = {
#include "mask_ui_bg_topbar_left.lbm"
};
@@ -502,8 +495,6 @@ static const _BuiltinIcon _builtinIcons[EDGETX_ICONS_COUNT] = {
BI(ICON_MPLEX_MULTIPLY, mask_inline_multiply),
BI(ICON_MPLEX_REPLACE, mask_inline_replace),
- BI(ICON_ROUND_TITLE_LEFT, mask_round_title_left),
- BI(ICON_ROUND_TITLE_RIGHT, mask_round_title_right),
BI(ICON_MODEL_GRID_LARGE, mask_btn_grid_large),
BI(ICON_MODEL_GRID_SMALL, mask_btn_grid_small),
BI(ICON_MODEL_LIST_TWO, mask_btn_list_two),
diff --git a/radio/src/gui/colorlcd/bitmaps.h b/radio/src/gui/colorlcd/bitmaps.h
index e646484cf..5fe22c2d8 100644
--- a/radio/src/gui/colorlcd/bitmaps.h
+++ b/radio/src/gui/colorlcd/bitmaps.h
@@ -122,9 +122,6 @@ enum EdgeTxIcon {
ICON_MPLEX_MULTIPLY,
ICON_MPLEX_REPLACE,
- ICON_ROUND_TITLE_LEFT,
- ICON_ROUND_TITLE_RIGHT,
-
ICON_MODEL_GRID_LARGE,
ICON_MODEL_GRID_SMALL,
ICON_MODEL_LIST_TWO,
diff --git a/radio/src/gui/colorlcd/controls/color_editor.cpp b/radio/src/gui/colorlcd/controls/color_editor.cpp
index 8449bfa18..1891fab76 100644
--- a/radio/src/gui/colorlcd/controls/color_editor.cpp
+++ b/radio/src/gui/colorlcd/controls/color_editor.cpp
@@ -28,7 +28,20 @@
static const char* const RGBChars[MAX_BARS] = {"R", "G", "B"};
static const char* const HSVChars[MAX_BARS] = {"H", "S", "V"};
-typedef std::function getRGBFromPos;
+// ColorTypes()
+// A ColorType implements an editor for selecting a color. Currently we support
+// HSV, RGB and SYS (choose from system defined colors)
+class ColorType
+{
+ public:
+ ColorType() {}
+ virtual ~ColorType() {}
+
+ virtual void setText() {};
+ virtual uint32_t getRGB() { return 0; };
+
+ protected:
+};
class ColorBar : public FormField
{
@@ -93,7 +106,7 @@ class ColorBar : public FormField
rel_pos.y = point_act.y - obj_coords.y1;
bar->value = bar->screenToValue(rel_pos.y);
- lv_event_send(target->parent, LV_EVENT_VALUE_CHANGED, nullptr);
+ Messaging::send(Messaging::COLOR_CHANGED);
}
static void on_key(lv_event_t* e)
@@ -114,7 +127,7 @@ class ColorBar : public FormField
else
bar->value -= accel;
}
- lv_event_send(obj->parent, LV_EVENT_VALUE_CHANGED, nullptr);
+ Messaging::send(Messaging::COLOR_CHANGED);
}
} else if (key == LV_KEY_RIGHT) {
if (bar->value < bar->maxValue) {
@@ -126,7 +139,7 @@ class ColorBar : public FormField
else
bar->value = bar->maxValue;
}
- lv_event_send(obj->parent, LV_EVENT_VALUE_CHANGED, nullptr);
+ Messaging::send(Messaging::COLOR_CHANGED);
}
}
}
@@ -189,22 +202,7 @@ class ColorBar : public FormField
uint32_t maxValue = 0;
uint32_t value = 0;
- getRGBFromPos getRGB = nullptr;
-};
-
-// ColorTypes()
-// A ColorType implements an editor for selecting a color. Currently we support
-// HSV, RGB and SYS (choose from system defined colors)
-class ColorType
-{
- public:
- ColorType() {}
- virtual ~ColorType() {}
-
- virtual void setText() {};
- virtual uint32_t getRGB() { return 0; };
-
- protected:
+ std::function getRGB = nullptr;
};
// Color editor with three bars for selecting color value. Base class for HSV
@@ -391,8 +389,7 @@ class ThemeColorType : public ColorType
etx_bg_color(btn->getLvObj(), (LcdColorIndex)color);
btn->setPressHandler([=]() {
m_color = color;
- lv_event_send(parent->getParent()->getParent()->getLvObj(),
- LV_EVENT_VALUE_CHANGED, nullptr);
+ Messaging::send(Messaging::COLOR_CHANGED);
return 0;
});
}
@@ -442,8 +439,7 @@ class FixedColorType : public ColorType
etx_bg_color(btn->getLvObj(), (LcdColorIndex)color);
btn->setPressHandler([=]() {
m_color = color;
- lv_event_send(parent->getParent()->getLvObj(),
- LV_EVENT_VALUE_CHANGED, nullptr);
+ Messaging::send(Messaging::COLOR_CHANGED);
return 0;
});
}
@@ -456,9 +452,8 @@ class FixedColorType : public ColorType
/////////////////////////////////////////////////////////////////////////
ColorEditor::ColorEditor(Window* parent, const rect_t& rect, uint32_t color,
std::function setValue,
- std::function preview,
COLOR_EDITOR_FMT fmt, COLOR_EDITOR_TYPE typ) :
- Window(parent, rect), _setValue(std::move(setValue)), _preview(std::move(preview)),
+ Window(parent, rect), _setValue(std::move(setValue)),
format(fmt)
{
if (format == ETX_RGB565) {
@@ -475,10 +470,9 @@ ColorEditor::ColorEditor(Window* parent, const rect_t& rect, uint32_t color,
_color = color;
setColorEditorType(typ);
- lv_obj_add_event_cb(lvobj, ColorEditor::value_changed, LV_EVENT_VALUE_CHANGED,
- nullptr);
+ Messaging::send(Messaging::COLOR_PREVIEW, _color);
- if (_preview) _preview(_color);
+ colorUpdateMsg.subscribe(Messaging::COLOR_CHANGED, [=](uint32_t param) { setRGB(); });
}
void ColorEditor::setColorEditorType(COLOR_EDITOR_TYPE colorType)
@@ -528,12 +522,5 @@ void ColorEditor::setRGB()
_color = _colorType->getRGB();
// update bars & labels
setText();
- if (_preview) _preview(_color);
-}
-
-void ColorEditor::value_changed(lv_event_t* e)
-{
- lv_obj_t* target = lv_event_get_target(e);
- ColorEditor* edit = (ColorEditor*)lv_obj_get_user_data(target);
- if (edit) edit->setRGB();
+ Messaging::send(Messaging::COLOR_PREVIEW, _color);
}
diff --git a/radio/src/gui/colorlcd/controls/color_editor.h b/radio/src/gui/colorlcd/controls/color_editor.h
index 27f6f01e5..d944ac8d0 100644
--- a/radio/src/gui/colorlcd/controls/color_editor.h
+++ b/radio/src/gui/colorlcd/controls/color_editor.h
@@ -21,6 +21,7 @@
#pragma once
#include "window.h"
+#include "messaging.h"
class ColorType;
@@ -39,7 +40,6 @@ class ColorEditor : public Window
public:
ColorEditor(Window* parent, const rect_t& rect, uint32_t color,
std::function setValue = nullptr,
- std::function preview = nullptr,
COLOR_EDITOR_FMT fmt = ETX_RGB565, COLOR_EDITOR_TYPE typ = HSV_COLOR_EDITOR);
#if defined(DEBUG_WINDOWS)
@@ -57,11 +57,10 @@ class ColorEditor : public Window
protected:
ColorType* _colorType = nullptr;
std::function _setValue;
- std::function _preview;
uint32_t _color;
COLOR_EDITOR_FMT format;
+ Messaging colorUpdateMsg;
void setText();
void setRGB();
- static void value_changed(lv_event_t* e);
};
diff --git a/radio/src/gui/colorlcd/controls/color_picker.cpp b/radio/src/gui/colorlcd/controls/color_picker.cpp
index 5f24e554b..5064efb5f 100644
--- a/radio/src/gui/colorlcd/controls/color_picker.cpp
+++ b/radio/src/gui/colorlcd/controls/color_picker.cpp
@@ -76,7 +76,6 @@ class ColorEditorPopup : public BaseDialog
public:
ColorEditorPopup(uint32_t color,
std::function _setValue,
- std::function _preview,
COLOR_EDITOR_FMT fmt) :
BaseDialog(STR_COLOR_PICKER, false, COLOR_EDIT_WIDTH, COLOR_EDIT_HEIGHT),
origColor(color), setValue(std::move(_setValue)), format(fmt)
@@ -85,7 +84,7 @@ class ColorEditorPopup : public BaseDialog
auto line = form->newLine(grid);
rect_t r{0, 0, CE_SZ, CE_SZ};
- auto cedit = new ColorEditor(line, r, color, [=](uint32_t c) { updateColor(c); }, _preview, format, THM_COLOR_EDITOR);
+ auto cedit = new ColorEditor(line, r, color, [=](uint32_t c) { updateColor(c); }, format, THM_COLOR_EDITOR);
lv_obj_set_style_grid_cell_x_align(cedit->getLvObj(), LV_GRID_ALIGN_CENTER, 0);
auto vbox = new Window(line, rect_t{});
@@ -183,25 +182,19 @@ class ColorEditorPopup : public BaseDialog
};
ColorPicker::ColorPicker(Window* parent, const rect_t& rect,
- std::function getValue,
- std::function setValue,
- std::function preview,
+ std::function _getValue,
+ std::function _setValue,
COLOR_EDITOR_FMT fmt) :
Button(parent, {rect.x, rect.y, rect.w == 0 ? ColorEditorPopup::COLOR_PAD_WIDTH : rect.w, EdgeTxStyles::UI_ELEMENT_HEIGHT}),
- setValue(std::move(setValue)), preview(std::move(preview)), format(fmt)
+ getValue(std::move(_getValue)), setValue(std::move(_setValue)), format(fmt)
{
updateColor(getValue());
}
void ColorPicker::onClicked()
{
- new ColorEditorPopup(getColor(), [=](uint32_t c) { setColor(c); }, preview, format);
-}
-
-void ColorPicker::setColor(uint32_t c)
-{
- setValue(c);
- updateColor(c);
+ updateColor(getValue());
+ new ColorEditorPopup(color, [=](uint32_t c) { setValue(c); updateColor(c); }, format);
}
void ColorPicker::updateColor(uint32_t c)
diff --git a/radio/src/gui/colorlcd/controls/color_picker.h b/radio/src/gui/colorlcd/controls/color_picker.h
index a39eda7bf..7e038eaea 100644
--- a/radio/src/gui/colorlcd/controls/color_picker.h
+++ b/radio/src/gui/colorlcd/controls/color_picker.h
@@ -27,6 +27,7 @@
class ColorPicker : public Button
{
uint32_t color;
+ std::function getValue;
std::function setValue;
std::function preview;
COLOR_EDITOR_FMT format;
@@ -37,11 +38,7 @@ public:
ColorPicker(Window* parent, const rect_t& rect,
std::function getValue,
std::function setValue = nullptr,
- std::function preview = nullptr,
COLOR_EDITOR_FMT fmt = ETX_RGB565);
- void setColor(uint32_t c);
- uint32_t getColor() const { return color; }
-
void onClicked() override;
};
diff --git a/radio/src/gui/colorlcd/controls/curve.cpp b/radio/src/gui/colorlcd/controls/curve.cpp
index 45f49d76f..434a4b8b2 100644
--- a/radio/src/gui/colorlcd/controls/curve.cpp
+++ b/radio/src/gui/colorlcd/controls/curve.cpp
@@ -147,17 +147,6 @@ Curve::Curve(Window* parent, const rect_t& rect,
dw = rect.w - dx * 2;
dh = rect.h - dy * 2;
- for (int i = 0; i < 17; i += 1) {
- auto p = lv_obj_create(lvobj);
- etx_solid_bg(p, COLOR_THEME_PRIMARY2_INDEX);
- etx_obj_add_style(p, styles->circle, LV_PART_MAIN);
- etx_obj_add_style(p, styles->border, LV_PART_MAIN);
- etx_obj_add_style(p, styles->border_color[COLOR_THEME_SECONDARY1_INDEX], LV_PART_MAIN);
- lv_obj_set_size(p, POS_PT_SZ, POS_PT_SZ);
- lv_obj_add_flag(p, LV_OBJ_FLAG_HIDDEN);
- pointDots[i] = p;
- }
-
if (positionFunc) {
posVLine = lv_line_create(lvobj);
etx_obj_add_style(posVLine, styles->graph_position_line, LV_PART_MAIN);
@@ -178,6 +167,8 @@ Curve::Curve(Window* parent, const rect_t& rect,
updatePosition();
}
+
+ curveUpdateMsg.subscribe(Messaging::CURVE_UPDATE, [=](uint32_t param) { update(); });
}
coord_t Curve::getPointX(int x) const
@@ -220,28 +211,6 @@ void Curve::updatePosition()
}
}
-void Curve::addPoint(const point_t& point)
-{
- int i = points.size();
- coord_t x = getPointX(point.x);
- coord_t y = getPointY(point.y);
- lv_obj_set_pos(pointDots[i], x - POS_PT_SZ / 2, y - POS_PT_SZ / 2);
- lv_obj_clear_flag(pointDots[i], LV_OBJ_FLAG_HIDDEN);
-
- points.push_back(point);
-
- update();
-}
-
-void Curve::clearPoints()
-{
- points.clear();
- for (int i = 0; i < 17; i += 1)
- lv_obj_add_flag(pointDots[i], LV_OBJ_FLAG_HIDDEN);
-
- update();
-}
-
void Curve::update()
{
base.update();
diff --git a/radio/src/gui/colorlcd/controls/curve.h b/radio/src/gui/colorlcd/controls/curve.h
index 680c9514e..625d62b1a 100644
--- a/radio/src/gui/colorlcd/controls/curve.h
+++ b/radio/src/gui/colorlcd/controls/curve.h
@@ -22,6 +22,7 @@
#pragma once
#include "window.h"
+#include "messaging.h"
class StaticText;
@@ -59,9 +60,6 @@ class Curve : public Window
std::string getName() const override { return "Curve"; }
#endif
- void addPoint(const point_t& point);
- void clearPoints();
-
void update();
protected:
@@ -71,13 +69,12 @@ class Curve : public Window
int lastPos = 0;
std::function valueFunc;
std::function positionFunc;
- std::list points;
StaticText* positionValue = nullptr;
lv_point_t posLinePoints[4];
lv_obj_t* posVLine = nullptr;
lv_obj_t* posHLine = nullptr;
lv_obj_t* posPoint = nullptr;
- lv_obj_t* pointDots[17] = { nullptr };
+ Messaging curveUpdateMsg;
void updatePosition();
diff --git a/radio/src/gui/colorlcd/controls/curve_param.cpp b/radio/src/gui/colorlcd/controls/curve_param.cpp
index c6b83475b..c94d8cef8 100644
--- a/radio/src/gui/colorlcd/controls/curve_param.cpp
+++ b/radio/src/gui/colorlcd/controls/curve_param.cpp
@@ -21,6 +21,7 @@
#include "curve_param.h"
+#include "curve.h"
#include "edgetx.h"
#include "getset_helpers.h"
#include "gvar_numberedit.h"
@@ -30,9 +31,9 @@
#define SET_DIRTY() storageDirty(EE_MODEL)
CurveChoice::CurveChoice(Window* parent, std::function getRefValue,
- std::function setRefValue, std::function refreshView, mixsrc_t source) :
+ std::function setRefValue, mixsrc_t source) :
Choice(parent, rect_t{}, -MAX_CURVES, MAX_CURVES, getRefValue, setRefValue),
- source(source), refreshView(std::move(refreshView))
+ source(source)
{
setTextHandler([](int value) { return getCurveString(value); });
}
@@ -42,16 +43,15 @@ bool CurveChoice::onLongPress()
if (modelCurvesEnabled()) {
if (_getValue()) {
lv_obj_clear_state(lvobj, LV_STATE_PRESSED);
- ModelCurvesPage::pushEditCurve(abs(_getValue()) - 1, refreshView, source);
+ ModelCurvesPage::pushEditCurve(abs(_getValue()) - 1, source);
}
}
return true;
}
CurveParam::CurveParam(Window* parent, const rect_t& rect, CurveRef* ref,
- std::function setRefValue, int16_t sourceMin, mixsrc_t source,
- std::function refreshView) :
- Window(parent, rect), ref(ref), refreshView(std::move(refreshView))
+ std::function setRefValue, int16_t sourceMin, mixsrc_t source) :
+ Window(parent, rect), ref(ref)
{
padAll(PAD_TINY);
lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW_WRAP);
@@ -98,7 +98,7 @@ CurveParam::CurveParam(Window* parent, const rect_t& rect, CurveRef* ref,
v.isSource = false;
v.value = newValue;
setRefValue(v.rawValue);
- }, refreshView, source);
+ }, source);
update();
}
@@ -133,8 +133,7 @@ void CurveParam::update()
}
act_field->show();
- if (refreshView)
- refreshView();
+ Messaging::send(Messaging::CURVE_UPDATE);
auto act_obj = act_field->getLvObj();
if (has_focus) {
diff --git a/radio/src/gui/colorlcd/controls/curve_param.h b/radio/src/gui/colorlcd/controls/curve_param.h
index c614a980e..db8386b06 100644
--- a/radio/src/gui/colorlcd/controls/curve_param.h
+++ b/radio/src/gui/colorlcd/controls/curve_param.h
@@ -31,7 +31,7 @@ class CurveChoice : public Choice
{
public:
CurveChoice(Window* parent, std::function getRefValue,
- std::function setRefValue, std::function refreshView,
+ std::function setRefValue,
mixsrc_t source);
bool onLongPress() override;
@@ -46,8 +46,7 @@ class CurveParam : public Window
public:
CurveParam(Window* parent, const rect_t& rect, CurveRef* ref,
std::function setRefValue,
- int16_t sourceMin, mixsrc_t source,
- std::function refreshView = nullptr);
+ int16_t sourceMin, mixsrc_t source);
protected:
// Curve
@@ -59,7 +58,5 @@ class CurveParam : public Window
Choice* cust_choice;
Window* act_field = nullptr;
- std::function refreshView;
-
void update();
};
diff --git a/radio/src/gui/colorlcd/controls/gvar_numberedit.cpp b/radio/src/gui/colorlcd/controls/gvar_numberedit.cpp
index 4fac9bed3..f2b57c5ad 100644
--- a/radio/src/gui/colorlcd/controls/gvar_numberedit.cpp
+++ b/radio/src/gui/colorlcd/controls/gvar_numberedit.cpp
@@ -88,15 +88,6 @@ void GVarNumberEdit::switchGVarMode()
#endif
}
-void GVarNumberEdit::onEvent(event_t event)
-{
- if (event == EVT_KEY_LONG(KEY_ENTER)) {
- switchGVarMode();
- } else {
- Window::onEvent(event);
- }
-}
-
void GVarNumberEdit::update()
{
bool has_focus = act_field && act_field->hasFocus();
diff --git a/radio/src/gui/colorlcd/controls/gvar_numberedit.h b/radio/src/gui/colorlcd/controls/gvar_numberedit.h
index 0190e49b0..938c44dbc 100644
--- a/radio/src/gui/colorlcd/controls/gvar_numberedit.h
+++ b/radio/src/gui/colorlcd/controls/gvar_numberedit.h
@@ -58,7 +58,6 @@ class GVarNumberEdit : public Window
std::function setValue;
int32_t voffset;
- void onEvent(event_t event) override;
void update();
static void value_changed(lv_event_t* e);
diff --git a/radio/src/gui/colorlcd/controls/switch_warn_dialog.cpp b/radio/src/gui/colorlcd/controls/switch_warn_dialog.cpp
index d00afa167..e8301e1d0 100644
--- a/radio/src/gui/colorlcd/controls/switch_warn_dialog.cpp
+++ b/radio/src/gui/colorlcd/controls/switch_warn_dialog.cpp
@@ -28,33 +28,20 @@ SwitchWarnDialog::SwitchWarnDialog() :
FullScreenDialog(WARNING_TYPE_ALERT, STR_SWITCHWARN, "",
STR_PRESS_ANY_KEY_TO_SKIP)
{
- last_bad_switches = 0xff;
- last_bad_pots = 0x0;
- setCloseCondition(std::bind(&SwitchWarnDialog::warningInactive, this));
lv_label_set_long_mode(messageLabel->getLvObj(), LV_LABEL_LONG_WRAP);
AUDIO_ERROR_MESSAGE(AU_SWITCH_ALERT);
}
-bool SwitchWarnDialog::warningInactive()
-{
- uint16_t bad_pots;
-
- if (!isSwitchWarningRequired(bad_pots)) return true;
-
- if (last_bad_switches != switches_states || last_bad_pots != bad_pots) {
- last_bad_pots = bad_pots;
- last_bad_switches = switches_states;
- }
-
- return false;
-}
-
void SwitchWarnDialog::checkEvents()
{
- if (!running) return;
-
FullScreenDialog::checkEvents();
+ uint16_t bad_pots;
+ if (!isSwitchWarningRequired(bad_pots)) {
+ deleteLater();
+ return;
+ };
+
std::string warn_txt;
for (int i = 0; i < switchGetMaxAllSwitches(); ++i) {
if (SWITCH_WARNING_ALLOWED(i)) {
@@ -95,13 +82,15 @@ ThrottleWarnDialog::ThrottleWarnDialog(const char* msg) :
FullScreenDialog(WARNING_TYPE_ALERT, STR_THROTTLE_UPPERCASE, msg,
STR_PRESS_ANY_KEY_TO_SKIP)
{
- setCloseCondition(std::bind(&ThrottleWarnDialog::warningInactive, this));
lv_label_set_long_mode(messageLabel->getLvObj(), LV_LABEL_LONG_WRAP);
AUDIO_ERROR_MESSAGE(AU_THROTTLE_ALERT);
}
-bool ThrottleWarnDialog::warningInactive()
+void ThrottleWarnDialog::checkEvents()
{
+ FullScreenDialog::checkEvents();
+
extern bool isThrottleWarningAlertNeeded();
- return !isThrottleWarningAlertNeeded();
+ if (!isThrottleWarningAlertNeeded())
+ deleteLater();
}
diff --git a/radio/src/gui/colorlcd/controls/switch_warn_dialog.h b/radio/src/gui/colorlcd/controls/switch_warn_dialog.h
index 4bb7c452e..cf0bed8b7 100644
--- a/radio/src/gui/colorlcd/controls/switch_warn_dialog.h
+++ b/radio/src/gui/colorlcd/controls/switch_warn_dialog.h
@@ -35,11 +35,6 @@ class SwitchWarnDialog : public FullScreenDialog
#endif
protected:
- swarnstate_t last_bad_switches;
- uint16_t last_bad_pots;
-
- bool warningInactive();
-
void checkEvents() override;
};
@@ -53,5 +48,5 @@ class ThrottleWarnDialog : public FullScreenDialog
#endif
protected:
- bool warningInactive();
+ void checkEvents() override;
};
diff --git a/radio/src/gui/colorlcd/layouts/layout2x4.cpp b/radio/src/gui/colorlcd/layouts/layout2x4.cpp
index 0e3f9e71c..183af767c 100644
--- a/radio/src/gui/colorlcd/layouts/layout2x4.cpp
+++ b/radio/src/gui/colorlcd/layouts/layout2x4.cpp
@@ -56,10 +56,10 @@ class Layout2x4 : public Layout
lv_obj_t* panel1 = nullptr;
lv_obj_t* panel2 = nullptr;
- void checkEvents() override
+ void updateDecorations() override
{
+ Layout::updateDecorations();
setPanels();
- Layout::checkEvents();
}
void setPanels()
diff --git a/radio/src/gui/colorlcd/layouts/layout6x1.cpp b/radio/src/gui/colorlcd/layouts/layout6x1.cpp
index 98097a7a4..59e2479a0 100644
--- a/radio/src/gui/colorlcd/layouts/layout6x1.cpp
+++ b/radio/src/gui/colorlcd/layouts/layout6x1.cpp
@@ -49,10 +49,10 @@ class Layout6x1 : public Layout
rect_t mainZone = {0, 0, 0, 0};
lv_obj_t* panel = nullptr;
- void checkEvents() override
+ void updateDecorations() override
{
+ Layout::updateDecorations();
setPanel();
- Layout::checkEvents();
}
void setPanel()
diff --git a/radio/src/gui/colorlcd/libui/bitmapbuffer_fileio.cpp b/radio/src/gui/colorlcd/libui/bitmapbuffer_fileio.cpp
index bcbbbfe3e..e02b458ed 100644
--- a/radio/src/gui/colorlcd/libui/bitmapbuffer_fileio.cpp
+++ b/radio/src/gui/colorlcd/libui/bitmapbuffer_fileio.cpp
@@ -97,6 +97,8 @@ const stbi_io_callbacks stbCallbacks = {stbc_read, stbc_skip, stbc_eof};
BitmapBuffer *BitmapBuffer::loadBitmap(const char *filename, BitmapFormats fmt)
{
+ if ((filename == nullptr) || (filename[0] == 0)) return nullptr;
+
FRESULT result = f_open(&imgFile, filename, FA_OPEN_EXISTING | FA_READ);
if (result != FR_OK) {
return nullptr;
diff --git a/radio/src/gui/colorlcd/libui/button.cpp b/radio/src/gui/colorlcd/libui/button.cpp
index 9f1aefe69..a7179a821 100644
--- a/radio/src/gui/colorlcd/libui/button.cpp
+++ b/radio/src/gui/colorlcd/libui/button.cpp
@@ -150,17 +150,21 @@ MomentaryButton::MomentaryButton(Window* parent, const rect_t& rect, std::string
lv_obj_center(label);
}
-void MomentaryButton::onPressed()
+bool MomentaryButton::customEventHandler(lv_event_code_t code)
{
- if (pressHandler)
- pressHandler();
- lv_obj_add_state(lvobj, LV_STATE_CHECKED);
- lv_obj_clear_state(lvobj, LV_STATE_PRESSED);
-}
-
-void MomentaryButton::onReleased()
-{
- if (releaseHandler)
- releaseHandler();
- lv_obj_clear_state(lvobj, LV_STATE_CHECKED);
+ switch (code) {
+ case LV_EVENT_PRESSED:
+ if (pressHandler)
+ pressHandler();
+ lv_obj_add_state(lvobj, LV_STATE_CHECKED);
+ lv_obj_clear_state(lvobj, LV_STATE_PRESSED);
+ return true;
+ case LV_EVENT_RELEASED:
+ if (releaseHandler)
+ releaseHandler();
+ lv_obj_clear_state(lvobj, LV_STATE_CHECKED);
+ return true;
+ default:
+ return false;
+ };
}
diff --git a/radio/src/gui/colorlcd/libui/button.h b/radio/src/gui/colorlcd/libui/button.h
index 3527a389c..2740bd8df 100644
--- a/radio/src/gui/colorlcd/libui/button.h
+++ b/radio/src/gui/colorlcd/libui/button.h
@@ -140,9 +140,6 @@ class MomentaryButton : public FormField
std::string getName() const override { return "MomentaryButton"; }
#endif
- void onPressed() override;
- void onReleased() override;
-
void setText(std::string value)
{
if (value != text) {
@@ -161,4 +158,6 @@ class MomentaryButton : public FormField
std::function releaseHandler;
std::string text;
lv_obj_t* label = nullptr;
+
+ bool customEventHandler(lv_event_code_t code) override;
};
diff --git a/radio/src/gui/colorlcd/libui/fullscreen_dialog.cpp b/radio/src/gui/colorlcd/libui/fullscreen_dialog.cpp
index 037053c5b..497816d32 100644
--- a/radio/src/gui/colorlcd/libui/fullscreen_dialog.cpp
+++ b/radio/src/gui/colorlcd/libui/fullscreen_dialog.cpp
@@ -23,16 +23,20 @@
#include "edgetx.h"
#include "etx_lv_theme.h"
+#include "hal/usb_driver.h"
#include "hal/watchdog_driver.h"
#include "mainwindow.h"
#include "os/sleep.h"
#include "static.h"
+#include "theme_manager.h"
#include "view_main.h"
+//-----------------------------------------------------------------------------
+
FullScreenDialog::FullScreenDialog(
uint8_t type, std::string title, std::string message, std::string action,
const std::function& confirmHandler) :
- Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}),
+ NavWindow(MainWindow::instance(), {0, 0, LCD_W, LCD_H}),
type(type),
title(std::move(title)),
message(std::move(message)),
@@ -129,75 +133,26 @@ bool FullScreenDialog::onLongPress()
return false;
}
-void FullScreenDialog::onEvent(event_t event)
+#if defined(HARDWARE_KEYS)
+void FullScreenDialog::alertCancel()
{
// Buttons other than RTN or ENTER
- if (type == WARNING_TYPE_ALERT) {
+ if (type == WARNING_TYPE_ALERT)
closeDialog();
- killEvents(event);
- }
-}
-
-void FullScreenDialog::onCancel() { deleteLater(); }
-
-void FullScreenDialog::checkEvents()
-{
- Window::checkEvents();
- if (closeCondition && closeCondition()) {
- deleteLater();
- }
-}
-
-void FullScreenDialog::deleteLater()
-{
- if (_deleted) return;
-
- if (running) {
- running = false;
- } else {
- Window::deleteLater();
- }
}
+void FullScreenDialog::onPressSYS() { alertCancel(); }
+void FullScreenDialog::onPressMDL() { alertCancel(); }
+void FullScreenDialog::onPressPGUP() { alertCancel(); }
+void FullScreenDialog::onPressPGDN() { alertCancel(); }
+void FullScreenDialog::onPressTELE() { alertCancel(); }
+#endif
void FullScreenDialog::setMessage(const char* text)
{
if (messageLabel) messageLabel->setText(text);
}
-void FullScreenDialog::runForever(bool checkPwr)
-{
- running = true;
-
- // reset input devices to avoid
- // RELEASED/CLICKED to be called in a loop
- lv_indev_reset(nullptr, nullptr);
-
- while (running) {
- resetBacklightTimeout();
-
- if (checkPwr) {
- auto check = pwrCheck();
- if (check == e_power_off) {
- boardOff();
-#if defined(SIMU)
- return;
-#endif
- } else if (check == e_power_press) {
- WDG_RESET();
- sleep_ms(1);
- continue;
- }
- }
-
- checkBacklight();
- WDG_RESET();
-
- MainWindow::instance()->run();
- sleep_ms(10);
- }
-
- deleteLater();
-}
+//-----------------------------------------------------------------------------
void raiseAlert(const char* title, const char* msg, const char* action,
uint8_t sound)
@@ -207,7 +162,9 @@ void raiseAlert(const char* title, const char* msg, const char* action,
LED_ERROR_BEGIN();
auto dialog = new FullScreenDialog(WARNING_TYPE_ALERT, title ? title : "",
msg ? msg : "", action ? action : "");
- dialog->runForever();
+ MainWindow::instance()->blockUntilClose(true, [=]() {
+ return dialog->deleted();
+ });
LED_ERROR_END();
}
@@ -219,18 +176,15 @@ bool confirmationDialog(const char* title, const char* msg, bool checkPwr,
auto dialog = new FullScreenDialog(WARNING_TYPE_CONFIRM, title ? title : "",
msg ? msg : "", "",
[&confirmed]() { confirmed = true; });
- if (closeCondition) {
- dialog->setCloseCondition([&confirmed, &closeCondition]() {
- if (closeCondition()) {
- confirmed = true;
- return true;
- } else {
- return false;
- }
- });
- }
- dialog->runForever(checkPwr);
+ MainWindow::instance()->blockUntilClose(checkPwr, [&]() {
+ if (dialog->deleted()) return true;
+ if (closeCondition && closeCondition()) {
+ confirmed = true;
+ dialog->deleteLater();
+ }
+ return confirmed;
+ });
return confirmed;
}
diff --git a/radio/src/gui/colorlcd/libui/fullscreen_dialog.h b/radio/src/gui/colorlcd/libui/fullscreen_dialog.h
index 7b7f54a4b..6615e84d7 100644
--- a/radio/src/gui/colorlcd/libui/fullscreen_dialog.h
+++ b/radio/src/gui/colorlcd/libui/fullscreen_dialog.h
@@ -25,7 +25,9 @@
class StaticText;
-class FullScreenDialog : public Window
+//-----------------------------------------------------------------------------
+
+class FullScreenDialog : public NavWindow
{
public:
FullScreenDialog(uint8_t type, std::string title, std::string message = "",
@@ -41,23 +43,20 @@ class FullScreenDialog : public Window
void setMessage(const char* text);
- void onEvent(event_t event) override;
- void onCancel() override;
bool onLongPress() override;
-
- void deleteLater() override;
-
- void checkEvents() override;
-
- void setCloseCondition(std::function handler)
- {
- closeCondition = std::move(handler);
- }
-
- void runForever(bool checkPwr = true);
+ void onCancel() override { deleteLater(); }
void closeDialog();
+#if defined(HARDWARE_KEYS)
+ void alertCancel();
+ void onPressSYS() override;
+ void onPressMDL() override;
+ void onPressPGUP() override;
+ void onPressPGDN() override;
+ void onPressTELE() override;
+#endif
+
static LAYOUT_SIZE_SCALED(ALERT_FRAME_TOP, 50, 70)
static LAYOUT_SIZE(ALERT_FRAME_HO, LAYOUT_SCALE(120), 2 * ALERT_FRAME_TOP)
static constexpr coord_t ALERT_FRAME_HEIGHT = LCD_H - ALERT_FRAME_HO;
@@ -80,10 +79,10 @@ class FullScreenDialog : public Window
std::string title;
std::string message;
std::string action;
- bool running = false;
- std::function closeCondition;
std::function confirmHandler;
StaticText* messageLabel = nullptr;
void build();
};
+
+//-----------------------------------------------------------------------------
diff --git a/radio/src/gui/colorlcd/libui/mainwindow.cpp b/radio/src/gui/colorlcd/libui/mainwindow.cpp
index 21d6dcf15..ab5470b22 100644
--- a/radio/src/gui/colorlcd/libui/mainwindow.cpp
+++ b/radio/src/gui/colorlcd/libui/mainwindow.cpp
@@ -20,10 +20,12 @@
#include "board.h"
#include "debug.h"
+#include "edgetx.h"
#include "keyboard_base.h"
#include "layout.h"
#include "LvglWrapper.h"
#include "etx_lv_theme.h"
+#include "os/sleep.h"
#include "sdcard.h"
#include "view_main.h"
@@ -56,7 +58,7 @@ void MainWindow::emptyTrash()
trash.clear();
}
-void MainWindow::run()
+void MainWindow::run(bool trash)
{
LvglWrapper::instance()->run();
@@ -79,7 +81,8 @@ void MainWindow::run()
}
}
- emptyTrash();
+ if (trash)
+ emptyTrash();
#if defined(DEBUG_WINDOWS)
auto delta = timersGetMsTick() - start;
@@ -97,11 +100,9 @@ void MainWindow::shutdown()
LayoutFactory::deleteCustomScreens();
// clear layer stack first
- for (Window* w = Window::topWindow(); w; w = Window::topWindow()) {
+ for (Window* w = Window::topWindow(); w; w = Window::topWindow())
w->deleteLater();
- }
- children.clear();
clear();
emptyTrash();
@@ -128,3 +129,48 @@ bool MainWindow::setBackgroundImage(std::string& fileName)
return false;
}
+
+void MainWindow::blockUntilClose(bool checkPwr, std::function closeCondition, bool isError)
+{
+ // reset input devices to avoid
+ // RELEASED/CLICKED to be called in a loop
+ lv_indev_reset(nullptr, nullptr);
+
+ if (isError) {
+ // refresh screen and turn backlight on
+ backlightEnable(BACKLIGHT_LEVEL_MAX);
+ // On startup error wait for power button to be released
+ while (pwrPressed()) {
+ WDG_RESET();
+ run(false);
+ sleep_ms(10);
+ }
+ }
+
+ while (!closeCondition()) {
+ if (checkPwr) {
+ auto check = pwrCheck();
+ if (check == e_power_off) {
+ boardOff();
+#if defined(SIMU)
+ return;
+#endif
+ } else if (check == e_power_press) {
+ WDG_RESET();
+ sleep_ms(1);
+ continue;
+ }
+ }
+
+ resetBacklightTimeout();
+ if (isError)
+ backlightEnable(BACKLIGHT_LEVEL_MAX);
+ else
+ checkBacklight();
+
+ WDG_RESET();
+
+ run(false);
+ sleep_ms(10);
+ }
+}
diff --git a/radio/src/gui/colorlcd/libui/mainwindow.h b/radio/src/gui/colorlcd/libui/mainwindow.h
index 54f0e589c..06f6fcff9 100644
--- a/radio/src/gui/colorlcd/libui/mainwindow.h
+++ b/radio/src/gui/colorlcd/libui/mainwindow.h
@@ -45,7 +45,7 @@ class MainWindow: public Window
}
#endif
- void run();
+ void run(bool trash = true);
bool setBackgroundImage(std::string& fileName);
@@ -53,6 +53,8 @@ class MainWindow: public Window
void enableWidgetRefresh(bool state) { widgetRefreshEnable = state; }
+ void blockUntilClose(bool checkPwr, std::function closeCondition, bool isError = false);
+
protected:
lv_obj_t* background = nullptr;
const BitmapBuffer *backgroundBitmap = nullptr;
diff --git a/radio/src/gui/colorlcd/libui/menu.cpp b/radio/src/gui/colorlcd/libui/menu.cpp
index 13bbb89d1..645d97cbd 100644
--- a/radio/src/gui/colorlcd/libui/menu.cpp
+++ b/radio/src/gui/colorlcd/libui/menu.cpp
@@ -29,9 +29,6 @@
class MenuBody : public TableField
{
- friend class MenuWindowContent;
- friend class Menu;
-
enum MENU_DIRECTION { DIRECTION_UP = 1, DIRECTION_DOWN = -1 };
class MenuLine
@@ -132,17 +129,6 @@ class MenuBody : public TableField
int count() const { return lines.size(); }
- void onEvent(event_t event) override
- {
-#if defined(HARDWARE_KEYS)
- if (event == EVT_KEY_BREAK(KEY_EXIT)) {
- onCancel();
- } else {
- TableField::onEvent(event);
- }
-#endif
- }
-
void addLine(const MaskBitmap* icon_mask, const std::string& text,
std::function onPress, std::function isChecked,
bool update = true)
@@ -197,7 +183,7 @@ class MenuBody : public TableField
{
Menu* menu = getParentMenu();
if (row < lines.size()) {
- if (menu->multiple) {
+ if (menu->isMultiple()) {
if (selectedIndex == (int)row)
lines[row]->onPress();
else {
@@ -300,11 +286,11 @@ static lv_obj_t* menu_content_create(lv_obj_t* parent)
return etx_create(&menu_content_class, parent);
}
-class MenuWindowContent : public Window
+class MenuWindowContent : public NavWindow
{
public:
explicit MenuWindowContent(Menu* parent, coord_t popupWidth) :
- Window(parent, rect_t{}, menu_content_create)
+ NavWindow(parent, rect_t{}, menu_content_create)
{
setWindowFlag(OPAQUE);
@@ -348,6 +334,18 @@ class MenuWindowContent : public Window
body->addLine(icon_mask, text, onPress, isChecked, update);
}
+#if defined(HARDWARE_KEYS)
+ void onPressPGUP() override
+ {
+ Messaging::send(Messaging::MENU_CHANGE_FILTER, -1);
+ }
+
+ void onPressPGDN() override
+ {
+ Messaging::send(Messaging::MENU_CHANGE_FILTER, 1);
+ }
+#endif
+
static LAYOUT_VAL_SCALED(MENUS_WIDTH, 200)
protected:
@@ -406,18 +404,10 @@ void Menu::addLine(const std::string &text, std::function onPress,
addLine(nullptr, text, onPress, isChecked);
}
-void Menu::addLineBuffered(const MaskBitmap* icon_mask, const std::string& text,
- std::function onPress,
- std::function isChecked)
-{
- content->addLine(icon_mask, text, std::move(onPress), std::move(isChecked),
- false);
-}
-
void Menu::addLineBuffered(const std::string &text, std::function onPress,
std::function isChecked)
{
- addLineBuffered(nullptr, text, onPress, isChecked);
+ content->addLine(nullptr, text, std::move(onPress), std::move(isChecked), false);
}
void Menu::updateLines()
@@ -432,16 +422,6 @@ void Menu::removeLines()
updatePosition();
}
-void Menu::onEvent(event_t event)
-{
-#if defined(HARDWARE_KEYS)
- if (toolbar && (event == EVT_KEY_BREAK(KEY_PAGEDN) ||
- event == EVT_KEY_BREAK(KEY_PAGEUP))) {
- toolbar->onEvent(event);
- }
-#endif
-}
-
void Menu::onCancel()
{
if (cancelHandler) cancelHandler();
@@ -474,3 +454,10 @@ unsigned Menu::count() const { return content->count(); }
int Menu::selection() const { return content->selection(); }
void Menu::select(int index) { content->setIndex(index); }
+
+void Menu::checkEvents()
+{
+ ModalWindow::checkEvents();
+ if (waitHandler)
+ waitHandler();
+}
diff --git a/radio/src/gui/colorlcd/libui/menu.h b/radio/src/gui/colorlcd/libui/menu.h
index 77f007b6e..10d7f99b1 100644
--- a/radio/src/gui/colorlcd/libui/menu.h
+++ b/radio/src/gui/colorlcd/libui/menu.h
@@ -27,8 +27,6 @@ class MenuToolbar;
class Menu : public ModalWindow
{
- friend class MenuBody;
-
public:
explicit Menu(bool multiple = false, coord_t popupWidth = 0);
@@ -51,10 +49,6 @@ class Menu : public ModalWindow
void addLine(const std::string &text, std::function onPress,
std::function isChecked = nullptr);
- void addLineBuffered(const MaskBitmap *icon_mask, const std::string &text,
- std::function onPress,
- std::function isChecked = nullptr);
-
void addLineBuffered(const std::string &text, std::function onPress,
std::function isChecked = nullptr);
@@ -68,19 +62,13 @@ class Menu : public ModalWindow
void select(int index);
- void onEvent(event_t event) override;
void onCancel() override;
-
- void checkEvents() override
- {
- ModalWindow::checkEvents();
- if (waitHandler) {
- waitHandler();
- }
- }
+ void checkEvents() override;
void handleLongPress();
+ bool isMultiple() const { return multiple; }
+
protected:
bool multiple;
MenuWindowContent *content;
diff --git a/radio/src/gui/colorlcd/libui/menutoolbar.cpp b/radio/src/gui/colorlcd/libui/menutoolbar.cpp
index b6f158df2..1856b51b9 100644
--- a/radio/src/gui/colorlcd/libui/menutoolbar.cpp
+++ b/radio/src/gui/colorlcd/libui/menutoolbar.cpp
@@ -80,6 +80,13 @@ MenuToolbar::MenuToolbar(Choice* choice, Menu* menu, const int columns) :
addButton(STR_SELECT_MENU_ALL, choice->getMin(), choice->getMax(), nullptr,
nullptr, true);
+
+ changeFilterMsg.subscribe(Messaging::MENU_CHANGE_FILTER, [=](uint32_t param) {
+ if (param == 1)
+ nextFilter();
+ else
+ prevFilter();
+ });
}
MenuToolbar::~MenuToolbar() { lv_group_del(group); }
@@ -93,15 +100,16 @@ void MenuToolbar::resetFilter()
}
}
-void MenuToolbar::onEvent(event_t event)
+void MenuToolbar::nextFilter()
{
- if (event == EVT_KEY_BREAK(KEY_PAGEDN)) {
- lv_group_focus_next(group);
- }
- else if (event == EVT_KEY_BREAK(KEY_PAGEUP)) {
- lv_group_focus_prev(group);
- }
+ lv_group_focus_next(group);
+ auto obj = lv_group_get_focused(group);
+ lv_event_send(obj, LV_EVENT_CLICKED, nullptr);
+}
+void MenuToolbar::prevFilter()
+{
+ lv_group_focus_prev(group);
auto obj = lv_group_get_focused(group);
lv_event_send(obj, LV_EVENT_CLICKED, nullptr);
}
diff --git a/radio/src/gui/colorlcd/libui/menutoolbar.h b/radio/src/gui/colorlcd/libui/menutoolbar.h
index d011a09f8..548dc761a 100644
--- a/radio/src/gui/colorlcd/libui/menutoolbar.h
+++ b/radio/src/gui/colorlcd/libui/menutoolbar.h
@@ -21,6 +21,7 @@
#include "button.h"
#include "choice.h"
#include "listbox.h"
+#include "messaging.h"
class Menu;
@@ -34,14 +35,14 @@ class MenuToolbarButton : public ButtonBase
class MenuToolbar : public Window
{
- // friend Menu;
-
public:
MenuToolbar(Choice* choice, Menu* menu, const int columns);
~MenuToolbar();
void resetFilter();
- void onEvent(event_t event) override;
+
+ void nextFilter();
+ void prevFilter();
virtual void longPress() {}
@@ -54,6 +55,7 @@ class MenuToolbar : public Window
int nxtBtnPos = 0;
int filterColumns = 0;
MenuToolbarButton* allBtn = nullptr;
+ Messaging changeFilterMsg;
lv_group_t* group;
diff --git a/radio/src/gui/colorlcd/libui/messaging.cpp b/radio/src/gui/colorlcd/libui/messaging.cpp
new file mode 100644
index 000000000..2eaf4ea67
--- /dev/null
+++ b/radio/src/gui/colorlcd/libui/messaging.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) EdgeTX
+ *
+ * Based on code named
+ * libopenui - https://github.com/opentx/libopenui
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "messaging.h"
+
+#include
+#include
+
+static std::list subscriptions;
+
+Messaging::~Messaging()
+{
+ unsubscribe();
+}
+
+void Messaging::subscribe(uint32_t _id, std::function cb)
+{
+ unsubscribe();
+ id = _id;
+ callback = cb;
+ subscriptions.emplace_back(this);
+}
+
+void Messaging::unsubscribe()
+{
+ if (id) {
+ auto s = std::find_if(subscriptions.begin(), subscriptions.end(),
+ [=](Messaging* lh) -> bool { return lh == this; });
+ if (s != subscriptions.end()) subscriptions.erase(s);
+ }
+
+ callback = nullptr;
+ id = 0;
+}
+
+void Messaging::send(uint32_t id)
+{
+ send(id, 0);
+}
+
+void Messaging::send(uint32_t msgId, uint32_t msgData)
+{
+ for (auto it = subscriptions.rbegin(); it != subscriptions.rend(); ++it) {
+ Messaging* m = *it;
+ if (m->id == msgId && m->callback)
+ m->callback(msgData);
+ }
+}
diff --git a/radio/src/gui/colorlcd/libui/messaging.h b/radio/src/gui/colorlcd/libui/messaging.h
new file mode 100644
index 000000000..6bde89378
--- /dev/null
+++ b/radio/src/gui/colorlcd/libui/messaging.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) EdgeTX
+ *
+ * Based on code named
+ * libopenui - https://github.com/opentx/libopenui
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#pragma once
+
+#include
+#include
+
+class Messaging
+{
+ public:
+ enum MessageId
+ {
+ COLOR_CHANGED = 1,
+ COLOR_PREVIEW,
+ MODULE_UPDATE,
+ CURVE_UPDATE,
+ CURVE_EDIT,
+ DECORATION_UPDATE,
+ QUICK_MENU_ITEM_SELECT,
+ MENU_CHANGE_FILTER,
+ REFRESH,
+ REFRESH_OUTPUTS_WIDGET,
+ };
+
+ Messaging() {}
+ ~Messaging();
+ void subscribe(uint32_t id, std::function cb);
+ void unsubscribe();
+
+ uint32_t getUIntParam();
+ bool getBoolParam();
+
+ static void send(uint32_t id);
+ static void send(uint32_t id, uint32_t data);
+
+ protected:
+ uint32_t id = 0;
+ std::function callback = nullptr;
+};
diff --git a/radio/src/gui/colorlcd/libui/page.cpp b/radio/src/gui/colorlcd/libui/page.cpp
index c9b4f8061..5899d9681 100644
--- a/radio/src/gui/colorlcd/libui/page.cpp
+++ b/radio/src/gui/colorlcd/libui/page.cpp
@@ -87,7 +87,7 @@ Page::Page(EdgeTxIcon icon, PaddingSize padding, bool pauseRefresh) :
#if VERSION_MAJOR == 2
addCustomButton(0, 0, [=]() { onCancel(); });
#else
- addCustomButton(0, 0, [=]() { openMenu(); });
+ addCustomButton(0, 0, [=]() { QuickMenu::openQuickMenu(); });
addCustomButton(LCD_W - EdgeTxStyles::MENU_HEADER_HEIGHT, 0, [=]() { onCancel(); });
#endif
#endif
@@ -104,31 +104,17 @@ Page::Page(EdgeTxIcon icon, PaddingSize padding, bool pauseRefresh) :
pushLayer(true);
body->padAll(padding);
-}
-void Page::openMenu()
-{
- PageGroup* p = Window::pageGroup();
- QMPage qmPage = QM_NONE;
- if (p)
- qmPage = p->getCurrentTab()->pageId();
- QuickMenu::openQuickMenu(
- [=](bool close) {
- onCancel();
- if (p) {
- while (!Window::topWindow()->isPageGroup()) {
- Window::topWindow()->deleteLater();
- }
- if (close)
- Window::topWindow()->onCancel();
- }
- }, p, qmPage);
+ quickMenuMsg.subscribe(Messaging::QUICK_MENU_ITEM_SELECT,
+ [=](uint32_t param) {
+ onCancel();
+ });
}
void Page::onCancel()
{
- QuickMenu::closeQuickMenu();
- deleteLater();
+ if (!_deleted)
+ deleteLater();
}
void Page::onClicked() { Keyboard::hide(false); }
@@ -151,7 +137,7 @@ void Page::onPressSYS()
{
QMPage pg = g_eeGeneral.getKeyShortcut(EVT_KEY_BREAK(KEY_SYS));
if (pg == QM_OPEN_QUICK_MENU) {
- if (!QuickMenu::isOpen()) openMenu();
+ QuickMenu::openQuickMenu();
} else {
auto p = navWindow();
if (p) {
@@ -218,7 +204,7 @@ SubPage::SubPage(EdgeTxIcon icon, const char* title, const char* subtitle, bool
header->setTitle2(subtitle);
}
-SubPage::SubPage(EdgeTxIcon icon, const char* title, const char* subtitle, SetupLineDef* setupLines, int lineCount) :
+SubPage::SubPage(EdgeTxIcon icon, const char* title, const char* subtitle, const SetupLineDef* setupLines) :
Page(icon, PAD_SMALL, true)
{
body->padBottom(PAD_LARGE * 2);
@@ -226,14 +212,19 @@ SubPage::SubPage(EdgeTxIcon icon, const char* title, const char* subtitle, Setup
header->setTitle(title);
header->setTitle2(subtitle);
- SetupLine::showLines(body, y, EDT_X, PAD_SMALL, setupLines, lineCount);
+ SetupLine::showLines(body, y, EDT_X, PAD_SMALL, setupLines);
enableRefresh();
}
-Window* SubPage::setupLine(const char* title, std::function createEdit, coord_t lblYOffset)
+Window* SubPage::setupLine(const char* title, std::function createEdit, coord_t lblYOffset)
{
auto w = new SetupLine(body, y, EDT_X, PAD_SMALL, title, createEdit, lblYOffset);
y += w->height();
return w;
}
+
+void SubPage::useFlexLayout()
+{
+ body->setFlexLayout();
+}
diff --git a/radio/src/gui/colorlcd/libui/page.h b/radio/src/gui/colorlcd/libui/page.h
index d2a6d418e..97cda57de 100644
--- a/radio/src/gui/colorlcd/libui/page.h
+++ b/radio/src/gui/colorlcd/libui/page.h
@@ -22,6 +22,7 @@
#pragma once
#include "static.h"
+#include "messaging.h"
class PageHeader : public Window
{
@@ -54,11 +55,10 @@ class Page : public NavWindow
void enableRefresh();
- void openMenu();
-
protected:
PageHeader* header = nullptr;
Window* body = nullptr;
+ Messaging quickMenuMsg;
bool bubbleEvents() override { return false; }
@@ -79,9 +79,11 @@ class SubPage : public Page
{
public:
SubPage(EdgeTxIcon icon, const char* title, const char* subtitle, bool pauseRefresh = false);
- SubPage(EdgeTxIcon icon, const char* title, const char* subtitle, SetupLineDef* setupLines, int lineCount);
+ SubPage(EdgeTxIcon icon, const char* title, const char* subtitle, const SetupLineDef* setupLines);
- Window* setupLine(const char* title, std::function createEdit, coord_t lblYOffset = 0);
+ Window* setupLine(const char* title, std::function createEdit, coord_t lblYOffset = 0);
+
+ void useFlexLayout();
static LAYOUT_SIZE(EDT_X, LCD_W * 9 / 20, LCD_W * 8 / 20)
diff --git a/radio/src/gui/colorlcd/libui/popups.cpp b/radio/src/gui/colorlcd/libui/popups.cpp
index a23fbc631..5f70b2212 100644
--- a/radio/src/gui/colorlcd/libui/popups.cpp
+++ b/radio/src/gui/colorlcd/libui/popups.cpp
@@ -33,36 +33,11 @@
static void _run_popup_dialog(const char* title, const char* msg,
const char* info = nullptr)
{
- bool running = true;
-
- resetBacklightTimeout();
-
- // reset input devices to avoid
- // RELEASED/CLICKED to be called in a loop
- lv_indev_reset(nullptr, nullptr);
-
auto md = new MessageDialog(title, msg, info);
- md->setCloseHandler([&]() { running = false; });
- while (running) {
- // Allow power off while showing popup
- auto check = pwrCheck();
- if (check == e_power_off) {
- boardOff();
-#if defined(SIMU)
- // Required so simulator exits cleanly when window closed
- return;
-#endif
- } else if (check == e_power_press) {
- WDG_RESET();
- sleep_ms(1);
- continue;
- }
- checkBacklight();
- WDG_RESET();
- MainWindow::instance()->run();
- sleep_ms(20);
- }
+ MainWindow::instance()->blockUntilClose(true, [=]() {
+ return md->deleted();
+ });
}
void POPUP_INFORMATION(const char* message)
diff --git a/radio/src/gui/colorlcd/libui/table.cpp b/radio/src/gui/colorlcd/libui/table.cpp
index ac206c38a..8980c1043 100644
--- a/radio/src/gui/colorlcd/libui/table.cpp
+++ b/radio/src/gui/colorlcd/libui/table.cpp
@@ -237,55 +237,6 @@ void TableField::adjustScroll()
lv_obj_scroll_by_bounded(lvobj, 0, diff_y, LV_ANIM_OFF);
}
-void TableField::selectNext(int16_t dir)
-{
- lv_table_t* table = (lv_table_t*)lvobj;
-
- if (table->col_act == LV_TABLE_CELL_NONE ||
- table->row_act == LV_TABLE_CELL_NONE) {
- if (table->col_cnt > 0 && table->row_cnt > 0) {
- table->col_act = 0;
- table->row_act = 0;
- }
- } else {
- table->col_act += dir;
- if (table->col_act >= table->col_cnt) {
- table->col_act = 0;
- table->row_act += dir;
-
- if (table->row_act >= table->row_cnt) {
- table->col_act = LV_TABLE_CELL_NONE;
- table->row_act = LV_TABLE_CELL_NONE;
-
- // wrap around
- if (table->col_cnt > 0 && table->row_cnt > 0) {
- if (dir < 0) {
- table->col_act = table->col_cnt - 1;
- table->row_act = table->row_cnt - 1;
- } else {
- table->col_act = 0;
- table->row_act = 0;
- }
- }
- }
- }
- }
-
- lv_obj_invalidate(lvobj);
- adjustScroll();
-}
-
-void TableField::onEvent(event_t event)
-{
- if (event == EVT_ROTARY_RIGHT) {
- selectNext(1);
- } else if (event == EVT_ROTARY_LEFT) {
- selectNext(-1);
- } else {
- Window::onEvent(event);
- }
-}
-
int TableField::getSelected() const
{
uint16_t row, col;
diff --git a/radio/src/gui/colorlcd/libui/table.h b/radio/src/gui/colorlcd/libui/table.h
index 94bdcf172..7a35ba589 100644
--- a/radio/src/gui/colorlcd/libui/table.h
+++ b/radio/src/gui/colorlcd/libui/table.h
@@ -43,7 +43,6 @@ class TableField : public Window
virtual void onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) {}
void adjustScroll();
- void selectNext(int16_t dir);
void setAutoEdit();
bool isAutoEdit() const { return autoedit; }
@@ -63,7 +62,6 @@ class TableField : public Window
lv_group_t* group = nullptr;
lv_group_t* oldGroup = nullptr;
- void onEvent(event_t event) override;
bool onLongPress() override;
void deleteLater() override;
diff --git a/radio/src/gui/colorlcd/libui/view_text.cpp b/radio/src/gui/colorlcd/libui/view_text.cpp
index 479ea5367..3605ea37c 100644
--- a/radio/src/gui/colorlcd/libui/view_text.cpp
+++ b/radio/src/gui/colorlcd/libui/view_text.cpp
@@ -25,6 +25,7 @@
#include "etx_lv_theme.h"
#include "fullscreen_dialog.h"
#include "lib_file.h"
+#include "mainwindow.h"
#include "menu.h"
#include "sdcard.h"
@@ -85,17 +86,11 @@ class TextViewer
}
}
- void onEvent(event_t event)
- {
#if defined(HARDWARE_KEYS)
+ void changePage(int direction)
+ {
if (int(bufSize) < fileLength) {
- if (event == EVT_KEY_BREAK(KEY_PAGEDN)) {
- offset += bufSize;
- }
-
- if (event == EVT_KEY_BREAK(KEY_PAGEUP)) {
- offset -= bufSize;
- }
+ offset = offset + bufSize * direction;
offset = std::max(offset, 0);
offset = std::min(offset, fileLength - (int)bufSize);
@@ -103,8 +98,8 @@ class TextViewer
sdReadTextFileBlock(bufSize, offset);
lv_label_set_text_static(lb, buffer);
}
- #endif
}
+ #endif
void build(Window* window)
{
@@ -268,15 +263,18 @@ void ViewTextWindow::onCancel()
checkListOpen = false;
}
-void ViewTextWindow::onEvent(event_t event)
-{
#if defined(HARDWARE_KEYS)
- if (textViewer) textViewer->onEvent(event);
-
- if (event == EVT_KEY_BREAK(KEY_EXIT)) onCancel();
-#endif
+void ViewTextWindow::onPressPGUP()
+{
+ if (textViewer) textViewer->changePage(-1);
}
+void ViewTextWindow::onPressPGDN()
+{
+ if (textViewer) textViewer->changePage(1);
+}
+#endif
+
class ViewChecklistWindow : public Page, public TextViewer
{
public:
@@ -354,13 +352,6 @@ class ViewChecklistWindow : public Page, public TextViewer
}
}
- void onEvent(event_t event) override
- {
-#if defined(HARDWARE_KEYS)
- if (event == EVT_KEY_BREAK(KEY_EXIT)) onCancel();
-#endif
- }
-
static void checkbox_event_handler(lv_event_t* e)
{
lv_obj_t* target = lv_event_get_target(e);
@@ -494,7 +485,7 @@ static std::string getModelNotesFile()
return std::string("");
}
-void readModelNotes(bool fromMenu)
+static Window* _readModelNotes(bool fromMenu)
{
std::string modelNotesName = getModelNotesFile();
if (!modelNotesName.empty()) {
@@ -502,49 +493,29 @@ void readModelNotes(bool fromMenu)
if (isFileAvailable(fullPath.c_str())) {
if (fromMenu || !g_model.checklistInteractive)
- new ViewTextWindow(std::string(MODELS_PATH), modelNotesName, ICON_MODEL);
+ return new ViewTextWindow(std::string(MODELS_PATH), modelNotesName, ICON_MODEL);
else
- new ViewChecklistWindow(std::string(MODELS_PATH), modelNotesName, ICON_MODEL);
- } else {
+ return new ViewChecklistWindow(std::string(MODELS_PATH), modelNotesName, ICON_MODEL);
}
}
+ return nullptr;
}
-class CheckListDialog : public FullScreenDialog
+void readModelNotes(bool fromMenu)
{
- public:
- CheckListDialog() :
- FullScreenDialog(WARNING_TYPE_ALERT, "", "", "")
- {
- LED_ERROR_BEGIN();
- checkListOpen = true;
- setCloseCondition(std::bind(&CheckListDialog::warningInactive, this));
- readModelNotes();
- }
-
-#if defined(DEBUG_WINDOWS)
- std::string getName() const override { return "CheckListDialog"; }
-#endif
-
- protected:
-
- bool warningInactive()
- {
- if (!checkListOpen) {
- LED_ERROR_END();
- deleteLater();
- }
- return !checkListOpen;
- }
-};
+ _readModelNotes(fromMenu);
+}
// Blocking version of readModelNotes.
void readChecklist()
{
- std::string s = getModelNotesFile();
- if (!s.empty()) {
- auto dialog = new CheckListDialog();
- dialog->runForever();
+ auto dialog = _readModelNotes(false);
+ if (dialog) {
+ LED_ERROR_BEGIN();
+ MainWindow::instance()->blockUntilClose(true, [=]() {
+ return dialog->deleted();
+ });
+ LED_ERROR_END();
}
}
diff --git a/radio/src/gui/colorlcd/libui/view_text.h b/radio/src/gui/colorlcd/libui/view_text.h
index cc787002e..901e67c96 100644
--- a/radio/src/gui/colorlcd/libui/view_text.h
+++ b/radio/src/gui/colorlcd/libui/view_text.h
@@ -43,10 +43,13 @@ class ViewTextWindow : public Page
void delayedInit() override;
+#if defined(HARDWARE_KEYS)
+ void onPressPGUP() override;
+ void onPressPGDN() override;
+#endif
+
protected:
TextViewer* textViewer = nullptr;
-
- void onEvent(event_t event) override;
};
class ModelNotesPage : public PageGroupItem
diff --git a/radio/src/gui/colorlcd/libui/window.cpp b/radio/src/gui/colorlcd/libui/window.cpp
index d1e79d135..90f3c2b86 100644
--- a/radio/src/gui/colorlcd/libui/window.cpp
+++ b/radio/src/gui/colorlcd/libui/window.cpp
@@ -74,10 +74,14 @@ void Layer::pop(Window* w)
lv_group_t* prevGroup = stack.back().prevGroup;
stack.pop_back();
w = back();
- if (prevGroup) {
- w->assignLvGroup(prevGroup, true);
- } else if (!stack.empty()) {
- w->assignLvGroup(stack.back().group, true);
+ if (w) {
+ if (prevGroup) {
+ w->assignLvGroup(prevGroup, true);
+ } else if (!stack.empty()) {
+ w->assignLvGroup(stack.back().group, true);
+ } else {
+ lv_group_set_default(NULL);
+ }
} else {
lv_group_set_default(NULL);
}
@@ -165,6 +169,8 @@ void Window::eventHandler(lv_event_t *e)
if (code == LV_EVENT_DELETE || deleted()) return;
+ if (customEventHandler(code)) return;
+
switch (code) {
case LV_EVENT_SCROLL: {
lv_coord_t scroll_x = lv_obj_get_scroll_x(target);
@@ -172,7 +178,7 @@ void Window::eventHandler(lv_event_t *e)
if (scrollHandler) scrollHandler(scroll_x, scroll_y);
// exclude pointer based scrolling (only focus scrolling)
- if (!lv_obj_is_scrolling(target) && !noForcedScroll) {
+ if (!lv_obj_is_scrolling(target) && ((windowFlags & NO_FORCED_SCROLL) == 0)) {
lv_point_t *p = (lv_point_t *)lv_event_get_param(e);
lv_coord_t scroll_bottom = lv_obj_get_scroll_bottom(target);
@@ -209,12 +215,6 @@ void Window::eventHandler(lv_event_t *e)
TRACE("LONG PRESS[%p]", this);
_longPressed = onLongPress();
break;
- case LV_EVENT_PRESSED:
- onPressed();
- break;
- case LV_EVENT_RELEASED:
- onReleased();
- break;
default:
break;
}
@@ -311,7 +311,7 @@ void Window::pushLayer(bool hideParent)
if (!layerCreated) {
parentHidden = hideParent;
layerCreated = true;
- if (parentHidden) Window::topWindow()->hide();
+ if (parentHidden && Window::topWindow()) Window::topWindow()->hide();
Layer::push(this);
}
}
@@ -320,7 +320,7 @@ void Window::popLayer()
{
if (layerCreated) {
Layer::pop(this);
- if (parentHidden) Window::topWindow()->show();
+ if (parentHidden && Window::topWindow()) Window::topWindow()->show();
layerCreated = false;
parentHidden = false;
}
@@ -642,7 +642,7 @@ NavWindow::NavWindow(Window *parent, const rect_t &rect,
class SetupTextButton : public TextButton
{
public:
- SetupTextButton(Window* parent, const rect_t& rect, PageButtonDef& entry) :
+ SetupTextButton(Window* parent, const rect_t& rect, const PageButtonDef& entry) :
TextButton(parent, rect, STR_VAL(entry.title))
{
setPressHandler([=] {
@@ -660,14 +660,17 @@ class SetupTextButton : public TextButton
};
SetupButtonGroup::SetupButtonGroup(Window* parent, const rect_t& rect, const char* title, int cols,
- PaddingSize padding, PageDefs pages, coord_t btnHeight) :
+ PaddingSize padding, const PageButtonDef* pages, coord_t btnHeight) :
Window(parent, rect)
{
padAll(padding);
coord_t buttonWidth = (width() - PAD_SMALL * (cols + 1) - PAD_TINY * 2) / cols;
- int rows = (pages.size() + cols - 1) / cols;
+ int size = 0;
+ for (; pages[size].title; size += 1);
+
+ int rows = (size + cols - 1) / cols;
int height = rows * btnHeight + (rows - 1) * PAD_MEDIUM + PAD_TINY * 2;
if (title) {
height += EdgeTxStyles::STD_FONT_HEIGHT + PAD_TINY;
@@ -678,12 +681,12 @@ SetupButtonGroup::SetupButtonGroup(Window* parent, const rect_t& rect, const cha
new Subtitle(this, title);
int n = 0;
- int remaining = pages.size();
+ int remaining = size;
coord_t yo = title ? EdgeTxStyles::STD_FONT_HEIGHT + PAD_TINY : 0;
coord_t xw = buttonWidth + PAD_SMALL;
coord_t xo = (width() - (cols * xw - PAD_SMALL)) / 2;
coord_t x, y;
- for (auto& entry : pages) {
+ for (int p = 0; p < size; p += 1) {
if (remaining < cols && (n % cols == 0)) {
coord_t space = ((cols - remaining) * xw) / (remaining + 1);
xw += space;
@@ -692,14 +695,14 @@ SetupButtonGroup::SetupButtonGroup(Window* parent, const rect_t& rect, const cha
x = xo + (n % cols) * xw;
y = yo + (n / cols) * (btnHeight + PAD_MEDIUM);
- new SetupTextButton(this, {x, y, buttonWidth, btnHeight}, entry);
+ new SetupTextButton(this, {x, y, buttonWidth, btnHeight}, pages[p]);
n += 1;
remaining -= 1;
}
}
SetupLine::SetupLine(Window* parent, coord_t y, coord_t col2, PaddingSize padding, const char* title,
- std::function createEdit, coord_t lblYOffset) :
+ std::function createEdit, coord_t lblYOffset) :
Window(parent, {0, y, LCD_W - padding * 2, 0})
{
padAll(PAD_ZERO);
@@ -726,11 +729,11 @@ SetupLine::SetupLine(Window* parent, coord_t y, coord_t col2, PaddingSize paddin
}
}
-coord_t SetupLine::showLines(Window* parent, coord_t y, coord_t col2, PaddingSize padding, SetupLineDef* setupLines, int lineCount)
+coord_t SetupLine::showLines(Window* parent, coord_t y, coord_t col2, PaddingSize padding, const SetupLineDef* setupLines)
{
Window* w;
- for (int i = 0; i < lineCount; i += 1) {
+ for (int i = 0; setupLines[i].title || setupLines[i].createEdit; i += 1) {
#if !defined(ALL_LANGS)
w = new SetupLine(parent, y, col2, padding, setupLines[i].title, setupLines[i].createEdit);
#else
diff --git a/radio/src/gui/colorlcd/libui/window.h b/radio/src/gui/colorlcd/libui/window.h
index 1012c0d6b..d23fd906d 100644
--- a/radio/src/gui/colorlcd/libui/window.h
+++ b/radio/src/gui/colorlcd/libui/window.h
@@ -25,6 +25,7 @@
#include "definitions.h"
#include "edgetx_helpers.h"
#include "etx_lv_theme.h"
+#include "messaging.h"
class FlexGridLayout;
class FormLine;
@@ -40,8 +41,11 @@ typedef lv_obj_t *(*LvglCreate)(lv_obj_t *);
constexpr WindowFlags OPAQUE = 1u << 0u;
constexpr WindowFlags NO_FOCUS = 1u << 1u;
-constexpr WindowFlags NO_SCROLL = 1u << 2u;
-constexpr WindowFlags NO_CLICK = 1u << 3u;
+constexpr WindowFlags NO_SCROLL = 1u << 2u;
+constexpr WindowFlags NO_CLICK = 1u << 3u;
+constexpr WindowFlags NO_FORCED_SCROLL = 1u << 4u;
+
+//-----------------------------------------------------------------------------
class Window
{
@@ -143,13 +147,10 @@ class Window
virtual void onClicked();
virtual void onCancel();
virtual bool onLongPress();
- virtual void onPressed() {}
- virtual void onReleased() {}
+ virtual void checkEvents();
void invalidate();
- virtual void checkEvents();
-
void attach(Window *window);
void detach();
@@ -164,10 +165,8 @@ class Window
inline lv_obj_t *getLvObj() { return lvobj; }
virtual bool isTopBar() { return false; }
- virtual bool isWidgetsContainer() { return false; }
virtual bool isNavWindow() { return false; }
virtual bool isPageGroup() { return false; }
-
virtual bool isBubblePopup() { return false; }
void setFlexLayout(lv_flex_flow_t flow = LV_FLEX_FLOW_COLUMN,
@@ -182,8 +181,6 @@ class Window
virtual void enable(bool enabled = true);
void disable() { enable(false); }
- void disableForcedScroll() { noForcedScroll = true; }
-
void pushLayer(bool hideParent = false);
void popLayer();
static Window* topWindow();
@@ -204,7 +201,6 @@ class Window
WindowFlags windowFlags = 0;
LcdFlags textFlags = 0;
- bool noForcedScroll = false;
bool _deleted = false;
@@ -222,12 +218,15 @@ class Window
void eventHandler(lv_event_t *e);
static void window_event_cb(lv_event_t *e);
+ virtual bool customEventHandler(lv_event_code_t code) { return false; }
static void delayLoader(lv_event_t* e);
void delayLoad();
virtual void delayedInit() {}
};
+//-----------------------------------------------------------------------------
+
class NavWindow : public Window
{
public:
@@ -260,39 +259,39 @@ struct PageButtonDef {
std::function createPage;
std::function isActive;
std::function enabled;
-
- PageButtonDef(
- STR_TYP title,
- std::function createPage,
- std::function isActive = nullptr,
- std::function enabled = nullptr) :
- title(title), createPage(std::move(createPage)), isActive(std::move(isActive)), enabled(std::move(enabled))
- {}
};
+//-----------------------------------------------------------------------------
+
class SetupButtonGroup : public Window
{
public:
- typedef std::list PageDefs;
-
SetupButtonGroup(Window* parent, const rect_t& rect, const char* title, int cols,
- PaddingSize padding, PageDefs pages, coord_t btnHeight = EdgeTxStyles::UI_ELEMENT_HEIGHT);
+ PaddingSize padding, const PageButtonDef* pages, coord_t btnHeight = EdgeTxStyles::UI_ELEMENT_HEIGHT);
protected:
};
+//-----------------------------------------------------------------------------
+
+class SetupLine;
+
struct SetupLineDef {
STR_TYP title;
- std::function createEdit;
+ std::function createEdit;
};
class SetupLine : public Window
{
public:
SetupLine(Window* parent, coord_t y, coord_t col2, PaddingSize padding, const char* title,
- std::function createEdit, coord_t lblYOffset = 0);
+ std::function createEdit, coord_t lblYOffset = 0);
- static coord_t showLines(Window* parent, coord_t y, coord_t col2, PaddingSize padding, SetupLineDef* setupLines, int lineCount);
+ static coord_t showLines(Window* parent, coord_t y, coord_t col2, PaddingSize padding, const SetupLineDef* setupLines);
+
+ Messaging setupMsg;
protected:
};
+
+//-----------------------------------------------------------------------------
diff --git a/radio/src/gui/colorlcd/lz4_fonts.h b/radio/src/gui/colorlcd/lz4_fonts.h
index 6a90fc201..a5306946f 100644
--- a/radio/src/gui/colorlcd/lz4_fonts.h
+++ b/radio/src/gui/colorlcd/lz4_fonts.h
@@ -25,7 +25,7 @@
/*
Structures for handling LZ4 compressed versions of LVGL fonts
- Compressed data is uncompressed at runtime and these strucutres
+ Compressed data is uncompressed at runtime and these structures
then used to rebuild the LVGL font structures.
Note: this is dependant on the LVGL font structure formats. If
diff --git a/radio/src/gui/colorlcd/mainview/layout.cpp b/radio/src/gui/colorlcd/mainview/layout.cpp
index ad1789366..8641ea4c3 100644
--- a/radio/src/gui/colorlcd/mainview/layout.cpp
+++ b/radio/src/gui/colorlcd/mainview/layout.cpp
@@ -307,36 +307,29 @@ Layout::Layout(Window* parent, const LayoutFactory* factory,
uint8_t* zoneMap) :
WidgetsContainer(parent, {0, 0, LCD_W, LCD_H}, zoneCount),
factory(factory),
- decoration(new ViewMainDecoration(this)),
zoneMap(zoneMap), screenNum(screenNum)
{
+ decoration = new ViewMainDecoration(this);
setWindowFlag(NO_FOCUS);
- show(true);
+ decorationUpdateMsg.subscribe(Messaging::DECORATION_UPDATE, [=](uint32_t param) { updateDecorations(); });
+ updateDecorations();
+ zoneUpdateRequired = false;
}
-void Layout::setTrimsVisible(bool visible)
+void Layout::updateDecorations()
{
- decoration->setTrimsVisible(visible);
-}
-
-void Layout::setSlidersVisible(bool visible)
-{
- decoration->setSlidersVisible(visible);
-}
-
-void Layout::setFlightModeVisible(bool visible)
-{
- decoration->setFlightModeVisible(visible);
+ // Set visible decoration
+ decoration->setSlidersVisible(hasSliders());
+ decoration->setTrimsVisible(hasTrims());
+ decoration->setFlightModeVisible(hasFlightMode());
+ zoneUpdateRequired = true;
}
void Layout::show(bool visible)
{
- // Set visible decoration
- setSlidersVisible(visible && hasSliders());
- setTrimsVisible(visible && hasTrims());
- setFlightModeVisible(visible && hasFlightMode());
-
- if (visible) {
+ decoration->show(visible);
+ if (visible && zoneUpdateRequired) {
+ zoneUpdateRequired = false;
// and update relevant windows
updateZones();
}
@@ -352,7 +345,11 @@ rect_t Layout::getMainZone() const
zone.w -= 2 * PAD_LARGE;
zone.h -= 2 * PAD_LARGE;
}
- return ViewMain::instance()->getMainZone(zone, hasTopbar());
+ if (hasTopbar()) {
+ zone.y += EdgeTxStyles::MENU_HEADER_HEIGHT;
+ zone.h -= EdgeTxStyles::MENU_HEADER_HEIGHT;
+ }
+ return zone;
}
rect_t Layout::getZone(unsigned int index) const
diff --git a/radio/src/gui/colorlcd/mainview/layout.h b/radio/src/gui/colorlcd/mainview/layout.h
index 5fa76be9a..f14b85ecf 100644
--- a/radio/src/gui/colorlcd/mainview/layout.h
+++ b/radio/src/gui/colorlcd/mainview/layout.h
@@ -25,6 +25,7 @@
#include "dataconstants.h"
#include "widget.h"
#include "view_main_decoration.h"
+#include "messaging.h"
#include
@@ -83,8 +84,6 @@ extern const LayoutOption defaultLayoutOptions[];
class Layout: public WidgetsContainer
{
- friend class LayoutFactory;
-
public:
Layout(Window* parent, const LayoutFactory * factory,
int screenNum, uint8_t zoneCount, uint8_t* zoneMap);
@@ -114,12 +113,8 @@ class Layout: public WidgetsContainer
virtual bool hasTrims() const;
virtual bool isMirrored() const;
- // Set decoration visibility
- void setTrimsVisible(bool visible);
- void setSlidersVisible(bool visible);
- void setFlightModeVisible(bool visible);
-
// Updates settings for trims, sliders, pots, etc...
+ virtual void updateDecorations();
void show(bool visible = true) override;
bool isLayout() override { return true; }
@@ -127,11 +122,13 @@ class Layout: public WidgetsContainer
void removeWidget(unsigned int index) override;
protected:
- const LayoutFactory * factory = nullptr;
- std::unique_ptr decoration;
+ const LayoutFactory* factory = nullptr;
+ ViewMainDecoration* decoration = nullptr;
uint8_t* zoneMap = nullptr;
int screenNum;
rect_t lastMainZone = {0,0,0,0};
+ Messaging decorationUpdateMsg;
+ bool zoneUpdateRequired = false;
// Last time we refreshed the window
uint32_t lastRefresh = 0;
diff --git a/radio/src/gui/colorlcd/mainview/screen_setup.cpp b/radio/src/gui/colorlcd/mainview/screen_setup.cpp
index aa0a73ad0..7dd76932c 100644
--- a/radio/src/gui/colorlcd/mainview/screen_setup.cpp
+++ b/radio/src/gui/colorlcd/mainview/screen_setup.cpp
@@ -51,7 +51,7 @@ class LayoutChoice : public Button
LayoutFactorySetter setValue) :
Button(parent, {0, 0, LayoutFactory::BM_W + PAD_LARGE + PAD_SMALL, LayoutFactory::BM_H + PAD_LARGE + PAD_SMALL}),
getValue(std::move(getValue)),
- _setValue(std::move(setValue))
+ setValue(std::move(setValue))
{
padAll(PAD_ZERO);
canvas = lv_canvas_create(lvobj);
@@ -64,7 +64,7 @@ class LayoutChoice : public Button
auto menu = new Menu();
for (auto layout : LayoutFactory::getRegisteredLayouts()) {
menu->addLine(layout->getBitmap(), layout->getName(),
- [=]() { setValue(layout); });
+ [=]() { if (setValue) setValue(layout); update(); });
}
auto it =
@@ -82,7 +82,7 @@ class LayoutChoice : public Button
protected:
lv_obj_t* canvas = nullptr;
std::function getValue;
- std::function _setValue;
+ std::function setValue;
void update()
{
@@ -98,12 +98,6 @@ class LayoutChoice : public Button
lv_coord_t h = bitmap->height;
lv_canvas_set_buffer(canvas, (void*)&bitmap->data[0], w, h, LV_IMG_CF_ALPHA_8BIT);
}
-
- void setValue(const LayoutFactory* layout)
- {
- if (_setValue) _setValue(layout);
- update();
- }
};
#if LANDSCAPE
@@ -117,14 +111,8 @@ static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT,
LV_GRID_TEMPLATE_LAST};
ScreenSetupPage::ScreenSetupPage(unsigned index, const PageDef& pageDef) :
- PageGroupItem(pageDef)
+ PageGroupItem(pageDef), customScreenIndex(index)
{
- update(index + QuickMenu::pageIndex(QM_UI_SCREEN1));
-}
-
-void ScreenSetupPage::update(uint8_t index)
-{
- customScreenIndex = index - QuickMenu::pageIndex(QM_UI_SCREEN1);
}
void ScreenSetupPage::build(Window* window)
@@ -271,12 +259,19 @@ void ScreenSetupPage::buildLayoutOptions()
GET_DEFAULT(value->boolValue),
[=](int newValue) {
value->boolValue = newValue;
+ Messaging::send(Messaging::DECORATION_UPDATE);
SET_DIRTY();
});
break;
case LayoutOption::Color:
- new ColorPicker(line, rect_t{}, GET_SET_DEFAULT(value->unsignedValue));
+ new ColorPicker(line, rect_t{},
+ GET_DEFAULT(value->unsignedValue),
+ [=](int newValue) {
+ value->unsignedValue = newValue;
+ Messaging::send(Messaging::DECORATION_UPDATE);
+ SET_DIRTY();
+ });
break;
default:
diff --git a/radio/src/gui/colorlcd/mainview/screen_setup.h b/radio/src/gui/colorlcd/mainview/screen_setup.h
index 7c1659ec5..ca0665653 100644
--- a/radio/src/gui/colorlcd/mainview/screen_setup.h
+++ b/radio/src/gui/colorlcd/mainview/screen_setup.h
@@ -45,8 +45,6 @@ class ScreenSetupPage : public PageGroupItem
void build(Window* form) override;
- void update(uint8_t index) override;
-
static void addScreen();
protected:
diff --git a/radio/src/gui/colorlcd/mainview/topbar.cpp b/radio/src/gui/colorlcd/mainview/topbar.cpp
index d869b2452..332406bd7 100644
--- a/radio/src/gui/colorlcd/mainview/topbar.cpp
+++ b/radio/src/gui/colorlcd/mainview/topbar.cpp
@@ -72,7 +72,7 @@ bool TopBarPersistentData::isWidget(int idx, const char* s)
//-----------------------------------------------------------------------------
SetupTopBarWidgetsPage::SetupTopBarWidgetsPage() :
- Window(ViewMain::instance(), rect_t{})
+ NavWindow(ViewMain::instance(), rect_t{})
{
// remember focus
pushLayer();
@@ -116,33 +116,15 @@ void SetupTopBarWidgetsPage::deleteLater()
storageDirty(EE_MODEL);
}
-void SetupTopBarWidgetsPage::onEvent(event_t event)
-{
-#if defined(HARDWARE_KEYS)
- if (event == EVT_KEY_FIRST(KEY_PAGEUP) || event == EVT_KEY_FIRST(KEY_PAGEDN) ||
- event == EVT_KEY_FIRST(KEY_SYS) || event == EVT_KEY_FIRST(KEY_MODEL)) {
- killEvents(event);
- } else if (event == EVT_KEY_FIRST(KEY_TELE)) {
- onCancel();
- } else {
- Window::onEvent(event);
- }
-#else
- Window::onEvent(event);
-#endif
-}
-
//-----------------------------------------------------------------------------
-constexpr uint32_t TOPBAR_REFRESH = 1000 / 10; // 10 Hz
-
TopBar::TopBar(Window * parent) :
WidgetsContainer(parent, {0, 0, LCD_W, EdgeTxStyles::MENU_HEADER_HEIGHT}, MAX_TOPBAR_ZONES)
{
setWindowFlag(NO_FOCUS);
etx_solid_bg(lvobj, COLOR_THEME_SECONDARY1_INDEX);
- headerIcon = new HeaderIcon(parent, ICON_EDGETX, [=]() { ViewMain::instance()->openMenu(); });
+ headerIcon = new HeaderIcon(parent, ICON_EDGETX, [=]() { QuickMenu::openQuickMenu(); });
}
unsigned int TopBar::getZonesCount() const
@@ -203,15 +185,6 @@ coord_t TopBar::getVisibleHeight(float visible) const // 0.0 -> 1.0
return (coord_t)h;
}
-void TopBar::checkEvents()
-{
- uint32_t now = lv_tick_get();
- if (now - lastRefresh >= TOPBAR_REFRESH) {
- lastRefresh = now;
- WidgetsContainer::checkEvents();
- }
-}
-
void TopBar::removeWidget(unsigned int index)
{
if (index >= zoneCount) return;
diff --git a/radio/src/gui/colorlcd/mainview/topbar.h b/radio/src/gui/colorlcd/mainview/topbar.h
index 9be71762a..0a313d48d 100644
--- a/radio/src/gui/colorlcd/mainview/topbar.h
+++ b/radio/src/gui/colorlcd/mainview/topbar.h
@@ -27,7 +27,7 @@ class HeaderIcon;
//-----------------------------------------------------------------------------
-class SetupTopBarWidgetsPage : public Window
+class SetupTopBarWidgetsPage : public NavWindow
{
public:
explicit SetupTopBarWidgetsPage();
@@ -38,8 +38,19 @@ class SetupTopBarWidgetsPage : public Window
void onClicked() override;
void onCancel() override;
- void onEvent(event_t event) override;
void deleteLater() override;
+
+#if defined(HARDWARE_KEYS)
+ void onPressSYS() override {}
+ void onLongPressSYS() override {}
+ void onPressMDL() override {}
+ void onLongPressMDL() override {}
+ void onPressPGUP() override {}
+ void onPressPGDN() override {}
+ void onLongPressPGUP() override {}
+ void onLongPressPGDN() override {}
+ void onPressTELE() override { onCancel(); }
+#endif
};
//-----------------------------------------------------------------------------
@@ -64,8 +75,6 @@ class TopBar: public WidgetsContainer
void setEdgeTxButtonVisible(float visible);
coord_t getVisibleHeight(float visible) const; // 0.0 -> 1.0
- void checkEvents() override;
-
bool isTopBar() override { return true; }
void removeWidget(unsigned int index) override;
diff --git a/radio/src/gui/colorlcd/mainview/view_logical_switches.cpp b/radio/src/gui/colorlcd/mainview/view_logical_switches.cpp
index 953bf6935..2e81f0859 100644
--- a/radio/src/gui/colorlcd/mainview/view_logical_switches.cpp
+++ b/radio/src/gui/colorlcd/mainview/view_logical_switches.cpp
@@ -25,6 +25,7 @@
#include "edgetx.h"
#include "etx_lv_theme.h"
#include "quick_menu.h"
+#include "static.h"
#include "switches.h"
#if PORTRAIT
@@ -208,34 +209,6 @@ class LogicalSwitchDisplayFooter : public Window
lv_obj_t* lsDelay = nullptr;
};
-class LogicalSwitchDisplayButton : public TextButton
-{
- public:
- LogicalSwitchDisplayButton(Window* parent, const rect_t& rect,
- std::string text, unsigned index) :
- TextButton(parent, rect, std::move(text), nullptr), index(index)
- {
- }
-
- void checkEvents() override
- {
- bool newvalue = getSwitch(SWSRC_FIRST_LOGICAL_SWITCH + index);
- if (value != newvalue) {
- if (newvalue) {
- lv_obj_add_state(lvobj, LV_STATE_CHECKED);
- } else {
- lv_obj_clear_state(lvobj, LV_STATE_CHECKED);
- }
- value = newvalue;
- }
- ButtonBase::checkEvents();
- }
-
- protected:
- unsigned index = 0;
- bool value = false;
-};
-
LogicalSwitchesViewPage::LogicalSwitchesViewPage() :
PageGroupItem(STR_MONITOR_SWITCHES, QM_TOOLS_LS_MON)
{
@@ -273,24 +246,13 @@ void LogicalSwitchesViewPage::build(Window* window)
strAppendSigned(&lsString[1], i + 1, 2);
if (isActive) {
- auto button = new LogicalSwitchDisplayButton(
- window, {x, y, BTN_WIDTH, btnHeight}, lsString, i);
-
- button->setFocusHandler([=](bool focus) {
- if (focus) {
- footer->setIndex(i);
- }
- return 0;
- });
+ auto button = new TextButton(window, {x, y, BTN_WIDTH, btnHeight}, lsString);
+ button->setCheckHandler([=]() { button->check(getSwitch(SWSRC_FIRST_LOGICAL_SWITCH + i)); });
+ button->setFocusHandler([=](bool focus) { if (focus) { footer->setIndex(i); } });
} else {
if (btnHeight > EdgeTxStyles::STD_FONT_HEIGHT)
y += (btnHeight - EdgeTxStyles::STD_FONT_HEIGHT) / 2;
- auto lbl = etx_label_create(window->getLvObj());
- lv_obj_set_size(lbl, BTN_WIDTH, btnHeight);
- lv_obj_set_pos(lbl, x, y);
- etx_obj_add_style(lbl, styles->text_align_center, LV_PART_MAIN);
- etx_txt_color(lbl, COLOR_THEME_DISABLED_INDEX);
- lv_label_set_text(lbl, lsString.c_str());
+ new StaticText(window, {x, y, BTN_WIDTH, btnHeight}, lsString, COLOR_THEME_DISABLED_INDEX, CENTERED);
}
}
}
diff --git a/radio/src/gui/colorlcd/mainview/view_main.cpp b/radio/src/gui/colorlcd/mainview/view_main.cpp
index c26905003..70e1fe3eb 100644
--- a/radio/src/gui/colorlcd/mainview/view_main.cpp
+++ b/radio/src/gui/colorlcd/mainview/view_main.cpp
@@ -108,14 +108,6 @@ ViewMain::ViewMain() :
ViewMain::~ViewMain() { _instance = nullptr; }
-void ViewMain::deleteLater()
-{
- if (_deleted) return;
-
- NavWindow::deleteLater();
- QuickMenu::shutdownQuickMenu();
-}
-
void ViewMain::addMainView(WidgetsContainer* view, uint32_t viewId)
{
TRACE("addMainView(0x%p, %d)", view, viewId);
@@ -141,18 +133,6 @@ unsigned ViewMain::getMainViewsCount() const
return lv_obj_get_child_cnt(tile_view);
}
-rect_t ViewMain::getMainZone(rect_t zone, bool hasTopbar) const
-{
- if (isVisible) {
- auto visibleHeight = topbar->getVisibleHeight(hasTopbar ? 1.0 : 0.0);
- zone.y += visibleHeight;
- zone.h -= visibleHeight;
- return zone;
- } else {
- return {0, 0, LCD_W, LCD_H};
- }
-}
-
unsigned ViewMain::getCurrentMainView() const
{
return lv_obj_get_scroll_x(tile_view) / width();
@@ -248,9 +228,8 @@ void ViewMain::doKeyShortcut(event_t event)
{
QMPage pg = g_eeGeneral.getKeyShortcut(event);
if (pg == QM_OPEN_QUICK_MENU) {
- if (!QuickMenu::isOpen()) openMenu();
+ QuickMenu::openQuickMenu();
} else {
- QuickMenu::closeQuickMenu();
QuickMenu::openPage(pg);
}
}
@@ -263,20 +242,18 @@ void ViewMain::onLongPressTELE() { doKeyShortcut(EVT_KEY_LONG(KEY_TELE)); }
void ViewMain::onPressPGUP()
{
if (!widget_select) {
- QuickMenu::closeQuickMenu();
previousMainView();
}
}
void ViewMain::onPressPGDN()
{
if (!widget_select) {
- QuickMenu::closeQuickMenu();
nextMainView();
}
}
#endif
-void ViewMain::onClicked() { openMenu(); }
+void ViewMain::onClicked() { QuickMenu::openQuickMenu(); }
void ViewMain::onCancel()
{
@@ -333,11 +310,6 @@ bool ViewMain::enableWidgetSelect(bool enable)
return true;
}
-void ViewMain::openMenu()
-{
- QuickMenu::openQuickMenu();
-}
-
void ViewMain::ws_timer(lv_timer_t* t)
{
ViewMain* view = (ViewMain*)t->user_data;
diff --git a/radio/src/gui/colorlcd/mainview/view_main.h b/radio/src/gui/colorlcd/mainview/view_main.h
index 7fcc66ad5..ad2270110 100644
--- a/radio/src/gui/colorlcd/mainview/view_main.h
+++ b/radio/src/gui/colorlcd/mainview/view_main.h
@@ -45,10 +45,6 @@ class ViewMain : public NavWindow
void updateTopbarVisibility();
bool enableWidgetSelect(bool enable);
- // Get the available space in the middle of the screen
- // (without topbar)
- rect_t getMainZone(rect_t zone, bool hasTopbar) const;
-
unsigned getMainViewsCount() const;
unsigned getCurrentMainView() const;
void setCurrentMainView(unsigned view);
@@ -60,7 +56,6 @@ class ViewMain : public NavWindow
void onClicked() override;
void onCancel() override;
- void openMenu();
bool onLongPress() override;
void show(bool visible = true) override;
@@ -85,8 +80,6 @@ class ViewMain : public NavWindow
bool widget_select = false;
lv_timer_t* widget_select_timer = nullptr;
- void deleteLater() override;
-
// Set topbar visibility [0.0 -> 1.0]
void setTopbarVisible(float visible);
void setEdgeTxButtonVisible(float visible);
diff --git a/radio/src/gui/colorlcd/mainview/view_main_decoration.cpp b/radio/src/gui/colorlcd/mainview/view_main_decoration.cpp
index 229a46cb2..3bbcee6f6 100644
--- a/radio/src/gui/colorlcd/mainview/view_main_decoration.cpp
+++ b/radio/src/gui/colorlcd/mainview/view_main_decoration.cpp
@@ -30,23 +30,24 @@
#include "hal/adc_driver.h"
-ViewMainDecoration::ViewMainDecoration(Window* parent, bool showTrims, bool showSliders, bool showFM) :
- parent(parent), showTrims(showTrims), showSliders(showSliders), showFM(showFM)
+ViewMainDecoration::ViewMainDecoration(Window* parent, bool calibration) :
+ Window(parent, {0, 0, parent->width(), parent->height()})
{
- w_ml = layoutBox(parent, LV_ALIGN_LEFT_MID, LV_FLEX_FLOW_ROW_REVERSE);
- w_mr = layoutBox(parent, LV_ALIGN_RIGHT_MID, LV_FLEX_FLOW_ROW);
- w_bl = layoutBox(parent, LV_ALIGN_BOTTOM_LEFT, LV_FLEX_FLOW_COLUMN);
- w_br = layoutBox(parent, LV_ALIGN_BOTTOM_RIGHT, LV_FLEX_FLOW_COLUMN);
+ w_ml = layoutBox(this, LV_ALIGN_LEFT_MID, LV_FLEX_FLOW_ROW_REVERSE);
+ w_mr = layoutBox(this, LV_ALIGN_RIGHT_MID, LV_FLEX_FLOW_ROW);
+ w_bl = layoutBox(this, LV_ALIGN_BOTTOM_LEFT, LV_FLEX_FLOW_COLUMN);
+ w_br = layoutBox(this, LV_ALIGN_BOTTOM_RIGHT, LV_FLEX_FLOW_COLUMN);
- w_bc = layoutBox(parent, LV_ALIGN_BOTTOM_MID, LV_FLEX_FLOW_COLUMN);
+ w_bc = layoutBox(this, LV_ALIGN_BOTTOM_MID, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(w_bc->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
- if (this->showTrims)
+ if (!calibration) {
createTrims(w_ml, w_mr, w_bl, w_br);
- if (this->showFM)
createFlightMode(w_bc);
- if (this->showSliders)
- createSliders(w_ml, w_mr, w_bl, w_bc, w_br);
+ } else {
+ showTrims = showFM = false;
+ }
+ createSliders(w_ml, w_mr, w_bl, w_bc, w_br);
}
Window* ViewMainDecoration::layoutBox(Window* parent, lv_align_t align,
@@ -109,7 +110,7 @@ static bool canTrimShow(int idx)
rect_t ViewMainDecoration::getMainZone() const
{
- coord_t x = 0, w = LCD_W, h = LCD_H;
+ coord_t x = 0, w = width(), h = height();
coord_t bh = 0;
if (showSliders) {
diff --git a/radio/src/gui/colorlcd/mainview/view_main_decoration.h b/radio/src/gui/colorlcd/mainview/view_main_decoration.h
index 9441b9a4d..4421f4269 100644
--- a/radio/src/gui/colorlcd/mainview/view_main_decoration.h
+++ b/radio/src/gui/colorlcd/mainview/view_main_decoration.h
@@ -25,10 +25,10 @@
class MainViewTrim;
-class ViewMainDecoration
+class ViewMainDecoration : public Window
{
public:
- ViewMainDecoration(Window* parent, bool showTrims = true, bool showSliders = true, bool showFM = true);
+ ViewMainDecoration(Window* parent, bool calibration = false);
// Set decoration visibility
void setTrimsVisible(bool visible);
@@ -65,9 +65,9 @@ class ViewMainDecoration
Window* w_bl;
Window* w_bc;
Window* w_br;
- bool showTrims;
- bool showSliders;
- bool showFM;
+ bool showTrims = true;
+ bool showSliders = true;
+ bool showFM = true;
Window* sliders[SLIDERS_MAX] = { 0 };
MainViewTrim* trims[TRIMS_MAX] = { 0 };
diff --git a/radio/src/gui/colorlcd/mainview/widget.cpp b/radio/src/gui/colorlcd/mainview/widget.cpp
index 48d6ea661..bccb98295 100644
--- a/radio/src/gui/colorlcd/mainview/widget.cpp
+++ b/radio/src/gui/colorlcd/mainview/widget.cpp
@@ -160,8 +160,6 @@ Widget::Widget(const WidgetFactory* factory, Window* parent, const rect_t& rect,
{
setWindowFlag(NO_FOCUS | NO_SCROLL);
- if (parent->isTopBar()) fsAllowed = false;
-
setPressHandler([&]() -> uint8_t {
// When ViewMain is in "widget select mode",
// the widget is added to a focus group
@@ -172,16 +170,16 @@ Widget::Widget(const WidgetFactory* factory, Window* parent, const rect_t& rect,
void Widget::openMenu()
{
- if (fsAllowed && ViewMain::instance()->isAppMode())
+ if (!parent->isTopBar() && ViewMain::instance()->isAppMode())
{
setFullscreen(true);
return;
}
- if (hasOptions() || fsAllowed) {
+ if (hasOptions() || !parent->isTopBar()) {
Menu* menu = new Menu();
menu->setTitle(getFactory()->getDisplayName());
- if (fsAllowed) {
+ if (!parent->isTopBar()) {
menu->addLine(STR_WIDGET_FULLSCREEN, [&]() { setFullscreen(true); });
}
if (hasOptions()) {
@@ -209,11 +207,12 @@ void Widget::update() {}
void Widget::setFullscreen(bool enable)
{
- if (!fsAllowed || (enable == fullscreen)) return;
+ if (!!parent->isTopBar() || (enable == fullscreen)) return;
fullscreen = enable;
// Show or hide ViewMain widgets and decorations
+ Messaging::send(Messaging::DECORATION_UPDATE);
ViewMain::instance()->show(!enable);
// Leave Fullscreen Mode
diff --git a/radio/src/gui/colorlcd/mainview/widget.h b/radio/src/gui/colorlcd/mainview/widget.h
index 2a80c90c2..2da507ccb 100644
--- a/radio/src/gui/colorlcd/mainview/widget.h
+++ b/radio/src/gui/colorlcd/mainview/widget.h
@@ -126,7 +126,6 @@ class Widget : public ButtonBase
int screenNum;
int zoneNum;
bool fullscreen = false;
- bool fsAllowed = true;
bool closeFS = false;
lv_obj_t* focusBorder = nullptr;
lv_style_t borderStyle;
diff --git a/radio/src/gui/colorlcd/mainview/widgets_container.h b/radio/src/gui/colorlcd/mainview/widgets_container.h
index 05bc870ad..7fb9a8990 100644
--- a/radio/src/gui/colorlcd/mainview/widgets_container.h
+++ b/radio/src/gui/colorlcd/mainview/widgets_container.h
@@ -45,7 +45,6 @@ class WidgetsContainer: public Window
virtual bool isLayout() { return false; }
virtual bool isAppMode() const { return false; }
- bool isWidgetsContainer() override { return true; }
void deleteLater() override;
diff --git a/radio/src/gui/colorlcd/mainview/widgets_setup.cpp b/radio/src/gui/colorlcd/mainview/widgets_setup.cpp
index 6becb8e25..0b9223f82 100644
--- a/radio/src/gui/colorlcd/mainview/widgets_setup.cpp
+++ b/radio/src/gui/colorlcd/mainview/widgets_setup.cpp
@@ -115,7 +115,7 @@ void SetupWidgetsPageSlot::addNewWidget(WidgetsContainer* container,
}
SetupWidgetsPage::SetupWidgetsPage(uint8_t customScreenIdx) :
- Window(ViewMain::instance(), rect_t{}), customScreenIdx(customScreenIdx)
+ NavWindow(ViewMain::instance(), rect_t{}), customScreenIdx(customScreenIdx)
{
pushLayer();
@@ -172,20 +172,3 @@ void SetupWidgetsPage::deleteLater()
storageDirty(EE_MODEL);
}
-
-void SetupWidgetsPage::onEvent(event_t event)
-{
-#if defined(HARDWARE_KEYS)
- if (event == EVT_KEY_FIRST(KEY_PAGEUP) ||
- event == EVT_KEY_FIRST(KEY_PAGEDN) || event == EVT_KEY_FIRST(KEY_SYS) ||
- event == EVT_KEY_FIRST(KEY_MODEL)) {
- killEvents(event);
- } else if (event == EVT_KEY_FIRST(KEY_TELE)) {
- onCancel();
- } else {
- Window::onEvent(event);
- }
-#else
- Window::onEvent(event);
-#endif
-}
diff --git a/radio/src/gui/colorlcd/mainview/widgets_setup.h b/radio/src/gui/colorlcd/mainview/widgets_setup.h
index 9db629c62..3c9f4cd86 100644
--- a/radio/src/gui/colorlcd/mainview/widgets_setup.h
+++ b/radio/src/gui/colorlcd/mainview/widgets_setup.h
@@ -26,7 +26,7 @@
class ScreenMenu;
class WidgetsContainer;
-class SetupWidgetsPage : public Window
+class SetupWidgetsPage : public NavWindow
{
public:
SetupWidgetsPage(uint8_t customScreenIdx);
@@ -41,11 +41,21 @@ class SetupWidgetsPage : public Window
void onClicked() override;
void onCancel() override;
+#if defined(HARDWARE_KEYS)
+ void onPressSYS() override {}
+ void onLongPressSYS() override {}
+ void onPressMDL() override {}
+ void onLongPressMDL() override {}
+ void onPressPGUP() override {}
+ void onPressPGDN() override {}
+ void onLongPressPGUP() override {}
+ void onLongPressPGDN() override {}
+#endif
+
protected:
uint8_t customScreenIdx;
unsigned savedView = 0;
- void onEvent(event_t event) override;
void deleteLater() override;
};
diff --git a/radio/src/gui/colorlcd/model/curveedit.cpp b/radio/src/gui/colorlcd/model/curveedit.cpp
index 1fb98c22a..f39c47e1f 100644
--- a/radio/src/gui/colorlcd/model/curveedit.cpp
+++ b/radio/src/gui/colorlcd/model/curveedit.cpp
@@ -38,25 +38,32 @@ static const lv_coord_t default_row_dsc[] = {LV_GRID_CONTENT,
class CurveEdit : public Curve
{
public:
- CurveEdit(Window* parent, const rect_t& rect, uint8_t index) :
+ CurveEdit(Window* parent, const rect_t& rect, uint8_t index, mixsrc_t source) :
Curve(parent, rect,
[=](int x) -> int { return applyCustomCurve(x, index); },
- [=]() -> int { return getValue(currentSource); }
- ),
+ [=]() -> int { return getValue(currentSource); }),
index(index),
- current(0)
+ current(0),
+ currentSource(source)
{
setWindowFlag(NO_FOCUS);
- updatePreview();
- }
- void setCurrentSource(mixsrc_t source)
- {
- currentSource = source;
- if (source)
- lockSource = true;
- else
- lockSource = false;
+ lockSource = currentSource;
+
+ for (int i = 0; i < 17; i += 1) {
+ auto p = lv_obj_create(lvobj);
+ etx_solid_bg(p, COLOR_THEME_PRIMARY2_INDEX);
+ etx_obj_add_style(p, styles->circle, LV_PART_MAIN);
+ etx_obj_add_style(p, styles->border, LV_PART_MAIN);
+ etx_obj_add_style(p, styles->border_color[COLOR_THEME_SECONDARY1_INDEX], LV_PART_MAIN);
+ lv_obj_set_size(p, POS_PT_SZ, POS_PT_SZ);
+ lv_obj_add_flag(p, LV_OBJ_FLAG_HIDDEN);
+ pointDots[i] = p;
+ }
+
+ previewUpdateMsg.subscribe(Messaging::CURVE_EDIT, [=](uint32_t param) { updatePreview(); });
+
+ updatePreview();
}
void updatePreview()
@@ -66,6 +73,25 @@ class CurveEdit : public Curve
for (uint8_t i = 0; i < 5 + curve.points; i++) {
addPoint(getPoint(index, i));
}
+ update();
+ }
+
+ void clearPoints()
+ {
+ points.clear();
+ for (int i = 0; i < 17; i += 1)
+ lv_obj_add_flag(pointDots[i], LV_OBJ_FLAG_HIDDEN);
+ }
+
+ void addPoint(const point_t& point)
+ {
+ int i = points.size();
+ coord_t x = getPointX(point.x);
+ coord_t y = getPointY(point.y);
+ lv_obj_set_pos(pointDots[i], x - POS_PT_SZ / 2, y - POS_PT_SZ / 2);
+ lv_obj_clear_flag(pointDots[i], LV_OBJ_FLAG_HIDDEN);
+
+ points.push_back(point);
}
protected:
@@ -73,15 +99,18 @@ class CurveEdit : public Curve
uint8_t current;
mixsrc_t currentSource = 0;
bool lockSource = false;
+ std::list points;
+ lv_obj_t* pointDots[17] = { nullptr };
+ Messaging previewUpdateMsg;
- void checkEvents(void) override
+ void checkEvents() override
{
if (!lockSource) {
int16_t val = getMovedSource(MIXSRC_FIRST_STICK);
if (val > 0)
currentSource = val;
}
- Window::checkEvents();
+ Curve::checkEvents();
}
};
@@ -98,12 +127,6 @@ class CurveDataEdit : public Window
padBottom(PAD_SMALL);
}
- void setCurveEdit(CurveEdit* _curveEdit)
- {
- curveEdit = _curveEdit;
- update();
- }
-
void update()
{
clear();
@@ -137,7 +160,6 @@ class CurveDataEdit : public Window
protected:
uint8_t index;
- CurveEdit* curveEdit;
NumberEdit* numEditX[16];
void curvePointsRow(Window* parent, coord_t y, int start, int count,
@@ -195,7 +217,7 @@ class CurveDataEdit : public Window
numEditX[px + 1]->setMin(newValue);
}
SET_DIRTY();
- curveEdit->updatePreview();
+ Messaging::send(Messaging::CURVE_EDIT);
},
CENTERED);
}
@@ -232,16 +254,15 @@ class CurveDataEdit : public Window
[=](int32_t newValue) {
points[i + start] = newValue;
SET_DIRTY();
- curveEdit->updatePreview();
+ Messaging::send(Messaging::CURVE_EDIT);
},
CENTERED);
}
}
};
-CurveEditWindow::CurveEditWindow(uint8_t index,
- std::function refreshView) :
- Page(ICON_MODEL_CURVES, PAD_ZERO), index(index), refreshView(refreshView)
+CurveEditWindow::CurveEditWindow(uint8_t index, mixsrc_t source) :
+ Page(ICON_MODEL_CURVES, PAD_ZERO), index(index), source(source)
{
buildBody(body);
buildHeader(header);
@@ -306,7 +327,7 @@ void CurveEditWindow::buildBody(Window* window)
auto smooth =
new TextButton(iLine, rect_t{0, 0, EdgeTxStyles::EDIT_FLD_WIDTH_NARROW, 0}, STR_SMOOTH, [=]() {
g_model.curves[index].smooth = !g_model.curves[index].smooth;
- curveEdit->updatePreview();
+ Messaging::send(Messaging::CURVE_EDIT);
return g_model.curves[index].smooth;
});
smooth->check(g_model.curves[index].smooth);
@@ -336,7 +357,7 @@ void CurveEditWindow::buildBody(Window* window)
curve.type = newValue;
}
SET_DIRTY();
- curveEdit->updatePreview();
+ Messaging::send(Messaging::CURVE_EDIT);
if (curveDataEdit) {
curveDataEdit->update();
}
@@ -364,7 +385,7 @@ void CurveEditWindow::buildBody(Window* window)
}
curve.points = newValue;
SET_DIRTY();
- curveEdit->updatePreview();
+ Messaging::send(Messaging::CURVE_EDIT);
if (curveDataEdit) {
curveDataEdit->update();
}
@@ -385,22 +406,16 @@ void CurveEditWindow::buildBody(Window* window)
0, 0, box->width(),
box->height() - (EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_TINY * 2) * 2},
index);
+ curveDataEdit->update();
// Curve editor
lv_obj_set_flex_align(line->getLvObj(), LV_FLEX_ALIGN_CENTER,
LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
- curveEdit = new CurveEdit(line, {0, 0, CurveDataEdit::CURVE_WIDTH, CurveDataEdit::CURVE_WIDTH}, index);
-
- curveDataEdit->setCurveEdit(curveEdit);
+ new CurveEdit(line, {0, 0, CurveDataEdit::CURVE_WIDTH, CurveDataEdit::CURVE_WIDTH}, index, source);
}
void CurveEditWindow::onCancel()
{
- if (refreshView) refreshView();
+ Messaging::send(Messaging::CURVE_UPDATE);
Page::onCancel();
}
-
-void CurveEditWindow::setCurrentSource(mixsrc_t source)
-{
- curveEdit->setCurrentSource(source);
-}
diff --git a/radio/src/gui/colorlcd/model/curveedit.h b/radio/src/gui/colorlcd/model/curveedit.h
index 25f30554c..b85732e62 100644
--- a/radio/src/gui/colorlcd/model/curveedit.h
+++ b/radio/src/gui/colorlcd/model/curveedit.h
@@ -25,23 +25,18 @@
#include "page.h"
#include "window.h"
-class NumberEdit;
-class CurveEdit;
class CurveDataEdit;
class CurveEditWindow : public Page
{
public:
CurveEditWindow(uint8_t index,
- std::function refreshView = nullptr);
-
- void setCurrentSource(mixsrc_t source);
+ mixsrc_t source = 0);
protected:
uint8_t index;
- CurveEdit* curveEdit = nullptr;
CurveDataEdit* curveDataEdit = nullptr;
- std::function refreshView = nullptr;
+ mixsrc_t source = 0;
void buildHeader(Window* window);
void buildBody(Window* window);
diff --git a/radio/src/gui/colorlcd/model/function_switches.cpp b/radio/src/gui/colorlcd/model/function_switches.cpp
index 73c45bb61..d061daf00 100644
--- a/radio/src/gui/colorlcd/model/function_switches.cpp
+++ b/radio/src/gui/colorlcd/model/function_switches.cpp
@@ -41,19 +41,60 @@ const char* edgetx_fs_manual_url =
"https://edgetx.gitbook.io/edgetx-user-manual/b-and-w-radios/model-select/"
"setup#function-switches";
-class FunctionSwitch : public Window
+//-----------------------------------------------------------------------------
+
+FunctionSwitchBase::FunctionSwitchBase(Window* parent, uint8_t sw) :
+ Window(parent, {0, 0, LCD_W - PAD_SMALL * 2, ROW_H}),
+ switchIndex(sw)
+{
+ padAll(PAD_TINY);
+
+ std::string s(CHAR_SWITCH);
+ s += switchGetDefaultName(switchIndex);
+
+ new StaticText(this, {PAD_LARGE, PAD_MEDIUM, SW_W, EdgeTxStyles::STD_FONT_HEIGHT}, s);
+
+#if defined(FUNCTION_SWITCHES_RGB_LEDS)
+#if NARROW_LAYOUT
+ offLabel = new StaticText(this, {C1_X - C1_W - PAD_TINY, C1_Y + COLLBL_YO, C1_W, 0}, STR_OFF, COLOR_THEME_PRIMARY1_INDEX, FONT(XS) | RIGHT);
+ onLabel = new StaticText(this, {C2_X - C2_W - PAD_TINY, C2_Y + COLLBL_YO, C2_W, 0}, STR_ON_ONE_SWITCHES[0], COLOR_THEME_PRIMARY1_INDEX, FONT(XS) | RIGHT);
+#endif
+
+ overrideLabel = new StaticText(this, {OVRLBL_X, C1_Y + EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_LARGE, OVRLBL_W, 0},
+ STR_LUA_OVERRIDE, COLOR_THEME_PRIMARY1_INDEX, FONT(XS) | RIGHT);
+#endif
+}
+
+void FunctionSwitchBase::setLEDState(uint8_t typ)
+{
+#if defined(FUNCTION_SWITCHES_RGB_LEDS)
+#if NARROW_LAYOUT
+ offLabel->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
+ onLabel->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
+#endif
+ offColor->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
+ onColor->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
+ overrideLabel->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
+ onOverride->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
+ offOverride->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
+ if (typ != SWITCH_NONE && typ != SWITCH_GLOBAL)
+ setHeight(ROW_H);
+ else
+ setHeight(ROW_HS);
+#endif
+}
+
+#if defined(FUNCTION_SWITCHES_RGB_LEDS)
+uint8_t FunctionSwitchBase::activeSwitch = 0;
+#endif
+
+//-----------------------------------------------------------------------------
+
+class FunctionSwitch : public FunctionSwitchBase
{
public:
- FunctionSwitch(Window* parent, uint8_t sw) :
- Window(parent, {0, 0, LCD_W - PAD_SMALL * 2, ROW_H}), switchIndex(sw)
+ FunctionSwitch(Window* parent, uint8_t sw) : FunctionSwitchBase(parent, sw)
{
- padAll(PAD_TINY);
-
- std::string s(CHAR_SWITCH);
- s += switchGetDefaultName(switchIndex);
-
- new StaticText(this, {PAD_LARGE, PAD_MEDIUM, SW_W, EdgeTxStyles::STD_FONT_HEIGHT}, s);
-
new ModelTextEdit(this, {NM_X, 0, NM_W, 0},
g_model.cfsName(switchIndex), LEN_SWITCH_NAME);
@@ -118,17 +159,13 @@ class FunctionSwitch : public Window
});
#if defined(FUNCTION_SWITCHES_RGB_LEDS)
-#if NARROW_LAYOUT
- offLabel = new StaticText(this, {C1_X - C1_W - PAD_TINY, C1_Y + COLLBL_YO, C1_W, 0}, STR_OFF, COLOR_THEME_PRIMARY1_INDEX, FONT(XS) | RIGHT);
- onLabel = new StaticText(this, {C2_X - C2_W - PAD_TINY, C2_Y + COLLBL_YO, C2_W, 0}, STR_ON_ONE_SWITCHES[0], COLOR_THEME_PRIMARY1_INDEX, FONT(XS) | RIGHT);
-#endif
-
offValue = g_model.cfsOffColor(switchIndex);
onValue = g_model.cfsOnColor(switchIndex);
offColor = new ColorPicker(
this, {C1_X, C1_Y, C1_W, 0},
[=]() -> int { // getValue
+ activeSwitch = switchIndex;
return g_model.cfsOffColor(switchIndex).getColor() | RGB888_FLAG;
},
[=](int newValue) { // setValue
@@ -142,12 +179,12 @@ class FunctionSwitch : public Window
offValue = g_model.cfsOffColor(switchIndex);
setFSEditOverride(-1, 0);
SET_DIRTY();
- },
- [=](int newValue) { previewColor(newValue); }, ETX_RGB888);
+ }, ETX_RGB888);
onColor = new ColorPicker(
this, {C2_X, C2_Y, C2_W, 0},
[=]() -> int { // getValue
+ activeSwitch = switchIndex;
return g_model.cfsOnColor(switchIndex).getColor() | RGB888_FLAG;
},
[=](int newValue) { // setValue
@@ -161,11 +198,8 @@ class FunctionSwitch : public Window
onValue = g_model.cfsOnColor(switchIndex);
setFSEditOverride(-1, 0);
SET_DIRTY();
- },
- [=](int newValue) { previewColor(newValue); }, ETX_RGB888);
+ }, ETX_RGB888);
- overrideLabel = new StaticText(this, {OVRLBL_X, C1_Y + EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_LARGE, OVRLBL_W, 0},
- STR_LUA_OVERRIDE, COLOR_THEME_PRIMARY1_INDEX, FONT(XS) | RIGHT);
offOverride = new ToggleSwitch(this, {OVROFF_X, C1_Y + EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE, 0, 0},
[=]() { return g_model.cfsOffColorLuaOverride(switchIndex); },
[=](bool v) { g_model.cfsSetOffColorLuaOverride(switchIndex, v); });
@@ -177,104 +211,15 @@ class FunctionSwitch : public Window
setState();
}
-#if defined(FUNCTION_SWITCHES_RGB_LEDS)
- static LAYOUT_VAL_SCALED(SW_W, 70)
- static constexpr coord_t NM_X = SW_W + PAD_SMALL;
- static LAYOUT_VAL_SCALED(NM_W, 60)
- static constexpr coord_t TP_X = NM_X + NM_W + PAD_SMALL;
- static LAYOUT_VAL_SCALED(TP_W, 78)
- static constexpr coord_t GR_X = TP_X + TP_W + PAD_SMALL;
- static LAYOUT_VAL_SCALED(GR_W, 84)
- static constexpr coord_t ST_X = GR_X + GR_W + PAD_SMALL;
- static LAYOUT_VAL_SCALED(ST_W, 60)
- static constexpr coord_t ROW_HS = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE * 2;
-#if NARROW_LAYOUT
- static constexpr coord_t ROW_H = EdgeTxStyles::UI_ELEMENT_HEIGHT * 3 + PAD_OUTLINE * 4;
- static constexpr coord_t C1_X = GR_X;
- static constexpr coord_t C1_Y = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE;
- static LAYOUT_VAL_SCALED(C1_W, 40)
- static constexpr coord_t C2_X = ST_X;
- static constexpr coord_t C2_Y = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE;
- static LAYOUT_VAL_SCALED(C2_W, 40)
- static constexpr coord_t OVRLBL_X = NM_X;
- static constexpr coord_t OVRLBL_W = NM_W + TP_W;
- static constexpr coord_t OVROFF_X = C1_X;
- static constexpr coord_t COLLBL_YO = PAD_MEDIUM;
-#else
- static constexpr coord_t ROW_H = EdgeTxStyles::UI_ELEMENT_HEIGHT * 2 + PAD_OUTLINE * 3;
- static constexpr coord_t C1_X = ST_X + ST_W + PAD_SMALL;
- static constexpr coord_t C1_Y = 0;
- static LAYOUT_VAL_SCALED(C1_W, 40)
- static constexpr coord_t C2_X = C1_X + C1_W + PAD_SMALL;
- static constexpr coord_t C2_Y = 0;
- static LAYOUT_VAL_SCALED(C2_W, 40)
- static constexpr coord_t OVRLBL_X = GR_X;
- static constexpr coord_t OVRLBL_W = GR_W + ST_W - PAD_LARGE;
- static constexpr coord_t OVROFF_X = C1_X - PAD_MEDIUM * 2;
- static constexpr coord_t COLLBL_YO = PAD_SMALL;
-#endif
-#else
- static constexpr coord_t ROW_H = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE * 2;
- static constexpr coord_t SW_W = (LCD_W - PAD_SMALL * 2 - PAD_TINY * 4) / 5;
- static constexpr coord_t NM_X = SW_W + PAD_TINY;
- static LAYOUT_VAL_SCALED(NM_W, 80)
- static constexpr coord_t TP_X = NM_X + SW_W + PAD_TINY;
- static LAYOUT_VAL_SCALED(TP_W, 86)
- static constexpr coord_t GR_X = TP_X + SW_W + PAD_TINY;
- static LAYOUT_VAL_SCALED(GR_W, 94)
- static constexpr coord_t ST_X = GR_X + SW_W + PAD_LARGE * 2 + PAD_SMALL;
- static LAYOUT_VAL_SCALED(ST_W, 70)
-#endif
-
protected:
- uint8_t switchIndex;
- Choice* typeChoice = nullptr;
Choice* groupChoice = nullptr;
- Choice* startChoice = nullptr;
-#if defined(FUNCTION_SWITCHES_RGB_LEDS)
-#if defined(NARROW_LAYOUT)
- StaticText *offLabel = nullptr;
- StaticText *onLabel = nullptr;
-#endif
- ColorPicker* offColor = nullptr;
- ColorPicker* onColor = nullptr;
- RGBLedColor offValue;
- RGBLedColor onValue;
- StaticText* overrideLabel = nullptr;
- ToggleSwitch* onOverride = nullptr;
- ToggleSwitch* offOverride = nullptr;
-#endif
- int lastType = -1;
-
-#if defined(FUNCTION_SWITCHES_RGB_LEDS)
- void previewColor(int newValue)
- {
- // Convert color index to RGB
- newValue = color32ToRGB(newValue);
- setFSEditOverride(switchIndex, newValue);
- }
-#endif
void setState()
{
uint8_t typ = g_model.cfsType(switchIndex);
startChoice->show(typ == SWITCH_2POS && g_model.cfsGroup(switchIndex) == 0);
groupChoice->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
-#if defined(FUNCTION_SWITCHES_RGB_LEDS)
-#if NARROW_LAYOUT
- offLabel->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
- onLabel->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
-#endif
- offColor->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
- onColor->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
- overrideLabel->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
- onOverride->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
- offOverride->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
- if (typ != SWITCH_NONE && typ != SWITCH_GLOBAL)
- setHeight(ROW_H);
- else
- setHeight(ROW_HS);
-#endif
+ setLEDState(typ);
}
void checkEvents() override
@@ -288,6 +233,8 @@ class FunctionSwitch : public Window
}
};
+//-----------------------------------------------------------------------------
+
class SwitchGroup : public Window
{
public:
@@ -360,14 +307,24 @@ class SwitchGroup : public Window
Choice* startChoice;
};
-ModelFunctionSwitches::ModelFunctionSwitches() : Page(ICON_MODEL_SETUP)
+//-----------------------------------------------------------------------------
+
+FunctionSwitchesBase::FunctionSwitchesBase(EdgeTxIcon icon, const char* title) : Page(icon)
{
- header->setTitle(STR_MAIN_MENU_MODEL_SETTINGS);
+ header->setTitle(title);
header->setTitle2(STR_FUNCTION_SWITCHES);
body->padAll(PAD_TINY);
body->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO);
+#if defined(FUNCTION_SWITCHES_RGB_LEDS)
+ previewMsg.subscribe(Messaging::COLOR_PREVIEW, [=](uint32_t param) {
+ // Convert color index to RGB
+ uint32_t c = color32ToRGB(param);
+ setFSEditOverride(FunctionSwitchBase::editSwitch(), c);
+ });
+#endif
+
auto box = new Window(body, {0, 0, LV_PCT(100), LV_SIZE_CONTENT});
new StaticText(box, {0, 0, FunctionSwitch::SW_W, 0}, STR_SWITCHES);
new StaticText(box, {FunctionSwitch::NM_X + PAD_OUTLINE, 0, FunctionSwitch::NM_W, 0}, STR_NAME, COLOR_THEME_PRIMARY1_INDEX, FONT(XS));
@@ -380,20 +337,14 @@ ModelFunctionSwitches::ModelFunctionSwitches() : Page(ICON_MODEL_SETUP)
new StaticText(box, {FunctionSwitch::C1_X + PAD_OUTLINE, 0, FunctionSwitch::C1_W, 0}, STR_OFF, COLOR_THEME_PRIMARY1_INDEX, FONT(XS));
new StaticText(box, {FunctionSwitch::C2_X + PAD_OUTLINE, 0, FunctionSwitch::C2_W, 0}, STR_ON_ONE_SWITCHES[0], COLOR_THEME_PRIMARY1_INDEX, FONT(XS));
#endif
+}
- for (uint8_t i = 0; i < switchGetMaxSwitches(); i += 1) {
- if (switchIsCustomSwitch(i))
- new FunctionSwitch(body, i);
- }
-
- for (uint8_t i = 1; i <= 3; i += 1) {
- groupLines[i - 1] = new SwitchGroup(body, i);
- }
-
+void FunctionSwitchesBase::addQRCode()
+{
#if defined(HARDWARE_TOUCH)
body->padBottom(PAD_LARGE);
- box = new Window(body, {0, 0, LV_PCT(100), LV_SIZE_CONTENT});
+ auto box = new Window(body, {0, 0, LV_PCT(100), LV_SIZE_CONTENT});
new StaticText(box, rect_t{}, STR_MORE_INFO);
@@ -403,25 +354,48 @@ ModelFunctionSwitches::ModelFunctionSwitches() : Page(ICON_MODEL_SETUP)
lv_qrcode_update(qr, edgetx_fs_manual_url, strlen(edgetx_fs_manual_url));
lv_obj_set_pos(qr, (LCD_W - 150) / 2, EdgeTxStyles::STD_FONT_HEIGHT);
#endif
+}
+
+void FunctionSwitchesBase::checkEvents()
+{
+ setState();
+ Page::checkEvents();
+}
+
+//-----------------------------------------------------------------------------
+
+ModelFunctionSwitches::ModelFunctionSwitches() : FunctionSwitchesBase(ICON_MODEL_SETUP, STR_MAIN_MENU_MODEL_SETTINGS)
+{
+ for (uint8_t i = 0; i < switchGetMaxSwitches(); i += 1) {
+ if (switchIsCustomSwitch(i))
+ new FunctionSwitch(body, i);
+ }
+
+ for (uint8_t i = 1; i <= 3; i += 1) {
+ groupLines[i - 1] = new SwitchGroup(body, i);
+ }
+
+ addQRCode();
setState();
}
void ModelFunctionSwitches::setState()
{
- int cnt = 0;
for (int i = 0; i < 3; i += 1) {
- cnt += getSwitchCountInFSGroup(i + 1);
groupLines[i]->show(firstSwitchInGroup(i + 1) >= 0);
groupLines[i]->refresh();
}
- startupHeader->show(cnt != NUM_FUNCTIONS_SWITCHES);
-}
-
-void ModelFunctionSwitches::checkEvents()
-{
- setState();
- Page::checkEvents();
+ bool showStartHeader = false;
+ for (uint8_t i = 0; i < switchGetMaxSwitches(); i += 1) {
+ if (switchIsCustomSwitch(i) && g_model.cfsType(i) == SWITCH_2POS && g_model.cfsGroup(i) == 0) {
+ showStartHeader = true;
+ break;
+ }
+ }
+ startupHeader->show(showStartHeader);
}
#endif
+
+//-----------------------------------------------------------------------------
diff --git a/radio/src/gui/colorlcd/model/function_switches.h b/radio/src/gui/colorlcd/model/function_switches.h
index 2f42e18d4..962c00bbc 100644
--- a/radio/src/gui/colorlcd/model/function_switches.h
+++ b/radio/src/gui/colorlcd/model/function_switches.h
@@ -23,22 +23,132 @@
#if defined(FUNCTION_SWITCHES)
+#include "edgetx.h"
#include "page.h"
+#include "messaging.h"
+class Choice;
+class ColorPicker;
+class StaticText;
class SwitchGroup;
+class ToggleSwitch;
-class ModelFunctionSwitches : public Page
+//-----------------------------------------------------------------------------
+
+class FunctionSwitchBase : public Window
+{
+ public:
+ FunctionSwitchBase(Window* parent, uint8_t sw);
+
+#if defined(FUNCTION_SWITCHES_RGB_LEDS)
+ static uint8_t editSwitch() { return activeSwitch; }
+#endif
+
+#if defined(FUNCTION_SWITCHES_RGB_LEDS)
+ static LAYOUT_VAL_SCALED(SW_W, 70)
+ static constexpr coord_t NM_X = SW_W + PAD_SMALL;
+ static LAYOUT_VAL_SCALED(NM_W, 60)
+ static constexpr coord_t TP_X = NM_X + NM_W + PAD_SMALL;
+ static LAYOUT_VAL_SCALED(TP_W, 78)
+ static constexpr coord_t GR_X = TP_X + TP_W + PAD_SMALL;
+ static LAYOUT_VAL_SCALED(GR_W, 84)
+ static constexpr coord_t ST_X = GR_X + GR_W + PAD_SMALL;
+ static LAYOUT_VAL_SCALED(ST_W, 60)
+ static constexpr coord_t ROW_HS = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE * 2;
+#if NARROW_LAYOUT
+ static constexpr coord_t ROW_H = EdgeTxStyles::UI_ELEMENT_HEIGHT * 3 + PAD_OUTLINE * 4;
+ static constexpr coord_t C1_X = GR_X;
+ static constexpr coord_t C1_Y = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE;
+ static LAYOUT_VAL_SCALED(C1_W, 40)
+ static constexpr coord_t C2_X = ST_X;
+ static constexpr coord_t C2_Y = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE;
+ static LAYOUT_VAL_SCALED(C2_W, 40)
+ static constexpr coord_t OVRLBL_X = NM_X;
+ static constexpr coord_t OVRLBL_W = NM_W + TP_W;
+ static constexpr coord_t OVROFF_X = C1_X;
+ static constexpr coord_t COLLBL_YO = PAD_MEDIUM;
+#else
+ static constexpr coord_t ROW_H = EdgeTxStyles::UI_ELEMENT_HEIGHT * 2 + PAD_OUTLINE * 3;
+ static constexpr coord_t C1_X = ST_X + ST_W + PAD_SMALL;
+ static constexpr coord_t C1_Y = 0;
+ static LAYOUT_VAL_SCALED(C1_W, 40)
+ static constexpr coord_t C2_X = C1_X + C1_W + PAD_SMALL;
+ static constexpr coord_t C2_Y = 0;
+ static LAYOUT_VAL_SCALED(C2_W, 40)
+ static constexpr coord_t OVRLBL_X = GR_X;
+ static constexpr coord_t OVRLBL_W = GR_W + ST_W - PAD_LARGE;
+ static constexpr coord_t OVROFF_X = C1_X - PAD_MEDIUM * 2;
+ static constexpr coord_t COLLBL_YO = PAD_SMALL;
+#endif
+#else
+ static constexpr coord_t ROW_H = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE * 2;
+ static constexpr coord_t SW_W = (LCD_W - PAD_SMALL * 2 - PAD_TINY * 4) / 5;
+ static constexpr coord_t NM_X = SW_W + PAD_TINY;
+ static LAYOUT_VAL_SCALED(NM_W, 80)
+ static constexpr coord_t TP_X = NM_X + SW_W + PAD_TINY;
+ static LAYOUT_VAL_SCALED(TP_W, 86)
+ static constexpr coord_t GR_X = TP_X + SW_W + PAD_TINY;
+ static LAYOUT_VAL_SCALED(GR_W, 94)
+ static constexpr coord_t ST_X = GR_X + SW_W + PAD_LARGE * 2 + PAD_SMALL;
+ static LAYOUT_VAL_SCALED(ST_W, 70)
+#endif
+
+ protected:
+ uint8_t switchIndex;
+ Choice* typeChoice = nullptr;
+ Choice* startChoice = nullptr;
+#if defined(FUNCTION_SWITCHES_RGB_LEDS)
+#if defined(NARROW_LAYOUT)
+ StaticText *offLabel = nullptr;
+ StaticText *onLabel = nullptr;
+#endif
+ ColorPicker* offColor = nullptr;
+ ColorPicker* onColor = nullptr;
+ RGBLedColor offValue;
+ RGBLedColor onValue;
+ StaticText* overrideLabel = nullptr;
+ ToggleSwitch* onOverride = nullptr;
+ ToggleSwitch* offOverride = nullptr;
+ static uint8_t activeSwitch;
+#endif
+ int lastType = -1;
+
+ void setLEDState(uint8_t typ);
+};
+
+//-----------------------------------------------------------------------------
+
+class FunctionSwitchesBase : public Page
+{
+ public:
+ FunctionSwitchesBase(EdgeTxIcon icon, const char* title);
+
+ void addQRCode();
+
+ protected:
+ BitmapBuffer* qrcode = nullptr;
+ StaticText* startupHeader = nullptr;
+#if defined(FUNCTION_SWITCHES_RGB_LEDS)
+ Messaging previewMsg;
+#endif
+
+ virtual void setState() = 0;
+ void checkEvents() override;
+};
+
+//-----------------------------------------------------------------------------
+
+class ModelFunctionSwitches : public FunctionSwitchesBase
{
public:
ModelFunctionSwitches();
protected:
SwitchGroup* groupLines[3] = {nullptr};
- BitmapBuffer* qrcode = nullptr;
- StaticText* startupHeader = nullptr;
- void setState();
- void checkEvents() override;
+ void setState() override;
};
#endif
+
+//-----------------------------------------------------------------------------
diff --git a/radio/src/gui/colorlcd/model/input_edit.cpp b/radio/src/gui/colorlcd/model/input_edit.cpp
index 5b8548fc4..eb342a9e2 100644
--- a/radio/src/gui/colorlcd/model/input_edit.cpp
+++ b/radio/src/gui/colorlcd/model/input_edit.cpp
@@ -47,7 +47,7 @@ static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
class InputEditAdvanced : public Page
{
public:
- InputEditAdvanced(InputEditWindow* parent, uint8_t input_n, uint8_t index) : Page(ICON_MODEL_INPUTS)
+ InputEditAdvanced(uint8_t input_n, uint8_t index) : Page(ICON_MODEL_INPUTS)
{
std::string title2(getSourceString(MIXSRC_FIRST_INPUT + input_n));
header->setTitle(STR_MENUINPUTS);
@@ -66,7 +66,7 @@ class InputEditAdvanced : public Page
[=]() -> int16_t { return 4 - input->mode; },
[=](int16_t newValue) {
input->mode = 4 - newValue;
- parent->previewUpdate();
+ Messaging::send(Messaging::CURVE_UPDATE);
SET_DIRTY();
});
@@ -218,10 +218,7 @@ void InputEditWindow::buildBody(Window* form)
input->curve.value = newValue;
updatePreview = true;
SET_DIRTY();
- }, MIXSRC_FIRST, input->srcRaw,
- [=]() {
- updatePreview = true;
- });
+ }, MIXSRC_FIRST, input->srcRaw);
lv_obj_set_style_grid_cell_x_align(param->getLvObj(), LV_GRID_ALIGN_STRETCH,
0);
@@ -229,7 +226,7 @@ void InputEditWindow::buildBody(Window* form)
line->padAll(PAD_LARGE);
auto btn =
new TextButton(line, rect_t{}, LV_SYMBOL_SETTINGS, [=]() -> uint8_t {
- new InputEditAdvanced(this, this->input, index);
+ new InputEditAdvanced(this->input, index);
return 0;
});
lv_obj_set_width(btn->getLvObj(), lv_pct(100));
@@ -237,6 +234,8 @@ void InputEditWindow::buildBody(Window* form)
void InputEditWindow::checkEvents()
{
+ if (_deleted) return;
+
ExpoData* input = expoAddress(index);
getvalue_t val;
@@ -292,7 +291,7 @@ void InputEditWindow::checkEvents()
if (updatePreview) {
updatePreview = false;
- if (preview) preview->update();
+ Messaging::send(Messaging::CURVE_UPDATE);
}
Page::checkEvents();
diff --git a/radio/src/gui/colorlcd/model/input_edit.h b/radio/src/gui/colorlcd/model/input_edit.h
index acdf2e624..d89283662 100644
--- a/radio/src/gui/colorlcd/model/input_edit.h
+++ b/radio/src/gui/colorlcd/model/input_edit.h
@@ -30,8 +30,6 @@ class InputEditWindow : public Page
public:
InputEditWindow(int8_t input, uint8_t index);
- void previewUpdate() { updatePreview = true; }
-
static LAYOUT_SIZE(CURVE_W_LANDSCAPE, 138, 120)
static LAYOUT_ORIENTATION_SCALED(INPUT_EDIT_CURVE_WIDTH, CURVE_W_LANDSCAPE, 176)
static LAYOUT_ORIENTATION(INPUT_EDIT_CURVE_HEIGHT, INPUT_EDIT_CURVE_WIDTH, LAYOUT_SCALE(132))
diff --git a/radio/src/gui/colorlcd/model/model_curves.cpp b/radio/src/gui/colorlcd/model/model_curves.cpp
index b3855c7e0..48f2622cd 100644
--- a/radio/src/gui/colorlcd/model/model_curves.cpp
+++ b/radio/src/gui/colorlcd/model/model_curves.cpp
@@ -43,7 +43,7 @@ class CurveButton : public Button
s = strAppend(s, ":");
strAppend(s, g_model.curves[index].name, LEN_CURVE_NAME);
}
- title = new StaticText(this, {PAD_SMALL, -1, width() - PAD_MEDIUM * 2, EdgeTxStyles::STD_FONT_HEIGHT}, buf,
+ title = new StaticText(this, {0, 0, lv_pct(100), EdgeTxStyles::STD_FONT_HEIGHT}, buf,
COLOR_THEME_SECONDARY1_INDEX, CENTERED | FONT(BOLD));
etx_txt_color(title->getLvObj(), COLOR_THEME_PRIMARY2_INDEX,
LV_PART_MAIN | LV_STATE_USER_1);
@@ -51,13 +51,6 @@ class CurveButton : public Button
etx_solid_bg(title->getLvObj(), COLOR_THEME_FOCUS_INDEX,
LV_PART_MAIN | LV_STATE_USER_1);
- hdrLeft = new StaticIcon(this, 0, 0, ICON_ROUND_TITLE_LEFT,
- COLOR_THEME_SECONDARY2_INDEX);
- auto mask = getBuiltinIcon(ICON_ROUND_TITLE_RIGHT);
- hdrRight = new StaticIcon(this, width() - mask->width - PAD_BORDER * 2, 0,
- ICON_ROUND_TITLE_RIGHT,
- COLOR_THEME_SECONDARY2_INDEX);
-
// Preview
preview = new CurveRenderer(
this,
@@ -83,19 +76,13 @@ class CurveButton : public Button
uint8_t index;
StaticText *title;
CurveRenderer *preview;
- StaticIcon *hdrLeft = nullptr;
- StaticIcon *hdrRight = nullptr;
void checkEvents() override
{
if (hasFocus()) {
lv_obj_add_state(title->getLvObj(), LV_STATE_USER_1);
- hdrLeft->setColor(COLOR_THEME_FOCUS_INDEX);
- hdrRight->setColor(COLOR_THEME_FOCUS_INDEX);
} else {
lv_obj_clear_state(title->getLvObj(), LV_STATE_USER_1);
- hdrLeft->setColor(COLOR_THEME_SECONDARY2_INDEX);
- hdrRight->setColor(COLOR_THEME_SECONDARY2_INDEX);
}
}
};
@@ -117,7 +104,7 @@ ModelCurvesPage::ModelCurvesPage(const PageDef& pageDef) : PageGroupItem(pageDef
// can be called from any other screen to edit a curve.
// currently called from model_mixes.cpp on longpress.
-void ModelCurvesPage::pushEditCurve(int index, std::function refreshView, mixsrc_t source)
+void ModelCurvesPage::pushEditCurve(int index, mixsrc_t source)
{
if (!isCurveUsed(index)) {
CurveHeader &curve = g_model.curves[index];
@@ -125,8 +112,7 @@ void ModelCurvesPage::pushEditCurve(int index, std::function refresh
initPoints(curve, points);
}
- auto cv = new CurveEditWindow(index, refreshView);
- cv->setCurrentSource(source);
+ new CurveEditWindow(index, source);
}
void ModelCurvesPage::rebuild(Window *window)
diff --git a/radio/src/gui/colorlcd/model/model_curves.h b/radio/src/gui/colorlcd/model/model_curves.h
index 8fe364fc6..d3f041377 100644
--- a/radio/src/gui/colorlcd/model/model_curves.h
+++ b/radio/src/gui/colorlcd/model/model_curves.h
@@ -29,7 +29,7 @@ class ModelCurvesPage : public PageGroupItem
public:
ModelCurvesPage(const PageDef& pageDef);
- static void pushEditCurve(int index, std::function refreshView, mixsrc_t source);
+ static void pushEditCurve(int index, mixsrc_t source);
virtual void build(Window* window) override;
diff --git a/radio/src/gui/colorlcd/model/model_outputs.cpp b/radio/src/gui/colorlcd/model/model_outputs.cpp
index 7ddd89937..b749a728c 100644
--- a/radio/src/gui/colorlcd/model/model_outputs.cpp
+++ b/radio/src/gui/colorlcd/model/model_outputs.cpp
@@ -28,6 +28,7 @@
#include "getset_helpers.h"
#include "list_line_button.h"
#include "menu.h"
+#include "messaging.h"
#include "output_edit.h"
#include "toggleswitch.h"
@@ -109,6 +110,8 @@ class OutputLineButton : public ListLineButton
setHeight(CH_LINE_H);
padAll(PAD_ZERO);
+ refreshMsg.subscribe(Messaging::REFRESH, [=](uint32_t param) { refresh(); });
+
delayLoad();
}
@@ -187,6 +190,7 @@ class OutputLineButton : public ListLineButton
protected:
int value = -10000;
+ Messaging refreshMsg;
bool isActive() const override { return false; }
@@ -232,8 +236,7 @@ void ModelOutputsPage::build(Window* window)
STR_TRIMS2OFFSETS, STR_ADD_ALL_TRIMS_TO_SUBTRIMS,
[=] {
moveTrimsToOffsets();
- for (int i = 0; i < outputButtons.size(); i += 1)
- outputButtons[i]->refresh();
+ Messaging::send(Messaging::REFRESH);
});
return 0;
});
@@ -247,8 +250,6 @@ void ModelOutputsPage::build(Window* window)
lv_obj_set_pos(btn->getLvObj(), TRIMB_X, TRIMB_Y + (ch * (OutputLineButton::CH_LINE_H + PAD_TINY)));
btn->setWidth(TRIMB_W);
- outputButtons.emplace_back(btn);
-
LimitData* output = limitAddress(ch);
btn->setPressHandler([=]() -> uint8_t {
Menu* menu = new Menu();
diff --git a/radio/src/gui/colorlcd/model/model_select.cpp b/radio/src/gui/colorlcd/model/model_select.cpp
index da77e2427..3f370a789 100644
--- a/radio/src/gui/colorlcd/model/model_select.cpp
+++ b/radio/src/gui/colorlcd/model/model_select.cpp
@@ -71,7 +71,7 @@ class ModelButton : public Button
delayLoad();
}
- void addDetails()
+ void delayedInit() override
{
coord_t w = width() - PAD_SMALL * 2;
@@ -98,16 +98,18 @@ class ModelButton : public Button
}
lv_label_set_long_mode(modelName->getLvObj(), LV_LABEL_LONG_DOT);
- checkEvents();
+ bool chk = (modelCell == modelslist.getCurrentModel());
+ if (chk != checked()) {
+ check(chk);
+ if (chk)
+ lv_obj_add_state(modelName->getLvObj(), LV_STATE_USER_1);
+ else
+ lv_obj_clear_state(modelName->getLvObj(), LV_STATE_USER_1);
+ }
lv_obj_update_layout(lvobj);
}
- void delayedInit() override
- {
- addDetails();
- }
-
const char *modelFilename() { return modelCell->modelFilename; }
ModelCell *getModelCell() const { return modelCell; }
@@ -169,18 +171,6 @@ class ModelButton : public Button
COLOR_THEME_SECONDARY1_INDEX, CENTERED | font);
}
- void checkEvents() override
- {
- bool chk = (modelCell == modelslist.getCurrentModel());
- if (chk != checked()) {
- check(chk);
- if (chk)
- lv_obj_add_state(modelName->getLvObj(), LV_STATE_USER_1);
- else
- lv_obj_clear_state(modelName->getLvObj(), LV_STATE_USER_1);
- }
- }
-
void onClicked() override
{
setFocused();
diff --git a/radio/src/gui/colorlcd/model/model_setup.cpp b/radio/src/gui/colorlcd/model/model_setup.cpp
index effd3ea4d..41b736e05 100644
--- a/radio/src/gui/colorlcd/model/model_setup.cpp
+++ b/radio/src/gui/colorlcd/model/model_setup.cpp
@@ -24,6 +24,7 @@
#include
#include "button_matrix.h"
+#include "dialog.h"
#include "edgetx.h"
#include "etx_lv_theme.h"
#include "filechoice.h"
@@ -33,12 +34,12 @@
#include "model_heli.h"
#include "module_setup.h"
#include "preflight_checks.h"
+#include "sourcechoice.h"
#include "storage/modelslist.h"
#include "textedit.h"
-#include "throttle_params.h"
#include "timer_setup.h"
+#include "toggleswitch.h"
#include "trainer_setup.h"
-#include "trims_setup.h"
#if defined(FUNCTION_SWITCHES)
#include "function_switches.h"
@@ -69,7 +70,7 @@ static void viewOption(Window* parent, coord_t x, coord_t y,
lbl->show(getValue() == 0);
}
-static SetupLineDef viewOptionsPageSetupLines[] = {
+const static SetupLineDef viewOptionsPageSetupLines[] = {
{
STR_DEF(STR_RADIO_MENU_TABS), nullptr,
},
@@ -172,6 +173,7 @@ static SetupLineDef viewOptionsPageSetupLines[] = {
g_eeGeneral.modelTelemetryDisabled);
}
},
+ {nullptr, nullptr},
};
struct CenterBeepsMatrix : public ButtonMatrix {
@@ -254,7 +256,7 @@ struct CenterBeepsMatrix : public ButtonMatrix {
uint8_t ana_idx[MAX_ANALOG_INPUTS];
};
-static SetupLineDef otherPageSetupLines[] = {
+const static SetupLineDef otherPageSetupLines[] = {
{
STR_DEF(STR_JITTER_FILTER),
[](Window* parent, coord_t x, coord_t y) {
@@ -272,9 +274,116 @@ static SetupLineDef otherPageSetupLines[] = {
parent->setHeight(bm->height() + PAD_SMALL);
}
},
+ {nullptr, nullptr},
};
-static SetupLineDef setupLines[] = {
+const static SetupLineDef throttleParamsSetupLines[] = {
+ {
+ // Throttle reversed
+ STR_DEF(STR_THROTTLEREVERSE),
+ [](Window* parent, coord_t x, coord_t y) {
+ new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_model.throttleReversed));
+ }
+ },
+ {
+ // Throttle source
+ STR_DEF(STR_TTRACE),
+ [](Window* parent, coord_t x, coord_t y) {
+ auto sc = new SourceChoice(parent, {x, y, 0, 0}, 0, MIXSRC_LAST_CH,
+ []() {return throttleSource2Source(g_model.thrTraceSrc); },
+ [](int16_t src) {
+ int16_t val = source2ThrottleSource(src);
+ if (val >= 0) {
+ g_model.thrTraceSrc = val;
+ SET_DIRTY();
+ }
+ });
+ sc->setAvailableHandler(isThrottleSourceAvailable);
+ }
+ },
+ {
+ // Throttle trim
+ STR_DEF(STR_TTRIM),
+ [](Window* parent, coord_t x, coord_t y) {
+ new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_model.thrTrim));
+ }
+ },
+ {
+ // Throttle trim source
+ STR_DEF(STR_TTRIM_SW),
+ [](Window* parent, coord_t x, coord_t y) {
+ new SourceChoice(
+ parent, {x, y, 0, 0}, MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM,
+ []() { return g_model.getThrottleStickTrimSource(); },
+ [](int16_t src) {
+ g_model.setThrottleStickTrimSource(src);
+ SET_DIRTY();
+ });
+ }
+ },
+ {nullptr, nullptr},
+};
+
+#if defined(USE_HATS_AS_KEYS)
+static LAYOUT_VAL_SCALED(HATSMODE_W, 120)
+#endif
+
+const static SetupLineDef trimsSetupLines[] = {
+ {
+ // Reset trims
+ nullptr,
+ [](Window* parent, coord_t x, coord_t y) {
+ new TextButton(parent, {PAD_TINY, y, LCD_W - PAD_MEDIUM * 2, 0}, STR_RESET_BTN, []() -> uint8_t {
+ for (auto &fm : g_model.flightModeData) memclear(&fm.trim, sizeof(fm.trim));
+ SET_DIRTY();
+ AUDIO_WARNING1();
+ return 0;
+ });
+ }
+ },
+#if defined(USE_HATS_AS_KEYS)
+ {
+ // Hats mode for NV14/EL18
+ STR_DEF(STR_HATSMODE),
+ [](Window* parent, coord_t x, coord_t y) {
+ new Choice(parent, {x, y, HATSMODE_W, 0}, STR_HATSOPT, HATSMODE_TRIMS_ONLY, HATSMODE_GLOBAL,
+ GET_SET_DEFAULT(g_model.hatsMode));
+ new TextButton(parent, {x + HATSMODE_W + PAD_SMALL, y, 0, 0}, "?", [=]() {
+ new MessageDialog(STR_HATSMODE_KEYS, STR_HATSMODE_KEYS_HELP, "",
+ LEFT);
+ return 0;
+ });
+ }
+ },
+#endif
+ {
+ // Trim step
+ STR_DEF(STR_TRIMINC),
+ [](Window* parent, coord_t x, coord_t y) {
+ new Choice(parent, {x, y, 0, 0}, STR_VTRIMINC, -2, 2,
+ GET_SET_DEFAULT(g_model.trimInc));
+ }
+ },
+ {
+ // Extended trims
+ STR_DEF(STR_ETRIMS),
+ [](Window* parent, coord_t x, coord_t y) {
+ new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_model.extendedTrims));
+ }
+ },
+ {
+ // Display trims
+ // TODO: move to "Screen setup" ?
+ STR_DEF(STR_DISPLAY_TRIMS),
+ [](Window* parent, coord_t x, coord_t y) {
+ new Choice(parent, {x, y, 0, 0}, STR_VDISPLAYTRIMS, 0, 2,
+ GET_SET_DEFAULT(g_model.displayTrims));
+ }
+ },
+ {nullptr, nullptr},
+};
+
+const static SetupLineDef setupLines[] = {
{
// Model name
STR_DEF(STR_MODELNAME),
@@ -342,35 +451,39 @@ static SetupLineDef setupLines[] = {
}, false, STR_BITMAP);
}
},
+ {nullptr, nullptr},
+};
+
+const static PageButtonDef modelSetupButtons[] = {
+ // Modules
+ {STR_DEF(STR_INTERNALRF), []() { new ModulePage(INTERNAL_MODULE); }, []() { return g_model.moduleData[INTERNAL_MODULE].type > 0; }},
+ {STR_DEF(STR_EXTERNALRF), []() { new ModulePage(EXTERNAL_MODULE); }, []() { return g_model.moduleData[EXTERNAL_MODULE].type > 0; }},
+ {STR_DEF(STR_TRAINER), []() { new TrainerPage(); }, []() { return g_model.trainerData.mode > 0; }},
+ // Timer buttons
+ {STR_DEF(STR_TIMER_1), []() { new TimerWindow(0); }, []() { return g_model.timers[0].mode > 0; }},
+ {STR_DEF(STR_TIMER_2), []() { new TimerWindow(1); }, []() { return g_model.timers[1].mode > 0; }},
+ {STR_DEF(STR_TIMER_3), []() { new TimerWindow(2); }, []() { return g_model.timers[2].mode > 0; }},
+
+ {STR_DEF(STR_PREFLIGHT), []() { new PreflightChecks(); }},
+ {STR_DEF(STR_TRIMS), []() { new SubPage(ICON_MODEL_SETUP, STR_MAIN_MENU_MODEL_SETTINGS, STR_TRIMS, trimsSetupLines); }},
+ {STR_DEF(STR_THROTTLE_LABEL), []() { new SubPage(ICON_MODEL_SETUP, STR_MAIN_MENU_MODEL_SETTINGS, STR_THROTTLE_LABEL, throttleParamsSetupLines); }},
+ {STR_DEF(STR_ENABLED_FEATURES), []() { new SubPage(ICON_MODEL_SETUP, STR_MAIN_MENU_MODEL_SETTINGS, STR_ENABLED_FEATURES, viewOptionsPageSetupLines); }},
+#if defined(USBJ_EX)
+ {STR_DEF(STR_USBJOYSTICK_LABEL), []() { new ModelUSBJoystickPage(); }},
+#endif
+#if defined(FUNCTION_SWITCHES)
+ {STR_DEF(STR_FUNCTION_SWITCHES), []() { new ModelFunctionSwitches(); }},
+#endif
+ {STR_DEF(STR_MENU_OTHER), []() { new SubPage(ICON_MODEL_SETUP, STR_MAIN_MENU_MODEL_SETTINGS, STR_MENU_OTHER, otherPageSetupLines); }},
+#if defined(HELI)
+ {STR_DEF(STR_MENUHELISETUP), []() { return new ModelHeliPage(); }, nullptr, modelHeliEnabled},
+#endif
+ {nullptr},
};
void ModelSetupPage::build(Window * window)
{
- coord_t y = SetupLine::showLines(window, 0, SubPage::EDT_X, padding, setupLines, DIM(setupLines));
+ coord_t y = SetupLine::showLines(window, 0, SubPage::EDT_X, padding, setupLines);
- new SetupButtonGroup(window, {0, y, LCD_W - padding * 2, 0}, nullptr, BTN_COLS, PAD_TINY, {
- // Modules
- {STR_DEF(STR_INTERNALRF), []() { new ModulePage(INTERNAL_MODULE); }, []() { return g_model.moduleData[INTERNAL_MODULE].type > 0; }},
- {STR_DEF(STR_EXTERNALRF), []() { new ModulePage(EXTERNAL_MODULE); }, []() { return g_model.moduleData[EXTERNAL_MODULE].type > 0; }},
- {STR_DEF(STR_TRAINER), []() { new TrainerPage(); }, []() { return g_model.trainerData.mode > 0; }},
- // Timer buttons
- {STR_DEF(STR_TIMER_1), []() { new TimerWindow(0); }, []() { return g_model.timers[0].mode > 0; }},
- {STR_DEF(STR_TIMER_2), []() { new TimerWindow(1); }, []() { return g_model.timers[1].mode > 0; }},
- {STR_DEF(STR_TIMER_3), []() { new TimerWindow(2); }, []() { return g_model.timers[2].mode > 0; }},
-
- {STR_DEF(STR_PREFLIGHT), []() { new PreflightChecks(); }},
- {STR_DEF(STR_TRIMS), []() { new TrimsSetup(); }},
- {STR_DEF(STR_THROTTLE_LABEL), []() { new ThrottleParams(); }},
- {STR_DEF(STR_ENABLED_FEATURES), []() { new SubPage(ICON_MODEL_SETUP, STR_MAIN_MENU_MODEL_SETTINGS, STR_ENABLED_FEATURES, viewOptionsPageSetupLines, DIM(viewOptionsPageSetupLines)); }},
-#if defined(USBJ_EX)
- {STR_DEF(STR_USBJOYSTICK_LABEL), []() { new ModelUSBJoystickPage(); }},
-#endif
-#if defined(FUNCTION_SWITCHES)
- {STR_DEF(STR_FUNCTION_SWITCHES), []() { new ModelFunctionSwitches(); }},
-#endif
- {STR_DEF(STR_MENU_OTHER), []() { new SubPage(ICON_MODEL_SETUP, STR_MAIN_MENU_MODEL_SETTINGS, STR_MENU_OTHER, otherPageSetupLines, DIM(otherPageSetupLines)); }},
-#if defined(HELI)
- {STR_DEF(STR_MENUHELISETUP), []() { return new ModelHeliPage(); }, nullptr, modelHeliEnabled},
-#endif
- }, BTN_H);
+ new SetupButtonGroup(window, {0, y, LCD_W - padding * 2, 0}, nullptr, BTN_COLS, PAD_TINY, modelSetupButtons, BTN_H);
}
diff --git a/radio/src/gui/colorlcd/model/output_edit.cpp b/radio/src/gui/colorlcd/model/output_edit.cpp
index 4c9e34c76..6a47ea9d9 100644
--- a/radio/src/gui/colorlcd/model/output_edit.cpp
+++ b/radio/src/gui/colorlcd/model/output_edit.cpp
@@ -185,7 +185,7 @@ void OutputEditWindow::buildBody(Window *form)
// Curve
new StaticText(line, rect_t{}, STR_CURVE);
- new CurveChoice(line, GET_SET_DEFAULT(output->curve), nullptr, channel + MIXSRC_FIRST_CH);
+ new CurveChoice(line, GET_SET_DEFAULT(output->curve), channel + MIXSRC_FIRST_CH);
// PPM center
line = form->newLine(grid);
diff --git a/radio/src/gui/colorlcd/model/throttle_params.h b/radio/src/gui/colorlcd/model/throttle_params.h
deleted file mode 100644
index 0d481b904..000000000
--- a/radio/src/gui/colorlcd/model/throttle_params.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) EdgeTX
- *
- * Based on code named
- * opentx - https://github.com/opentx/opentx
- * th9x - http://code.google.com/p/th9x
- * er9x - http://code.google.com/p/er9x
- * gruvin9x - http://code.google.com/p/gruvin9x
- *
- * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#pragma once
-
-#include "page.h"
-
-class ThrottleParams : public SubPage
-{
- public:
- ThrottleParams();
-};
diff --git a/radio/src/gui/colorlcd/model/trims_setup.cpp b/radio/src/gui/colorlcd/model/trims_setup.cpp
deleted file mode 100644
index f18d99b85..000000000
--- a/radio/src/gui/colorlcd/model/trims_setup.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) EdgeTX
- *
- * Based on code named
- * opentx - https://github.com/opentx/opentx
- * th9x - http://code.google.com/p/th9x
- * er9x - http://code.google.com/p/er9x
- * gruvin9x - http://code.google.com/p/gruvin9x
- *
- * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "trims_setup.h"
-
-#include "button.h"
-#include "choice.h"
-#include "dialog.h"
-#include "edgetx.h"
-#include "getset_helpers.h"
-#include "toggleswitch.h"
-
-#define SET_DIRTY() storageDirty(EE_MODEL)
-
-static SetupLineDef setupLines[] = {
- {
- // Reset trims
- nullptr,
- [](Window* parent, coord_t x, coord_t y) {
- new TextButton(parent, {PAD_TINY, y, LCD_W - PAD_MEDIUM * 2, 0}, STR_RESET_BTN, []() -> uint8_t {
- for (auto &fm : g_model.flightModeData) memclear(&fm.trim, sizeof(fm.trim));
- SET_DIRTY();
- AUDIO_WARNING1();
- return 0;
- });
- }
- },
-#if defined(USE_HATS_AS_KEYS)
- {
- // Hats mode for NV14/EL18
- STR_DEF(STR_HATSMODE),
- [](Window* parent, coord_t x, coord_t y) {
- 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(STR_HATSMODE_KEYS, STR_HATSMODE_KEYS_HELP, "",
- LEFT);
- return 0;
- });
- }
- },
-#endif
- {
- // Trim step
- STR_DEF(STR_TRIMINC),
- [](Window* parent, coord_t x, coord_t y) {
- new Choice(parent, {x, y, 0, 0}, STR_VTRIMINC, -2, 2,
- GET_SET_DEFAULT(g_model.trimInc));
- }
- },
- {
- // Extended trims
- STR_DEF(STR_ETRIMS),
- [](Window* parent, coord_t x, coord_t y) {
- new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_model.extendedTrims));
- }
- },
- {
- // Display trims
- // TODO: move to "Screen setup" ?
- STR_DEF(STR_DISPLAY_TRIMS),
- [](Window* parent, coord_t x, coord_t y) {
- new Choice(parent, {x, y, 0, 0}, STR_VDISPLAYTRIMS, 0, 2,
- GET_SET_DEFAULT(g_model.displayTrims));
- }
- },
-};
-
-TrimsSetup::TrimsSetup() : SubPage(ICON_MODEL_SETUP, STR_MAIN_MENU_MODEL_SETTINGS, STR_TRIMS, setupLines, DIM(setupLines))
-{
-}
diff --git a/radio/src/gui/colorlcd/model/trims_setup.h b/radio/src/gui/colorlcd/model/trims_setup.h
deleted file mode 100644
index 750ff4809..000000000
--- a/radio/src/gui/colorlcd/model/trims_setup.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) EdgeTX
- *
- * Based on code named
- * opentx - https://github.com/opentx/opentx
- * th9x - http://code.google.com/p/th9x
- * er9x - http://code.google.com/p/er9x
- * gruvin9x - http://code.google.com/p/gruvin9x
- *
- * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#pragma once
-
-#include "page.h"
-
-class TrimsSetup : public SubPage
-{
- public:
- TrimsSetup();
-
- static LAYOUT_VAL_SCALED(HATSMODE_W, 120)
-};
diff --git a/radio/src/gui/colorlcd/module/module_setup.cpp b/radio/src/gui/colorlcd/module/module_setup.cpp
index a3cea7b53..36f7a3102 100644
--- a/radio/src/gui/colorlcd/module/module_setup.cpp
+++ b/radio/src/gui/colorlcd/module/module_setup.cpp
@@ -30,6 +30,7 @@
#include "etx_lv_theme.h"
#include "form.h"
#include "getset_helpers.h"
+#include "messaging.h"
#include "mixer_scheduler.h"
#include "os/sleep.h"
#include "ppm_settings.h"
@@ -120,6 +121,7 @@ class ModuleWindow : public Window
setFlexLayout();
updateModule();
lv_obj_add_event_cb(lvobj, ModuleWindow::mw_refresh_cb, LV_EVENT_REFRESH, this);
+ moduleUpdateMsg.subscribe(Messaging::MODULE_UPDATE, [=](uint32_t param) { updateLayout(); });
}
void updateModule()
@@ -513,6 +515,7 @@ class ModuleWindow : public Window
FailsafeChoice* fsChoice = nullptr;
Choice* rfPower = nullptr;
StaticText* idUnique = nullptr;
+ Messaging moduleUpdateMsg;
void startRSSIDialog(std::function closeHandler = nullptr)
{
@@ -631,8 +634,7 @@ class ModuleSubTypeChoice : public Choice
#endif
}
- if (moduleWindow)
- moduleWindow->updateLayout();
+ Messaging::send(Messaging::MODULE_UPDATE);
}
void updateLayout()
@@ -732,11 +734,8 @@ class ModuleSubTypeChoice : public Choice
}
}
- void setModuleWindow(ModuleWindow* w) { moduleWindow = w; }
-
protected:
uint8_t moduleIdx;
- ModuleWindow* moduleWindow = nullptr;
};
ModulePage::ModulePage(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP)
@@ -772,8 +771,6 @@ ModulePage::ModulePage(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP)
auto subTypeChoice = new ModuleSubTypeChoice(box, moduleIdx);
auto moduleWindow = new ModuleWindow(body, moduleIdx);
- subTypeChoice->setModuleWindow(moduleWindow);
-
// This needs to be after moduleWindow has been created
moduleChoice->setSetValueHandler([=](int32_t newValue) {
setModuleType(moduleIdx, newValue);
diff --git a/radio/src/gui/colorlcd/radio/preview_window.cpp b/radio/src/gui/colorlcd/radio/preview_window.cpp
index 1d165ce73..5e9943389 100644
--- a/radio/src/gui/colorlcd/radio/preview_window.cpp
+++ b/radio/src/gui/colorlcd/radio/preview_window.cpp
@@ -83,10 +83,6 @@ class ThemedCheckBox : public ToggleSwitch
setFocusHandler([](bool focus) {});
}
-#if defined(HARDWARE_KEYS)
- void onEvent(event_t event) override { return parent->onEvent(event); }
-#endif
-
protected:
bool checked;
};
@@ -103,10 +99,6 @@ class ThemedButton : public TextButton
setWindowFlag(NO_FOCUS | NO_CLICK);
setPressHandler([=]() { return isChecked; });
}
-
-#if defined(HARDWARE_KEYS)
- void onEvent(event_t event) override { parent->onEvent(event); }
-#endif
};
class ThemedTextEdit : public TextEdit
@@ -120,10 +112,6 @@ class ThemedTextEdit : public TextEdit
preview(edited, editText, strlen(editText));
}
-#if defined(HARDWARE_KEYS)
- void onEvent(event_t event) override { parent->onEvent(event); }
-#endif
-
protected:
char editText[50];
};
diff --git a/radio/src/gui/colorlcd/radio/radio_calibration.cpp b/radio/src/gui/colorlcd/radio/radio_calibration.cpp
index b7db72eef..fb7818bee 100644
--- a/radio/src/gui/colorlcd/radio/radio_calibration.cpp
+++ b/radio/src/gui/colorlcd/radio/radio_calibration.cpp
@@ -106,7 +106,7 @@ void RadioCalibrationPage::buildBody(Window *window)
3, 2);
}
- std::unique_ptr deco(new ViewMainDecoration(window, false, true, false));
+ new ViewMainDecoration(window, true);
axisBtn = new TextButton(window, {AXIS_X, PAD_LARGE, AXIS_W, 0}, STR_STICKS,
[=]() -> uint8_t {
diff --git a/radio/src/gui/colorlcd/radio/radio_cfs.cpp b/radio/src/gui/colorlcd/radio/radio_cfs.cpp
index 2b4555965..0bcf000fe 100644
--- a/radio/src/gui/colorlcd/radio/radio_cfs.cpp
+++ b/radio/src/gui/colorlcd/radio/radio_cfs.cpp
@@ -37,19 +37,13 @@
extern const char* _fct_sw_start[];
extern const char* edgetx_fs_manual_url;
-class RadioFunctionSwitch : public Window
+//-----------------------------------------------------------------------------
+
+class RadioFunctionSwitch : public FunctionSwitchBase
{
public:
- RadioFunctionSwitch(Window* parent, uint8_t sw) :
- Window(parent, {0, 0, LCD_W - PAD_SMALL * 2, ROW_H}), switchIndex(sw)
+ RadioFunctionSwitch(Window* parent, uint8_t sw) : FunctionSwitchBase(parent, sw)
{
- padAll(PAD_TINY);
-
- std::string s(CHAR_SWITCH);
- s += switchGetDefaultName(switchIndex);
-
- new StaticText(this, {PAD_LARGE, PAD_MEDIUM, SW_W, EdgeTxStyles::STD_FONT_HEIGHT}, s);
-
new ModelTextEdit(this, {NM_X, 0, NM_W, 0},
g_eeGeneral.switchName(switchIndex), LEN_SWITCH_NAME);
@@ -87,17 +81,13 @@ class RadioFunctionSwitch : public Window
});
#if defined(FUNCTION_SWITCHES_RGB_LEDS)
-#if NARROW_LAYOUT
- new StaticText(this, {C1_X - C1_W - PAD_TINY, C1_Y + COLLBL_YO, C1_W, 0}, STR_OFF, COLOR_THEME_PRIMARY1_INDEX, FONT(XS) | RIGHT);
- new StaticText(this, {C2_X - C2_W - PAD_TINY, C2_Y + COLLBL_YO, C2_W, 0}, STR_ON_ONE_SWITCHES[0], COLOR_THEME_PRIMARY1_INDEX, FONT(XS) | RIGHT);
-#endif
-
offValue = g_eeGeneral.switchOffColor(switchIndex);
onValue = g_eeGeneral.switchOnColor(switchIndex);
offColor = new ColorPicker(
this, {C1_X, C1_Y, C1_W, 0},
[=]() -> int { // getValue
+ activeSwitch = switchIndex;
return g_eeGeneral.switchOffColor(switchIndex).getColor() | RGB888_FLAG;
},
[=](int newValue) { // setValue
@@ -111,12 +101,12 @@ class RadioFunctionSwitch : public Window
offValue = g_eeGeneral.switchOffColor(switchIndex);
setFSEditOverride(-1, 0);
SET_DIRTY();
- },
- [=](int newValue) { previewColor(newValue); }, ETX_RGB888);
+ }, ETX_RGB888);
onColor = new ColorPicker(
this, {C2_X, C2_Y, C2_W, 0},
[=]() -> int { // getValue
+ activeSwitch = switchIndex;
return g_eeGeneral.switchOnColor(switchIndex).getColor() | RGB888_FLAG;
},
[=](int newValue) { // setValue
@@ -130,11 +120,8 @@ class RadioFunctionSwitch : public Window
onValue = g_eeGeneral.switchOnColor(switchIndex);
setFSEditOverride(-1, 0);
SET_DIRTY();
- },
- [=](int newValue) { previewColor(newValue); }, ETX_RGB888);
+ }, ETX_RGB888);
- overrideLabel = new StaticText(this, {OVRLBL_X, C1_Y + EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_LARGE, OVRLBL_W, 0},
- STR_LUA_OVERRIDE, COLOR_THEME_PRIMARY1_INDEX, FONT(XS) | RIGHT);
offOverride = new ToggleSwitch(this, {OVROFF_X, C1_Y + EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE, 0, 0},
[=]() { return g_eeGeneral.cfsOffColorLuaOverride(switchIndex); },
[=](bool v) { g_eeGeneral.cfsSetOffColorLuaOverride(switchIndex, v); });
@@ -146,93 +133,13 @@ class RadioFunctionSwitch : public Window
setState();
}
-#if defined(FUNCTION_SWITCHES_RGB_LEDS)
- static LAYOUT_VAL_SCALED(SW_W, 70)
- static constexpr coord_t NM_X = SW_W + PAD_SMALL;
- static LAYOUT_VAL_SCALED(NM_W, 60)
- static constexpr coord_t TP_X = NM_X + NM_W + PAD_SMALL;
- static LAYOUT_VAL_SCALED(TP_W, 78)
- static constexpr coord_t GR_X = TP_X + TP_W + PAD_SMALL;
- static LAYOUT_VAL_SCALED(GR_W, 84)
- static constexpr coord_t ST_X = GR_X + GR_W + PAD_SMALL;
- static LAYOUT_VAL_SCALED(ST_W, 60)
-#if NARROW_LAYOUT
- static constexpr coord_t ROW_H = EdgeTxStyles::UI_ELEMENT_HEIGHT * 3 + PAD_OUTLINE * 4;
- static constexpr coord_t C1_X = GR_X;
- static constexpr coord_t C1_Y = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE;
- static LAYOUT_VAL_SCALED(C1_W, 40)
- static constexpr coord_t C2_X = ST_X;
- static constexpr coord_t C2_Y = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE;
- static LAYOUT_VAL_SCALED(C2_W, 40)
- static constexpr coord_t OVRLBL_X = NM_X;
- static constexpr coord_t OVRLBL_W = NM_W + TP_W;
- static constexpr coord_t OVROFF_X = C1_X;
- static constexpr coord_t COLLBL_YO = PAD_MEDIUM;
-#else
- static constexpr coord_t ROW_H = EdgeTxStyles::UI_ELEMENT_HEIGHT * 2 + PAD_OUTLINE * 3;
- static constexpr coord_t C1_X = ST_X + ST_W + PAD_SMALL;
- static constexpr coord_t C1_Y = 0;
- static LAYOUT_VAL_SCALED(C1_W, 40)
- static constexpr coord_t C2_X = C1_X + C1_W + PAD_SMALL;
- static constexpr coord_t C2_Y = 0;
- static LAYOUT_VAL_SCALED(C2_W, 40)
- static constexpr coord_t OVRLBL_X = GR_X;
- static constexpr coord_t OVRLBL_W = GR_W + ST_W - PAD_LARGE;
- static constexpr coord_t OVROFF_X = C1_X - PAD_MEDIUM * 2;
- static constexpr coord_t COLLBL_YO = PAD_SMALL;
-#endif
-#else
- static constexpr coord_t ROW_H = EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_OUTLINE * 2;
- static constexpr coord_t SW_W = (LCD_W - PAD_SMALL * 2 - PAD_TINY * 4) / 5;
- static constexpr coord_t NM_X = SW_W + PAD_TINY;
- static LAYOUT_VAL_SCALED(NM_W, 80)
- static constexpr coord_t TP_X = NM_X + SW_W + PAD_TINY;
- static LAYOUT_VAL_SCALED(TP_W, 86)
- static constexpr coord_t GR_X = TP_X + SW_W + PAD_TINY;
- static LAYOUT_VAL_SCALED(GR_W, 94)
- static constexpr coord_t ST_X = GR_X + SW_W + PAD_LARGE * 2 + PAD_SMALL;
- static LAYOUT_VAL_SCALED(ST_W, 70)
-#endif
-
protected:
- uint8_t switchIndex;
- Choice* typeChoice = nullptr;
- Choice* startChoice = nullptr;
-#if defined(FUNCTION_SWITCHES_RGB_LEDS)
- ColorPicker* offColor = nullptr;
- ColorPicker* onColor = nullptr;
- RGBLedColor offValue;
- RGBLedColor onValue;
- StaticText* overrideLabel = nullptr;
- ToggleSwitch* onOverride = nullptr;
- ToggleSwitch* offOverride = nullptr;
-#endif
- int lastType = -1;
-
-#if defined(FUNCTION_SWITCHES_RGB_LEDS)
- void previewColor(int newValue)
- {
- // Convert color index to RGB
- newValue = color32ToRGB(newValue);
- setFSEditOverride(switchIndex, newValue);
- }
-#endif
void setState()
{
uint8_t typ = g_eeGeneral.switchType(switchIndex);
startChoice->show(typ == SWITCH_2POS && g_eeGeneral.switchGroup(switchIndex) == 0);
-#if defined(FUNCTION_SWITCHES_RGB_LEDS)
- offColor->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
- onColor->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
- overrideLabel->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
- onOverride->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
- offOverride->show(typ != SWITCH_NONE && typ != SWITCH_GLOBAL);
- if (typ != SWITCH_NONE && typ != SWITCH_GLOBAL)
- setHeight(ROW_H);
- else
- setHeight(ROW_H - EdgeTxStyles::UI_ELEMENT_HEIGHT - PAD_OUTLINE);
-#endif
+ setLEDState(typ);
}
void checkEvents() override
@@ -246,61 +153,32 @@ class RadioFunctionSwitch : public Window
}
};
-RadioFunctionSwitches::RadioFunctionSwitches() : Page(ICON_RADIO_HARDWARE)
+//-----------------------------------------------------------------------------
+
+RadioFunctionSwitches::RadioFunctionSwitches() : FunctionSwitchesBase(ICON_RADIO_HARDWARE, STR_HARDWARE)
{
- header->setTitle(STR_HARDWARE);
- header->setTitle2(STR_FUNCTION_SWITCHES);
-
- body->padAll(PAD_TINY);
- body->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO);
-
- auto box = new Window(body, {0, 0, LV_PCT(100), LV_SIZE_CONTENT});
- new StaticText(box, {0, 0, RadioFunctionSwitch::SW_W, 0}, STR_SWITCHES);
- new StaticText(box, {RadioFunctionSwitch::NM_X + PAD_OUTLINE, 0, RadioFunctionSwitch::NM_W, 0}, STR_NAME, COLOR_THEME_PRIMARY1_INDEX, FONT(XS));
- new StaticText(box, {RadioFunctionSwitch::TP_X + PAD_OUTLINE, 0, RadioFunctionSwitch::TP_W, 0}, STR_SWITCH_TYPE,
- COLOR_THEME_PRIMARY1_INDEX, FONT(XS));
- startupHeader = new StaticText(box, {RadioFunctionSwitch::ST_X + PAD_OUTLINE, 0, RadioFunctionSwitch::ST_W, 0}, STR_SWITCH_STARTUP,
- COLOR_THEME_PRIMARY1_INDEX, FONT(XS));
-#if defined(FUNCTION_SWITCHES_RGB_LEDS) && !NARROW_LAYOUT
- new StaticText(box, {RadioFunctionSwitch::C1_X + PAD_OUTLINE, 0, RadioFunctionSwitch::C1_W, 0}, STR_OFF, COLOR_THEME_PRIMARY1_INDEX, FONT(XS));
- new StaticText(box, {RadioFunctionSwitch::C2_X + PAD_OUTLINE, 0, RadioFunctionSwitch::C2_W, 0}, STR_ON_ONE_SWITCHES[0], COLOR_THEME_PRIMARY1_INDEX, FONT(XS));
-#endif
-
for (uint8_t i = 0; i < switchGetMaxSwitches(); i += 1) {
if (switchIsCustomSwitch(i))
new RadioFunctionSwitch(body, i);
}
-#if defined(HARDWARE_TOUCH)
- body->padBottom(PAD_LARGE);
-
- box = new Window(body, {0, 0, LV_PCT(100), LV_SIZE_CONTENT});
-
- new StaticText(box, rect_t{}, STR_MORE_INFO);
-
- auto qr = lv_qrcode_create(box->getLvObj(), 150,
- makeLvColor(COLOR_THEME_SECONDARY1),
- makeLvColor(COLOR_THEME_SECONDARY3));
- lv_qrcode_update(qr, edgetx_fs_manual_url, strlen(edgetx_fs_manual_url));
- lv_obj_set_pos(qr, (LCD_W - 150) / 2, EdgeTxStyles::STD_FONT_HEIGHT);
-#endif
+ addQRCode();
setState();
}
void RadioFunctionSwitches::setState()
{
- // int cnt = 0;
- // for (int i = 1; i <= 3; i += 1) {
- // cnt += getSwitchCountInFSGroup(i);
- // }
- // startupHeader->show(cnt != NUM_FUNCTIONS_SWITCHES);
-}
-
-void RadioFunctionSwitches::checkEvents()
-{
- setState();
- Page::checkEvents();
+ bool showStartHeader = false;
+ for (uint8_t i = 0; i < switchGetMaxSwitches(); i += 1) {
+ if (switchIsCustomSwitch(i) && g_eeGeneral.switchType(i) == SWITCH_2POS) {
+ showStartHeader = true;
+ break;
+ }
+ }
+ startupHeader->show(showStartHeader);
}
#endif
+
+//-----------------------------------------------------------------------------
diff --git a/radio/src/gui/colorlcd/radio/radio_cfs.h b/radio/src/gui/colorlcd/radio/radio_cfs.h
index fa86257fd..fe3f540a6 100644
--- a/radio/src/gui/colorlcd/radio/radio_cfs.h
+++ b/radio/src/gui/colorlcd/radio/radio_cfs.h
@@ -19,24 +19,19 @@
* GNU General Public License for more details.
*/
- #pragma once
+#pragma once
- #if defined(FUNCTION_SWITCHES)
+#if defined(FUNCTION_SWITCHES)
- #include "page.h"
+#include "function_switches.h"
- class RadioFunctionSwitches : public Page
- {
- public:
- RadioFunctionSwitches();
+class RadioFunctionSwitches : public FunctionSwitchesBase
+{
+ public:
+ RadioFunctionSwitches();
- protected:
- BitmapBuffer* qrcode = nullptr;
- StaticText* startupHeader = nullptr;
+ protected:
+ void setState() override;
+};
- void setState();
- void checkEvents() override;
- };
-
- #endif
-
\ No newline at end of file
+#endif
diff --git a/radio/src/gui/colorlcd/radio/radio_diaganas.cpp b/radio/src/gui/colorlcd/radio/radio_diaganas.cpp
index a2396fc7b..560230ed4 100644
--- a/radio/src/gui/colorlcd/radio/radio_diaganas.cpp
+++ b/radio/src/gui/colorlcd/radio/radio_diaganas.cpp
@@ -159,8 +159,6 @@ class AnaViewWindow : public Window
#endif
}
- void checkEvents() override { Window::checkEvents(); }
-
protected:
FlexGridLayout grid;
FormLine* line = nullptr;
@@ -479,8 +477,8 @@ class AnaMinMaxViewWindow : public AnaViewWindow
class AnaCalibratedViewPage : public PageGroupItem
{
public:
- AnaCalibratedViewPage(QMPage qmPage) :
- PageGroupItem(STR_ANADIAGS_CALIB, qmPage)
+ AnaCalibratedViewPage() :
+ PageGroupItem(STR_ANADIAGS_CALIB)
{
icon = ICON_STATS;
}
@@ -495,8 +493,8 @@ class AnaCalibratedViewPage : public PageGroupItem
class AnaFilteredDevViewPage : public PageGroupItem
{
public:
- AnaFilteredDevViewPage(QMPage qmPage) :
- PageGroupItem(STR_ANADIAGS_FILTRAWDEV, qmPage)
+ AnaFilteredDevViewPage() :
+ PageGroupItem(STR_ANADIAGS_FILTRAWDEV)
{
icon = ICON_STATS;
}
@@ -511,8 +509,8 @@ class AnaFilteredDevViewPage : public PageGroupItem
class AnaUnfilteredRawViewPage : public PageGroupItem
{
public:
- AnaUnfilteredRawViewPage(QMPage qmPage) :
- PageGroupItem(STR_ANADIAGS_UNFILTRAW, qmPage)
+ AnaUnfilteredRawViewPage() :
+ PageGroupItem(STR_ANADIAGS_UNFILTRAW)
{
icon = ICON_STATS;
}
@@ -527,8 +525,8 @@ class AnaUnfilteredRawViewPage : public PageGroupItem
class AnaMinMaxViewPage : public PageGroupItem
{
public:
- AnaMinMaxViewPage(QMPage qmPage) :
- PageGroupItem(STR_ANADIAGS_MINMAX, qmPage)
+ AnaMinMaxViewPage() :
+ PageGroupItem(STR_ANADIAGS_MINMAX)
{
icon = ICON_STATS;
}
@@ -540,11 +538,11 @@ class AnaMinMaxViewPage : public PageGroupItem
}
};
-RadioAnalogsDiagsViewPageGroup::RadioAnalogsDiagsViewPageGroup(QMPage qmPage) :
+RadioAnalogsDiagsViewPageGroup::RadioAnalogsDiagsViewPageGroup() :
TabsGroup(ICON_STATS, STR_ANALOGS_BTN)
{
- addTab(new AnaCalibratedViewPage(qmPage));
- addTab(new AnaFilteredDevViewPage(qmPage));
- addTab(new AnaUnfilteredRawViewPage(qmPage));
- addTab(new AnaMinMaxViewPage(qmPage));
+ addTab(new AnaCalibratedViewPage());
+ addTab(new AnaFilteredDevViewPage());
+ addTab(new AnaUnfilteredRawViewPage());
+ addTab(new AnaMinMaxViewPage());
}
diff --git a/radio/src/gui/colorlcd/radio/radio_diaganas.h b/radio/src/gui/colorlcd/radio/radio_diaganas.h
index 701d2efcf..fbffaade1 100644
--- a/radio/src/gui/colorlcd/radio/radio_diaganas.h
+++ b/radio/src/gui/colorlcd/radio/radio_diaganas.h
@@ -26,5 +26,5 @@
class RadioAnalogsDiagsViewPageGroup : public TabsGroup
{
public:
- RadioAnalogsDiagsViewPageGroup(QMPage qmPage);
+ RadioAnalogsDiagsViewPageGroup();
};
diff --git a/radio/src/gui/colorlcd/radio/radio_hardware.cpp b/radio/src/gui/colorlcd/radio/radio_hardware.cpp
index ca50b359a..998483430 100644
--- a/radio/src/gui/colorlcd/radio/radio_hardware.cpp
+++ b/radio/src/gui/colorlcd/radio/radio_hardware.cpp
@@ -93,7 +93,7 @@ class BatCalEdit : public NumberEdit
}
};
-static SetupLineDef setupLines[] = {
+const static SetupLineDef setupLines[] = {
{
// Batt meter range - Range 3.0v to 16v
STR_DEF(STR_BATTERY_RANGE),
@@ -159,13 +159,34 @@ static SetupLineDef setupLines[] = {
}
},
#endif
+ {nullptr, nullptr},
+};
+
+const static PageButtonDef calibrationButtons[] = {
+ {STR_DEF(STR_MENUCALIBRATION), []() { new RadioCalibrationPage(); }},
+ {STR_DEF(STR_STICKS), []() { new HWInputDialog(STR_STICKS); }},
+ {STR_DEF(STR_POTS), []() { new HWInputDialog(STR_POTS, HWPots::POTS_WINDOW_WIDTH); }},
+ {STR_DEF(STR_SWITCHES), []() { new HWInputDialog(STR_SWITCHES, HWSwitches::SW_WINDOW_WIDTH); }},
+#if defined(FUNCTION_SWITCHES)
+ {STR_DEF(STR_FUNCTION_SWITCHES), []() { new RadioFunctionSwitches(); }},
+#endif
+ {nullptr},
+};
+
+const static PageButtonDef debugButtons[] = {
+ {STR_DEF(STR_ANALOGS_BTN), []() { new RadioAnalogsDiagsViewPageGroup(); }},
+ {STR_DEF(STR_KEYS_BTN), []() { new RadioKeyDiagsPage(); }},
+#if defined(FUNCTION_SWITCHES)
+ {STR_DEF(STR_FS_BTN), []() { new RadioCustSwitchesDiagsPage(); }},
+#endif
+ {nullptr},
};
void RadioHardwarePage::build(Window* window)
{
window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_TINY);
- SetupLine::showLines(window, 0, SubPage::EDT_X, padding, setupLines, DIM(setupLines));
+ SetupLine::showLines(window, 0, SubPage::EDT_X, padding, setupLines);
FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY);
@@ -188,22 +209,8 @@ void RadioHardwarePage::build(Window* window)
new SerialConfigWindow(window, grid);
// Calibration
- new SetupButtonGroup(window, {0, 0, LCD_W - padding * 2, 0}, STR_INPUTS, BTN_COLS, PAD_ZERO, {
- {STR_DEF(STR_MENUCALIBRATION), []() { new RadioCalibrationPage(); }},
- {STR_DEF(STR_STICKS), []() { new HWInputDialog(STR_STICKS); }},
- {STR_DEF(STR_POTS), []() { new HWInputDialog(STR_POTS, HWPots::POTS_WINDOW_WIDTH); }},
- {STR_DEF(STR_SWITCHES), []() { new HWInputDialog(STR_SWITCHES, HWSwitches::SW_WINDOW_WIDTH); }},
-#if defined(FUNCTION_SWITCHES)
- {STR_DEF(STR_FUNCTION_SWITCHES), []() { new RadioFunctionSwitches(); }},
-#endif
- });
+ new SetupButtonGroup(window, {0, 0, LCD_W - padding * 2, 0}, STR_INPUTS, BTN_COLS, PAD_ZERO, calibrationButtons);
// Debugs
- new SetupButtonGroup(window, {0, 0, LCD_W - padding * 2, 0}, STR_DEBUG, FS_BTN_COLS, PAD_ZERO, {
- {STR_DEF(STR_ANALOGS_BTN), [=]() { new RadioAnalogsDiagsViewPageGroup(qmPageId); }},
- {STR_DEF(STR_KEYS_BTN), []() { new RadioKeyDiagsPage(); }},
-#if defined(FUNCTION_SWITCHES)
- {STR_DEF(STR_FS_BTN), []() { new RadioCustSwitchesDiagsPage(); }},
-#endif
- });
+ new SetupButtonGroup(window, {0, 0, LCD_W - padding * 2, 0}, STR_DEBUG, FS_BTN_COLS, PAD_ZERO, debugButtons);
}
diff --git a/radio/src/gui/colorlcd/radio/radio_setup.cpp b/radio/src/gui/colorlcd/radio/radio_setup.cpp
index 53c4740ea..1f1eb0233 100644
--- a/radio/src/gui/colorlcd/radio/radio_setup.cpp
+++ b/radio/src/gui/colorlcd/radio/radio_setup.cpp
@@ -48,6 +48,36 @@ static const lv_coord_t col_two_dsc[] = {LV_GRID_FR(19), LV_GRID_FR(21),
LV_GRID_TEMPLATE_LAST};
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
+class DateNumberEdit : public NumberEdit
+{
+ public:
+ DateNumberEdit(Window* parent, coord_t x, coord_t y, int vmin, int vmax, bool leading0,
+ std::function getValue,
+ std::function setValue) :
+ NumberEdit(parent, {x, y, DT_EDT_W, 0}, vmin, vmax,
+ getValue,
+ [=](int32_t newValue) {
+ setValue(newValue);
+ SET_DIRTY();
+ })
+ {
+ lastValue = this->getValue();
+ if (leading0)
+ setDisplayHandler([](int32_t value) { return formatNumberAsString(value, LEADING0, 2); });
+}
+
+ static LAYOUT_ORIENTATION(DT_EDT_W, EdgeTxStyles::EDIT_FLD_WIDTH_NARROW, LAYOUT_SCALE(52))
+
+ protected:
+ int32_t lastValue;
+
+ void checkEvents() override
+ {
+ if (lastValue != getValue())
+ update();
+ }
+};
+
class DateTimeWindow : public Window
{
public:
@@ -62,42 +92,19 @@ class DateTimeWindow : public Window
{
Window::checkEvents();
- if (seconds && (get_tmr10ms() - lastRefresh >= 10)) {
+ if (get_tmr10ms() - lastRefresh >= 10) {
lastRefresh = get_tmr10ms();
-
gettime(&m_tm);
- if (m_tm.tm_year != m_last_tm.tm_year)
- year->update();
- if (m_tm.tm_mon != m_last_tm.tm_mon)
- month->update();
- if (m_tm.tm_mday != m_last_tm.tm_mday)
- day->update();
- if (m_tm.tm_hour != m_last_tm.tm_hour)
- hour->update();
- if (m_tm.tm_min != m_last_tm.tm_min)
- minutes->update();
- if (m_tm.tm_sec != m_last_tm.tm_sec)
- seconds->update();
- m_last_tm = m_tm;
}
}
- // Absolute layout for date/time setion due to slow performance
- // of lv_textarea in a flex layout.
- static LAYOUT_ORIENTATION(DT_EDT_W, EdgeTxStyles::EDIT_FLD_WIDTH_NARROW, LAYOUT_SCALE(52))
static constexpr coord_t DT_Y2 = PAD_TINY + EdgeTxStyles::UI_ELEMENT_HEIGHT + PAD_MEDIUM;
protected:
bool init = false;
struct gtm m_tm;
- struct gtm m_last_tm;
tmr10ms_t lastRefresh = 0;
- NumberEdit* year = nullptr;
- NumberEdit* month = nullptr;
NumberEdit* day = nullptr;
- NumberEdit* hour = nullptr;
- NumberEdit* minutes = nullptr;
- NumberEdit* seconds = nullptr;
int8_t daysInMonth()
{
@@ -127,71 +134,54 @@ class DateTimeWindow : public Window
void build()
{
gettime(&m_tm);
- m_last_tm = m_tm;
// Date
new StaticText(this, rect_t{PAD_TINY, PAD_TINY + PAD_MEDIUM, SubPage::EDT_X - PAD_TINY - PAD_SMALL, EdgeTxStyles::STD_FONT_HEIGHT}, STR_DATE);
- year = new NumberEdit(
- this, rect_t{SubPage::EDT_X, PAD_TINY, DT_EDT_W, 0}, 2023, 2037,
+ new DateNumberEdit(this, SubPage::EDT_X, PAD_TINY, 2023, 2037, false,
[=]() -> int32_t { return TM_YEAR_BASE + m_tm.tm_year; },
[=](int32_t newValue) {
- m_last_tm.tm_year = m_tm.tm_year = newValue - TM_YEAR_BASE;
+ m_tm.tm_year = newValue - TM_YEAR_BASE;
setDaysInMonth();
SET_LOAD_DATETIME(&m_tm);
});
- month = new NumberEdit(
- this, rect_t{SubPage::EDT_X + DT_EDT_W + PAD_TINY, PAD_TINY, DT_EDT_W, 0}, 1, 12,
+ new DateNumberEdit(this, SubPage::EDT_X + DateNumberEdit::DT_EDT_W + PAD_TINY, PAD_TINY, 1, 12, false,
[=]() -> int32_t { return 1 + m_tm.tm_mon; },
[=](int32_t newValue) {
- m_last_tm.tm_mon = m_tm.tm_mon = newValue - 1;
+ m_tm.tm_mon = newValue - 1;
setDaysInMonth();
SET_LOAD_DATETIME(&m_tm);
});
- month->setDisplayHandler(
- [](int32_t value) { return formatNumberAsString(value, LEADING0); });
- day = new NumberEdit(
- this, rect_t{SubPage::EDT_X + 2 * DT_EDT_W + PAD_SMALL, PAD_TINY, DT_EDT_W, 0}, 1,
- daysInMonth(), [=]() -> int32_t { return m_tm.tm_mday; },
+ day = new DateNumberEdit(this, SubPage::EDT_X + 2 * DateNumberEdit::DT_EDT_W + PAD_SMALL, PAD_TINY, 1, daysInMonth(), true,
+ [=]() -> int32_t { return m_tm.tm_mday; },
[=](int32_t newValue) {
- m_last_tm.tm_mday = m_tm.tm_mday = newValue;
+ m_tm.tm_mday = newValue;
SET_LOAD_DATETIME(&m_tm);
});
- day->setDisplayHandler(
- [](int32_t value) { return formatNumberAsString(value, LEADING0, 2); });
// Time
new StaticText(this, rect_t{PAD_TINY, DT_Y2 + PAD_MEDIUM, SubPage::EDT_X - PAD_TINY - PAD_SMALL, EdgeTxStyles::STD_FONT_HEIGHT}, STR_TIME);
- hour = new NumberEdit(
- this, rect_t{SubPage::EDT_X, DT_Y2, DT_EDT_W, 0}, 0, 23,
+ new DateNumberEdit(this, SubPage::EDT_X, DT_Y2, 0, 23, true,
[=]() -> int32_t { return m_tm.tm_hour; },
[=](int32_t newValue) {
- m_last_tm.tm_hour = m_tm.tm_hour = newValue;
+ m_tm.tm_hour = newValue;
SET_LOAD_DATETIME(&m_tm);
});
- hour->setDisplayHandler(
- [](int32_t value) { return formatNumberAsString(value, LEADING0, 2); });
- minutes = new NumberEdit(
- this, rect_t{SubPage::EDT_X + DT_EDT_W + PAD_TINY, DT_Y2, DT_EDT_W, 0}, 0, 59,
+ new DateNumberEdit(this, SubPage::EDT_X + DateNumberEdit::DT_EDT_W + PAD_TINY, DT_Y2, 0, 59, true,
[=]() -> int32_t { return m_tm.tm_min; },
[=](int32_t newValue) {
- m_last_tm.tm_min = m_tm.tm_min = newValue;
+ m_tm.tm_min = newValue;
SET_LOAD_DATETIME(&m_tm);
});
- minutes->setDisplayHandler(
- [](int32_t value) { return formatNumberAsString(value, LEADING0, 2); });
- seconds = new NumberEdit(
- this, rect_t{SubPage::EDT_X + DT_EDT_W * 2 + PAD_SMALL, DT_Y2, DT_EDT_W, 0}, 0, 59,
+ new DateNumberEdit(this, SubPage::EDT_X + DateNumberEdit::DT_EDT_W * 2 + PAD_SMALL, DT_Y2, 0, 59, true,
[=]() -> int32_t { return m_tm.tm_sec; },
[=](int32_t newValue) {
- m_last_tm.tm_sec = m_tm.tm_sec = newValue;
+ m_tm.tm_sec = newValue;
SET_LOAD_DATETIME(&m_tm);
});
- seconds->setDisplayHandler(
- [](int value) { return formatNumberAsString(value, LEADING0, 2); });
}
};
@@ -201,6 +191,7 @@ class ControlTextOverride : public StaticText
ControlTextOverride(Window* parent, coord_t x, coord_t y, FunctionsActive func) :
StaticText(parent, {x + XO, y + PAD_MEDIUM, 0, 0}, STR_SF_OVERRIDDEN, COLOR_THEME_WARNING_INDEX, FONT_SZ), func(func)
{
+ hide();
}
void checkEvents() override
@@ -216,7 +207,7 @@ class ControlTextOverride : public StaticText
};
#if defined(AUDIO)
-static SetupLineDef soundPageSetupLines[] = {
+const static SetupLineDef soundPageSetupLines[] = {
{
// Beeps mode
STR_DEF(STR_MODE),
@@ -302,11 +293,12 @@ static SetupLineDef soundPageSetupLines[] = {
}
},
#endif
+ {nullptr, nullptr},
};
#endif
#if defined(VARIO)
-static SetupLineDef varioPageSetupLines[] = {
+const static SetupLineDef varioPageSetupLines[] = {
{
// Vario volume
STR_DEF(STR_VOLUME),
@@ -354,11 +346,12 @@ static SetupLineDef varioPageSetupLines[] = {
edit->setSuffix("ms");
}
},
+ {nullptr, nullptr},
};
#endif
#if defined(HAPTIC)
-static SetupLineDef hapticPageSetupLines[] = {
+const static SetupLineDef hapticPageSetupLines[] = {
{
// Haptic mode
STR_DEF(STR_MODE),
@@ -383,10 +376,11 @@ static SetupLineDef hapticPageSetupLines[] = {
GET_SET_DEFAULT(g_eeGeneral.hapticStrength)))->setPos(x, y);
}
},
+ {nullptr, nullptr},
};
#endif
-static SetupLineDef alarmsPageSetupLines[] = {
+const static SetupLineDef alarmsPageSetupLines[] = {
{
// Battery warning
STR_DEF(STR_BATTERYWARNING),
@@ -451,124 +445,133 @@ static SetupLineDef alarmsPageSetupLines[] = {
GET_SET_INVERTED(g_eeGeneral.disableTrainerPoweroffAlarm));
}
},
+ {nullptr, nullptr},
};
-class BacklightPage : public SubPage
+class BacklightSlider : public Slider
{
public:
- BacklightPage() : SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_BACKLIGHT_LABEL, true)
+ BacklightSlider(Window* parent, coord_t x, coord_t y,
+ std::function getValue,
+ std::function setValue) :
+ Slider(parent, LV_PCT(50), BACKLIGHT_LEVEL_MIN, BACKLIGHT_LEVEL_MAX,
+ getValue, setValue)
{
- body->setFlexLayout();
-
- // Backlight mode
- setupLine(STR_MODE, [=](Window* parent, coord_t x, coord_t y) {
- auto blMode = new Choice(
- parent, {x, y, 0, 0}, STR_VBLMODE, e_backlight_mode_off, e_backlight_mode_on,
- GET_DEFAULT(g_eeGeneral.backlightMode), [=](int32_t newValue) {
- g_eeGeneral.backlightMode = newValue;
- updateBacklightControls();
- SET_DIRTY();
- });
-
- blMode->setAvailableHandler(
- [=](int newValue) { return newValue != e_backlight_mode_off; });
- });
-
- // Delay
- backlightTimeout = setupLine(STR_BACKLIGHT_TIMER, [=](Window* parent, coord_t x, coord_t y) {
- auto edit =
- new NumberEdit(parent, {x, y, EdgeTxStyles::EDIT_FLD_WIDTH_NARROW, 0}, 5, 600,
- GET_DEFAULT(g_eeGeneral.lightAutoOff * 5),
- SET_VALUE(g_eeGeneral.lightAutoOff, newValue / 5));
- edit->setStep(5);
- edit->setSuffix("s");
- });
-
- // Backlight ON bright
- setupLine(STR_BLONBRIGHTNESS, [=](Window* parent, coord_t x, coord_t y) {
- backlightOnSlider = new Slider(
- parent, lv_pct(50), BACKLIGHT_LEVEL_MIN, BACKLIGHT_LEVEL_MAX,
- [=]() -> int32_t {
- return BACKLIGHT_LEVEL_MAX - g_eeGeneral.backlightBright;
- },
- [=](int32_t newValue) {
- if (newValue >= g_eeGeneral.blOffBright ||
- g_eeGeneral.backlightMode == e_backlight_mode_on) {
- g_eeGeneral.backlightBright = BACKLIGHT_LEVEL_MAX - newValue;
- } else {
- g_eeGeneral.backlightBright =
- BACKLIGHT_LEVEL_MAX - g_eeGeneral.blOffBright;
- backlightOnSlider->update();
- }
- SET_DIRTY();
- });
- backlightOnSlider->setPos(x, y);
- });
-
- // Backlight OFF bright
- setupLine(STR_BLOFFBRIGHTNESS, [=](Window* parent, coord_t x, coord_t y) {
- backlightOffSlider = new Slider(
- parent, lv_pct(50), BACKLIGHT_LEVEL_MIN,
- BACKLIGHT_LEVEL_MAX, GET_DEFAULT(g_eeGeneral.blOffBright),
- [=](int32_t newValue) {
- int32_t onBright = BACKLIGHT_LEVEL_MAX - g_eeGeneral.backlightBright;
- if (newValue <= onBright ||
- g_eeGeneral.backlightMode == e_backlight_mode_off) {
- g_eeGeneral.blOffBright = newValue;
- } else {
- g_eeGeneral.blOffBright = onBright;
- backlightOffSlider->update();
- }
- SET_DIRTY();
- });
- backlightOffSlider->setPos(x, y);
- });
-
-#if defined(KEYS_BACKLIGHT_GPIO)
- // Keys backlight
- setupLine(STR_KEYS_BACKLIGHT, [=](Window* parent, coord_t x, coord_t y) {
- new ToggleSwitch(parent, {x, y, 0, 0},
- GET_SET_DEFAULT(g_eeGeneral.keysBacklight));
- });
-#endif
-
- // Backlight/Brightness source
- setupLine(STR_CONTROL, [=](Window* parent, coord_t x, coord_t y) {
- auto choice = new SourceChoice(parent, {x, y, 0, 0}, MIXSRC_NONE, MIXSRC_LAST_SWITCH,
- GET_SET_DEFAULT(g_eeGeneral.backlightSrc), true);
- choice->setAvailableHandler(isSourceAvailableForBacklightOrVolume);
- new ControlTextOverride(parent, x, y, FUNCTION_BACKLIGHT);
- });
-
- // Flash beep
- setupLine(STR_ALARM, [=](Window* parent, coord_t x, coord_t y) {
- new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_eeGeneral.alarmsFlash));
- });
-
- updateBacklightControls();
-
- enableRefresh();
+ setPos(x, y);
+ updateMsg.subscribe(Messaging::REFRESH, [=](uint32_t param) { update(); });
}
protected:
- Window* backlightTimeout = nullptr;
- Slider* backlightOffSlider = nullptr;
- Slider* backlightOnSlider = nullptr;
-
- void updateBacklightControls()
- {
- int32_t onBright = BACKLIGHT_LEVEL_MAX - g_eeGeneral.backlightBright;
- if (onBright < g_eeGeneral.blOffBright)
- g_eeGeneral.backlightBright =
- BACKLIGHT_LEVEL_MAX - g_eeGeneral.blOffBright;
-
- backlightTimeout->show(g_eeGeneral.backlightMode != e_backlight_mode_on);
-
- resetBacklightTimeout();
- }
+ Messaging updateMsg;
};
-static SetupLineDef gpsPageSetupLines[] = {
+const static SetupLineDef backlightSetupLines[] = {
+ {
+ // Backlight mode
+ STR_DEF(STR_MODE),
+ [](Window* parent, coord_t x, coord_t y) {
+ auto blMode = new Choice(
+ parent, {x, y, 0, 0}, STR_VBLMODE, e_backlight_mode_off, e_backlight_mode_on,
+ GET_DEFAULT(g_eeGeneral.backlightMode), [=](int32_t newValue) {
+ g_eeGeneral.backlightMode = newValue;
+ Messaging::send(Messaging::REFRESH);
+ SET_DIRTY();
+ });
+
+ blMode->setAvailableHandler(
+ [=](int newValue) { return newValue != e_backlight_mode_off; });
+ }
+ },
+ {
+ // Delay
+ STR_DEF(STR_BACKLIGHT_TIMER),
+ [](SetupLine* parent, coord_t x, coord_t y) {
+ parent->setupMsg.subscribe(Messaging::REFRESH, [=](uint32_t param) {
+ parent->show(g_eeGeneral.backlightMode != e_backlight_mode_on);
+ resetBacklightTimeout();
+ });
+ auto edit =
+ new NumberEdit(parent, {x, y, EdgeTxStyles::EDIT_FLD_WIDTH_NARROW, 0}, 5, 600,
+ GET_DEFAULT(g_eeGeneral.lightAutoOff * 5),
+ SET_VALUE(g_eeGeneral.lightAutoOff, newValue / 5));
+ edit->setStep(5);
+ edit->setSuffix("s");
+ parent->show(g_eeGeneral.backlightMode != e_backlight_mode_on);
+ }
+ },
+ {
+ // Backlight ON bright
+ STR_DEF(STR_BLONBRIGHTNESS),
+ [](Window* parent, coord_t x, coord_t y) {
+ new BacklightSlider(
+ parent, x, y,
+ [=]() -> int32_t {
+ return BACKLIGHT_LEVEL_MAX - g_eeGeneral.backlightBright;
+ },
+ [=](int32_t newValue) {
+ if (newValue >= g_eeGeneral.blOffBright ||
+ g_eeGeneral.backlightMode == e_backlight_mode_on) {
+ g_eeGeneral.backlightBright = BACKLIGHT_LEVEL_MAX - newValue;
+ } else {
+ g_eeGeneral.backlightBright =
+ BACKLIGHT_LEVEL_MAX - g_eeGeneral.blOffBright;
+ Messaging::send(Messaging::REFRESH);
+ }
+ SET_DIRTY();
+ });
+}
+ },
+ {
+ // Backlight OFF bright
+ STR_DEF(STR_BLOFFBRIGHTNESS),
+ [](Window* parent, coord_t x, coord_t y) {
+ new BacklightSlider(
+ parent, x, y,
+ GET_DEFAULT(g_eeGeneral.blOffBright),
+ [=](int32_t newValue) {
+ int32_t onBright = BACKLIGHT_LEVEL_MAX - g_eeGeneral.backlightBright;
+ if (newValue <= onBright ||
+ g_eeGeneral.backlightMode == e_backlight_mode_off) {
+ g_eeGeneral.blOffBright = newValue;
+ } else {
+ g_eeGeneral.blOffBright = onBright;
+ Messaging::send(Messaging::REFRESH);
+ }
+ SET_DIRTY();
+ });
+}
+ },
+#if defined(KEYS_BACKLIGHT_GPIO)
+ {
+ // Keys backlight
+ STR_DEF(STR_KEYS_BACKLIGHT),
+ [](Window* parent, coord_t x, coord_t y) {
+ new ToggleSwitch(parent, {x, y, 0, 0},
+ GET_SET_DEFAULT(g_eeGeneral.keysBacklight));
+ }
+ },
+#endif
+ {
+ // Backlight/Brightness source
+ STR_DEF(STR_CONTROL),
+ [](Window* parent, coord_t x, coord_t y) {
+ auto choice = new SourceChoice(parent, {x, y, 0, 0}, MIXSRC_NONE, MIXSRC_LAST_SWITCH,
+ GET_SET_DEFAULT(g_eeGeneral.backlightSrc), true);
+ choice->setAvailableHandler(isSourceAvailableForBacklightOrVolume);
+ new ControlTextOverride(parent, x, y, FUNCTION_BACKLIGHT);
+ }
+ },
+ {
+ // Flash beep
+ STR_DEF(STR_ALARM),
+ [](Window* parent, coord_t x, coord_t y) {
+ new ToggleSwitch(parent, {x, y, 0, 0}, GET_SET_DEFAULT(g_eeGeneral.alarmsFlash));
+ }
+ },
+ {nullptr, nullptr},
+};
+
+const static SetupLineDef gpsPageSetupLines[] = {
{
// Timezone
STR_DEF(STR_TIMEZONE),
@@ -601,6 +604,7 @@ static SetupLineDef gpsPageSetupLines[] = {
GET_SET_DEFAULT(g_eeGeneral.gpsFormat));
}
},
+ {nullptr, nullptr},
};
static void viewOption(Window* parent, coord_t x, coord_t y,
@@ -616,7 +620,7 @@ static void viewOption(Window* parent, coord_t x, coord_t y,
}
}
-static SetupLineDef viewOptionsPageSetupLines[] = {
+const static SetupLineDef viewOptionsPageSetupLines[] = {
{
STR_DEF(STR_RADIO_MENU_TABS), nullptr,
},
@@ -719,61 +723,65 @@ static SetupLineDef viewOptionsPageSetupLines[] = {
g_model.modelTelemetryDisabled);
}
},
+ {nullptr, nullptr},
};
-class ManageModelsSetupPage : public SubPage
-{
- public:
- ManageModelsSetupPage() : SubPage(ICON_MODEL, STR_MAIN_MENU_RADIO_SETTINGS, STR_MANAGE_MODELS, true)
+const static SetupLineDef manageModelsSetupLines[] = {
{
- body->setFlexLayout();
-
// Model quick select
- setupLine(STR_MODEL_QUICK_SELECT, [=](Window* parent, coord_t x, coord_t y) {
- new ToggleSwitch(parent, {x, y, 0, 0},
- GET_SET_DEFAULT(g_eeGeneral.modelQuickSelect));
- });
-
- // Label single/multi select
- setupLine(STR_LABELS_SELECT, [=](Window* parent, coord_t x, coord_t y) {
- new Choice(parent, {x, y, 0, 0}, STR_LABELS_SELECT_MODE, 0, 1,
- GET_DEFAULT(g_eeGeneral.labelSingleSelect),
- [=](int newValue) {
- g_eeGeneral.labelSingleSelect = newValue;
- modelslabels.clearFilter();
- SET_DIRTY();
- });
- });
-
- // Label multi select matching mode
- multiSelectMatch = setupLine(STR_LABELS_MATCH, [=](Window* parent, coord_t x, coord_t y) {
- new Choice(parent, {x, y, 0, 0}, STR_LABELS_MATCH_MODE, 0, 1,
- GET_SET_DEFAULT(g_eeGeneral.labelMultiMode));
- });
-
- // Favorites multi select matching mode
- favSelectMatch = setupLine(STR_FAV_MATCH, [=](Window* parent, coord_t x, coord_t y) {
- new Choice(parent, {x, y, 0, 0}, STR_FAV_MATCH_MODE, 0, 1,
- GET_SET_DEFAULT(g_eeGeneral.favMultiMode));
- });
-
- checkEvents();
-
- enableRefresh();
- }
-
- void checkEvents() override
+ STR_DEF(STR_MODEL_QUICK_SELECT),
+ [](Window* parent, coord_t x, coord_t y) {
+ new ToggleSwitch(parent, {x, y, 0, 0},
+ GET_SET_DEFAULT(g_eeGeneral.modelQuickSelect));
+ }
+ },
{
- multiSelectMatch->show(!g_eeGeneral.labelSingleSelect);
- favSelectMatch->show(!g_eeGeneral.labelSingleSelect && (g_eeGeneral.labelMultiMode != 0));
- }
-
- protected:
- Window* multiSelectMatch = nullptr;
- Window* favSelectMatch = nullptr;
+ // Label single/multi select
+ STR_DEF(STR_LABELS_SELECT),
+ [](Window* parent, coord_t x, coord_t y) {
+ new Choice(parent, {x, y, 0, 0}, STR_LABELS_SELECT_MODE, 0, 1,
+ GET_DEFAULT(g_eeGeneral.labelSingleSelect),
+ [=](int newValue) {
+ g_eeGeneral.labelSingleSelect = newValue;
+ modelslabels.clearFilter();
+ Messaging::send(Messaging::REFRESH);
+ SET_DIRTY();
+ });
+ }
+ },
+ {
+ // Label multi select matching mode
+ STR_DEF(STR_LABELS_MATCH),
+ [](SetupLine* parent, coord_t x, coord_t y) {
+ parent->setupMsg.subscribe(Messaging::REFRESH, [=](uint32_t param) {
+ parent->show(!g_eeGeneral.labelSingleSelect);
+ });
+ new Choice(parent, {x, y, 0, 0}, STR_LABELS_MATCH_MODE, 0, 1,
+ GET_DEFAULT(g_eeGeneral.labelMultiMode),
+ [=](int newValue) {
+ g_eeGeneral.labelMultiMode = newValue;
+ Messaging::send(Messaging::REFRESH);
+ SET_DIRTY();
+ });
+ parent->show(!g_eeGeneral.labelSingleSelect);
+ }
+ },
+ {
+ // Favorites multi select matching mode
+ STR_DEF(STR_FAV_MATCH),
+ [](SetupLine* parent, coord_t x, coord_t y) {
+ parent->setupMsg.subscribe(Messaging::REFRESH, [=](uint32_t param) {
+ parent->show(!g_eeGeneral.labelSingleSelect && (g_eeGeneral.labelMultiMode != 0));
+ });
+ new Choice(parent, {x, y, 0, 0}, STR_FAV_MATCH_MODE, 0, 1,
+ GET_SET_DEFAULT(g_eeGeneral.favMultiMode));
+ parent->show(!g_eeGeneral.labelSingleSelect && (g_eeGeneral.labelMultiMode != 0));
+ }
+ },
+ {nullptr, nullptr},
};
-static SetupLineDef setupLines[] = {
+const static SetupLineDef setupLines[] = {
{
// Splash screen
STR_DEF(STR_SPLASHSCREEN),
@@ -1013,6 +1021,7 @@ static SetupLineDef setupLines[] = {
});
}
},
+ {nullptr, nullptr},
};
RadioSetupPage::RadioSetupPage(const PageDef& pageDef) : PageGroupItem(pageDef, PAD_TINY) {}
@@ -1028,6 +1037,28 @@ static bool hasShortcutKeys()
}
#endif
+const static PageButtonDef radioSetupButtons[] = {
+#if defined(AUDIO)
+ {STR_DEF(STR_SOUND_LABEL), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_SOUND_LABEL, soundPageSetupLines); }},
+#endif
+#if defined(VARIO)
+ {STR_DEF(STR_VARIO), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_VARIO, varioPageSetupLines); }},
+#endif
+#if defined(HAPTIC)
+ {STR_DEF(STR_HAPTIC_LABEL), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_HAPTIC_LABEL, hapticPageSetupLines); }},
+#endif
+ {STR_DEF(STR_ALARMS_LABEL), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_ALARMS_LABEL, alarmsPageSetupLines); }},
+ {STR_DEF(STR_BACKLIGHT_LABEL), []() { (new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_BACKLIGHT_LABEL, backlightSetupLines))->useFlexLayout(); }},
+ {STR_DEF(STR_GPS), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_GPS, gpsPageSetupLines); }},
+ {STR_DEF(STR_ENABLED_FEATURES), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_ENABLED_FEATURES, viewOptionsPageSetupLines); }},
+ {STR_DEF(STR_MAIN_MENU_MANAGE_MODELS), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_MANAGE_MODELS, manageModelsSetupLines); }},
+#if VERSION_MAJOR > 2
+ {STR_DEF(STR_KEY_SHORTCUTS), []() { new QMKeyShortcutsPage(); }, nullptr, []() { return hasShortcutKeys(); }},
+ {STR_DEF(STR_QUICK_MENU_FAVORITES), []() { new QMFavoritesPage(); }, nullptr},
+#endif
+ {nullptr},
+};
+
void RadioSetupPage::build(Window* window)
{
coord_t y = 0;
@@ -1038,27 +1069,8 @@ void RadioSetupPage::build(Window* window)
y += w->height() + padding;
// Sub-pages
- w = new SetupButtonGroup(window, {0, y, LCD_W - padding * 2, 0}, nullptr, BTN_COLS, PAD_TINY, {
-#if defined(AUDIO)
- {STR_DEF(STR_SOUND_LABEL), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_SOUND_LABEL, soundPageSetupLines, DIM(soundPageSetupLines)); }},
-#endif
-#if defined(VARIO)
- {STR_DEF(STR_VARIO), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_VARIO, varioPageSetupLines, DIM(varioPageSetupLines)); }},
-#endif
-#if defined(HAPTIC)
- {STR_DEF(STR_HAPTIC_LABEL), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_HAPTIC_LABEL, hapticPageSetupLines, DIM(hapticPageSetupLines)); }},
-#endif
- {STR_DEF(STR_ALARMS_LABEL), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_ALARMS_LABEL, alarmsPageSetupLines, DIM(alarmsPageSetupLines)); }},
- {STR_DEF(STR_BACKLIGHT_LABEL), []() { new BacklightPage(); }},
- {STR_DEF(STR_GPS), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_GPS, gpsPageSetupLines, DIM(gpsPageSetupLines)); }},
- {STR_DEF(STR_ENABLED_FEATURES), []() { new SubPage(ICON_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, STR_ENABLED_FEATURES, viewOptionsPageSetupLines, DIM(viewOptionsPageSetupLines)); }},
- {STR_DEF(STR_MAIN_MENU_MANAGE_MODELS), []() { new ManageModelsSetupPage(); }},
-#if VERSION_MAJOR > 2
- {STR_DEF(STR_KEY_SHORTCUTS), []() { new QMKeyShortcutsPage(); }, nullptr, [=]() { return hasShortcutKeys(); }},
- {STR_DEF(STR_QUICK_MENU_FAVORITES), []() { new QMFavoritesPage(); }, nullptr},
-#endif
- }, BTN_H);
+ w = new SetupButtonGroup(window, {0, y, LCD_W - padding * 2, 0}, nullptr, BTN_COLS, PAD_TINY, radioSetupButtons, BTN_H);
y += w->height() + padding;
- SetupLine::showLines(window, y, SubPage::EDT_X, padding, setupLines, DIM(setupLines));
+ SetupLine::showLines(window, y, SubPage::EDT_X, padding, setupLines);
}
diff --git a/radio/src/gui/colorlcd/radio/radio_theme.cpp b/radio/src/gui/colorlcd/radio/radio_theme.cpp
index fa973147d..45554438c 100644
--- a/radio/src/gui/colorlcd/radio/radio_theme.cpp
+++ b/radio/src/gui/colorlcd/radio/radio_theme.cpp
@@ -284,7 +284,6 @@ class ColorEditPage : public Page
}
setHexStr(rgb);
});
- _colorEditor->setColorEditorType(HSV_COLOR_EDITOR);
_activeTab = 1;
r.w = COLOR_BOX_WIDTH;
diff --git a/radio/src/gui/colorlcd/setup_menus/pagegroup.cpp b/radio/src/gui/colorlcd/setup_menus/pagegroup.cpp
index 17e8b3afd..b229fd0e1 100644
--- a/radio/src/gui/colorlcd/setup_menus/pagegroup.cpp
+++ b/radio/src/gui/colorlcd/setup_menus/pagegroup.cpp
@@ -278,19 +278,7 @@ class PageGroupHeader : public PageGroupHeaderBase
menu->setCurrentTab(idx);
}
- void updateLayout()
- {
- for (uint8_t i = 0; i < pages.size(); i += 1) {
- pages[i]->update(i);
- }
- }
-
protected:
- void checkEvents() override
- {
- updateLayout();
- PageGroupHeaderBase::checkEvents();
- }
};
//-----------------------------------------------------------------------------
@@ -311,6 +299,12 @@ PageGroupBase::PageGroupBase(coord_t bodyY, EdgeTxIcon icon) :
lv_obj_add_event_cb(lvobj, on_draw_begin, LV_EVENT_COVER_CHECK, nullptr);
lv_obj_add_event_cb(lvobj, on_draw_end, LV_EVENT_DRAW_POST_END, nullptr);
#endif
+
+ quickMenuMsg.subscribe(Messaging::QUICK_MENU_ITEM_SELECT,
+ [=](uint32_t param) {
+ if (param)
+ onCancel();
+ });
}
void PageGroupBase::checkEvents()
@@ -327,8 +321,9 @@ void PageGroupBase::onClicked() { Keyboard::hide(false); }
void PageGroupBase::onCancel()
{
- QuickMenu::closeQuickMenu();
- deleteLater();
+ if (!_deleted) {
+ deleteLater();
+ }
}
uint8_t PageGroupBase::tabCount() const
@@ -399,7 +394,7 @@ void PageGroupBase::doKeyShortcut(event_t event)
{
QMPage pg = g_eeGeneral.getKeyShortcut(event);
if (pg == QM_OPEN_QUICK_MENU) {
- if (!QuickMenu::isOpen()) openMenu();
+ QuickMenu::openQuickMenu();
} else {
if (QuickMenu::subMenuIcon(pg) == icon) {
setCurrentTab(QuickMenu::pageIndex(pg));
@@ -454,7 +449,7 @@ PageGroup::PageGroup(EdgeTxIcon icon, const char* title, const PageDef* pages) :
#if VERSION_MAJOR == 2
addCustomButton(0, 0, [=]() { onCancel(); });
#else
- addCustomButton(0, 0, [=]() { openMenu(); });
+ addCustomButton(0, 0, [=]() { QuickMenu::openQuickMenu(); });
addCustomButton(LCD_W - EdgeTxStyles::MENU_HEADER_HEIGHT, 0, [=]() { onCancel(); });
#endif
#endif
@@ -465,15 +460,6 @@ PageGroup::PageGroup(EdgeTxIcon icon, const char* title, const PageDef* pages) :
});
}
-void PageGroup::openMenu()
-{
- QuickMenu::openQuickMenu(
- [=](bool close) {
- if (close)
- onCancel();
- }, this, currentTab->pageId());
-}
-
//-----------------------------------------------------------------------------
class TabsGroupHeader : public PageGroupHeaderBase
@@ -545,31 +531,12 @@ TabsGroup::TabsGroup(EdgeTxIcon icon, const char* parentLabel) :
#if VERSION_MAJOR == 2
addCustomButton(0, 0, [=]() { onCancel(); });
#else
- addCustomButton(0, 0, [=]() { openMenu(); });
+ addCustomButton(0, 0, [=]() { QuickMenu::openQuickMenu(); });
addCustomButton(LCD_W - EdgeTxStyles::MENU_HEADER_HEIGHT, 0, [=]() { onCancel(); });
#endif
#endif
}
-void TabsGroup::openMenu()
-{
- PageGroup* p = Window::pageGroup();
- QMPage qmPage = QM_NONE;
- if (p)
- qmPage = p->getCurrentTab()->pageId();
- QuickMenu::openQuickMenu(
- [=](bool close) {
- onCancel();
- if (p) {
- while (!Window::topWindow()->isPageGroup()) {
- Window::topWindow()->deleteLater();
- }
- if (close)
- Window::topWindow()->onCancel();
- }
- }, p, qmPage);
-}
-
void TabsGroup::hidePageButtons()
{
((TabsGroupHeader*)header)->hidePageButtons();
diff --git a/radio/src/gui/colorlcd/setup_menus/pagegroup.h b/radio/src/gui/colorlcd/setup_menus/pagegroup.h
index b109007ab..02ba9dd17 100644
--- a/radio/src/gui/colorlcd/setup_menus/pagegroup.h
+++ b/radio/src/gui/colorlcd/setup_menus/pagegroup.h
@@ -22,6 +22,7 @@
#pragma once
#include "bitmaps.h"
+#include "messaging.h"
#include "quick_menu.h"
class HeaderIcon;
@@ -31,6 +32,7 @@ class PageGroupBase;
class SelectedTabIcon;
class PageGroupIconButton;
#endif
+
//-----------------------------------------------------------------------------
enum PageDefAction {
@@ -53,24 +55,6 @@ struct PageDef {
extern PageDef favoritesMenuItems[];
#endif
-enum QMTopDefAction {
- QM_SUBMENU,
- QM_ACTION
-};
-
-struct QMTopDef {
- EdgeTxIcon icon;
- STR_TYP qmTitle;
- STR_TYP title;
- QMTopDefAction pageAction;
- QMPage qmPage;
- const PageDef* subMenuItems;
- std::function action;
- std::function enabled;
-};
-
-extern const QMTopDef qmTopItems[];
-
//-----------------------------------------------------------------------------
class PageGroupItem
@@ -101,7 +85,6 @@ class PageGroupItem
PaddingSize getPadding() const { return padding; }
- virtual void update(uint8_t index) {}
virtual void cleanup() {}
QMPage pageId() const { return qmPageId; }
@@ -191,8 +174,7 @@ class PageGroupBase : public NavWindow
Window* body = nullptr;
PageGroupItem* currentTab = nullptr;
EdgeTxIcon icon;
-
- virtual void openMenu() = 0;
+ Messaging quickMenuMsg;
void checkEvents() override;
@@ -241,8 +223,6 @@ class PageGroup : public PageGroupBase
static constexpr coord_t PAGE_GROUP_BODY_Y = PAGE_GROUP_TOP_BAR_H + PAGE_GROUP_ALT_TITLE_H;
protected:
-
- void openMenu() override;
};
//-----------------------------------------------------------------------------
@@ -270,6 +250,4 @@ class TabsGroup : public PageGroupBase
static constexpr coord_t TABS_GROUP_BODY_Y = TABS_GROUP_TOP_BAR_H + TABS_GROUP_ALT_TITLE_H;
protected:
-
- void openMenu() override;
};
diff --git a/radio/src/gui/colorlcd/setup_menus/quick_menu.cpp b/radio/src/gui/colorlcd/setup_menus/quick_menu.cpp
index 7c6e8ad1d..7f7276a04 100644
--- a/radio/src/gui/colorlcd/setup_menus/quick_menu.cpp
+++ b/radio/src/gui/colorlcd/setup_menus/quick_menu.cpp
@@ -33,65 +33,80 @@
//-----------------------------------------------------------------------------
+bool QMMainDef::isSubMenu(QMPage page) const
+{
+ for (int i = 0; subMenuItems[i].icon < EDGETX_ICONS_COUNT; i += 1)
+ if (subMenuItems[i].qmPage == page)
+ return true;
+ return false;
+}
+
+bool QMMainDef::isSubMenu(QMPage page, EdgeTxIcon curIcon) const
+{
+ if ((icon != EDGETX_ICONS_COUNT) && (icon != curIcon))
+ return false;
+ return isSubMenu(page);
+}
+
+int QMMainDef::getIndex(QMPage n) const
+{
+ for (int i = 0; subMenuItems[i].icon < EDGETX_ICONS_COUNT; i += 1)
+ if (subMenuItems[i].qmPage == n)
+ return i;
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+
#if VERSION_MAJOR > 2
class QuickSubMenu
{
public:
- QuickSubMenu(Window* parent, QuickMenu* quickMenu,
- EdgeTxIcon icon, const char* title, const char* parentTitle,
- const PageDef* items):
- parent(parent), quickMenu(quickMenu),
- icon(icon), title(title), parentTitle(parentTitle), items(items)
+ QuickSubMenu(Window* parent, QuickMenu* quickMenu, const QMMainDef* mainDef):
+ parent(parent), quickMenu(quickMenu), mainDef(mainDef)
{}
bool isSubMenu(QMPage n)
{
- for (int i = 0; items[i].icon < EDGETX_ICONS_COUNT; i += 1)
- if (items[i].qmPage == n) return true;
- return false;
+ return mainDef->isSubMenu(n);
}
bool isSubMenu(QMPage n, EdgeTxIcon curIcon)
{
- if ((icon != EDGETX_ICONS_COUNT) && (icon != curIcon)) return false;
- return isSubMenu(n);
+ return mainDef->isSubMenu(n, curIcon);
}
bool isSubMenu(ButtonBase* b)
{
- for (int i = 0; items[i].icon < EDGETX_ICONS_COUNT; i += 1)
- if (menuButton == b) return true;
- return false;
+ return menuButton == b;
}
int getIndex(QMPage n)
{
- for (int i = 0; items[i].icon < EDGETX_ICONS_COUNT; i += 1)
- if (items[i].qmPage == n) return i;
- return -1;
+ return mainDef->getIndex(n);
}
ButtonBase* addButton()
{
- menuButton = quickMenu->getTopMenu()->addButton(icon, title,
+ menuButton = quickMenu->getTopMenu()->addButton(mainDef->icon, STR_VAL(mainDef->qmTitle),
[=]() -> uint8_t {
activate();
return 0;
+ },
+ mainDef->enabled,
+ [=](bool focus) {
+ if (!quickMenu->deleted()) {
+ if (focus) {
+ if (!subMenu) buildSubMenu();
+ quickMenu->getTopMenu()->setCurrent(menuButton);
+ }
+ if (subMenu)
+ subMenu->show(focus);
+ if (!focus && quickMenu->getTopMenu())
+ quickMenu->getTopMenu()->setGroup();
+ }
});
- menuButton->setFocusHandler([=](bool focus) {
- if (!quickMenu->deleted()) {
- if (focus) {
- if (!subMenu) buildSubMenu();
- quickMenu->getTopMenu()->setCurrent(menuButton);
- }
- if (subMenu)
- subMenu->show(focus);
- if (!focus && quickMenu->getTopMenu())
- quickMenu->getTopMenu()->setGroup();
- }
- });
-
return menuButton;
}
@@ -129,11 +144,11 @@ class QuickSubMenu
{
subMenu = new QuickMenuGroup(parent);
- for (int i = 0; items[i].icon < EDGETX_ICONS_COUNT; i += 1) {
- subMenu->addButton(items[i].icon, STR_VAL(items[i].qmTitle),
+ for (int i = 0; mainDef->subMenuItems[i].icon < EDGETX_ICONS_COUNT; i += 1) {
+ subMenu->addButton(mainDef->subMenuItems[i].icon, STR_VAL(mainDef->subMenuItems[i].qmTitle),
std::bind(&QuickSubMenu::onPress, this, i),
- items[i].enabled,
- [=]() { QuickMenu::setCurrentPage(items[i].qmPage, icon); });
+ mainDef->subMenuItems[i].enabled,
+ [=](bool focus) { if (focus) QuickMenu::setCurrentPage(mainDef->subMenuItems[i].qmPage, mainDef->icon); });
}
doLayout();
@@ -143,15 +158,15 @@ class QuickSubMenu
uint8_t onPress(int n)
{
- if (items[n].pageAction == PAGE_CREATE) {
+ if (mainDef->subMenuItems[n].pageAction == PAGE_CREATE) {
quickMenu->getTopMenu()->clearFocus();
int pgIdx = getPageNumber(n);
- if (quickMenu->getPageGroup() && quickMenu->getPageGroup()->hasSubMenu(items[n].qmPage)) {
+ if (quickMenu->getPageGroup() && quickMenu->getPageGroup()->hasSubMenu(mainDef->subMenuItems[n].qmPage)) {
quickMenu->onSelect(false);
quickMenu->getPageGroup()->setCurrentTab(pgIdx);
} else {
quickMenu->onSelect(true);
- auto pg = new PageGroup(icon, parentTitle, items);
+ auto pg = new PageGroup(mainDef->icon, STR_VAL(mainDef->title), mainDef->subMenuItems);
pg->setCurrentTab(pgIdx);
}
} else {
@@ -160,7 +175,7 @@ class QuickSubMenu
quickMenu->getTopMenu()->clearFocus();
enableSubMenu();
onSelect(true);
- items[n].action();
+ mainDef->subMenuItems[n].action();
}
return 0;
}
@@ -174,7 +189,7 @@ class QuickSubMenu
{
int pageNumber = 0;
for (int i = 0; i < iconNumber; i += 1)
- if (items[i].pageAction == PAGE_CREATE)
+ if (mainDef->subMenuItems[i].pageAction == PAGE_CREATE)
pageNumber += 1;
return pageNumber;
}
@@ -185,13 +200,18 @@ class QuickSubMenu
subMenu->doLayout(QuickMenu::QM_SUB_COLS);
}
+ void clearSubMenu()
+ {
+ if (subMenu) {
+ subMenu->deleteLater();
+ subMenu = nullptr;
+ }
+ }
+
protected:
Window* parent;
QuickMenu* quickMenu;
- EdgeTxIcon icon;
- const char* title;
- const char* parentTitle;
- const PageDef* items;
+ const QMMainDef* mainDef;
QuickMenuGroup* subMenu = nullptr;
ButtonBase* menuButton = nullptr;
};
@@ -200,34 +220,26 @@ class QuickSubMenu
//-----------------------------------------------------------------------------
QuickMenu* QuickMenu::instance = nullptr;
-QMPage QuickMenu::curPage = QM_NONE;
-EdgeTxIcon QuickMenu::curIcon = EDGETX_ICONS_COUNT;
-QuickMenu* QuickMenu::openQuickMenu(std::function selectHandler,
- PageGroupBase* pageGroup, QMPage curPage)
+void QuickMenu::openQuickMenu()
{
- if (!instance) {
+ if (instance && instance->isVisible())
+ return;
+
+ if (!instance)
instance = new QuickMenu();
- }
- instance->openQM(selectHandler, pageGroup, curPage);
- return instance;
-}
-void QuickMenu::closeQuickMenu()
-{
- if (instance)
- instance->closeQM();
-}
+ QMPage qmPage = QM_NONE;
+ PageGroup* p = Window::pageGroup();
+ if (p)
+ qmPage = p->getCurrentTab()->pageId();
-bool QuickMenu::isOpen()
-{
- return instance && instance->isVisible();
+ instance->openQM(p, qmPage);
}
void QuickMenu::shutdownQuickMenu()
{
if (instance) instance->deleteLater();
- instance = nullptr;
}
QuickMenu::QuickMenu() :
@@ -261,42 +273,32 @@ QuickMenu::QuickMenu() :
#if VERSION_MAJOR > 2
box = new Window(this, {QM_SUB_X, QM_SUB_Y, QM_SUB_W, QM_SUB_H});
- int f = 0;
- for (int i = 0; i < MAX_QM_FAVORITES; i += 1) {
- if (g_eeGeneral.qmFavorites[i].shortcut != QM_NONE) {
- setupFavorite((QMPage)g_eeGeneral.qmFavorites[i].shortcut, f);
- f += 1;
- }
- }
- favoritesMenuItems[f].icon = EDGETX_ICONS_COUNT;
+ updateFavorites();
#endif
for (int i = 0; qmTopItems[i].icon != EDGETX_ICONS_COUNT; i += 1) {
- if ((qmTopItems[i].enabled == nullptr) || qmTopItems[i].enabled()) {
- if (qmTopItems[i].pageAction == QM_ACTION) {
- mainMenu->addButton(qmTopItems[i].icon, STR_VAL(qmTopItems[i].qmTitle), [=]() { onSelect(true); qmTopItems[i].action(); });
+ if (qmTopItems[i].pageAction == QM_ACTION) {
+ mainMenu->addButton(qmTopItems[i].icon, STR_VAL(qmTopItems[i].qmTitle),
+ [=]() { onSelect(true); qmTopItems[i].action(); }, qmTopItems[i].enabled);
#if VERSION_MAJOR > 2
- } else {
- auto sub = new QuickSubMenu(box, this, qmTopItems[i].icon, STR_VAL(qmTopItems[i].qmTitle), STR_VAL(qmTopItems[i].title), qmTopItems[i].subMenuItems);
- sub->addButton();
- subMenus.emplace_back(sub);
+ } else {
+ auto sub = new QuickSubMenu(box, this, &qmTopItems[i]);
+ sub->addButton();
+ subMenus.emplace_back(sub);
#endif
- }
}
}
}
void QuickMenu::deleteLater()
{
- if (_deleted) return;
-
- instance = nullptr;
-
- NavWindow::deleteLater();
+ if (!_deleted) {
+ instance = nullptr;
+ NavWindow::deleteLater();
+ }
}
-void QuickMenu::openQM(std::function selectHandler,
- PageGroupBase* newPageGroup, QMPage newCurPage)
+void QuickMenu::openQM(PageGroupBase* newPageGroup, QMPage newCurPage)
{
pushLayer();
@@ -310,7 +312,6 @@ void QuickMenu::openQM(std::function selectHandler,
subMenus[i]->doLayout();
#endif
- this->selectHandler = std::move(selectHandler);
show();
lv_obj_move_foreground(lvobj);
if (newPageGroup) {
@@ -458,6 +459,27 @@ std::vector QuickMenu::menuPageNames(bool forFavorites)
}
#if VERSION_MAJOR > 2
+void QuickMenu::resetFavorites()
+{
+ if (instance)
+ instance->updateFavorites();
+}
+
+void QuickMenu::updateFavorites()
+{
+ int f = 0;
+ for (int i = 0; i < MAX_QM_FAVORITES; i += 1) {
+ if (g_eeGeneral.qmFavorites[i].shortcut != QM_NONE) {
+ setupFavorite((QMPage)g_eeGeneral.qmFavorites[i].shortcut, f);
+ f += 1;
+ }
+ }
+ favoritesMenuItems[f].icon = EDGETX_ICONS_COUNT;
+
+ if (subMenus.size() >= 1)
+ subMenus[0]->clearSubMenu();
+}
+
void QuickMenu::setupFavorite(QMPage page, int f)
{
PageDef& fav = favoritesMenuItems[f];
@@ -497,8 +519,10 @@ void QuickMenu::setupFavorite(QMPage page, int f)
void QuickMenu::setCurrentPage(QMPage newPage, EdgeTxIcon newIcon)
{
- curPage = newPage;
- curIcon = newIcon;
+ if (instance) {
+ instance->curPage = newPage;
+ instance->curIcon = newIcon;
+ }
}
void QuickMenu::focusMainMenu()
@@ -513,9 +537,8 @@ void QuickMenu::focusMainMenu()
void QuickMenu::onSelect(bool close)
{
- if (selectHandler) selectHandler(close);
- selectHandler = nullptr;
closeQM();
+ Messaging::send(Messaging::QUICK_MENU_ITEM_SELECT, close);
}
void QuickMenu::closeQM()
@@ -523,7 +546,6 @@ void QuickMenu::closeQM()
if (isVisible()) {
popLayer();
hide();
- selectHandler = nullptr;
}
}
diff --git a/radio/src/gui/colorlcd/setup_menus/quick_menu.h b/radio/src/gui/colorlcd/setup_menus/quick_menu.h
index bee497cf3..db2b95c26 100644
--- a/radio/src/gui/colorlcd/setup_menus/quick_menu.h
+++ b/radio/src/gui/colorlcd/setup_menus/quick_menu.h
@@ -27,16 +27,44 @@
#include "quick_menu_group.h"
#include "quick_menu_def.h"
-std::string replaceAll(std::string str, const std::string& from, const std::string& to);
+//-----------------------------------------------------------------------------
-class PageGroup;
class PageGroupBase;
-class ButtonBase;
struct PageDef;
#if VERSION_MAJOR > 2
class QuickSubMenu;
#endif
+//-----------------------------------------------------------------------------
+
+enum QMMainDefAction {
+ QM_SUBMENU,
+ QM_ACTION
+};
+
+struct QMMainDef {
+ EdgeTxIcon icon;
+ STR_TYP qmTitle;
+ STR_TYP title;
+ QMMainDefAction pageAction;
+ QMPage qmPage;
+ const PageDef* subMenuItems;
+ std::function action;
+ std::function enabled;
+
+ bool isSubMenu(QMPage page) const;
+ bool isSubMenu(QMPage page, EdgeTxIcon curIcon) const;
+ int getIndex(QMPage page) const;
+};
+
+extern const QMMainDef qmTopItems[];
+
+//-----------------------------------------------------------------------------
+
+std::string replaceAll(std::string str, const std::string& from, const std::string& to);
+
+//-----------------------------------------------------------------------------
+
#define GRP_W(n) ((QuickMenuGroup::QM_BUTTON_WIDTH + PAD_MEDIUM) * n - PAD_MEDIUM + PAD_OUTLINE * 2)
#if LANDSCAPE
#define GRP_H(n) ((QuickMenuGroup::QM_BUTTON_HEIGHT + PAD_MEDIUM) * n - PAD_MEDIUM + PAD_OUTLINE * 2)
@@ -62,10 +90,7 @@ class QuickMenu : public NavWindow
PageGroupBase* getPageGroup() const { return pageGroup; }
QuickMenuGroup* getTopMenu() const { return mainMenu; }
- static QuickMenu* openQuickMenu(std::function selectHandler = nullptr,
- PageGroupBase* pageGroup = nullptr, QMPage curPage = QM_NONE);
- static void closeQuickMenu();
- static bool isOpen();
+ static void openQuickMenu();
static void shutdownQuickMenu();
static void openPage(QMPage page);
@@ -73,6 +98,10 @@ class QuickMenu : public NavWindow
static int pageIndex(QMPage page);
static std::vector menuPageNames(bool forFavorites);
+#if VERSION_MAJOR > 2
+ static void resetFavorites();
+#endif
+
#if defined(HARDWARE_KEYS)
void doKeyShortcut(event_t event);
void onPressSYS() override;
@@ -119,18 +148,16 @@ class QuickMenu : public NavWindow
protected:
static QuickMenu* instance;
- std::function selectHandler = nullptr;
bool inSubMenu = false;
QuickMenuGroup* mainMenu = nullptr;
#if VERSION_MAJOR > 2
std::vector subMenus;
#endif
PageGroupBase* pageGroup = nullptr;
- static QMPage curPage;
- static EdgeTxIcon curIcon;
+ QMPage curPage = QM_NONE;
+ EdgeTxIcon curIcon = EDGETX_ICONS_COUNT;
- void openQM(std::function selectHandler,
- PageGroupBase* pageGroup, QMPage curPage);
+ void openQM(PageGroupBase* pageGroup, QMPage curPage);
void closeQM();
void focusMainMenu();
@@ -140,6 +167,9 @@ class QuickMenu : public NavWindow
static void selected();
#if VERSION_MAJOR > 2
- static void setupFavorite(QMPage page, int f);
+ void updateFavorites();
+ void setupFavorite(QMPage page, int f);
#endif
};
+
+//-----------------------------------------------------------------------------
diff --git a/radio/src/gui/colorlcd/setup_menus/quick_menu_data.cpp b/radio/src/gui/colorlcd/setup_menus/quick_menu_data.cpp
index 5009f1967..ff5d80596 100644
--- a/radio/src/gui/colorlcd/setup_menus/quick_menu_data.cpp
+++ b/radio/src/gui/colorlcd/setup_menus/quick_menu_data.cpp
@@ -117,7 +117,7 @@ const PageDef statsMenuItems[] = {
{ EDGETX_ICONS_COUNT }
};
-const QMTopDef qmTopItems[] = {
+const QMMainDef qmTopItems[] = {
{ ICON_MODEL_SELECT, STR_DEF(STR_QM_MANAGE_MODELS), STR_DEF(STR_MANAGE_MODELS), QM_ACTION, QM_MANAGE_MODELS, nullptr, []() { new ModelLabelsWindow(); }},
{ ICON_MODEL_NOTES, STR_DEF(STR_MAIN_MENU_MODEL_NOTES), STR_DEF(STR_MAIN_MENU_MODEL_NOTES), QM_ACTION, QM_NONE, nullptr, []() { QuickMenu::openPage(QM_MODEL_NOTES); }, modelHasNotes},
{ ICON_MONITOR, STR_DEF(STR_QM_CHAN_MON), STR_DEF(STR_QM_CHAN_MON), QM_ACTION, QM_TOOLS_CHAN_MON, nullptr, []() { new ChannelsViewMenu(); }
@@ -183,7 +183,7 @@ const PageDef toolsMenuItems[] = {
{ EDGETX_ICONS_COUNT }
};
-const QMTopDef qmTopItems[] = {
+const QMMainDef qmTopItems[] = {
{ ICON_QM_FAVORITES, STR_DEF(STR_FAVORITE_LABEL), STR_DEF(STR_FAVORITE_LABEL), QM_SUBMENU, QM_NONE, favoritesMenuItems, nullptr, []() { return favoritesMenuItems[0].icon != EDGETX_ICONS_COUNT; }},
{ ICON_MODEL_SELECT, STR_DEF(STR_QM_MANAGE_MODELS), STR_DEF(STR_MANAGE_MODELS), QM_ACTION, QM_MANAGE_MODELS, nullptr, []() { new ModelLabelsWindow(); }},
{ ICON_MODEL, STR_DEF(STR_QM_MODEL_SETUP), STR_DEF(STR_MAIN_MENU_MODEL_SETTINGS), QM_SUBMENU, QM_NONE, modelMenuItems},
diff --git a/radio/src/gui/colorlcd/setup_menus/quick_menu_favorites.cpp b/radio/src/gui/colorlcd/setup_menus/quick_menu_favorites.cpp
index 0e6753b47..bbc54d8c9 100644
--- a/radio/src/gui/colorlcd/setup_menus/quick_menu_favorites.cpp
+++ b/radio/src/gui/colorlcd/setup_menus/quick_menu_favorites.cpp
@@ -67,7 +67,7 @@ void QMFavoritesPage::onCancel()
if (changed) {
// Delete quick menu, and close parent page group (in case it is Favorites group)
- QuickMenu::shutdownQuickMenu();
+ QuickMenu::resetFavorites();
QuickMenu::setCurrentPage(QM_NONE);
Window::topWindow()->onCancel();
}
diff --git a/radio/src/gui/colorlcd/setup_menus/quick_menu_group.cpp b/radio/src/gui/colorlcd/setup_menus/quick_menu_group.cpp
index 6cb13db1c..3618e3b9e 100644
--- a/radio/src/gui/colorlcd/setup_menus/quick_menu_group.cpp
+++ b/radio/src/gui/colorlcd/setup_menus/quick_menu_group.cpp
@@ -127,6 +127,11 @@ class QuickMenuButton : public ButtonBase
return true;
}
+ void show(bool vis) override
+ {
+ ButtonBase::show(vis && isVisible());
+ }
+
protected:
StaticIcon* iconPtr = nullptr;
StaticText* textPtr = nullptr;
@@ -143,22 +148,18 @@ QuickMenuGroup::QuickMenuGroup(Window* parent) :
ButtonBase* QuickMenuGroup::addButton(EdgeTxIcon icon, const char* title,
std::function pressHandler,
std::function visibleHandler,
- std::function focusHandler)
+ std::function focusHandler)
{
ButtonBase* b = new QuickMenuButton(this, icon, title, [=]() { pressHandler(); return 0; }, visibleHandler);
b->setLongPressHandler([=]() { pressHandler(); return 0; });
btns.push_back(b);
if (group) lv_group_add_obj(group, b->getLvObj());
b->setFocusHandler([=](bool focus) {
- if (focus) {
+ if (focus)
curBtn = b;
- if (focusHandler) focusHandler();
- }
+ if (focusHandler)
+ focusHandler(focus);
});
- if (btns.size() == 1) {
- curBtn = b;
- if (focusHandler) focusHandler();
- }
return b;
}
@@ -238,11 +239,9 @@ void QuickMenuGroup::doLayout(int cols)
coord_t x = (n % cols) * (QM_BUTTON_WIDTH + PAD_MEDIUM);
coord_t y = (n / cols) * (QM_BUTTON_HEIGHT + PAD_MEDIUM);
lv_obj_set_pos(btns[i]->getLvObj(), x, y);
- btns[i]->show();
n += 1;
- } else {
- btns[i]->hide();
}
+ btns[i]->show();
}
}
diff --git a/radio/src/gui/colorlcd/setup_menus/quick_menu_group.h b/radio/src/gui/colorlcd/setup_menus/quick_menu_group.h
index 70f542fdd..3baa56a26 100644
--- a/radio/src/gui/colorlcd/setup_menus/quick_menu_group.h
+++ b/radio/src/gui/colorlcd/setup_menus/quick_menu_group.h
@@ -40,7 +40,7 @@ class QuickMenuGroup : public Window
ButtonBase* addButton(EdgeTxIcon icon, const char* title,
std::function pressHandler,
std::function visibleHandler = nullptr,
- std::function focusHandler = nullptr);
+ std::function focusHandler = nullptr);
void setGroup();
void setFocus();
@@ -55,6 +55,8 @@ class QuickMenuGroup : public Window
void prevEntry();
ButtonBase* getFocusedButton();
+ void deleteLater() override;
+
#if PORTRAIT
static LAYOUT_VAL_SCALED(QM_BUTTON_WIDTH, 72)
#else
@@ -69,6 +71,4 @@ class QuickMenuGroup : public Window
std::vector btns;
ButtonBase* curBtn = nullptr;
lv_group_t* group = nullptr;
-
- void deleteLater() override;
};
diff --git a/radio/src/gui/colorlcd/startup_shutdown.cpp b/radio/src/gui/colorlcd/startup_shutdown.cpp
index df1cf7791..c675b6b32 100644
--- a/radio/src/gui/colorlcd/startup_shutdown.cpp
+++ b/radio/src/gui/colorlcd/startup_shutdown.cpp
@@ -81,8 +81,8 @@ void drawSplash()
#endif
}
- // Force screen refresh
- lv_refr_now(nullptr);
+ // Refresh to show splash screen
+ MainWindow::instance()->run();
}
static tmr10ms_t splashStartTime = 0;
@@ -110,25 +110,17 @@ void waitSplash()
if (splashStartTime) {
inactivityCheckInputs();
splashStartTime += SPLASH_TIMEOUT;
- while (splashStartTime >= get_tmr10ms()) {
- MainWindow::instance()->run();
- WDG_RESET();
- checkSpeakerVolume();
- checkBacklight();
- sleep_ms(10);
+
+ MainWindow::instance()->blockUntilClose(true, [=]() {
+ if (splashStartTime < get_tmr10ms())
+ return true;
auto evt = getEvent();
if (evt || inactivityCheckInputs()) {
if (evt) killEvents(evt);
- break;
+ return true;
}
-#if defined(SIMU)
- // Allow simulator to exit if closed while splash showing
- uint32_t pwr_check = pwrCheck();
- if (pwr_check == e_power_off) {
- break;
- }
-#endif // defined(SIMU)
- }
+ return false;
+ });
// Reset timer so special/global functions set to !1x don't get triggered
START_SILENCE_PERIOD();
@@ -217,49 +209,23 @@ void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration,
MainWindow::instance()->run();
}
-void drawFatalErrorScreen(const char* message)
+Window* drawFatalErrorScreen(const char* message)
{
- static Window* fatalErrorWindow = nullptr;
+ auto w = new Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H});
+ w->setWindowFlag(OPAQUE);
+ etx_solid_bg(w->getLvObj(), COLOR_BLACK_INDEX);
- if (!fatalErrorWindow) {
- fatalErrorWindow =
- new Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H});
- fatalErrorWindow->setWindowFlag(OPAQUE);
- etx_solid_bg(fatalErrorWindow->getLvObj(), COLOR_BLACK_INDEX);
+ new StaticText(w, rect_t{0, LCD_H / 2 - EdgeTxStyles::STD_FONT_HEIGHT, LCD_W, EdgeTxStyles::STD_FONT_HEIGHT * 2},
+ message, COLOR_WHITE_INDEX, FONT(XL) | CENTERED);
- new StaticText(fatalErrorWindow, rect_t{0, LCD_H / 2 - EdgeTxStyles::STD_FONT_HEIGHT, LCD_W, EdgeTxStyles::STD_FONT_HEIGHT * 2},
- message, COLOR_WHITE_INDEX, FONT(XL) | CENTERED);
- }
-
- backlightEnable(100);
- MainWindow::instance()->run();
+ return w;
}
void runFatalErrorScreen(const char* message)
{
- lcdInitDisplayDriver();
-
drawFatalErrorScreen(message);
- // On startup wait for power button to be released
- while (pwrPressed()) {
- WDG_RESET();
- }
-
- while (true) {
- drawFatalErrorScreen(message);
- WDG_RESET();
-
- // loop as long as PWR button is pressed
- while (true) {
- uint32_t pwr_check = pwrCheck();
- if (pwr_check == e_power_off) {
- boardOff();
- return; // only happens in SIMU, required for proper shutdown
- } else if (pwr_check == e_power_on) {
- break;
- }
- WDG_RESET();
- }
- }
+ MainWindow::instance()->blockUntilClose(true, []() {
+ return false;
+ }, true);
}
diff --git a/radio/src/gui/colorlcd/startup_shutdown.h b/radio/src/gui/colorlcd/startup_shutdown.h
index 6d8d72e1f..b4f9a82a1 100644
--- a/radio/src/gui/colorlcd/startup_shutdown.h
+++ b/radio/src/gui/colorlcd/startup_shutdown.h
@@ -23,7 +23,9 @@
#include
-void drawFatalErrorScreen(const char* message);
+class Window;
+
+Window* drawFatalErrorScreen(const char* message);
void runFatalErrorScreen(const char* message);
// Screen templates
diff --git a/radio/src/gui/colorlcd/themes/theme_manager.cpp b/radio/src/gui/colorlcd/themes/theme_manager.cpp
index fa070b4b0..0bea14b4e 100644
--- a/radio/src/gui/colorlcd/themes/theme_manager.cpp
+++ b/radio/src/gui/colorlcd/themes/theme_manager.cpp
@@ -586,15 +586,3 @@ HeaderBackIcon::HeaderBackIcon(Window* parent, std::function action) :
}
#endif
}
-
-UsbSDConnected::UsbSDConnected() :
- Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H})
-{
- setWindowFlag(OPAQUE);
-
- etx_solid_bg(lvobj, COLOR_THEME_PRIMARY1_INDEX);
- new HeaderDateTime(this, LCD_W - TopBar::HDR_DATE_XO, PAD_MEDIUM);
-
- auto icon = new StaticIcon(this, 0, 0, ICON_USB_PLUGGED, COLOR_THEME_PRIMARY2_INDEX);
- lv_obj_center(icon->getLvObj());
-}
diff --git a/radio/src/gui/colorlcd/themes/theme_manager.h b/radio/src/gui/colorlcd/themes/theme_manager.h
index 9a24525fd..7e3dff8bd 100644
--- a/radio/src/gui/colorlcd/themes/theme_manager.h
+++ b/radio/src/gui/colorlcd/themes/theme_manager.h
@@ -211,9 +211,3 @@ class HeaderBackIcon : public StaticIcon
if (action) action();
}
};
-
-class UsbSDConnected : public Window
-{
- public:
- UsbSDConnected();
-};
diff --git a/radio/src/gui/colorlcd/widgets/gauge.cpp b/radio/src/gui/colorlcd/widgets/gauge.cpp
index 4ae9fd563..b0b1b11b2 100644
--- a/radio/src/gui/colorlcd/widgets/gauge.cpp
+++ b/radio/src/gui/colorlcd/widgets/gauge.cpp
@@ -105,12 +105,10 @@ class GaugeWidget : public Widget
DynamicNumber* valueText = nullptr;
lv_obj_t* bar = nullptr;
- void checkEvents() override
+ void foreground() override
{
if (!loaded) return;
- Widget::checkEvents();
-
auto newValue = getGuageValue();
if (lastValue != newValue) {
lastValue = newValue;
diff --git a/radio/src/gui/colorlcd/widgets/modelbmp.cpp b/radio/src/gui/colorlcd/widgets/modelbmp.cpp
index 5e252eeb0..e5d81a992 100644
--- a/radio/src/gui/colorlcd/widgets/modelbmp.cpp
+++ b/radio/src/gui/colorlcd/widgets/modelbmp.cpp
@@ -50,15 +50,13 @@ class ModelBitmapWidget : public Widget
image = new StaticBitmap(this, {0, 0, width(), height()});
image->hide();
- checkEvents();
+ foreground();
}
- void checkEvents() override
+ void foreground() override
{
if (!loaded) return;
- Widget::checkEvents();
-
if (getHash() != deps_hash) {
update();
}
diff --git a/radio/src/gui/colorlcd/widgets/outputs.cpp b/radio/src/gui/colorlcd/widgets/outputs.cpp
index 8e3c5a86e..6b8998fdf 100644
--- a/radio/src/gui/colorlcd/widgets/outputs.cpp
+++ b/radio/src/gui/colorlcd/widgets/outputs.cpp
@@ -19,9 +19,10 @@
* GNU General Public License for more details.
*/
-#include "edgetx.h"
#include "widget.h"
-#include
+
+#include "edgetx.h"
+#include "messaging.h"
constexpr int16_t OUTPUT_INVALID_VALUE = INT16_MIN;
@@ -38,6 +39,8 @@ class ChannelValue : public Window
{
setWindowFlag(NO_FOCUS | NO_CLICK);
+ refreshMsg.subscribe(Messaging::REFRESH_OUTPUTS_WIDGET, [=](uint32_t param) { refresh(); });
+
delayLoad();
}
@@ -79,7 +82,7 @@ class ChannelValue : public Window
lv_line_set_points(divLine, divPoints, 2);
etx_obj_add_style(divLine, styles->div_line, LV_PART_MAIN);
- checkEvents();
+ refresh();
}
void setChannel()
@@ -94,7 +97,7 @@ class ChannelValue : public Window
lv_label_set_text(chanLabel, s);
}
- void checkEvents() override
+ void refresh()
{
if (!loaded) return;
@@ -136,8 +139,6 @@ class ChannelValue : public Window
chanHasName = hasName;
setChannel();
}
-
- Window::checkEvents();
}
static LAYOUT_VAL_SCALED(ROW_HEIGHT, 16)
@@ -155,6 +156,7 @@ class ChannelValue : public Window
lv_obj_t* chanLabel = nullptr;
lv_point_t divPoints[2];
lv_obj_t* bar = nullptr;
+ Messaging refreshMsg;
};
class OutputsWidget : public Widget
@@ -225,6 +227,11 @@ class OutputsWidget : public Widget
}
}
+ void foreground() override
+ {
+ Messaging::send(Messaging::REFRESH_OUTPUTS_WIDGET);
+ }
+
static const WidgetOption options[];
protected:
diff --git a/radio/src/gui/colorlcd/widgets/radio_info.cpp b/radio/src/gui/colorlcd/widgets/radio_info.cpp
index 976b531e2..0ac951177 100644
--- a/radio/src/gui/colorlcd/widgets/radio_info.cpp
+++ b/radio/src/gui/colorlcd/widgets/radio_info.cpp
@@ -19,28 +19,19 @@
* GNU General Public License for more details.
*/
-#include "hal/usb_driver.h"
-#include "edgetx.h"
-#include "theme_manager.h"
#include "widget.h"
+
+#include "edgetx.h"
+#include "hal/usb_driver.h"
#include "layout.h"
+#include "theme_manager.h"
-class TopBarWidget : public Widget
-{
- public:
- TopBarWidget(const WidgetFactory* factory, Window* parent, const rect_t& rect,
- int screenNum, int zoneNum) :
- Widget(factory, parent, rect, screenNum, zoneNum)
- {
- }
-};
-
-class RadioInfoWidget : public TopBarWidget
+class RadioInfoWidget : public Widget
{
public:
RadioInfoWidget(const WidgetFactory* factory, Window* parent, const rect_t& rect,
int screenNum, int zoneNum) :
- TopBarWidget(factory, parent, rect, screenNum, zoneNum)
+ Widget(factory, parent, rect, screenNum, zoneNum)
{
// Logs
logsIcon = new StaticIcon(this, W_LOG_X, PAD_THREE, ICON_DOT,
@@ -108,7 +99,7 @@ class RadioInfoWidget : public TopBarWidget
etx_bg_color(rssiBars[i], COLOR_THEME_PRIMARY2_INDEX, LV_STATE_USER_1);
}
- checkEvents();
+ foreground();
}
void update() override
@@ -121,10 +112,8 @@ class RadioInfoWidget : public TopBarWidget
etx_bg_color_from_flags(batteryFill, widgetData->options[0].value.unsignedValue, LV_STATE_USER_2);
}
- void checkEvents() override
+ void foreground() override
{
- TopBarWidget::checkEvents();
-
usbIcon->show(usbPlugged());
if (getSelectedUsbMode() == USB_UNSELECTED_MODE)
usbIcon->setColor(COLOR_THEME_PRIMARY3_INDEX);
@@ -240,18 +229,23 @@ const WidgetOption RadioInfoWidget::options[] = {
BaseWidgetFactory RadioInfoWidget("Radio Info", RadioInfoWidget::options,
STR_RADIO_INFO_WIDGET);
-class DateTimeWidget : public TopBarWidget
+class DateTimeWidget : public Widget
{
public:
DateTimeWidget(const WidgetFactory* factory, Window* parent, const rect_t& rect,
int screenNum, int zoneNum) :
- TopBarWidget(factory, parent, rect, screenNum, zoneNum)
+ Widget(factory, parent, rect, screenNum, zoneNum)
{
coord_t x = rect.w - HeaderDateTime::HDR_DATE_WIDTH - DT_XO;
dateTime = new HeaderDateTime(this, x, PAD_THREE);
update();
}
+ void foreground() override
+ {
+ Widget::checkEvents();
+ }
+
void update() override
{
auto widgetData = getPersistentData();
@@ -283,12 +277,12 @@ BaseWidgetFactory DateTimeWidget("Date Time",
#if defined(INTERNAL_GPS)
-class InternalGPSWidget : public TopBarWidget
+class InternalGPSWidget : public Widget
{
public:
InternalGPSWidget(const WidgetFactory* factory, Window* parent, const rect_t& rect,
int screenNum, int zoneNum) :
- TopBarWidget(factory, parent, rect, screenNum, zoneNum)
+ Widget(factory, parent, rect, screenNum, zoneNum)
{
icon =
new StaticIcon(this, width() / 2 - PAD_LARGE - PAD_TINY, ICON_H,
@@ -299,10 +293,8 @@ class InternalGPSWidget : public TopBarWidget
COLOR_THEME_PRIMARY2_INDEX, CENTERED | FONT(XS));
}
- void checkEvents() override
+ void foreground() override
{
- TopBarWidget::checkEvents();
-
bool hasGPS = serialGetModePort(UART_MODE_GPS) >= 0;
numSats->show(hasGPS && (gpsData.numSat > 0));
diff --git a/radio/src/gui/colorlcd/widgets/timer.cpp b/radio/src/gui/colorlcd/widgets/timer.cpp
index 1740dbd7d..f3a95cc4f 100644
--- a/radio/src/gui/colorlcd/widgets/timer.cpp
+++ b/radio/src/gui/colorlcd/widgets/timer.cpp
@@ -102,15 +102,13 @@ class TimerWidget : public Widget
lv_obj_add_flag(timerArc, LV_OBJ_FLAG_HIDDEN);
update();
- checkEvents();
+ foreground();
}
- void checkEvents() override
+ void foreground() override
{
if (!loaded) return;
- Widget::checkEvents();
-
auto widgetData = getPersistentData();
uint32_t index = widgetData->options[0].value.unsignedValue;
diff --git a/radio/src/gui/colorlcd/widgets/value.cpp b/radio/src/gui/colorlcd/widgets/value.cpp
index b8ef48dbf..7a6e2e535 100644
--- a/radio/src/gui/colorlcd/widgets/value.cpp
+++ b/radio/src/gui/colorlcd/widgets/value.cpp
@@ -71,15 +71,13 @@ class ValueWidget : public Widget
lv_label_set_text(value, "");
update();
- checkEvents();
+ foreground();
}
- void checkEvents() override
+ void foreground() override
{
if (!loaded) return;
- Widget::checkEvents();
-
bool changed = false;
auto widgetData = getPersistentData();
diff --git a/radio/src/gui/common/stdlcd/draw_functions.h b/radio/src/gui/common/stdlcd/draw_functions.h
index fe4ab6665..fb0fbec78 100644
--- a/radio/src/gui/common/stdlcd/draw_functions.h
+++ b/radio/src/gui/common/stdlcd/draw_functions.h
@@ -43,7 +43,6 @@ void drawFlightMode(coord_t x, coord_t y, int8_t idx, LcdFlags att = 0);
void drawStartupAnimation(uint32_t duration, uint32_t totalDuration);
void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration, const char * message);
void drawSleepBitmap();
-void drawFatalErrorScreen(const char * message);
void runFatalErrorScreen(const char * message);
void lcdDrawMMM(coord_t x, coord_t y, LcdFlags flags=0);
diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp
index 6d58240b3..706d33b7d 100644
--- a/radio/src/gui/gui_common.cpp
+++ b/radio/src/gui/gui_common.cpp
@@ -721,32 +721,28 @@ bool isSourceAvailableInResetSpecialFunction(int index)
class AntennaSelectionMenu : public Menu
{
- bool& done;
-
-public:
- AntennaSelectionMenu(bool& done) : Menu(), done(done) {
+ public:
+ AntennaSelectionMenu() : Menu()
+ {
setTitle(STR_ANTENNA);
addLine(STR_USE_INTERNAL_ANTENNA,
[] { globalData.externalAntennaEnabled = false; });
addLine(STR_USE_EXTERNAL_ANTENNA,
[] { globalData.externalAntennaEnabled = true; });
- setCloseHandler([=]() { this->done = true; });
setCloseWhenClickOutside(false);
}
-protected:
+
+ protected:
void onCancel() override {}
};
static void runAntennaSelectionMenu()
{
- bool finished = false;
- new AntennaSelectionMenu(finished);
+ auto menu = new AntennaSelectionMenu();
- while (!finished) {
- WDG_RESET();
- MainWindow::instance()->run();
- sleep_ms(20);
- }
+ MainWindow::instance()->blockUntilClose(true, [=]() {
+ return menu->deleted();
+ });
}
#else
void onAntennaSelection(const char* result)
diff --git a/radio/src/lua/lua_lvgl_widget.cpp b/radio/src/lua/lua_lvgl_widget.cpp
index 96edc184a..d0ce15b07 100644
--- a/radio/src/lua/lua_lvgl_widget.cpp
+++ b/radio/src/lua/lua_lvgl_widget.cpp
@@ -1500,7 +1500,7 @@ void LvglWidgetBox::build(lua_State *L)
{
window =
new Window(lvglManager->getCurrentParent(), {x, y, w, h}, lv_obj_create);
- window->disableForcedScroll();
+ window->setWindowFlag(NO_FORCED_SCROLL);
window->setScrollHandler([=](coord_t x, coord_t y) { pcallFuncWith2Int(L, scrolledFunction, 0, x, y); });
lv_obj_add_flag(window->getLvObj(), LV_OBJ_FLAG_EVENT_BUBBLE);
if (luaScriptManager->isWidget() && !luaScriptManager->isFullscreen()) {
@@ -2472,7 +2472,7 @@ void LvglWidgetPage::build(lua_State *L)
showBackButton, prevActionFunction != LUA_REFNIL, nextActionFunction != LUA_REFNIL);
window = page->getBody();
- window->disableForcedScroll();
+ window->setWindowFlag(NO_FORCED_SCROLL);
window->setScrollHandler([=](coord_t x, coord_t y) { pcallFuncWith2Int(L, scrolledFunction, 0, x, y); });
if (setFlex()) {
lv_flex_align_t align1 = (align.flags & RIGHT) ? LV_FLEX_ALIGN_END : (align.flags & CENTERED) ? LV_FLEX_ALIGN_CENTER : LV_FLEX_ALIGN_START;
diff --git a/radio/src/lua/lua_widget.h b/radio/src/lua/lua_widget.h
index 638c07eb4..88ec8750c 100644
--- a/radio/src/lua/lua_widget.h
+++ b/radio/src/lua/lua_widget.h
@@ -104,8 +104,6 @@ class LuaScriptManager : public LuaEventHandler
class LuaWidget : public Widget, public LuaScriptManager
{
- friend class LuaWidgetFactory;
-
public:
LuaWidget(const WidgetFactory* factory, Window* parent, const rect_t& rect,
int screenNum, int zoneNum, int zoneRectDataRef,
diff --git a/radio/src/main.cpp b/radio/src/main.cpp
index dc102e810..8abf1cff2 100644
--- a/radio/src/main.cpp
+++ b/radio/src/main.cpp
@@ -141,6 +141,23 @@ void closeUsbMenu()
#endif
#if defined(COLORLCD)
+class UsbSDConnected : public Window
+{
+ public:
+ UsbSDConnected() : Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H})
+ {
+ setWindowFlag(OPAQUE);
+
+ pushLayer(false);
+
+ etx_solid_bg(lvobj, COLOR_THEME_PRIMARY1_INDEX);
+ new HeaderDateTime(this, LCD_W - TopBar::HDR_DATE_XO, PAD_MEDIUM);
+
+ auto icon = new StaticIcon(this, 0, 0, ICON_USB_PLUGGED, COLOR_THEME_PRIMARY2_INDEX);
+ lv_obj_center(icon->getLvObj());
+ }
+};
+
static UsbSDConnected* usbConnectedWindow = nullptr;
#endif
@@ -193,11 +210,21 @@ void handleUsbConnection()
usbStop();
TRACE("USB stopped");
if (getSelectedUsbMode() == USB_MASS_STORAGE_MODE) {
- edgeTxResume();
#if defined(COLORLCD)
usbConnectedWindow->deleteLater();
usbConnectedWindow = nullptr;
+ // In case the SD card is removed during the session
+ if (!SD_CARD_PRESENT()) {
+ // Blocks until shutdown or SD card inserted
+ auto w = drawFatalErrorScreen(STR_NO_SDCARD);
+ MainWindow::instance()->blockUntilClose(true, []() {
+ return SD_CARD_PRESENT();
+ }, true);
+ w->deleteLater();
+ }
+ edgeTxResume();
#else
+ edgeTxResume();
pushEvent(EVT_ENTRY);
#endif
} else if (getSelectedUsbMode() == USB_SERIAL_MODE) {
@@ -350,8 +377,6 @@ void guiMain(event_t evt)
}
#endif
- MainWindow::instance()->run();
-
bool mainViewRequested = (mainRequestFlags & (1u << REQUEST_MAIN_VIEW));
if (mainViewRequested) {
auto viewMain = ViewMain::instance();
@@ -369,6 +394,20 @@ void guiMain(event_t evt)
writeScreenshot();
mainRequestFlags &= ~(1u << REQUEST_SCREENSHOT);
}
+
+ // For color screens show a popup deferred from another task
+ show_ui_popup();
+ // Show GVAR popup
+ if (gvarDisplayTimer > 0) {
+ char s[30], *p;
+ p = strAppendStringWithIndex(s, STR_GV, gvarLastChanged + 1);
+ p = strAppend(p, " ", 1);
+ p = strAppend(p, g_model.gvars[gvarLastChanged].name, LEN_GVAR_NAME);
+ p = strAppend(p, " = ", 3);
+ p = strAppendSigned(p, GVAR_VALUE(gvarLastChanged, getGVarFlightMode(mixerCurrentFlightMode, gvarLastChanged)));
+ POPUP_BUBBLE(s, gvarDisplayTimer * 10, 200);
+ gvarDisplayTimer = 0;
+ }
}
#elif defined(GUI)
@@ -510,10 +549,14 @@ void perMain()
checkHatsAsKeys();
#endif
+#if defined(COLORLCD)
+ MainWindow::instance()->run();
+#endif
+
#if defined(RTC_BACKUP_RAM)
if (UNEXPECTED_SHUTDOWN()) {
#if defined(COLORLCD)
- drawFatalErrorScreen(STR_EMERGENCY_MODE);
+ backlightEnable(BACKLIGHT_LEVEL_MAX);
#else
lcdClear();
menuMainView(0);
@@ -523,26 +566,18 @@ void perMain()
}
#endif
- if ((!usbPlugged() || (getSelectedUsbMode() == USB_UNSELECTED_MODE)) &&
- SD_CARD_PRESENT() && !sdMounted()) {
- sdMount();
- }
+ if (!usbPlugged() || (getSelectedUsbMode() == USB_UNSELECTED_MODE)) {
+ if (SD_CARD_PRESENT() && !sdMounted())
+ sdMount();
- // In case the SD card is removed during the session
- if ((!usbPlugged() || (getSelectedUsbMode() == USB_UNSELECTED_MODE)) &&
- !SD_CARD_PRESENT() && !UNEXPECTED_SHUTDOWN()) {
- // TODO: implement for b/w
-#if defined(COLORLCD)
- drawFatalErrorScreen(STR_NO_SDCARD);
- return;
-#endif
+ // In case the SD card is removed during the session
+ if (!SD_CARD_PRESENT()) {
+ // TODO: implement for b/w
+ }
}
if (usbPlugged() && getSelectedUsbMode() == USB_MASS_STORAGE_MODE) {
-#if defined(COLORLCD)
- MainWindow::instance()->run();
- usbConnectedWindow->checkEvents();
-#else
+#if !defined(COLORLCD)
// disable access to menus
lcdClear();
menuMainView(0);
@@ -567,19 +602,6 @@ void perMain()
DEBUG_TIMER_START(debugTimerGuiMain);
#if defined(COLORLCD)
guiMain(0);
- // For color screens show a popup deferred from another task
- show_ui_popup();
- // Show GVAR popup
- if (gvarDisplayTimer > 0) {
- char s[30], *p;
- p = strAppendStringWithIndex(s, STR_GV, gvarLastChanged + 1);
- p = strAppend(p, " ", 1);
- p = strAppend(p, g_model.gvars[gvarLastChanged].name, LEN_GVAR_NAME);
- p = strAppend(p, " = ", 3);
- p = strAppendSigned(p, GVAR_VALUE(gvarLastChanged, getGVarFlightMode(mixerCurrentFlightMode, gvarLastChanged)));
- POPUP_BUBBLE(s, gvarDisplayTimer * 10, 200);
- gvarDisplayTimer = 0;
- }
#else
guiMain(evt);
#endif
diff --git a/radio/src/storage/modelslist.cpp b/radio/src/storage/modelslist.cpp
index 4ffe397e3..990a62ab9 100644
--- a/radio/src/storage/modelslist.cpp
+++ b/radio/src/storage/modelslist.cpp
@@ -1293,7 +1293,7 @@ const char *ModelsList::save(LabelsVector newOrder)
f_puts("\r\n", &file);
f_close(&file);
- modelslabels._isDirty = false;
+ modelslabels.resetDirty();
return NULL;
}
diff --git a/radio/src/storage/modelslist.h b/radio/src/storage/modelslist.h
index b26575753..c3d334400 100644
--- a/radio/src/storage/modelslist.h
+++ b/radio/src/storage/modelslist.h
@@ -139,6 +139,7 @@ class ModelMap : protected std::multimap
}
std::string getBulletLabelString(ModelCell *, const char *noresults = "");
void setDirty(bool save = false);
+ void resetDirty() { _isDirty = false; }
bool isDirty() { return _isDirty; }
// Currently selected labels in the GUI
@@ -163,18 +164,6 @@ class ModelMap : protected std::multimap
const std::string &from,
const std::string &to);
- protected:
- ModelsSortBy _sortOrder = DEFAULT_MODEL_SORT;
- bool _isDirty = true;
- std::set filtlbls;
- std::string currentlabel = "";
-
- void updateModelCell(ModelCell *);
- bool removeModels(
- ModelCell *); // Should only be called from ModelsList remove model
- bool updateModelFile(ModelCell *);
- void sortModelsBy(ModelsVector &mv, ModelsSortBy sortby);
-
void clear()
{
_isDirty = true;
@@ -182,6 +171,18 @@ class ModelMap : protected std::multimap
std::multimap::clear();
}
+ void updateModelCell(ModelCell *);
+ bool removeModels(ModelCell *);
+
+ protected:
+ ModelsSortBy _sortOrder = DEFAULT_MODEL_SORT;
+ bool _isDirty = true;
+ std::set filtlbls;
+ std::string currentlabel = "";
+
+ bool updateModelFile(ModelCell *);
+ void sortModelsBy(ModelsVector &mv, ModelsSortBy sortby);
+
int getIndexByLabel(const std::string &str)
{
auto a = std::find(labels.begin(), labels.end(), str);
@@ -196,8 +197,6 @@ class ModelMap : protected std::multimap
return std::string();
}
- friend class ModelsList;
-
private:
LabelsVector labels; // Storage space for discovered labels
};
diff --git a/radio/src/storage/storage_common.cpp b/radio/src/storage/storage_common.cpp
index a39d894de..16b6bf7e0 100644
--- a/radio/src/storage/storage_common.cpp
+++ b/radio/src/storage/storage_common.cpp
@@ -118,6 +118,13 @@ void postRadioSettingsLoad()
serialSetMode(port_nr, UART_MODE_NONE);
}
#endif
+
+#if defined(COLORLCD)
+ // Ensure ON brightness >= OFF brightness
+ if ((BACKLIGHT_LEVEL_MAX - g_eeGeneral.backlightBright) < g_eeGeneral.blOffBright)
+ g_eeGeneral.backlightBright =
+ BACKLIGHT_LEVEL_MAX - g_eeGeneral.blOffBright;
+#endif
}
static bool sortMixerLines()
diff --git a/radio/src/switches.cpp b/radio/src/switches.cpp
index 23bd912b8..d202e37dd 100644
--- a/radio/src/switches.cpp
+++ b/radio/src/switches.cpp
@@ -95,6 +95,10 @@ uint8_t isSwitch3Pos(uint8_t idx)
return IS_CONFIG_3POS(idx);
}
+#if defined(SIMU)
+bool evalFSok = false;
+#endif
+
void setFSStartupPosition()
{
for (uint8_t i = 0; i < switchGetMaxSwitches(); i++) {
@@ -118,6 +122,10 @@ void setFSStartupPosition()
}
}
}
+
+#if defined(SIMU)
+ evalFSok = true;
+#endif
}
void setFSLogicalState(uint8_t index, uint8_t value)
@@ -159,6 +167,10 @@ bool isFSGroupUsed(uint8_t index)
void evalFunctionSwitches()
{
+#if defined(SIMU)
+ if (!evalFSok) return;
+#endif
+
for (uint8_t i = 0; i < switchGetMaxSwitches(); i++) {
if (switchIsCustomSwitch(i)) {
if (g_model.getSwitchType(i) == SWITCH_NONE) {
@@ -884,7 +896,9 @@ void checkSwitches()
LED_ERROR_BEGIN();
auto dialog = new SwitchWarnDialog();
- dialog->runForever();
+ MainWindow::instance()->blockUntilClose(true, [=]() {
+ return dialog->deleted();
+ });
LED_ERROR_END();
}
#elif defined(GUI)
diff --git a/radio/src/targets/pa01/battery_driver.cpp b/radio/src/targets/pa01/battery_driver.cpp
index 4b8ad5765..506540956 100644
--- a/radio/src/targets/pa01/battery_driver.cpp
+++ b/radio/src/targets/pa01/battery_driver.cpp
@@ -344,7 +344,8 @@ void handle_battery_charge(uint32_t last_press_time)
if (!lcdInited) {
lcdInited = true;
backlightInit();
- lcdInitDisplayDriver();
+ // Ensure lvgl is initialised before creating windows
+ LvglWrapper::instance();
}
if (updateTime == 0 || ((timersGetMsTick() - updateTime) >= 500))
diff --git a/radio/src/targets/pl18/battery_driver.cpp b/radio/src/targets/pl18/battery_driver.cpp
index 026316730..5ec4ee6df 100644
--- a/radio/src/targets/pl18/battery_driver.cpp
+++ b/radio/src/targets/pl18/battery_driver.cpp
@@ -480,7 +480,8 @@ void handle_battery_charge(uint32_t last_press_time)
if (!lcdInited) {
lcdInited = true;
backlightInit();
- lcdInitDisplayDriver();
+ // Ensure lvgl is initialised before creating windows
+ LvglWrapper::instance();
}
if (updateTime == 0 || ((timersGetMsTick() - updateTime) >= 500))
diff --git a/radio/src/targets/st16/battery_driver.cpp b/radio/src/targets/st16/battery_driver.cpp
index e37c51799..1c95d1eef 100644
--- a/radio/src/targets/st16/battery_driver.cpp
+++ b/radio/src/targets/st16/battery_driver.cpp
@@ -337,7 +337,8 @@ void handle_battery_charge(uint32_t last_press_time)
if (!lcdInited) {
lcdInited = true;
backlightInit();
- lcdInitDisplayDriver();
+ // Ensure lvgl is initialised before creating windows
+ LvglWrapper::instance();
}
if (updateTime == 0 || ((timersGetMsTick() - updateTime) >= 500))
diff --git a/radio/src/tasks.cpp b/radio/src/tasks.cpp
index 9e6e28bf5..f5b5896d4 100644
--- a/radio/src/tasks.cpp
+++ b/radio/src/tasks.cpp
@@ -33,7 +33,6 @@
#include "tasks/mixer_task.h"
#if defined(COLORLCD)
-#include "LvglWrapper.h"
#include "startup_shutdown.h"
#endif
@@ -55,14 +54,15 @@ bool perMainEnabled = true;
static void menusTask()
{
-#if defined(COLORLCD)
- LvglWrapper::instance();
-#endif
-
edgeTxInit();
mixerTaskInit();
+#if defined(COLORLCD) && defined(RTC_BACKUP_RAM)
+ if (UNEXPECTED_SHUTDOWN())
+ drawFatalErrorScreen(STR_EMERGENCY_MODE);
+#endif
+
#if defined(PWR_BUTTON_PRESS)
while (task_running()) {
uint32_t pwr_check = pwrCheck();
diff --git a/tools/convert-gfx-list.csv b/tools/convert-gfx-list.csv
index 14b4fdee8..11176773c 100644
--- a/tools/convert-gfx-list.csv
+++ b/tools/convert-gfx-list.csv
@@ -71,8 +71,6 @@ mask_inline_multiply,17,17,2026-01-13 11:36:16
mask_inline_replace,17,17,2026-01-13 11:36:16
mask_menu_edgetx,122,25,2026-01-13 11:36:16
mask_menu_favs,30,30,2026-01-13 11:36:16
-mask_ui_bg_tile_top_left,4,20,2026-01-13 11:36:16
-mask_ui_bg_tile_top_right,4,20,2026-01-13 11:36:16
mask_ui_bg_topbar_left,45,45,2026-01-13 11:36:16
mask_ui_bg_topbar_right,45,45,2026-01-13 11:36:16
mask_ui_btn_close,30,30,2026-01-13 11:36:16