feat(color): allow user to change key shortcut action; add Favorites quick menu (#6753)

Co-authored-by: elecpower <elecpower@users.noreply.github.com>
This commit is contained in:
philmoz
2025-11-19 18:40:23 +10:00
committed by GitHub
co-authored by elecpower
parent 5c96b1e15c
commit 72d290f89f
103 changed files with 2605 additions and 921 deletions
+5
View File
@@ -69,6 +69,10 @@ MaskBitmap* _decompressed_mask(const uint8_t* lz4_compressed)
return raw;
}
static const uint8_t mask_menu_favs[] = {
#include "mask_menu_favs.lbm"
};
static const uint8_t mask_menu_model[] = {
#include "mask_menu_model.lbm"
};
@@ -388,6 +392,7 @@ struct _BuiltinIcon {
// Note: Order must match EdgeTxIcon enum
static const _BuiltinIcon _builtinIcons[EDGETX_ICONS_COUNT] = {
BI(ICON_EDGETX, mask_edgetx),
BI(ICON_QM_FAVORITES, mask_menu_favs),
BI(ICON_RADIO, mask_menu_radio),
BI(ICON_RADIO_SETUP, mask_radio_setup),
BI(ICON_RADIO_SD_MANAGER, mask_radio_sd_browser),
+1
View File
@@ -25,6 +25,7 @@
enum EdgeTxIcon {
ICON_EDGETX,
ICON_QM_FAVORITES,
ICON_RADIO,
ICON_RADIO_SETUP,
ICON_RADIO_SD_MANAGER,
+13 -4
View File
@@ -111,9 +111,9 @@ void Page::deleteLater(bool detach, bool trash)
void Page::openMenu()
{
PageGroup* p = (PageGroup*)Layer::getPageGroup();
QuickMenu::SubMenu subMenu = QuickMenu::NONE;
QMPage qmPage = QM_NONE;
if (p)
subMenu = p->getCurrentTab()->subMenu();
qmPage = p->getCurrentTab()->pageId();
quickMenu = QuickMenu::openQuickMenu([=]() { quickMenu = nullptr; },
[=](bool close) {
onCancel();
@@ -124,7 +124,7 @@ void Page::openMenu()
if (close)
Layer::back()->onCancel();
}
}, p, subMenu);
}, p, qmPage);
}
void Page::onCancel()
@@ -158,7 +158,16 @@ NavWindow* Page::navWindow()
#if defined(HARDWARE_KEYS)
void Page::onPressSYS()
{
if (!quickMenu) openMenu();
QMPage pg = g_eeGeneral.getKeyShortcut(EVT_KEY_BREAK(KEY_SYS));
if (pg == QM_OPEN_QUICK_MENU) {
if (!quickMenu) openMenu();
} else {
auto p = navWindow();
if (p) {
onCancel();
p->onPressSYS();
}
}
}
void Page::onLongPressSYS()
-2
View File
@@ -54,8 +54,6 @@ class ModelNotesPage : public PageGroupItem
public:
ModelNotesPage(PageDef& pageDef);
bool isVisible() const override { return modelHasNotes(); }
void build(Window* window) override;
void cleanup() override;
@@ -115,12 +115,12 @@ static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT,
ScreenSetupPage::ScreenSetupPage(unsigned index, PageDef& pageDef) :
PageGroupItem(pageDef)
{
update(index + FIRST_SCREEN_OFFSET);
update(index + QuickMenu::pageIndex(QM_UI_SCREEN1));
}
void ScreenSetupPage::update(uint8_t index)
{
customScreenIndex = index - FIRST_SCREEN_OFFSET;
customScreenIndex = index - QuickMenu::pageIndex(QM_UI_SCREEN1);
}
void ScreenSetupPage::build(Window* window)
@@ -214,7 +214,7 @@ void ScreenSetupPage::build(Window* window)
// Reset to first screen so user knows something has happened
PageGroup* menu = (PageGroup*)window->getParent();
menu->setCurrentTab(FIRST_SCREEN_OFFSET);
menu->setCurrentTab(QuickMenu::pageIndex(QM_UI_SCREEN1));
storageDirty(EE_MODEL);
return 0;
@@ -34,10 +34,6 @@ class ScreenSetupPage : public PageGroupItem
void update(uint8_t index) override;
bool isVisible() const override { return customScreens[customScreenIndex] != nullptr; }
static constexpr int FIRST_SCREEN_OFFSET = 2;
protected:
unsigned customScreenIndex;
Window* layoutOptions = nullptr;
+1 -1
View File
@@ -112,7 +112,7 @@ void SetupTopBarWidgetsPage::deleteLater(bool detach, bool trash)
Layer::pop(this);
// restore screen setting tab on top
(PageGroup::ScreenMenu())->setCurrentTab(1);
QuickMenu::openPage(QM_UI_SETUP);
storageDirty(EE_MODEL);
}
@@ -120,7 +120,7 @@ class ChannelsViewPage : public PageGroupItem
ChannelsViewMenu::ChannelsViewMenu() :
TabsGroup(ICON_MONITOR, STR_MAIN_MENU_CHANNEL_MONITOR)
{
QuickMenu::setCurrentPage(QuickMenu::TOOLS_CHAN_MON);
QuickMenu::setCurrentPage(QM_TOOLS_CHAN_MON);
#if PORTRAIT
int cols = 1;
+15 -28
View File
@@ -245,36 +245,23 @@ void ViewMain::updateTopbarVisibility()
}
#if defined(HARDWARE_KEYS)
void ViewMain::onPressSYS()
void ViewMain::doKeyShortcut(event_t event)
{
if (!viewMainMenu) openMenu();
}
void ViewMain::onLongPressSYS()
{
if (viewMainMenu) viewMainMenu->closeMenu();
// Radio setup
PageGroup::ToolsMenu();
}
void ViewMain::onPressMDL()
{
if (viewMainMenu) viewMainMenu->closeMenu();
PageGroup::ModelMenu();
}
void ViewMain::onLongPressMDL()
{
if (viewMainMenu) viewMainMenu->closeMenu();
new ModelLabelsWindow();
}
void ViewMain::onPressTELE()
{
if (viewMainMenu) viewMainMenu->closeMenu();
(PageGroup::ScreenMenu())->setCurrentTab(getCurrentMainView() + ScreenSetupPage::FIRST_SCREEN_OFFSET);
}
void ViewMain::onLongPressTELE()
{
if (viewMainMenu) viewMainMenu->closeMenu();
new ChannelsViewMenu();
QMPage pg = g_eeGeneral.getKeyShortcut(event);
if (pg == QM_OPEN_QUICK_MENU) {
if (!viewMainMenu) openMenu();
} else {
if (viewMainMenu)
viewMainMenu->closeMenu();
QuickMenu::openPage(pg);
}
}
void ViewMain::onPressSYS() { doKeyShortcut(EVT_KEY_BREAK(KEY_SYS)); }
void ViewMain::onLongPressSYS() { doKeyShortcut(EVT_KEY_LONG(KEY_SYS)); }
void ViewMain::onPressMDL() { doKeyShortcut(EVT_KEY_BREAK(KEY_MODEL)); }
void ViewMain::onLongPressMDL() { doKeyShortcut(EVT_KEY_LONG(KEY_MODEL)); }
void ViewMain::onPressTELE() { doKeyShortcut(EVT_KEY_BREAK(KEY_TELE)); }
void ViewMain::onLongPressTELE() { doKeyShortcut(EVT_KEY_LONG(KEY_TELE)); }
void ViewMain::onPressPGUP()
{
if (!widget_select) {
@@ -111,6 +111,7 @@ class ViewMain : public NavWindow
static void ws_timer(lv_timer_t* t);
#if defined(HARDWARE_KEYS)
void doKeyShortcut(event_t event);
void onPressSYS() override;
void onLongPressSYS() override;
void onPressMDL() override;
@@ -155,7 +155,7 @@ void SetupWidgetsPage::onClicked()
void SetupWidgetsPage::onCancel()
{
deleteLater();
(PageGroup::ScreenMenu())->setCurrentTab(customScreenIdx + ScreenSetupPage::FIRST_SCREEN_OFFSET);
QuickMenu::openPage((QMPage)(QM_UI_SCREEN1 + customScreenIdx));
}
void SetupWidgetsPage::deleteLater(bool detach, bool trash)
@@ -31,8 +31,6 @@ class ModelCurvesPage : public PageGroupItem
static void pushEditCurve(int index, std::function<void(void)> refreshView, mixsrc_t source);
bool isVisible() const override { return modelCurvesEnabled(); }
virtual void build(Window* window) override;
static LAYOUT_ORIENTATION(PER_ROW, 3, 2)
@@ -29,8 +29,6 @@ class ModelFlightModesPage : public PageGroupItem
public:
ModelFlightModesPage(PageDef& pageDef);
bool isVisible() const override { return modelFMEnabled(); }
void build(Window* window) override;
protected:
@@ -29,8 +29,6 @@ class ModelGVarsPage : public PageGroupItem
public:
ModelGVarsPage(PageDef& pageDef);
bool isVisible() const override { return modelGVEnabled(); }
void cleanup() override;
protected:
@@ -29,8 +29,6 @@ class ModelLogicalSwitchesPage : public PageGroupItem
public:
ModelLogicalSwitchesPage(PageDef& pageDef);
bool isVisible() const override { return modelLSEnabled(); }
virtual void build(Window* window) override;
protected:
@@ -29,8 +29,6 @@ class ModelMixerScriptsPage : public PageGroupItem
public:
ModelMixerScriptsPage(PageDef& pageDef);
bool isVisible() const override { return modelCustomScriptsEnabled(); }
virtual void build(Window* window) override { build(window, 0); }
protected:
@@ -521,7 +521,7 @@ class ModelLayoutButton : public IconButton
ModelLabelsWindow::ModelLabelsWindow() : Page(ICON_MODEL_SELECT, PAD_ZERO, true)
{
QuickMenu::setCurrentPage(QuickMenu::MANAGE_MODELS);
QuickMenu::setCurrentPage(QM_MANAGE_MODELS);
buildHead(header);
buildBody(body);
@@ -550,23 +550,22 @@ ModelLabelsWindow::ModelLabelsWindow() : Page(ICON_MODEL_SELECT, PAD_ZERO, true)
void ModelLabelsWindow::onLongPressSYS()
{
onCancel();
// Radio setup
PageGroup::ToolsMenu();
Page::onLongPressSYS();
}
void ModelLabelsWindow::onPressMDL()
{
onCancel();
PageGroup::ModelMenu();
Page::onPressMDL();
}
void ModelLabelsWindow::onPressTELE()
{
onCancel();
(PageGroup::ScreenMenu())->setCurrentTab(ViewMain::instance()->getCurrentMainView() + ScreenSetupPage::FIRST_SCREEN_OFFSET);
Page::onPressTELE();
}
void ModelLabelsWindow::onLongPressTELE()
{
onCancel();
new ChannelsViewMenu();
Page::onLongPressTELE();
}
void ModelLabelsWindow::onPressPG(bool isNext)
{
@@ -76,6 +76,7 @@ class ModelLabelsWindow : public Page
#if defined(HARDWARE_KEYS)
void onLongPressSYS() override;
void onPressMDL() override;
void onLongPressMDL() override {}
void onPressTELE() override;
void onLongPressTELE() override;
void onPressPG(bool isNext);
@@ -29,8 +29,6 @@ class ModelTelemetryPage : public PageGroupItem
public:
ModelTelemetryPage(PageDef& pageDef);
bool isVisible() const override { return modelTelemetryEnabled(); }
void build(Window* window) override;
static LAYOUT_SIZE_SCALED(NUM_EDIT_W, 100, 65)
@@ -154,8 +154,6 @@ class SpecialFunctionsPage : public FunctionsPage
public:
SpecialFunctionsPage(PageDef& pageDef);
bool isVisible() const override { return modelSFEnabled(); }
protected:
CustomFunctionData* customFunctionData(uint8_t index) const override;
FunctionEditPage* editPage(uint8_t index) const override;
@@ -171,8 +169,6 @@ class GlobalFunctionsPage : public FunctionsPage
public:
GlobalFunctionsPage(PageDef& pageDef);
bool isVisible() const override { return radioGFEnabled(); }
protected:
CustomFunctionData* customFunctionData(uint8_t index) const override;
FunctionEditPage* editPage(uint8_t index) const override;
+13 -13
View File
@@ -470,8 +470,8 @@ class AnaMinMaxViewWindow : public AnaViewWindow
class AnaCalibratedViewPage : public PageGroupItem
{
public:
AnaCalibratedViewPage(QuickMenu::SubMenu subMenu) :
PageGroupItem(STR_ANADIAGS_CALIB, subMenu)
AnaCalibratedViewPage(QMPage qmPage) :
PageGroupItem(STR_ANADIAGS_CALIB, qmPage)
{
icon = ICON_STATS;
}
@@ -486,8 +486,8 @@ class AnaCalibratedViewPage : public PageGroupItem
class AnaFilteredDevViewPage : public PageGroupItem
{
public:
AnaFilteredDevViewPage(QuickMenu::SubMenu subMenu) :
PageGroupItem(STR_ANADIAGS_FILTRAWDEV, subMenu)
AnaFilteredDevViewPage(QMPage qmPage) :
PageGroupItem(STR_ANADIAGS_FILTRAWDEV, qmPage)
{
icon = ICON_STATS;
}
@@ -502,8 +502,8 @@ class AnaFilteredDevViewPage : public PageGroupItem
class AnaUnfilteredRawViewPage : public PageGroupItem
{
public:
AnaUnfilteredRawViewPage(QuickMenu::SubMenu subMenu) :
PageGroupItem(STR_ANADIAGS_UNFILTRAW, subMenu)
AnaUnfilteredRawViewPage(QMPage qmPage) :
PageGroupItem(STR_ANADIAGS_UNFILTRAW, qmPage)
{
icon = ICON_STATS;
}
@@ -518,8 +518,8 @@ class AnaUnfilteredRawViewPage : public PageGroupItem
class AnaMinMaxViewPage : public PageGroupItem
{
public:
AnaMinMaxViewPage(QuickMenu::SubMenu subMenu) :
PageGroupItem(STR_ANADIAGS_MINMAX, subMenu)
AnaMinMaxViewPage(QMPage qmPage) :
PageGroupItem(STR_ANADIAGS_MINMAX, qmPage)
{
icon = ICON_STATS;
}
@@ -531,11 +531,11 @@ class AnaMinMaxViewPage : public PageGroupItem
}
};
RadioAnalogsDiagsViewPageGroup::RadioAnalogsDiagsViewPageGroup(QuickMenu::SubMenu subMenu) :
RadioAnalogsDiagsViewPageGroup::RadioAnalogsDiagsViewPageGroup(QMPage qmPage) :
TabsGroup(ICON_STATS, STR_ANALOGS_BTN)
{
addTab(new AnaCalibratedViewPage(subMenu));
addTab(new AnaFilteredDevViewPage(subMenu));
addTab(new AnaUnfilteredRawViewPage(subMenu));
addTab(new AnaMinMaxViewPage(subMenu));
addTab(new AnaCalibratedViewPage(qmPage));
addTab(new AnaFilteredDevViewPage(qmPage));
addTab(new AnaUnfilteredRawViewPage(qmPage));
addTab(new AnaMinMaxViewPage(qmPage));
}
@@ -26,5 +26,5 @@
class RadioAnalogsDiagsViewPageGroup : public TabsGroup
{
public:
RadioAnalogsDiagsViewPageGroup(QuickMenu::SubMenu subMenu);
RadioAnalogsDiagsViewPageGroup(QMPage qmPage);
};
@@ -198,7 +198,7 @@ void RadioHardwarePage::build(Window* window)
// 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(quickMenuId); }},
{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(); }},
+14 -1
View File
@@ -33,6 +33,8 @@
#include "storage/modelslist.h"
#include "tasks/mixer_task.h"
#include "slider.h"
#include "key_shortcuts.h"
#include "quick_menu_favorites.h"
#define SET_DIRTY() storageDirty(EE_GENERAL)
@@ -827,7 +829,7 @@ static SetupLineDef setupLines[] = {
PageGroup* pg = (PageGroup*)Layer::getPageGroup();
coord_t y = pg->getScrollY();
pg->onCancel();
PageGroup::RadioMenu();
QuickMenu::openPage(QM_RADIO_SETUP);
pg = (PageGroup*)Layer::getPageGroup();
pg->setScrollY(y);
// Force QM rebuild for language change
@@ -955,6 +957,15 @@ static SetupLineDef setupLines[] = {
RadioSetupPage::RadioSetupPage(PageDef& pageDef) : PageGroupItem(pageDef, PAD_TINY) {}
static bool hasShortcutKeys()
{
#if defined(USE_HATS_AS_KEYS)
return true;
#else
return keysGetSupported() & ((1 << KEY_MODEL) | (1 << KEY_SYS) | (1 << KEY_TELE));
#endif
}
void RadioSetupPage::build(Window* window)
{
coord_t y = 0;
@@ -980,6 +991,8 @@ void RadioSetupPage::build(Window* window)
{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(); }},
{STR_DEF(STR_KEY_SHORTCUTS), []() { new QMKeyShortcutsPage(); }, nullptr, [=]() { return hasShortcutKeys(); }},
{STR_DEF(STR_QUICK_MENU_FAVORITES), []() { new QMFavoritesPage(); }, nullptr},
}, BTN_H);
y += w->height() + padding;
@@ -39,8 +39,6 @@ class ThemeSetupPage : public PageGroupItem
void build(Window *window) override;
void checkEvents() override;
bool isVisible() const override { return radioThemesEnabled(); }
static LAYOUT_VAL_SCALED(COLOR_PREVIEW_SIZE, 18)
static LAYOUT_ORIENTATION(LIST_SIZE, (LCD_W - PAD_MEDIUM * 2) / 2 - COLOR_PREVIEW_SIZE, LCD_H / 2 - LAYOUT_SCALE(38));
@@ -29,7 +29,5 @@ class RadioTrainerPage : public PageGroupItem
public:
RadioTrainerPage(PageDef& pageDef);
bool isVisible() const override { return radioTrainerEnabled(); }
void build(Window* window) override;
};
@@ -0,0 +1,88 @@
/*
* 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 "key_shortcuts.h"
#include "edgetx.h"
#include "pagegroup.h"
#define SET_DIRTY() storageDirty(EE_GENERAL)
static bool hasKey(event_t event)
{
#if defined(USE_HATS_AS_KEYS)
return true;
#else
EnumKeys key = (EnumKeys)EVT_KEY_MASK(event);
return (keysGetSupported() & (1 << key));
#endif
}
void QMKeyShortcutsPage::addKey(event_t event, std::vector<std::string> qmPages, const char* nm)
{
if (hasKey(event)) {
extern uint16_t keyMapping(uint16_t event);
event = keyMapping(event);
setupLine(nm, [=](Window* parent, coord_t x, coord_t y) {
auto c = new Choice(
parent, {LCD_W / 4, y, LCD_W * 2 / 3, 0}, qmPages, QM_NONE, QM_TOOLS_DEBUG,
GET_DEFAULT(g_eeGeneral.getKeyShortcut(event)),
[=](int32_t newValue) {
g_eeGeneral.setKeyShortcut(event, (QMPage)newValue);
SET_DIRTY();
}, STR_KEY_SHORTCUTS);
c->setPopupWidth(LCD_W * 3 / 4);
c->setAvailableHandler(
[=](int newValue) {
if (newValue == QM_NONE) return true;
if (g_eeGeneral.hasKeyShortcut((QMPage)newValue))
return false;
return newValue <= QM_UI_SCREEN1 || newValue > QM_UI_ADD_PG; }
);
});
}
}
QMKeyShortcutsPage::QMKeyShortcutsPage():
SubPage(ICON_RADIO, STR_MAIN_MENU_RADIO_SETTINGS, STR_KEY_SHORTCUTS, true)
{
std::vector<std::string> qmPages = QuickMenu::menuPageNames(false);
setupLine(STR_SHORT_PRESS, nullptr);
addKey(EVT_KEY_BREAK(KEY_SYS), qmPages, "SYS");
addKey(EVT_KEY_BREAK(KEY_MODEL), qmPages, "MDL");
addKey(EVT_KEY_BREAK(KEY_TELE), qmPages, "TELE");
setupLine(STR_LONG_PRESS, nullptr);
addKey(EVT_KEY_LONG(KEY_SYS), qmPages, "SYS");
addKey(EVT_KEY_LONG(KEY_MODEL), qmPages, "MDL");
addKey(EVT_KEY_LONG(KEY_TELE), qmPages, "TELE");
new TextButton(body, {LV_PCT(10), y + PAD_LARGE, LV_PCT(80), 0}, STR_SF_RESET,
[=]() {
g_eeGeneral.defaultKeyShortcuts();
SET_DIRTY();
return 0;
});
enableRefresh();
}
@@ -0,0 +1,33 @@
/*
* 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 QMKeyShortcutsPage : public SubPage
{
public:
QMKeyShortcutsPage();
protected:
void addKey(event_t event, std::vector<std::string> qmPages, const char* nm);
};
@@ -1,58 +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 "edgetx.h"
#include "model_curves.h"
#include "model_flightmodes.h"
#include "model_gvars.h"
#include "model_heli.h"
#include "model_inputs.h"
#include "model_logical_switches.h"
#include "model_mixer_scripts.h"
#include "model_mixes.h"
#include "model_outputs.h"
#include "model_select.h"
#include "model_setup.h"
#include "model_telemetry.h"
#include "special_functions.h"
#include "view_text.h"
PageDef modelMenuItems[] = {
{ ICON_MODEL_SETUP, STR_DEF(STR_QM_GEN_SETTINGS), STR_DEF(STR_MAIN_MENU_SETTINGS), PAGE_CREATE, QuickMenu::MODEL_SETUP, [](PageDef& pageDef) { return new ModelSetupPage(pageDef); }},
#if defined(FLIGHT_MODES)
{ ICON_MODEL_FLIGHT_MODES, STR_DEF(STR_QM_FLIGHT_MODES), STR_DEF(STR_MENUFLIGHTMODES), PAGE_CREATE, QuickMenu::MODEL_FLIGHTMODES, [](PageDef& pageDef) { return new ModelFlightModesPage(pageDef); }, modelFMEnabled},
#endif
{ ICON_MODEL_INPUTS, STR_DEF(STR_QM_INPUTS), STR_DEF(STR_MENUINPUTS), PAGE_CREATE, QuickMenu::MODEL_INPUTS, [](PageDef& pageDef) { return new ModelInputsPage(pageDef); }},
{ ICON_MODEL_MIXER, STR_DEF(STR_QM_MIXES), STR_DEF(STR_MIXES), PAGE_CREATE, QuickMenu::MODEL_MIXES, [](PageDef& pageDef) { return new ModelMixesPage(pageDef); }},
{ ICON_MODEL_OUTPUTS, STR_DEF(STR_QM_OUTPUTS), STR_DEF(STR_MENULIMITS), PAGE_CREATE, QuickMenu::MODEL_OUTPUTS, [](PageDef& pageDef) { return new ModelOutputsPage(pageDef); }},
{ ICON_MODEL_CURVES, STR_DEF(STR_QM_CURVES), STR_DEF(STR_MENUCURVES), PAGE_CREATE, QuickMenu::MODEL_CURVES, [](PageDef& pageDef) { return new ModelCurvesPage(pageDef); }, modelCurvesEnabled},
#if defined(GVARS)
{ ICON_MODEL_GVARS, STR_DEF(STR_QM_GLOBAL_VARS), STR_DEF(STR_MENU_GLOBAL_VARS), PAGE_CREATE, QuickMenu::MODEL_GVARS, [](PageDef& pageDef) { return new ModelGVarsPage(pageDef); }, modelGVEnabled},
#endif
{ ICON_MODEL_LOGICAL_SWITCHES, STR_DEF(STR_QM_LOGICAL_SW), STR_DEF(STR_MENULOGICALSWITCHES), PAGE_CREATE, QuickMenu::MODEL_LS, [](PageDef& pageDef) { return new ModelLogicalSwitchesPage(pageDef); }, modelLSEnabled},
{ ICON_MODEL_SPECIAL_FUNCTIONS, STR_DEF(STR_QM_SPEC_FUNC), STR_DEF(STR_MENUCUSTOMFUNC), PAGE_CREATE, QuickMenu::MODEL_SF, [](PageDef& pageDef) { return new SpecialFunctionsPage(pageDef); }, modelSFEnabled},
#if defined(LUA_MODEL_SCRIPTS)
{ ICON_MODEL_LUA_SCRIPTS, STR_DEF(STR_QM_CUSTOM_LUA), STR_DEF(STR_MENUCUSTOMSCRIPTS), PAGE_CREATE, QuickMenu::MODEL_SCRIPTS, [](PageDef& pageDef) { return new ModelMixerScriptsPage(pageDef); }, modelCustomScriptsEnabled},
#endif
{ ICON_MODEL_TELEMETRY, STR_DEF(STR_QM_TELEM), STR_DEF(STR_MENUTELEMETRY), PAGE_CREATE, QuickMenu::MODEL_TELEMETRY, [](PageDef& pageDef) { return new ModelTelemetryPage(pageDef); }, modelTelemetryEnabled},
{ ICON_MODEL_NOTES, STR_DEF(STR_MAIN_MENU_MODEL_NOTES), STR_DEF(STR_MAIN_MENU_MODEL_NOTES), PAGE_CREATE, QuickMenu::MODEL_NOTES, [](PageDef& pageDef) { return new ModelNotesPage(pageDef); }, modelHasNotes},
{ EDGETX_ICONS_COUNT }
};
@@ -1,36 +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 "edgetx.h"
#include "radio_hardware.h"
#include "radio_setup.h"
#include "radio_trainer.h"
#include "radio_version.h"
#include "special_functions.h"
PageDef radioMenuItems[] = {
{ ICON_RADIO_SETUP, STR_DEF(STR_QM_GEN_SETTINGS), STR_DEF(STR_MAIN_MENU_SETTINGS), PAGE_CREATE, QuickMenu::RADIO_SETUP, [](PageDef& pageDef) { return new RadioSetupPage(pageDef); }},
{ ICON_RADIO_GLOBAL_FUNCTIONS, STR_DEF(STR_QM_GLOB_FUNC), STR_DEF(STR_MENUSPECIALFUNCS), PAGE_CREATE, QuickMenu::RADIO_GF, [](PageDef& pageDef) { return new GlobalFunctionsPage(pageDef); }, radioGFEnabled},
{ ICON_RADIO_TRAINER, STR_DEF(STR_QM_TRAINER), STR_DEF(STR_MENUTRAINER), PAGE_CREATE, QuickMenu::RADIO_TRAINER, [](PageDef& pageDef) { return new RadioTrainerPage(pageDef); }, radioTrainerEnabled},
{ ICON_RADIO_HARDWARE, STR_DEF(STR_QM_HARDWARE), STR_DEF(STR_HARDWARE), PAGE_CREATE, QuickMenu::RADIO_HARDWARE, [](PageDef& pageDef) { return new RadioHardwarePage(pageDef); }},
{ ICON_RADIO_VERSION, STR_DEF(STR_QM_ABOUT), STR_DEF(STR_MAIN_MENU_ABOUT_EDGETX), PAGE_CREATE, QuickMenu::RADIO_VERSION, [](PageDef& pageDef) { return new RadioVersionPage(pageDef); }},
{ EDGETX_ICONS_COUNT }
};
@@ -1,71 +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 "edgetx.h"
#include "screen_setup.h"
#include "view_main.h"
#include "quick_menu.h"
PageDef screensMenuItems[] = {
{ ICON_RADIO_EDIT_THEME, STR_DEF(STR_QM_THEMES), STR_DEF(STR_MAIN_MENU_THEMES), PAGE_CREATE, QuickMenu::UI_THEMES, [](PageDef& pageDef) { return new ThemeSetupPage(pageDef); }, radioThemesEnabled},
{ ICON_THEME_SETUP, STR_DEF(STR_QM_TOP_BAR), STR_DEF(STR_USER_INTERFACE), PAGE_CREATE, QuickMenu::UI_SETUP, [](PageDef& pageDef) { return new ScreenUserInterfacePage(pageDef); }},
{ ICON_THEME_VIEW1, STR_DEF(STR_QM_SCREEN_1), STR_DEF(STR_MAIN_VIEW_1), PAGE_CREATE, QuickMenu::UI_SCREEN1, [](PageDef& pageDef) { return new ScreenSetupPage(0, pageDef); }},
{ ICON_THEME_VIEW2, STR_DEF(STR_QM_SCREEN_2), STR_DEF(STR_MAIN_VIEW_2), PAGE_CREATE, QuickMenu::UI_SCREEN2, [](PageDef& pageDef) { return new ScreenSetupPage(1, pageDef); }, []() { return customScreens[1] != nullptr; }},
{ ICON_THEME_VIEW3, STR_DEF(STR_QM_SCREEN_3), STR_DEF(STR_MAIN_VIEW_3), PAGE_CREATE, QuickMenu::UI_SCREEN3, [](PageDef& pageDef) { return new ScreenSetupPage(2, pageDef); }, []() { return customScreens[2] != nullptr; }},
{ ICON_THEME_VIEW4, STR_DEF(STR_QM_SCREEN_4), STR_DEF(STR_MAIN_VIEW_4), PAGE_CREATE, QuickMenu::UI_SCREEN4, [](PageDef& pageDef) { return new ScreenSetupPage(3, pageDef); }, []() { return customScreens[3] != nullptr; }},
{ ICON_THEME_VIEW5, STR_DEF(STR_QM_SCREEN_5), STR_DEF(STR_MAIN_VIEW_5), PAGE_CREATE, QuickMenu::UI_SCREEN5, [](PageDef& pageDef) { return new ScreenSetupPage(4, pageDef); }, []() { return customScreens[4] != nullptr; }},
{ ICON_THEME_VIEW6, STR_DEF(STR_QM_SCREEN_6), STR_DEF(STR_MAIN_VIEW_6), PAGE_CREATE, QuickMenu::UI_SCREEN6, [](PageDef& pageDef) { return new ScreenSetupPage(5, pageDef); }, []() { return customScreens[5] != nullptr; }},
{ ICON_THEME_VIEW7, STR_DEF(STR_QM_SCREEN_7), STR_DEF(STR_MAIN_VIEW_7), PAGE_CREATE, QuickMenu::UI_SCREEN7, [](PageDef& pageDef) { return new ScreenSetupPage(6, pageDef); }, []() { return customScreens[6] != nullptr; }},
{ ICON_THEME_VIEW8, STR_DEF(STR_QM_SCREEN_8), STR_DEF(STR_MAIN_VIEW_8), PAGE_CREATE, QuickMenu::UI_SCREEN8, [](PageDef& pageDef) { return new ScreenSetupPage(7, pageDef); }, []() { return customScreens[7] != nullptr; }},
{ ICON_THEME_VIEW9, STR_DEF(STR_QM_SCREEN_9), STR_DEF(STR_MAIN_VIEW_9), PAGE_CREATE, QuickMenu::UI_SCREEN9, [](PageDef& pageDef) { return new ScreenSetupPage(8, pageDef); }, []() { return customScreens[8] != nullptr; }},
{ ICON_THEME_VIEW10, STR_DEF(STR_QM_SCREEN_10), STR_DEF(STR_MAIN_VIEW_10), PAGE_CREATE, QuickMenu::UI_SCREEN10, [](PageDef& pageDef) { return new ScreenSetupPage(9, pageDef); }, []() { return customScreens[9] != nullptr; }},
{ ICON_THEME_ADD_VIEW, STR_DEF(STR_QM_ADD_SCREEN), nullptr, PAGE_ACTION, QuickMenu::UI_ADD_PG, nullptr, []() { return customScreens[9] == nullptr; },
[](QuickSubMenu* subMenu) {
int newIdx = 1;
for (; newIdx < MAX_CUSTOM_SCREENS; newIdx += 1)
if (customScreens[newIdx] == nullptr)
break;
TRACE("Add screen: add screen: newIdx = %d", newIdx);
auto& screen = customScreens[newIdx];
const LayoutFactory* factory = defaultLayout;
if (factory) {
TRACE("Add screen: add screen: factory = %p", factory);
auto viewMain = ViewMain::instance();
screen = factory->create(viewMain, newIdx);
viewMain->addMainView(screen, newIdx);
g_model.setScreenLayoutId(newIdx, factory->getId());
TRACE("Add screen: add screen: LayoutId = %s", g_model.getScreenLayoutId(newIdx));
subMenu->onPress(newIdx + ScreenSetupPage::FIRST_SCREEN_OFFSET);
storageDirty(EE_MODEL);
} else {
TRACE("Add screen: factory is NULL");
}
}
},
{ EDGETX_ICONS_COUNT }
};
@@ -1,53 +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 "edgetx.h"
#include "radio_sdmanager.h"
#include "radio_tools.h"
#include "view_statistics.h"
#include "view_logical_switches.h"
#include "view_channels.h"
PageDef toolsMenuItems[] = {
{ ICON_TOOLS_APPS, STR_DEF(STR_QM_APPS), STR_DEF(STR_MAIN_MENU_APPS), PAGE_CREATE, QuickMenu::TOOLS_APPS, [](PageDef& pageDef) { return new RadioToolsPage(pageDef); }},
{ ICON_RADIO_SD_MANAGER, STR_DEF(STR_QM_STORAGE), STR_DEF(STR_SD_CARD), PAGE_CREATE, QuickMenu::TOOLS_STORAGE, [](PageDef& pageDef) { return new RadioSdManagerPage(pageDef); }},
{ ICON_TOOLS_RESET, STR_DEF(STR_QM_RESET), nullptr, PAGE_ACTION, QuickMenu::TOOLS_RESET, nullptr, nullptr,
[](QuickSubMenu* subMenu) {
subMenu->onSelect(true);
Menu* resetMenu = new Menu();
resetMenu->addLine(STR_RESET_FLIGHT, []() { flightReset(); });
resetMenu->addLine(STR_RESET_TIMER1, []() { timerReset(0); });
resetMenu->addLine(STR_RESET_TIMER2, []() { timerReset(1); });
resetMenu->addLine(STR_RESET_TIMER3, []() { timerReset(2); });
resetMenu->addLine(STR_RESET_TELEMETRY, []() { telemetryReset(); });
}
},
{ ICON_MONITOR, STR_DEF(STR_QM_CHAN_MON), nullptr, PAGE_ACTION, QuickMenu::TOOLS_CHAN_MON, nullptr, nullptr,
[](QuickSubMenu* subMenu) {
subMenu->onSelect(true);
new ChannelsViewMenu();
}
},
{ ICON_MONITOR_LOGICAL_SWITCHES, STR_DEF(STR_QM_LS_MON), STR_DEF(STR_MONITOR_SWITCHES), PAGE_CREATE, QuickMenu::TOOLS_LS_MON, [](PageDef& pageDef) { return new LogicalSwitchesViewPage(pageDef); }},
{ ICON_STATS, STR_DEF(STR_QM_STATS), STR_DEF(STR_MAIN_MENU_STATISTICS), PAGE_CREATE, QuickMenu::TOOLS_STATS, [](PageDef& pageDef) { return new StatisticsViewPage(pageDef); }},
{ ICON_STATS_DEBUG, STR_DEF(STR_QM_DEBUG), STR_DEF(STR_DEBUG), PAGE_CREATE, QuickMenu::TOOLS_DEBUG, [](PageDef& pageDef) { return new DebugViewPage(pageDef); }},
{ EDGETX_ICONS_COUNT }
};
@@ -63,14 +63,14 @@ PageGroupHeaderBase::PageGroupHeaderBase(Window* parent, coord_t height, EdgeTxI
parentLabel = etx_label_create(lvobj);
etx_txt_color(parentLabel, COLOR_THEME_PRIMARY2_INDEX);
lv_obj_set_pos(parentLabel, PageGroup::PAGE_TOP_BAR_H + PAD_LARGE, PageHeader::PAGE_TITLE_TOP);
lv_obj_set_size(parentLabel, LCD_W - PageGroup::PAGE_TOP_BAR_H * 4 - PAD_LARGE * 2, EdgeTxStyles::STD_FONT_HEIGHT);
lv_obj_set_pos(parentLabel, PageHeader::PAGE_TITLE_LEFT, PageHeader::PAGE_TITLE_TOP);
lv_obj_set_size(parentLabel, LCD_W - PageHeader::PAGE_TITLE_LEFT - PageGroup::PAGE_TOP_BAR_H * 2 - PAD_LARGE * 2, EdgeTxStyles::STD_FONT_HEIGHT);
lv_label_set_text(parentLabel, parentTitle);
titleLabel = etx_label_create(lvobj);
etx_txt_color(titleLabel, COLOR_THEME_PRIMARY2_INDEX);
lv_obj_set_pos(titleLabel, PageGroup::PAGE_TOP_BAR_H + PAD_LARGE, PageHeader::PAGE_TITLE_TOP + EdgeTxStyles::STD_FONT_HEIGHT);
lv_obj_set_size(titleLabel, LCD_W - PageGroup::PAGE_TOP_BAR_H * 4 - PAD_LARGE * 2, EdgeTxStyles::STD_FONT_HEIGHT);
lv_obj_set_pos(titleLabel, PageHeader::PAGE_TITLE_LEFT, PageHeader::PAGE_TITLE_TOP + EdgeTxStyles::STD_FONT_HEIGHT);
lv_obj_set_size(titleLabel, LCD_W - PageHeader::PAGE_TITLE_LEFT - PageGroup::PAGE_TOP_BAR_H * 2 - PAD_LARGE * 2, EdgeTxStyles::STD_FONT_HEIGHT);
setTitle("");
}
@@ -89,10 +89,10 @@ void PageGroupHeaderBase::addTab(PageGroupItem* page)
pages.emplace_back(page);
}
bool PageGroupHeaderBase::hasSubMenu(QuickMenu::SubMenu subMenu)
bool PageGroupHeaderBase::hasSubMenu(QMPage qmPage)
{
for (uint8_t i = 0; i < pages.size(); i += 1) {
if (pages[i]->subMenu() == subMenu)
if (pages[i]->pageId() == qmPage)
return true;
}
return false;
@@ -233,6 +233,8 @@ void PageGroupBase::setCurrentTab(unsigned index)
header->setTitle(tab->getTitle().c_str());
header->setIcon(tab->getIcon());
QuickMenu::setCurrentPage(tab->pageId(), icon);
lv_obj_enable_style_refresh(false);
body->clear();
@@ -267,52 +269,26 @@ void PageGroupBase::setCurrentTab(unsigned index)
}
#if defined(HARDWARE_KEYS)
void PageGroupBase::onPressSYS()
void PageGroupBase::doKeyShortcut(event_t event)
{
if (!quickMenu) openMenu();
}
void PageGroupBase::onLongPressSYS()
{
if (icon == ICON_RADIO) {
setCurrentTab(0);
QMPage pg = g_eeGeneral.getKeyShortcut(event);
if (pg == QM_OPEN_QUICK_MENU) {
if (!quickMenu) openMenu();
} else {
onCancel();
PageGroup::ToolsMenu();
}
}
void PageGroupBase::onPressMDL()
{
if (icon == ICON_MODEL) {
setCurrentTab(0);
} else {
onCancel();
PageGroup::ModelMenu();
}
}
void PageGroupBase::onLongPressMDL()
{
onCancel();
new ModelLabelsWindow();
}
void PageGroupBase::onPressTELE()
{
if (icon != ICON_THEME) {
onCancel();
(PageGroup::ScreenMenu())->setCurrentTab(ViewMain::instance()->getCurrentMainView() + ScreenSetupPage::FIRST_SCREEN_OFFSET);
}
}
void PageGroupBase::onLongPressTELE()
{
if (icon != ICON_MONITOR) {
onCancel();
new ChannelsViewMenu();
if (QuickMenu::pageIcon(pg) == icon) {
setCurrentTab(QuickMenu::pageIndex(pg));
} else {
onCancel();
QuickMenu::openPage(pg);
}
}
}
void PageGroupBase::onPressSYS() { doKeyShortcut(EVT_KEY_BREAK(KEY_SYS)); }
void PageGroupBase::onLongPressSYS() { doKeyShortcut(EVT_KEY_LONG(KEY_SYS)); }
void PageGroupBase::onPressMDL() { doKeyShortcut(EVT_KEY_BREAK(KEY_MODEL)); }
void PageGroupBase::onLongPressMDL() { doKeyShortcut(EVT_KEY_LONG(KEY_MODEL)); }
void PageGroupBase::onPressTELE() { doKeyShortcut(EVT_KEY_BREAK(KEY_TELE)); }
void PageGroupBase::onLongPressTELE() { doKeyShortcut(EVT_KEY_LONG(KEY_TELE)); }
void PageGroupBase::onPressPGUP() { header->prevTab(); }
void PageGroupBase::onPressPGDN() { header->nextTab(); }
@@ -321,9 +297,9 @@ void PageGroupBase::onLongPressPGDN() { header->nextTab(); }
void PageGroupBase::onLongPressRTN() { onCancel(); }
#endif
bool PageGroupBase::hasSubMenu(QuickMenu::SubMenu subMenu)
bool PageGroupBase::hasSubMenu(QMPage qmPage)
{
return header->hasSubMenu(subMenu);
return header->hasSubMenu(qmPage);
}
coord_t PageGroupBase::getScrollY()
@@ -372,14 +348,9 @@ void PageGroup::openMenu()
[=](bool close) {
if (close)
onCancel();
}, this, currentTab->subMenu());
}, this, currentTab->pageId());
}
PageGroup* PageGroup::ScreenMenu() { return new PageGroup(ICON_THEME, STR_MAIN_MENU_SCREEN_SETTINGS, screensMenuItems); }
PageGroup* PageGroup::RadioMenu() { return new PageGroup(ICON_RADIO, STR_MAIN_MENU_RADIO_SETTINGS, radioMenuItems); }
PageGroup* PageGroup::ToolsMenu() { return new PageGroup(ICON_RADIO_TOOLS, STR_QM_TOOLS, toolsMenuItems); }
PageGroup* PageGroup::ModelMenu() { return new PageGroup(ICON_MODEL, STR_MAIN_MENU_MODEL_SETTINGS, modelMenuItems); }
//-----------------------------------------------------------------------------
class TabsGroupHeader : public PageGroupHeaderBase
@@ -454,9 +425,9 @@ TabsGroup::TabsGroup(EdgeTxIcon icon, const char* parentLabel) :
void TabsGroup::openMenu()
{
PageGroup* p = (PageGroup*)Layer::getPageGroup();
QuickMenu::SubMenu subMenu = QuickMenu::NONE;
QMPage qmPage = QM_NONE;
if (p)
subMenu = p->getCurrentTab()->subMenu();
qmPage = p->getCurrentTab()->pageId();
quickMenu = QuickMenu::openQuickMenu([=]() { quickMenu = nullptr; },
[=](bool close) {
onCancel();
@@ -467,7 +438,7 @@ void TabsGroup::openMenu()
if (close)
Layer::back()->onCancel();
}
}, p, subMenu);
}, p, qmPage);
}
void TabsGroup::hidePageButtons()
+34 -20
View File
@@ -40,34 +40,49 @@ struct PageDef {
STR_TYP qmTitle;
STR_TYP title;
PageDefAction pageAction;
QuickMenu::SubMenu subMenu;
QMPage qmPage;
std::function<PageGroupItem*(PageDef& pageDef)> create;
std::function<bool()> enabled;
std::function<void(QuickSubMenu* subMenu)> action;
std::function<void()> action;
};
extern PageDef modelMenuItems[];
extern PageDef radioMenuItems[];
extern PageDef screensMenuItems[];
extern PageDef toolsMenuItems[];
extern PageDef favoritesMenuItems[];
enum QMTopDefAction {
QM_SUBMENU,
QM_ACTION
};
struct QMTopDef {
EdgeTxIcon icon;
STR_TYP qmTitle;
STR_TYP title;
QMTopDefAction pageAction;
QMPage qmPage;
PageDef* subMenuItems;
std::function<void()> action;
std::function<bool()> enabled;
};
extern QMTopDef qmTopItems[];
//-----------------------------------------------------------------------------
class PageGroupItem
{
public:
PageGroupItem(const std::string& title, QuickMenu::SubMenu subMenu = QuickMenu::NONE) :
title(std::move(title)), icon(ICON_EDGETX), quickMenuId(subMenu), padding(PAD_SMALL)
PageGroupItem(std::string title, QMPage qmPage = QM_NONE) :
title(std::move(title)), icon(ICON_EDGETX), qmPageId(qmPage), padding(PAD_SMALL)
{}
PageGroupItem(PageDef& pageDef, PaddingSize padding = PAD_SMALL) :
title(STR_VAL(pageDef.title)), icon(pageDef.icon), quickMenuId(pageDef.subMenu),
padding(padding)
title(STR_VAL(pageDef.title)), icon(pageDef.icon), qmPageId(pageDef.qmPage),
padding(padding), enabled(std::move(pageDef.enabled))
{}
virtual ~PageGroupItem() = default;
virtual bool isVisible() const { return true; }
bool isVisible() const { return enabled == nullptr || enabled(); }
virtual void build(Window* window) = 0;
@@ -84,13 +99,14 @@ class PageGroupItem
virtual void update(uint8_t index) {}
virtual void cleanup() {}
QuickMenu::SubMenu subMenu() const { return quickMenuId; }
QMPage pageId() const { return qmPageId; }
protected:
std::string title;
EdgeTxIcon icon;
QuickMenu::SubMenu quickMenuId = QuickMenu::NONE;
QMPage qmPageId = QM_NONE;
PaddingSize padding;
std::function<bool()> enabled = nullptr;
};
//-----------------------------------------------------------------------------
@@ -118,7 +134,7 @@ class PageGroupHeaderBase : public Window
}
}
bool hasSubMenu(QuickMenu::SubMenu n);
bool hasSubMenu(QMPage n);
PageGroupItem* pageTab(uint8_t idx) const { return pages[idx]; }
bool isCurrent(uint8_t idx) const { return currentIndex == idx; }
@@ -151,11 +167,13 @@ class PageGroupBase : public NavWindow
void addTab(PageGroupItem* page);
bool hasSubMenu(QuickMenu::SubMenu n);
bool hasSubMenu(QMPage n);
coord_t getScrollY();
void setScrollY(coord_t y);
EdgeTxIcon getIcon() const { return icon; }
protected:
PageGroupHeaderBase* header = nullptr;
Window* body = nullptr;
@@ -170,6 +188,7 @@ class PageGroupBase : public NavWindow
void deleteLater(bool detach = true, bool trash = true) override;
#if defined(HARDWARE_KEYS)
void doKeyShortcut(event_t event);
void onPressSYS() override;
void onLongPressSYS() override;
void onPressMDL() override;
@@ -201,11 +220,6 @@ class PageGroup : public PageGroupBase
bool isPageGroup() override { return true; }
static PageGroup* ScreenMenu();
static PageGroup* RadioMenu();
static PageGroup* ToolsMenu();
static PageGroup* ModelMenu();
static LAYOUT_VAL_SCALED(PAGE_TOP_BAR_H, 45)
protected:
+358 -163
View File
@@ -32,151 +32,180 @@
//-----------------------------------------------------------------------------
ButtonBase* QuickSubMenu::addButton()
class QuickSubMenu
{
menuButton = quickMenu->getTopMenu()->addButton(icon, title,
[=]() -> uint8_t {
activate();
return 0;
});
public:
QuickSubMenu(Window* parent, QuickMenu* quickMenu,
EdgeTxIcon icon, const char* title, const char* parentTitle,
PageDef* items):
parent(parent), quickMenu(quickMenu),
icon(icon), title(title), parentTitle(parentTitle), items(items)
{}
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;
}
bool QuickSubMenu::isSubMenu(QuickMenu::SubMenu n)
{
for (int i = 0; items[i].icon < EDGETX_ICONS_COUNT; i += 1)
if (items[i].subMenu == n) return true;
return false;
}
bool QuickSubMenu::isSubMenu(ButtonBase* b)
{
for (int i = 0; items[i].icon < EDGETX_ICONS_COUNT; i += 1)
if (menuButton == b) return true;
return false;
}
int QuickSubMenu::getIndex(QuickMenu::SubMenu n)
{
for (int i = 0; items[i].icon < EDGETX_ICONS_COUNT; i += 1)
if (items[i].subMenu == n) return i;
return -1;
}
void QuickSubMenu::enableSubMenu()
{
subMenu->setGroup();
subMenu->setFocus();
subMenu->setEnabled();
subMenu->show();
quickMenu->enableSubMenu();
}
void QuickSubMenu::setDisabled(bool all)
{
if (subMenu)
subMenu->setDisabled(all);
}
void QuickSubMenu::setCurrent(QuickMenu::SubMenu n)
{
if (!subMenu) buildSubMenu();
quickMenu->getTopMenu()->setCurrent(menuButton);
quickMenu->getTopMenu()->setDisabled(false);
subMenu->setCurrent(getIndex(n));
enableSubMenu();
}
void QuickSubMenu::activate()
{
if (!subMenu) buildSubMenu();
quickMenu->getTopMenu()->setCurrent(menuButton);
quickMenu->getTopMenu()->setDisabled(false);
quickMenu->getTopMenu()->clearFocus();
enableSubMenu();
}
void QuickSubMenu::doLayout()
{
if (subMenu)
subMenu->doLayout(QuickMenu::QM_SUB_COLS);
}
void QuickSubMenu::buildSubMenu()
{
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),
std::bind(&QuickSubMenu::onPress, this, i),
[=]() { return items[i].enabled ? items[i].enabled() : true; },
[=]() { QuickMenu::setCurrentPage(items[i].subMenu); });
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;
}
doLayout();
subMenu->hide();
subMenu->setDisabled(true);
}
bool isSubMenu(QMPage n, EdgeTxIcon curIcon)
{
if ((icon != EDGETX_ICONS_COUNT) && (icon != curIcon)) return false;
return isSubMenu(n);
}
int QuickSubMenu::getPageNumber(int iconNumber)
{
int pageNumber = 0;
for (int i = 0; i < iconNumber; i += 1)
if (items[i].pageAction == PAGE_CREATE)
pageNumber += 1;
return pageNumber;
}
bool isSubMenu(ButtonBase* b)
{
for (int i = 0; items[i].icon < EDGETX_ICONS_COUNT; i += 1)
if (menuButton == b) return true;
return false;
}
uint8_t QuickSubMenu::onPress(int n)
{
if (items[n].pageAction == PAGE_CREATE) {
quickMenu->getTopMenu()->clearFocus();
int pgIdx = getPageNumber(n);
if (quickMenu->getPageGroup() && quickMenu->getPageGroup()->hasSubMenu(items[n].subMenu)) {
quickMenu->onSelect(false);
quickMenu->getPageGroup()->setCurrentTab(pgIdx);
} else {
quickMenu->onSelect(true);
auto pg = new PageGroup(icon, parentTitle, items);
pg->setCurrentTab(pgIdx);
}
} else {
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;
}
ButtonBase* addButton()
{
menuButton = quickMenu->getTopMenu()->addButton(icon, title,
[=]() -> uint8_t {
activate();
return 0;
});
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;
}
void enableSubMenu()
{
subMenu->setGroup();
subMenu->setFocus();
subMenu->setEnabled();
subMenu->show();
quickMenu->enableSubMenu();
}
void setDisabled(bool all)
{
if (subMenu)
subMenu->setDisabled(all);
}
void setCurrent(QMPage n)
{
if (!subMenu) buildSubMenu();
quickMenu->getTopMenu()->setCurrent(menuButton);
quickMenu->getTopMenu()->setDisabled(false);
subMenu->setCurrent(getIndex(n));
enableSubMenu();
}
void activate()
{
if (!subMenu) buildSubMenu();
quickMenu->getTopMenu()->setCurrent(menuButton);
quickMenu->getTopMenu()->setDisabled(false);
quickMenu->getTopMenu()->clearFocus();
enableSubMenu();
items[n].action(this);
}
return 0;
}
void QuickSubMenu::onSelect(bool close)
{
quickMenu->onSelect(close);
}
void buildSubMenu()
{
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),
std::bind(&QuickSubMenu::onPress, this, i),
items[i].enabled,
[=]() { QuickMenu::setCurrentPage(items[i].qmPage, icon); });
}
doLayout();
subMenu->hide();
subMenu->setDisabled(true);
}
uint8_t onPress(int n)
{
if (items[n].pageAction == PAGE_CREATE) {
quickMenu->getTopMenu()->clearFocus();
int pgIdx = getPageNumber(n);
if (quickMenu->getPageGroup() && quickMenu->getPageGroup()->hasSubMenu(items[n].qmPage)) {
quickMenu->onSelect(false);
quickMenu->getPageGroup()->setCurrentTab(pgIdx);
} else {
quickMenu->onSelect(true);
auto pg = new PageGroup(icon, parentTitle, items);
pg->setCurrentTab(pgIdx);
}
} else {
quickMenu->getTopMenu()->setCurrent(menuButton);
quickMenu->getTopMenu()->setDisabled(false);
quickMenu->getTopMenu()->clearFocus();
enableSubMenu();
onSelect(true);
items[n].action();
}
return 0;
}
void onSelect(bool close)
{
quickMenu->onSelect(close);
}
int getPageNumber(int iconNumber)
{
int pageNumber = 0;
for (int i = 0; i < iconNumber; i += 1)
if (items[i].pageAction == PAGE_CREATE)
pageNumber += 1;
return pageNumber;
}
void doLayout()
{
if (subMenu)
subMenu->doLayout(QuickMenu::QM_SUB_COLS);
}
protected:
Window* parent;
QuickMenu* quickMenu;
EdgeTxIcon icon;
const char* title;
const char* parentTitle;
PageDef* items;
QuickMenuGroup* subMenu = nullptr;
ButtonBase* menuButton = nullptr;
};
//-----------------------------------------------------------------------------
QuickMenu* QuickMenu::instance = nullptr;
QuickMenu::SubMenu QuickMenu::curPage = QuickMenu::NONE;
QMPage QuickMenu::curPage = QM_NONE;
EdgeTxIcon QuickMenu::curIcon = EDGETX_ICONS_COUNT;
QuickMenu* QuickMenu::openQuickMenu(std::function<void()> cancelHandler,
std::function<void(bool close)> selectHandler,
PageGroupBase* pageGroup, SubMenu curPage)
PageGroupBase* pageGroup, QMPage curPage)
{
if (!instance) {
instance = new QuickMenu();
@@ -188,6 +217,7 @@ QuickMenu* QuickMenu::openQuickMenu(std::function<void()> cancelHandler,
void QuickMenu::shutdownQuickMenu()
{
if (instance) instance->deleteLater();
instance = nullptr;
}
QuickMenu::QuickMenu() :
@@ -218,32 +248,28 @@ QuickMenu::QuickMenu() :
mainMenu = new QuickMenuGroup(box);
mainMenu->addButton(ICON_MODEL_SELECT, STR_QM_MANAGE_MODELS,
[=]() -> uint8_t {
onSelect(true);
new ModelLabelsWindow();
return 0;
});
box = new Window(this, {QM_SUB_X, QM_SUB_Y, QM_SUB_W, QM_SUB_H});
QuickSubMenu* sub;
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;
sub = new QuickSubMenu(box, this, ICON_MODEL, STR_QM_MODEL_SETUP, STR_MAIN_MENU_MODEL_SETTINGS, modelMenuItems);
sub->addButton();
subMenus.emplace_back(sub);
sub = new QuickSubMenu(box, this, ICON_RADIO, STR_QM_RADIO_SETUP, STR_MAIN_MENU_RADIO_SETTINGS, radioMenuItems);
sub->addButton();
subMenus.emplace_back(sub);
sub = new QuickSubMenu(box, this, ICON_THEME, STR_QM_UI_SETUP, STR_MAIN_MENU_SCREEN_SETTINGS, screensMenuItems);
sub->addButton();
subMenus.emplace_back(sub);
sub = new QuickSubMenu(box, this, ICON_RADIO_TOOLS, STR_QM_TOOLS, STR_QM_TOOLS, toolsMenuItems);
sub->addButton();
subMenus.emplace_back(sub);
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), qmTopItems[i].action);
} 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);
}
}
}
}
void QuickMenu::deleteLater(bool detach, bool trash)
@@ -257,7 +283,7 @@ void QuickMenu::deleteLater(bool detach, bool trash)
void QuickMenu::openQM(std::function<void()> cancelHandler,
std::function<void(bool close)> selectHandler,
PageGroupBase* newPageGroup, SubMenu newCurPage)
PageGroupBase* newPageGroup, QMPage newCurPage)
{
Layer::push(this);
@@ -272,23 +298,182 @@ void QuickMenu::openQM(std::function<void()> cancelHandler,
if (newPageGroup) {
pageGroup = newPageGroup;
curPage = newCurPage;
curIcon = pageGroup->getIcon();
mainMenu->setDisabled(false);
mainMenu->clearFocus();
setFocus(curPage);
} else {
pageGroup = nullptr;
if (curPage >= QuickMenu::FIRST_SUB_MENU_ITEM) {
if (curPage != QM_MANAGE_MODELS && curPage != QM_NONE) {
mainMenu->setDisabled(false);
mainMenu->clearFocus();
setFocus(curPage);
} else {
if (curPage == QuickMenu::MANAGE_MODELS)
mainMenu->setCurrent(0);
if (curPage == QM_MANAGE_MODELS)
mainMenu->setCurrent(favoritesMenuItems[0].icon == EDGETX_ICONS_COUNT ? 0 : 1);
focusMainMenu();
}
}
}
void QuickMenu::selected()
{
if (instance)
instance->onSelect(true);
}
void QuickMenu::openPage(QMPage page)
{
for (int i = 1; qmTopItems[i].icon != EDGETX_ICONS_COUNT; i += 1) {
if (qmTopItems[i].pageAction == QM_ACTION) {
if (qmTopItems[i].qmPage == page) {
qmTopItems[i].action();
return;
}
} else {
PageDef* sub = qmTopItems[i].subMenuItems;
for (int j = 0, k = 0; sub[j].icon != EDGETX_ICONS_COUNT; j += 1) {
if (sub[j].qmPage == page) {
if (sub[j].pageAction == PAGE_ACTION) {
sub[j].action();
} else {
auto pg = new PageGroup(qmTopItems[i].icon, STR_VAL(qmTopItems[i].title), sub);
pg->setCurrentTab(k);
return;
}
} else if (sub[j].pageAction == PAGE_CREATE) {
k += 1;
}
}
}
}
}
EdgeTxIcon QuickMenu::pageIcon(QMPage page)
{
for (int i = 1; qmTopItems[i].icon != EDGETX_ICONS_COUNT; i += 1) {
if (qmTopItems[i].pageAction == QM_ACTION) {
if (qmTopItems[i].qmPage == page) {
return qmTopItems[i].icon;
}
} else {
PageDef* sub = qmTopItems[i].subMenuItems;
for (int j = 0; sub[j].icon != EDGETX_ICONS_COUNT; j += 1) {
if (sub[j].qmPage == page) {
return sub[j].icon;
}
}
}
}
return EDGETX_ICONS_COUNT;
}
int QuickMenu::pageIndex(QMPage page)
{
for (int i = 1; qmTopItems[i].icon != EDGETX_ICONS_COUNT; i += 1) {
if (qmTopItems[i].pageAction == QM_ACTION) {
if (qmTopItems[i].qmPage == page) {
return 0;
}
} else {
PageDef* sub = qmTopItems[i].subMenuItems;
for (int j = 0, k = 0; sub[j].icon != EDGETX_ICONS_COUNT; j += 1) {
if (sub[j].qmPage == page) {
if (sub[j].pageAction == PAGE_CREATE)
return k;
else
return 0;
} else if (sub[j].pageAction == PAGE_CREATE) {
k += 1;
}
}
}
}
return 0;
}
static std::string replaceAll(std::string str, const std::string& from, const std::string& to)
{
auto&& pos = str.find(from, size_t{});
while (pos != std::string::npos)
{
str.replace(pos, from.length(), to);
// easy to forget to add to.length()
pos = str.find(from, pos + to.length());
}
return str;
}
std::vector<std::string> QuickMenu::menuPageNames(bool forFavorites)
{
std::vector<std::string> qmPages;
qmPages.emplace_back(STR_NONE);
qmPages.emplace_back(STR_OPEN_QUICK_MENU);
for (int i = 1; qmTopItems[i].icon != EDGETX_ICONS_COUNT; i += 1) {
if (qmTopItems[i].pageAction == QM_ACTION) {
qmPages.emplace_back(STR_VAL(qmTopItems[i].title));
} else {
PageDef* sub = qmTopItems[i].subMenuItems;
for (int j = 0; sub[j].icon != EDGETX_ICONS_COUNT; j += 1) {
std::string s(STR_VAL(qmTopItems[i].title));
s += " - ";
if (!forFavorites && sub[j].qmPage >= QM_UI_SCREEN1 && sub[j].qmPage <= QM_UI_SCREEN10)
s += STR_CURRENT_SCREEN;
else
s += STR_VAL(sub[j].title);
s = replaceAll(s, "\n", " ");
qmPages.emplace_back(s);
}
}
}
return qmPages;
}
void QuickMenu::setupFavorite(QMPage page, int f)
{
PageDef& fav = favoritesMenuItems[f];
for (int i = 1; qmTopItems[i].icon != EDGETX_ICONS_COUNT; i += 1) {
if (qmTopItems[i].pageAction == QM_ACTION) {
if (qmTopItems[i].qmPage == page) {
fav.icon = qmTopItems[i].icon;
fav.qmTitle = qmTopItems[i].qmTitle;
fav.title = qmTopItems[i].title;
fav.pageAction = PAGE_ACTION;
fav.qmPage = qmTopItems[i].qmPage;
fav.create = nullptr;
fav.enabled = nullptr;
fav.action = qmTopItems[i].action;
return;
}
} else {
PageDef* sub = qmTopItems[i].subMenuItems;
for (int j = 0; sub[j].icon != EDGETX_ICONS_COUNT; j += 1) {
if (sub[j].qmPage == page) {
fav.icon = sub[j].icon;
fav.qmTitle = sub[j].qmTitle;
fav.title = sub[j].title;
fav.pageAction = sub[j].pageAction;
fav.qmPage = sub[j].qmPage;
fav.create = sub[j].create;
fav.enabled = sub[j].enabled;
fav.action = sub[j].action;
return;
}
}
}
}
}
void QuickMenu::setCurrentPage(QMPage newPage, EdgeTxIcon newIcon)
{
curPage = newPage;
curIcon = newIcon;
}
void QuickMenu::focusMainMenu()
{
inSubMenu = false;
@@ -316,16 +501,16 @@ void QuickMenu::onCancel()
{
if (inSubMenu) {
focusMainMenu();
curPage = QuickMenu::NONE;
curPage = QM_NONE;
} else {
closeMenu();
}
}
void QuickMenu::setFocus(SubMenu selection)
void QuickMenu::setFocus(QMPage selection)
{
for(auto sub : subMenus) {
if (sub->isSubMenu(selection)) {
if (sub->isSubMenu(selection, curIcon)) {
sub->setCurrent(selection);
return;
}
@@ -338,12 +523,22 @@ void QuickMenu::enableSubMenu()
}
#if defined(HARDWARE_KEYS)
void QuickMenu::onPressSYS() { closeMenu(); }
void QuickMenu::onLongPressSYS() { subMenus[3]->onPress(0); }
void QuickMenu::onPressMDL() { subMenus[0]->onPress(0); }
void QuickMenu::onLongPressMDL() { onSelect(true); new ModelLabelsWindow(); }
void QuickMenu::onPressTELE() { subMenus[2]->onPress(ScreenSetupPage::FIRST_SCREEN_OFFSET); }
void QuickMenu::onLongPressTELE() { onSelect(true); new ChannelsViewMenu(); }
void QuickMenu::doKeyShortcut(event_t event)
{
QMPage pg = g_eeGeneral.getKeyShortcut(event);
if (pg == QM_OPEN_QUICK_MENU) {
closeMenu();
} else {
onSelect(true);
QuickMenu::openPage(pg);
}
}
void QuickMenu::onPressSYS() { doKeyShortcut(EVT_KEY_BREAK(KEY_SYS)); }
void QuickMenu::onLongPressSYS() { doKeyShortcut(EVT_KEY_LONG(KEY_SYS)); }
void QuickMenu::onPressMDL() { doKeyShortcut(EVT_KEY_BREAK(KEY_MODEL)); }
void QuickMenu::onLongPressMDL() { doKeyShortcut(EVT_KEY_LONG(KEY_MODEL)); }
void QuickMenu::onPressTELE() { doKeyShortcut(EVT_KEY_BREAK(KEY_TELE)); }
void QuickMenu::onLongPressTELE() { doKeyShortcut(EVT_KEY_LONG(KEY_TELE)); }
void QuickMenu::onLongPressRTN() { closeMenu(); }
void QuickMenu::afterPG()
@@ -357,7 +552,7 @@ void QuickMenu::afterPG()
}
}
focusMainMenu();
curPage = QuickMenu::NONE;
curPage = QM_NONE;
}
}
+19 -93
View File
@@ -25,6 +25,7 @@
#include "bitmaps.h"
#include <vector>
#include "quick_menu_group.h"
#include "quick_menu_def.h"
class PageGroup;
class PageGroupBase;
@@ -42,76 +43,36 @@ struct PageDef;
class QuickMenu : public NavWindow
{
public:
enum SubMenu {
NONE = 0,
MANAGE_MODELS,
FIRST_SUB_MENU_ITEM,
// Model menu
MODEL_SETUP = FIRST_SUB_MENU_ITEM,
MODEL_HELI,
MODEL_FLIGHTMODES,
MODEL_INPUTS,
MODEL_MIXES,
MODEL_OUTPUTS,
MODEL_CURVES,
MODEL_GVARS,
MODEL_LS,
MODEL_SF,
MODEL_SCRIPTS,
MODEL_TELEMETRY,
MODEL_NOTES,
// Radio menu
RADIO_SETUP,
RADIO_GF,
RADIO_TRAINER,
RADIO_HARDWARE,
RADIO_VERSION,
// UI menu
UI_THEMES,
UI_SETUP,
UI_SCREEN1,
UI_SCREEN2,
UI_SCREEN3,
UI_SCREEN4,
UI_SCREEN5,
UI_SCREEN6,
UI_SCREEN7,
UI_SCREEN8,
UI_SCREEN9,
UI_SCREEN10,
UI_ADD_PG,
// Tools menu
TOOLS_APPS,
TOOLS_STORAGE,
TOOLS_RESET,
TOOLS_CHAN_MON,
TOOLS_LS_MON,
TOOLS_STATS,
TOOLS_DEBUG,
};
QuickMenu();
static QuickMenu* openQuickMenu(std::function<void()> cancelHandler,
std::function<void(bool close)> selectHandler = nullptr,
PageGroupBase* pageGroup = nullptr, SubMenu curPage = NONE);
static void shutdownQuickMenu();
void onCancel() override;
void onSelect(bool close);
void closeMenu();
void setFocus(SubMenu selection);
void setFocus(QMPage selection);
void enableSubMenu();
SubMenu currentPage() const { return curPage; }
static void setCurrentPage(SubMenu newPage) { curPage = newPage; }
static void setCurrentPage(QMPage newPage, EdgeTxIcon newIcon = EDGETX_ICONS_COUNT);
PageGroupBase* getPageGroup() const { return pageGroup; }
QuickMenuGroup* getTopMenu() const { return mainMenu; }
static QuickMenu* openQuickMenu(std::function<void()> cancelHandler,
std::function<void(bool close)> selectHandler = nullptr,
PageGroupBase* pageGroup = nullptr, QMPage curPage = QM_NONE);
static void shutdownQuickMenu();
static void selected();
static void openPage(QMPage page);
static EdgeTxIcon pageIcon(QMPage page);
static int pageIndex(QMPage page);
static std::vector<std::string> menuPageNames(bool forFavorites);
static void setupFavorite(QMPage page, int f);
#if defined(HARDWARE_KEYS)
void doKeyShortcut(event_t event);
void onPressSYS() override;
void onLongPressSYS() override;
void onPressMDL() override;
@@ -147,49 +108,14 @@ class QuickMenu : public NavWindow
QuickMenuGroup* mainMenu = nullptr;
std::vector<QuickSubMenu*> subMenus;
PageGroupBase* pageGroup = nullptr;
static SubMenu curPage;
static QMPage curPage;
static EdgeTxIcon curIcon;
void openQM(std::function<void()> cancelHandler,
std::function<void(bool close)> selectHandler,
PageGroupBase* pageGroup, SubMenu curPage);
PageGroupBase* pageGroup, QMPage curPage);
void focusMainMenu();
void deleteLater(bool detach = true, bool trash = true) override;
};
class QuickSubMenu
{
public:
QuickSubMenu(Window* parent, QuickMenu* quickMenu,
EdgeTxIcon icon, const char* title, const char* parentTitle,
PageDef* items):
parent(parent), quickMenu(quickMenu),
icon(icon), title(title), parentTitle(parentTitle), items(items)
{}
bool isSubMenu(QuickMenu::SubMenu n);
bool isSubMenu(ButtonBase* b);
int getIndex(QuickMenu::SubMenu n);
ButtonBase* addButton();
void enableSubMenu();
void setDisabled(bool all);
void setCurrent(QuickMenu::SubMenu n);
void activate();
void buildSubMenu();
uint8_t onPress(int n);
void onSelect(bool close);
int getPageNumber(int iconNumber);
void doLayout();
protected:
Window* parent;
QuickMenu* quickMenu;
EdgeTxIcon icon;
const char* title;
const char* parentTitle;
PageDef* items;
QuickMenuGroup* subMenu = nullptr;
ButtonBase* menuButton = nullptr;
};
@@ -0,0 +1,179 @@
/*
* 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 "edgetx.h"
#include "pagegroup.h"
#include "model_curves.h"
#include "model_flightmodes.h"
#include "model_gvars.h"
#include "model_heli.h"
#include "model_inputs.h"
#include "model_logical_switches.h"
#include "model_mixer_scripts.h"
#include "model_mixes.h"
#include "model_outputs.h"
#include "model_select.h"
#include "model_setup.h"
#include "model_telemetry.h"
#include "special_functions.h"
#include "view_text.h"
#include "radio_hardware.h"
#include "radio_setup.h"
#include "radio_trainer.h"
#include "radio_version.h"
#include "screen_setup.h"
#include "view_main.h"
#include "radio_sdmanager.h"
#include "radio_tools.h"
#include "view_statistics.h"
#include "view_logical_switches.h"
#include "view_channels.h"
PageDef favoritesMenuItems[] = {
{ EDGETX_ICONS_COUNT, nullptr, nullptr, PAGE_CREATE, QM_NONE, nullptr},
{ EDGETX_ICONS_COUNT, nullptr, nullptr, PAGE_CREATE, QM_NONE, nullptr},
{ EDGETX_ICONS_COUNT, nullptr, nullptr, PAGE_CREATE, QM_NONE, nullptr},
{ EDGETX_ICONS_COUNT, nullptr, nullptr, PAGE_CREATE, QM_NONE, nullptr},
{ EDGETX_ICONS_COUNT, nullptr, nullptr, PAGE_CREATE, QM_NONE, nullptr},
{ EDGETX_ICONS_COUNT, nullptr, nullptr, PAGE_CREATE, QM_NONE, nullptr},
{ EDGETX_ICONS_COUNT, nullptr, nullptr, PAGE_CREATE, QM_NONE, nullptr},
{ EDGETX_ICONS_COUNT, nullptr, nullptr, PAGE_CREATE, QM_NONE, nullptr},
{ EDGETX_ICONS_COUNT, nullptr, nullptr, PAGE_CREATE, QM_NONE, nullptr},
{ EDGETX_ICONS_COUNT, nullptr, nullptr, PAGE_CREATE, QM_NONE, nullptr},
{ EDGETX_ICONS_COUNT, nullptr, nullptr, PAGE_CREATE, QM_NONE, nullptr},
{ EDGETX_ICONS_COUNT, nullptr, nullptr, PAGE_CREATE, QM_NONE, nullptr},
{ EDGETX_ICONS_COUNT }
};
PageDef modelMenuItems[] = {
{ ICON_MODEL_SETUP, STR_DEF(STR_QM_MODEL_SETTINGS), STR_DEF(STR_MAIN_MODEL_SETTINGS), PAGE_CREATE, QM_MODEL_SETUP, [](PageDef& pageDef) { return new ModelSetupPage(pageDef); }},
#if defined(FLIGHT_MODES)
{ ICON_MODEL_FLIGHT_MODES, STR_DEF(STR_QM_FLIGHT_MODES), STR_DEF(STR_MENUFLIGHTMODES), PAGE_CREATE, QM_MODEL_FLIGHTMODES, [](PageDef& pageDef) { return new ModelFlightModesPage(pageDef); }, modelFMEnabled},
#endif
{ ICON_MODEL_INPUTS, STR_DEF(STR_QM_INPUTS), STR_DEF(STR_MENUINPUTS), PAGE_CREATE, QM_MODEL_INPUTS, [](PageDef& pageDef) { return new ModelInputsPage(pageDef); }},
{ ICON_MODEL_MIXER, STR_DEF(STR_QM_MIXES), STR_DEF(STR_MIXES), PAGE_CREATE, QM_MODEL_MIXES, [](PageDef& pageDef) { return new ModelMixesPage(pageDef); }},
{ ICON_MODEL_OUTPUTS, STR_DEF(STR_QM_OUTPUTS), STR_DEF(STR_MENULIMITS), PAGE_CREATE, QM_MODEL_OUTPUTS, [](PageDef& pageDef) { return new ModelOutputsPage(pageDef); }},
{ ICON_MODEL_CURVES, STR_DEF(STR_QM_CURVES), STR_DEF(STR_MENUCURVES), PAGE_CREATE, QM_MODEL_CURVES, [](PageDef& pageDef) { return new ModelCurvesPage(pageDef); }, modelCurvesEnabled},
#if defined(GVARS)
{ ICON_MODEL_GVARS, STR_DEF(STR_QM_GLOBAL_VARS), STR_DEF(STR_MENU_GLOBAL_VARS), PAGE_CREATE, QM_MODEL_GVARS, [](PageDef& pageDef) { return new ModelGVarsPage(pageDef); }, modelGVEnabled},
#endif
{ ICON_MODEL_LOGICAL_SWITCHES, STR_DEF(STR_QM_LOGICAL_SW), STR_DEF(STR_MENULOGICALSWITCHES), PAGE_CREATE, QM_MODEL_LS, [](PageDef& pageDef) { return new ModelLogicalSwitchesPage(pageDef); }, modelLSEnabled},
{ ICON_MODEL_SPECIAL_FUNCTIONS, STR_DEF(STR_QM_SPEC_FUNC), STR_DEF(STR_MENUCUSTOMFUNC), PAGE_CREATE, QM_MODEL_SF, [](PageDef& pageDef) { return new SpecialFunctionsPage(pageDef); }, modelSFEnabled},
#if defined(LUA_MODEL_SCRIPTS)
{ ICON_MODEL_LUA_SCRIPTS, STR_DEF(STR_QM_CUSTOM_LUA), STR_DEF(STR_MENUCUSTOMSCRIPTS), PAGE_CREATE, QM_MODEL_SCRIPTS, [](PageDef& pageDef) { return new ModelMixerScriptsPage(pageDef); }, modelCustomScriptsEnabled},
#endif
{ ICON_MODEL_TELEMETRY, STR_DEF(STR_QM_TELEM), STR_DEF(STR_MENUTELEMETRY), PAGE_CREATE, QM_MODEL_TELEMETRY, [](PageDef& pageDef) { return new ModelTelemetryPage(pageDef); }, modelTelemetryEnabled},
{ ICON_MODEL_NOTES, STR_DEF(STR_MAIN_MENU_MODEL_NOTES), STR_DEF(STR_MAIN_MENU_MODEL_NOTES), PAGE_CREATE, QM_MODEL_NOTES, [](PageDef& pageDef) { return new ModelNotesPage(pageDef); }, modelHasNotes},
{ EDGETX_ICONS_COUNT }
};
PageDef radioMenuItems[] = {
{ ICON_RADIO_SETUP, STR_DEF(STR_QM_RADIO_SETTINGS), STR_DEF(STR_MAIN_RADIO_SETTINGS), PAGE_CREATE, QM_RADIO_SETUP, [](PageDef& pageDef) { return new RadioSetupPage(pageDef); }},
{ ICON_RADIO_GLOBAL_FUNCTIONS, STR_DEF(STR_QM_GLOB_FUNC), STR_DEF(STR_MENUSPECIALFUNCS), PAGE_CREATE, QM_RADIO_GF, [](PageDef& pageDef) { return new GlobalFunctionsPage(pageDef); }, radioGFEnabled},
{ ICON_RADIO_TRAINER, STR_DEF(STR_QM_TRAINER), STR_DEF(STR_MENUTRAINER), PAGE_CREATE, QM_RADIO_TRAINER, [](PageDef& pageDef) { return new RadioTrainerPage(pageDef); }, radioTrainerEnabled},
{ ICON_RADIO_HARDWARE, STR_DEF(STR_QM_HARDWARE), STR_DEF(STR_HARDWARE), PAGE_CREATE, QM_RADIO_HARDWARE, [](PageDef& pageDef) { return new RadioHardwarePage(pageDef); }},
{ ICON_RADIO_VERSION, STR_DEF(STR_QM_ABOUT), STR_DEF(STR_MAIN_MENU_ABOUT_EDGETX), PAGE_CREATE, QM_RADIO_VERSION, [](PageDef& pageDef) { return new RadioVersionPage(pageDef); }},
{ EDGETX_ICONS_COUNT }
};
PageDef screensMenuItems[] = {
{ ICON_RADIO_EDIT_THEME, STR_DEF(STR_QM_THEMES), STR_DEF(STR_MAIN_MENU_THEMES), PAGE_CREATE, QM_UI_THEMES, [](PageDef& pageDef) { return new ThemeSetupPage(pageDef); }, radioThemesEnabled},
{ ICON_THEME_SETUP, STR_DEF(STR_QM_TOP_BAR), STR_DEF(STR_USER_INTERFACE), PAGE_CREATE, QM_UI_SETUP, [](PageDef& pageDef) { return new ScreenUserInterfacePage(pageDef); }},
{ ICON_THEME_VIEW1, STR_DEF(STR_QM_SCREEN_1), STR_DEF(STR_MAIN_VIEW_1), PAGE_CREATE, QM_UI_SCREEN1, [](PageDef& pageDef) { return new ScreenSetupPage(0, pageDef); }},
{ ICON_THEME_VIEW2, STR_DEF(STR_QM_SCREEN_2), STR_DEF(STR_MAIN_VIEW_2), PAGE_CREATE, QM_UI_SCREEN2, [](PageDef& pageDef) { return new ScreenSetupPage(1, pageDef); }, []() { return customScreens[1] != nullptr; }},
{ ICON_THEME_VIEW3, STR_DEF(STR_QM_SCREEN_3), STR_DEF(STR_MAIN_VIEW_3), PAGE_CREATE, QM_UI_SCREEN3, [](PageDef& pageDef) { return new ScreenSetupPage(2, pageDef); }, []() { return customScreens[2] != nullptr; }},
{ ICON_THEME_VIEW4, STR_DEF(STR_QM_SCREEN_4), STR_DEF(STR_MAIN_VIEW_4), PAGE_CREATE, QM_UI_SCREEN4, [](PageDef& pageDef) { return new ScreenSetupPage(3, pageDef); }, []() { return customScreens[3] != nullptr; }},
{ ICON_THEME_VIEW5, STR_DEF(STR_QM_SCREEN_5), STR_DEF(STR_MAIN_VIEW_5), PAGE_CREATE, QM_UI_SCREEN5, [](PageDef& pageDef) { return new ScreenSetupPage(4, pageDef); }, []() { return customScreens[4] != nullptr; }},
{ ICON_THEME_VIEW6, STR_DEF(STR_QM_SCREEN_6), STR_DEF(STR_MAIN_VIEW_6), PAGE_CREATE, QM_UI_SCREEN6, [](PageDef& pageDef) { return new ScreenSetupPage(5, pageDef); }, []() { return customScreens[5] != nullptr; }},
{ ICON_THEME_VIEW7, STR_DEF(STR_QM_SCREEN_7), STR_DEF(STR_MAIN_VIEW_7), PAGE_CREATE, QM_UI_SCREEN7, [](PageDef& pageDef) { return new ScreenSetupPage(6, pageDef); }, []() { return customScreens[6] != nullptr; }},
{ ICON_THEME_VIEW8, STR_DEF(STR_QM_SCREEN_8), STR_DEF(STR_MAIN_VIEW_8), PAGE_CREATE, QM_UI_SCREEN8, [](PageDef& pageDef) { return new ScreenSetupPage(7, pageDef); }, []() { return customScreens[7] != nullptr; }},
{ ICON_THEME_VIEW9, STR_DEF(STR_QM_SCREEN_9), STR_DEF(STR_MAIN_VIEW_9), PAGE_CREATE, QM_UI_SCREEN9, [](PageDef& pageDef) { return new ScreenSetupPage(8, pageDef); }, []() { return customScreens[8] != nullptr; }},
{ ICON_THEME_VIEW10, STR_DEF(STR_QM_SCREEN_10), STR_DEF(STR_MAIN_VIEW_10), PAGE_CREATE, QM_UI_SCREEN10, [](PageDef& pageDef) { return new ScreenSetupPage(9, pageDef); }, []() { return customScreens[9] != nullptr; }},
{ ICON_THEME_ADD_VIEW, STR_DEF(STR_QM_ADD_SCREEN), STR_DEF(STR_QM_ADD_SCREEN), PAGE_ACTION, QM_UI_ADD_PG, nullptr, []() { return customScreens[9] == nullptr; },
[]() {
int newIdx = 1;
for (; newIdx < MAX_CUSTOM_SCREENS; newIdx += 1)
if (customScreens[newIdx] == nullptr)
break;
TRACE("Add screen: add screen: newIdx = %d", newIdx);
auto& screen = customScreens[newIdx];
const LayoutFactory* factory = defaultLayout;
if (factory) {
TRACE("Add screen: add screen: factory = %p", factory);
auto viewMain = ViewMain::instance();
screen = factory->create(viewMain, newIdx);
viewMain->addMainView(screen, newIdx);
g_model.setScreenLayoutId(newIdx, factory->getId());
TRACE("Add screen: add screen: LayoutId = %s", g_model.getScreenLayoutId(newIdx));
QuickMenu::openPage((QMPage)(QM_UI_SCREEN1 + newIdx));
storageDirty(EE_MODEL);
} else {
TRACE("Add screen: factory is NULL");
}
}
},
{ EDGETX_ICONS_COUNT }
};
PageDef toolsMenuItems[] = {
{ ICON_TOOLS_APPS, STR_DEF(STR_QM_APPS), STR_DEF(STR_MAIN_MENU_APPS), PAGE_CREATE, QM_TOOLS_APPS, [](PageDef& pageDef) { return new RadioToolsPage(pageDef); }},
{ ICON_RADIO_SD_MANAGER, STR_DEF(STR_QM_STORAGE), STR_DEF(STR_SD_CARD), PAGE_CREATE, QM_TOOLS_STORAGE, [](PageDef& pageDef) { return new RadioSdManagerPage(pageDef); }},
{ ICON_TOOLS_RESET, STR_DEF(STR_QM_RESET), STR_DEF(STR_QM_RESET), PAGE_ACTION, QM_TOOLS_RESET, nullptr, nullptr,
[]() {
Menu* resetMenu = new Menu();
resetMenu->addLine(STR_RESET_FLIGHT, []() { flightReset(); });
resetMenu->addLine(STR_RESET_TIMER1, []() { timerReset(0); });
resetMenu->addLine(STR_RESET_TIMER2, []() { timerReset(1); });
resetMenu->addLine(STR_RESET_TIMER3, []() { timerReset(2); });
resetMenu->addLine(STR_RESET_TELEMETRY, []() { telemetryReset(); });
}
},
{ ICON_MONITOR, STR_DEF(STR_QM_CHAN_MON), STR_DEF(STR_QM_CHAN_MON), PAGE_ACTION, QM_TOOLS_CHAN_MON, nullptr, nullptr,
[]() {
new ChannelsViewMenu();
}
},
{ ICON_MONITOR_LOGICAL_SWITCHES, STR_DEF(STR_QM_LS_MON), STR_DEF(STR_MONITOR_SWITCHES), PAGE_CREATE, QM_TOOLS_LS_MON, [](PageDef& pageDef) { return new LogicalSwitchesViewPage(pageDef); }},
{ ICON_STATS, STR_DEF(STR_QM_STATS), STR_DEF(STR_MAIN_MENU_STATISTICS), PAGE_CREATE, QM_TOOLS_STATS, [](PageDef& pageDef) { return new StatisticsViewPage(pageDef); }},
{ ICON_STATS_DEBUG, STR_DEF(STR_QM_DEBUG), STR_DEF(STR_DEBUG), PAGE_CREATE, QM_TOOLS_DEBUG, [](PageDef& pageDef) { return new DebugViewPage(pageDef); }},
{ EDGETX_ICONS_COUNT }
};
QMTopDef 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,
[]() {
QuickMenu::selected();
new ModelLabelsWindow();
}},
{ ICON_MODEL, STR_DEF(STR_QM_MODEL_SETUP), STR_DEF(STR_MAIN_MENU_MODEL_SETTINGS), QM_SUBMENU, QM_NONE, modelMenuItems},
{ ICON_RADIO, STR_DEF(STR_QM_RADIO_SETUP), STR_DEF(STR_MAIN_MENU_RADIO_SETTINGS), QM_SUBMENU, QM_NONE, radioMenuItems},
{ ICON_THEME, STR_DEF(STR_QM_UI_SETUP), STR_DEF(STR_MAIN_MENU_SCREEN_SETTINGS), QM_SUBMENU, QM_NONE, screensMenuItems},
{ ICON_RADIO_TOOLS, STR_DEF(STR_QM_TOOLS), STR_DEF(STR_QM_TOOLS), QM_SUBMENU, QM_NONE, toolsMenuItems},
{ EDGETX_ICONS_COUNT }
};
@@ -0,0 +1,69 @@
/*
* 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
enum QMPage {
QM_NONE = 0,
QM_OPEN_QUICK_MENU,
QM_MANAGE_MODELS,
// Model menu
QM_MODEL_SETUP,
QM_MODEL_FLIGHTMODES,
QM_MODEL_INPUTS,
QM_MODEL_MIXES,
QM_MODEL_OUTPUTS,
QM_MODEL_CURVES,
QM_MODEL_GVARS,
QM_MODEL_LS,
QM_MODEL_SF,
QM_MODEL_SCRIPTS,
QM_MODEL_TELEMETRY,
QM_MODEL_NOTES,
// Radio menu
QM_RADIO_SETUP,
QM_RADIO_GF,
QM_RADIO_TRAINER,
QM_RADIO_HARDWARE,
QM_RADIO_VERSION,
// UI menu
QM_UI_THEMES,
QM_UI_SETUP,
QM_UI_SCREEN1,
QM_UI_SCREEN2,
QM_UI_SCREEN3,
QM_UI_SCREEN4,
QM_UI_SCREEN5,
QM_UI_SCREEN6,
QM_UI_SCREEN7,
QM_UI_SCREEN8,
QM_UI_SCREEN9,
QM_UI_SCREEN10,
QM_UI_ADD_PG,
// Tools menu
QM_TOOLS_APPS,
QM_TOOLS_STORAGE,
QM_TOOLS_RESET,
QM_TOOLS_CHAN_MON,
QM_TOOLS_LS_MON,
QM_TOOLS_STATS,
QM_TOOLS_DEBUG,
};
@@ -0,0 +1,72 @@
/*
* 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 "quick_menu_favorites.h"
#include "edgetx.h"
#include "pagegroup.h"
#define SET_DIRTY() storageDirty(EE_GENERAL)
QMFavoritesPage::QMFavoritesPage():
SubPage(ICON_RADIO, STR_MAIN_MENU_RADIO_SETTINGS, STR_QUICK_MENU_FAVORITES, true)
{
std::vector<std::string> qmPages = QuickMenu::menuPageNames(true);
for (int i = 0; i < MAX_QM_FAVORITES; i += 1) {
char nm[50];
strAppendUnsigned(strAppend(strAppend(nm, "#"), " "), i + 1);
setupLine(nm, [=](Window* parent, coord_t x, coord_t y) {
auto c = new Choice(
parent, {LCD_W / 4, y, LCD_W * 2 / 3, 0}, qmPages, QM_NONE, QM_TOOLS_DEBUG,
GET_DEFAULT(g_eeGeneral.qmFavorites[i].shortcut),
[=](int32_t pg) {
g_eeGeneral.qmFavorites[i].shortcut = (QMPage)pg;
changed = true;
SET_DIRTY();
}, STR_QUICK_MENU_FAVORITES);
c->setPopupWidth(LCD_W * 3 / 4);
c->setAvailableHandler(
[=](int pg) {
if (pg == QM_NONE) return true;
for (int i = 0; i < MAX_QM_FAVORITES; i += 1)
if (g_eeGeneral.qmFavorites[i].shortcut == (QMPage)pg)
return false;
return pg != QM_OPEN_QUICK_MENU; }
);
});
}
enableRefresh();
}
void QMFavoritesPage::onCancel()
{
if (changed) {
// Delete quick menu, and close parent page group (in case it is Favorites group)
QuickMenu::shutdownQuickMenu();
QuickMenu::setCurrentPage(QM_NONE);
Layer::pop(this);
Layer::back()->onCancel();
}
SubPage::onCancel();
}
@@ -0,0 +1,37 @@
/*
* 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 QMFavoritesPage : public SubPage
{
public:
QMFavoritesPage();
protected:
bool changed = false;
void addKey(event_t event, std::vector<std::string> qmPages, const char* nm);
void onCancel() override;
};
@@ -138,12 +138,12 @@ QuickMenuGroup::QuickMenuGroup(Window* parent) :
}
ButtonBase* QuickMenuGroup::addButton(EdgeTxIcon icon, const char* title,
std::function<uint8_t(void)> pressHandler,
std::function<void(void)> pressHandler,
std::function<bool(void)> visibleHandler,
std::function<void(void)> focusHandler)
{
ButtonBase* b = new QuickMenuButton(this, icon, title, pressHandler, visibleHandler);
b->setLongPressHandler(pressHandler);
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) {
@@ -38,7 +38,7 @@ class QuickMenuGroup : public Window
// Add a new button to the carousel
ButtonBase* addButton(EdgeTxIcon icon, const char* title,
std::function<uint8_t(void)> pressHandler,
std::function<void(void)> pressHandler,
std::function<bool(void)> visibleHandler = nullptr,
std::function<void(void)> focusHandler = nullptr);