chore(color): implement publish/subscribe messaging to simplify code and further code consolidation (#7032)
@@ -0,0 +1 @@
|
||||
Mon Jan 26 18:05:25 AEST 2026
|
||||
@@ -1 +0,0 @@
|
||||
/gtest-1.6.0
|
||||
|
Before Width: | Height: | Size: 111 B |
|
Before Width: | Height: | Size: 123 B |
|
Before Width: | Height: | Size: 122 B |
|
Before Width: | Height: | Size: 124 B |
|
Before Width: | Height: | Size: 148 B |
|
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 |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -380,3 +380,8 @@ void LvglWrapper::run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initLvgl()
|
||||
{
|
||||
LvglWrapper::instance();
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||