chore(color): implement publish/subscribe messaging to simplify code and further code consolidation (#7032)

This commit is contained in:
philmoz
2026-01-29 15:45:10 +10:00
committed by GitHub
parent 2579bc6132
commit 9a44335601
125 changed files with 1701 additions and 2054 deletions
+1
View File
@@ -0,0 +1 @@
Mon Jan 26 18:05:25 AEST 2026
-1
View File
@@ -1 +0,0 @@
/gtest-1.6.0
Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 B

@@ -1,11 +0,0 @@
<svg width="4" height="20" viewBox="0 0 4 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="4" height="20" fill="white"/>
<g style="mix-blend-mode:difference" clip-path="url(#clip0_4680_3328)">
<rect width="8" height="24" rx="4" fill="white"/>
</g>
<defs>
<clipPath id="clip0_4680_3328">
<rect width="4" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 373 B

@@ -1,11 +0,0 @@
<svg width="4" height="20" viewBox="0 0 4 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="4" height="20" fill="white"/>
<g style="mix-blend-mode:difference" clip-path="url(#clip0_4680_3335)">
<rect x="-4" width="8" height="24" rx="4" fill="white"/>
</g>
<defs>
<clipPath id="clip0_4680_3335">
<rect width="4" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 380 B

+19 -19
View File
@@ -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
-2
View File
@@ -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
+5
View File
@@ -380,3 +380,8 @@ void LvglWrapper::run()
}
}
}
void initLvgl()
{
LvglWrapper::instance();
}
-9
View File
@@ -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),
-3
View File
@@ -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,
@@ -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<uint32_t(int pos)> 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<uint32_t(int pos)> 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<void(uint32_t rgb)> setValue,
std::function<void(uint32_t rgb)> 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);
}
@@ -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<void(uint32_t rgb)> setValue = nullptr,
std::function<void(uint32_t rgb)> 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<void(uint32_t)> _setValue;
std::function<void(uint32_t)> _preview;
uint32_t _color;
COLOR_EDITOR_FMT format;
Messaging colorUpdateMsg;
void setText();
void setRGB();
static void value_changed(lv_event_t* e);
};
@@ -76,7 +76,6 @@ class ColorEditorPopup : public BaseDialog
public:
ColorEditorPopup(uint32_t color,
std::function<void(uint32_t)> _setValue,
std::function<void(uint32_t)> _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<uint32_t()> getValue,
std::function<void(uint32_t)> setValue,
std::function<void(uint32_t)> preview,
std::function<uint32_t()> _getValue,
std::function<void(uint32_t)> _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)
@@ -27,6 +27,7 @@
class ColorPicker : public Button
{
uint32_t color;
std::function<uint32_t()> getValue;
std::function<void(uint32_t)> setValue;
std::function<void(uint32_t)> preview;
COLOR_EDITOR_FMT format;
@@ -37,11 +38,7 @@ public:
ColorPicker(Window* parent, const rect_t& rect,
std::function<uint32_t()> getValue,
std::function<void(uint32_t)> setValue = nullptr,
std::function<void(uint32_t)> preview = nullptr,
COLOR_EDITOR_FMT fmt = ETX_RGB565);
void setColor(uint32_t c);
uint32_t getColor() const { return color; }
void onClicked() override;
};
+2 -33
View File
@@ -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();
+2 -5
View File
@@ -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<int(int)> valueFunc;
std::function<int()> positionFunc;
std::list<point_t> 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();
@@ -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<int()> getRefValue,
std::function<void(int32_t)> setRefValue, std::function<void(void)> refreshView, mixsrc_t source) :
std::function<void(int32_t)> 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<void(int32_t)> setRefValue, int16_t sourceMin, mixsrc_t source,
std::function<void(void)> refreshView) :
Window(parent, rect), ref(ref), refreshView(std::move(refreshView))
std::function<void(int32_t)> 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) {
@@ -31,7 +31,7 @@ class CurveChoice : public Choice
{
public:
CurveChoice(Window* parent, std::function<int()> getRefValue,
std::function<void(int32_t)> setRefValue, std::function<void(void)> refreshView,
std::function<void(int32_t)> 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<void(int32_t)> setRefValue,
int16_t sourceMin, mixsrc_t source,
std::function<void(void)> 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<void(void)> refreshView;
void update();
};
@@ -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();
@@ -58,7 +58,6 @@ class GVarNumberEdit : public Window
std::function<void(int32_t)> setValue;
int32_t voffset;
void onEvent(event_t event) override;
void update();
static void value_changed(lv_event_t* e);
@@ -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();
}
@@ -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;
};
+2 -2
View File
@@ -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()
+2 -2
View File
@@ -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()
@@ -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;
+16 -12
View File
@@ -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;
};
}
+2 -3
View File
@@ -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<void(void)> releaseHandler;
std::string text;
lv_obj_t* label = nullptr;
bool customEventHandler(lv_event_code_t code) override;
};
@@ -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<void(void)>& 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;
}
@@ -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<bool(void)> 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<bool(void)> closeCondition;
std::function<void(void)> confirmHandler;
StaticText* messageLabel = nullptr;
void build();
};
//-----------------------------------------------------------------------------
+51 -5
View File
@@ -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<bool(void)> 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);
}
}
+3 -1
View File
@@ -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<bool(void)> closeCondition, bool isError = false);
protected:
lv_obj_t* background = nullptr;
const BitmapBuffer *backgroundBitmap = nullptr;
+23 -36
View File
@@ -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<void()> onPress, std::function<bool()> 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<void()> onPress,
addLine(nullptr, text, onPress, isChecked);
}
void Menu::addLineBuffered(const MaskBitmap* icon_mask, const std::string& text,
std::function<void()> onPress,
std::function<bool()> isChecked)
{
content->addLine(icon_mask, text, std::move(onPress), std::move(isChecked),
false);
}
void Menu::addLineBuffered(const std::string &text, std::function<void()> onPress,
std::function<bool()> 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();
}
+3 -15
View File
@@ -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<void()> onPress,
std::function<bool()> isChecked = nullptr);
void addLineBuffered(const MaskBitmap *icon_mask, const std::string &text,
std::function<void()> onPress,
std::function<bool()> isChecked = nullptr);
void addLineBuffered(const std::string &text, std::function<void()> onPress,
std::function<bool()> 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;
+15 -7
View File
@@ -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);
}
+5 -3
View File
@@ -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;
@@ -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 <list>
#include <algorithm>
static std::list<Messaging*> subscriptions;
Messaging::~Messaging()
{
unsubscribe();
}
void Messaging::subscribe(uint32_t _id, std::function<void(uint32_t)> 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);
}
}
+55
View File
@@ -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 <functional>
#include <stdint.h>
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<void(uint32_t)> 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<void(uint32_t)> callback = nullptr;
};
+16 -25
View File
@@ -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<void(Window*, coord_t, coord_t)> createEdit, coord_t lblYOffset)
Window* SubPage::setupLine(const char* title, std::function<void(SetupLine*, coord_t, coord_t)> 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();
}
+6 -4
View File
@@ -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<void(Window*, coord_t, coord_t)> createEdit, coord_t lblYOffset = 0);
Window* setupLine(const char* title, std::function<void(SetupLine*, coord_t, coord_t)> createEdit, coord_t lblYOffset = 0);
void useFlexLayout();
static LAYOUT_SIZE(EDT_X, LCD_W * 9 / 20, LCD_W * 8 / 20)
+3 -28
View File
@@ -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)
-49
View File
@@ -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;
-2
View File
@@ -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;
+28 -57
View File
@@ -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();
}
}
+5 -2
View File
@@ -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
+25 -22
View File
@@ -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<void(Window*, coord_t, coord_t)> createEdit, coord_t lblYOffset) :
std::function<void(SetupLine*, coord_t, coord_t)> 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
+24 -25
View File
@@ -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<void()> createPage;
std::function<bool()> isActive;
std::function<bool()> enabled;
PageButtonDef(
STR_TYP title,
std::function<void()> createPage,
std::function<bool()> isActive = nullptr,
std::function<bool()> enabled = nullptr) :
title(title), createPage(std::move(createPage)), isActive(std::move(isActive)), enabled(std::move(enabled))
{}
};
//-----------------------------------------------------------------------------
class SetupButtonGroup : public Window
{
public:
typedef std::list<PageButtonDef> 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<void(Window*, coord_t, coord_t)> createEdit;
std::function<void(SetupLine*, coord_t, coord_t)> createEdit;
};
class SetupLine : public Window
{
public:
SetupLine(Window* parent, coord_t y, coord_t col2, PaddingSize padding, const char* title,
std::function<void(Window*, coord_t, coord_t)> createEdit, coord_t lblYOffset = 0);
std::function<void(SetupLine*, coord_t, coord_t)> 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:
};
//-----------------------------------------------------------------------------
+1 -1
View File
@@ -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
+18 -21
View File
@@ -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
+6 -9
View File
@@ -25,6 +25,7 @@
#include "dataconstants.h"
#include "widget.h"
#include "view_main_decoration.h"
#include "messaging.h"
#include <memory>
@@ -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<ViewMainDecoration> 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;
@@ -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<const LayoutFactory*()> getValue;
std::function<void(const LayoutFactory*)> _setValue;
std::function<void(const LayoutFactory*)> 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:
@@ -45,8 +45,6 @@ class ScreenSetupPage : public PageGroupItem
void build(Window* form) override;
void update(uint8_t index) override;
static void addScreen();
protected:
+2 -29
View File
@@ -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;
+13 -4
View File
@@ -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;
@@ -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);
}
}
}
+2 -30
View File
@@ -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;
@@ -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);
@@ -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) {
@@ -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 };
+5 -6
View File
@@ -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
-1
View File
@@ -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;
@@ -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;
@@ -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
}
@@ -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;
};
+54 -39
View File
@@ -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<point_t> 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<void(void)> 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);
}
+2 -7
View File
@@ -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<void(void)> refreshView = nullptr);
void setCurrentSource(mixsrc_t source);
mixsrc_t source = 0);
protected:
uint8_t index;
CurveEdit* curveEdit = nullptr;
CurveDataEdit* curveDataEdit = nullptr;
std::function<void(void)> refreshView = nullptr;
mixsrc_t source = 0;
void buildHeader(Window* window);
void buildBody(Window* window);
+106 -132
View File
@@ -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
//-----------------------------------------------------------------------------
@@ -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
//-----------------------------------------------------------------------------
+7 -8
View File
@@ -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();
@@ -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))
+3 -17
View File
@@ -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<void(void)> 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<void(void)> refresh
initPoints(curve, points);
}
auto cv = new CurveEditWindow(index, refreshView);
cv->setCurrentSource(source);
new CurveEditWindow(index, source);
}
void ModelCurvesPage::rebuild(Window *window)
+1 -1
View File
@@ -29,7 +29,7 @@ class ModelCurvesPage : public PageGroupItem
public:
ModelCurvesPage(const PageDef& pageDef);
static void pushEditCurve(int index, std::function<void(void)> refreshView, mixsrc_t source);
static void pushEditCurve(int index, mixsrc_t source);
virtual void build(Window* window) override;
@@ -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();
+9 -19
View File
@@ -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();
+144 -31
View File
@@ -24,6 +24,7 @@
#include <algorithm>
#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);
}
+1 -1
View File
@@ -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);
@@ -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();
};
@@ -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))
{
}
@@ -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)
};
@@ -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<void()> 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);
@@ -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];
};
@@ -106,7 +106,7 @@ void RadioCalibrationPage::buildBody(Window *window)
3, 2);
}
std::unique_ptr<ViewMainDecoration> 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 {
+23 -145
View File
@@ -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
//-----------------------------------------------------------------------------
+11 -16
View File
@@ -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
#endif
+13 -15
View File
@@ -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());
}
@@ -26,5 +26,5 @@
class RadioAnalogsDiagsViewPageGroup : public TabsGroup
{
public:
RadioAnalogsDiagsViewPageGroup(QMPage qmPage);
RadioAnalogsDiagsViewPageGroup();
};
+25 -18
View File
@@ -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<HWSticks>(STR_STICKS); }},
{STR_DEF(STR_POTS), []() { new HWInputDialog<HWPots>(STR_POTS, HWPots::POTS_WINDOW_WIDTH); }},
{STR_DEF(STR_SWITCHES), []() { new HWInputDialog<HWSwitches>(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<HWSticks>(STR_STICKS); }},
{STR_DEF(STR_POTS), []() { new HWInputDialog<HWPots>(STR_POTS, HWPots::POTS_WINDOW_WIDTH); }},
{STR_DEF(STR_SWITCHES), []() { new HWInputDialog<HWSwitches>(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);
}
+248 -236
View File
@@ -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<int()> getValue,
std::function<void(int)> 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<int()> getValue,
std::function<void(int)> 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);
}
@@ -284,7 +284,6 @@ class ColorEditPage : public Page
}
setHexStr(rgb);
});
_colorEditor->setColorEditorType(HSV_COLOR_EDITOR);
_activeTab = 1;
r.w = COLOR_BOX_WIDTH;
@@ -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();
+3 -25
View File
@@ -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<void()> action;
std::function<bool()> 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;
};
+112 -90
View File
@@ -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<void(bool close)> 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<void(bool close)> selectHandler,
PageGroupBase* newPageGroup, QMPage newCurPage)
void QuickMenu::openQM(PageGroupBase* newPageGroup, QMPage newCurPage)
{
pushLayer();
@@ -310,7 +312,6 @@ void QuickMenu::openQM(std::function<void(bool close)> selectHandler,
subMenus[i]->doLayout();
#endif
this->selectHandler = std::move(selectHandler);
show();
lv_obj_move_foreground(lvobj);
if (newPageGroup) {
@@ -458,6 +459,27 @@ std::vector<std::string> 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;
}
}
+43 -13
View File
@@ -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<void()> action;
std::function<bool()> 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<void(bool close)> 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<std::string> 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<void(bool close)> selectHandler = nullptr;
bool inSubMenu = false;
QuickMenuGroup* mainMenu = nullptr;
#if VERSION_MAJOR > 2
std::vector<QuickSubMenu*> subMenus;
#endif
PageGroupBase* pageGroup = nullptr;
static QMPage curPage;
static EdgeTxIcon curIcon;
QMPage curPage = QM_NONE;
EdgeTxIcon curIcon = EDGETX_ICONS_COUNT;
void openQM(std::function<void(bool close)> 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
};
//-----------------------------------------------------------------------------
@@ -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},
@@ -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();
}
@@ -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<void(void)> pressHandler,
std::function<bool(void)> visibleHandler,
std::function<void(void)> focusHandler)
std::function<void(bool)> 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();
}
}

Some files were not shown because too many files have changed in this diff Show More