feat(color): key shortcuts and quick menu favorites can be set to run stand alone Lua tools (#7083)

Co-authored-by: elecpower <elecpower@users.noreply.github.com>
This commit is contained in:
philmoz
2026-02-20 13:53:36 +10:00
committed by GitHub
co-authored by elecpower
parent bcb154c0e2
commit 044c2a08d8
44 changed files with 1235 additions and 367 deletions
@@ -178,6 +178,7 @@ static const YamlLookupTable QMPageLut = {
{ GeneralSettings::QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ GeneralSettings::QM_TOOLS_STATS, "TOOLS_STATS" },
{ GeneralSettings::QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ GeneralSettings::QM_APP, "APP" },
};
YamlTelemetryBaudrate::YamlTelemetryBaudrate(
@@ -393,11 +394,25 @@ Node convert<GeneralSettings>::encode(const GeneralSettings& rhs)
if (hasColorLcd) {
for (int i = 0; i < MAX_KEYSHORTCUTS; i += 1)
if (rhs.keyShortcuts[i] != GeneralSettings::QM_NONE)
node["keyShortcuts"][std::to_string(i)]["shortcut"] = QMPageLut << rhs.keyShortcuts[i];
if (rhs.keyShortcuts[i] != GeneralSettings::QM_NONE) {
if (rhs.keyShortcuts[i] != GeneralSettings::QM_APP) {
node["keyShortcuts"][std::to_string(i)]["shortcut"] = QMPageLut << rhs.keyShortcuts[i];
} else {
std::string s("APP,");
s += rhs.keyShortcutTools[i];
node["keyShortcuts"][std::to_string(i)]["shortcut"] = s;
}
}
for (int i = 0; i < MAX_QMFAVOURITES; i += 1)
if (rhs.qmFavorites[i] != GeneralSettings::QM_NONE)
node["qmFavorites"][std::to_string(i)]["shortcut"] = QMPageLut << rhs.qmFavorites[i];
if (rhs.qmFavorites[i] != GeneralSettings::QM_NONE) {
if (rhs.qmFavorites[i] != GeneralSettings::QM_APP) {
node["qmFavorites"][std::to_string(i)]["shortcut"] = QMPageLut << rhs.qmFavorites[i];
} else {
std::string s("APP,");
s += rhs.qmFavoritesTools[i];
node["qmFavorites"][std::to_string(i)]["shortcut"] = s;
}
}
}
return node;
@@ -726,13 +741,35 @@ bool convert<GeneralSettings>::decode(const Node& node, GeneralSettings& rhs)
node["favMultiMode"] >> rhs.favMultiMode;
if (node["keyShortcuts"]) {
for (int i = 0; i < MAX_KEYSHORTCUTS; i += 1)
node["keyShortcuts"][std::to_string(i)]["shortcut"] >> QMPageLut >> rhs.keyShortcuts[i];
for (int i = 0; i < MAX_KEYSHORTCUTS; i += 1) {
std::string val = node["keyShortcuts"][std::to_string(i)]["shortcut"].as<std::string>();
if (rhs.keyShortcutTools[i]) delete rhs.keyShortcutTools[i];
if (val.substr(0, 4) == "APP,") {
rhs.keyShortcuts[i] = GeneralSettings::QM_APP;
rhs.keyShortcutTools[i] = new char[val.size() - 3];
strncpy(rhs.keyShortcutTools[i], val.substr(4).c_str(), val.size() - 4);
rhs.keyShortcutTools[i][val.size() - 4] = 0;
} else {
node["keyShortcuts"][std::to_string(i)]["shortcut"] >> QMPageLut >> rhs.keyShortcuts[i];
rhs.keyShortcutTools[i] = nullptr;
}
}
}
if (node["qmFavorites"]) {
for (int i = 0; i < MAX_QMFAVOURITES; i += 1)
if (node["qmFavorites"][std::to_string(i)])
if (node["qmFavorites"][std::to_string(i)]) {
std::string val = node["qmFavorites"][std::to_string(i)]["shortcut"].as<std::string>();
if (rhs.qmFavoritesTools[i]) delete rhs.qmFavoritesTools[i];
if (val.substr(0, 4) == "APP,") {
rhs.qmFavorites[i] = GeneralSettings::QM_APP;
rhs.qmFavoritesTools[i] = new char[val.size() - 3];
strncpy(rhs.qmFavoritesTools[i], val.substr(4).c_str(), val.size() - 4);
rhs.qmFavoritesTools[i][val.size() - 4] = 0;
} else {
node["qmFavorites"][std::to_string(i)]["shortcut"] >> QMPageLut >> rhs.qmFavorites[i];
rhs.qmFavoritesTools[i] = nullptr;
}
}
}
// override critical settings after import
@@ -1061,6 +1061,9 @@ QString GeneralSettings::quickMenuToString(int value, bool keys)
return tr("Tools - Statistics");
case QM_TOOLS_DEBUG:
return tr("Tools - Debug");
// Lua stand alone script
case QM_APP:
return tr("App");
default:
return CPN_STR_UNKNOWN_ITEM;
}
@@ -276,6 +276,8 @@ class GeneralSettings {
QM_TOOLS_LS_MON,
QM_TOOLS_STATS,
QM_TOOLS_DEBUG,
// Lua stand alone script
QM_APP,
QM_COUNT,
};
@@ -451,7 +453,9 @@ class GeneralSettings {
SwitchConfig switchConfig[CPN_MAX_SWITCHES];
unsigned int keyShortcuts[MAX_KEYSHORTCUTS];
char* keyShortcutTools[MAX_KEYSHORTCUTS];
unsigned int qmFavorites[MAX_QMFAVOURITES];
char* qmFavoritesTools[MAX_QMFAVOURITES];
void switchConfigClear();
+120 -7
View File
@@ -23,6 +23,7 @@
#include "autocombobox.h"
#include "compounditemmodels.h"
#include "exclusivecombogroup.h"
#include "helpers.h"
#include <QLabel>
#include <QGridLayout>
@@ -32,22 +33,76 @@ GeneralFavsPanel::GeneralFavsPanel(QWidget * parent, GeneralSettings & generalSe
board(firmware->getBoard()),
params(new QList<QWidget *>),
row(0),
col(0)
col(0),
lock(true),
cboFavTools(new QList<AutoComboBox *>),
strFavTools(new QList<QString *>)
{
grid = new QGridLayout(this);
// All values except QM_NONE are mutually exclusive
cboQMGrp = new ExclusiveComboGroup(this,
[=](const QVariant &value) { return value == GeneralSettings::QM_NONE; });
[=](const QVariant &value) { return value == GeneralSettings::QM_NONE ||
value == GeneralSettings::QM_APP; });
const int cnt = firmware->getCapability(QMFavourites);
// add lua tool scripts from radio profile sdcard
QStringList toolsSet = getListLuaTools();
QStandardItemModel *mdl = new QStandardItemModel(this);
for (int i = 0; i < toolsSet.size(); i++) {
QStandardItem *item = new QStandardItem(toolsSet[i]);
mdl->appendRow(item);
}
// Ensure existing configured tool is included in toolsSet as the radio profile
// sdcard contents may not match radio
for (int i = 0; i < cnt; i++) {
if (generalSettings.qmFavorites[i] == GeneralSettings::QM_APP) {
QString temp(generalSettings.qmFavoritesTools[i]);
if (!temp.isEmpty() && mdl->findItems(temp).size() < 1) {
QStandardItem *item = new QStandardItem(temp);
mdl->appendRow(item);
}
}
}
QSortFilterProxyModel *mdlTools = new QSortFilterProxyModel(this);
mdlTools->setSourceModel(mdl);
mdlTools->setSortCaseSensitivity(Qt::CaseInsensitive);
mdlTools->setFilterKeyColumn(0);
mdlTools->sort(0);
for (int i = 0; i < cnt; i++) {
addLabel(tr("# %1").arg(i + 1));
AutoComboBox *cbo = new AutoComboBox(this);
AutoComboBox *cboFav = new AutoComboBox(this);
cboFav->setProperty("index", i);
// separate item model per combo box due to mutual exclusivity
cbo->setModel(generalSettings.quickMenuItemModel(false));
cbo->setField(generalSettings.qmFavorites[i], this);
cboQMGrp->addCombo(cbo);
params->append(cbo);
cboFav->setModel(generalSettings.quickMenuItemModel(false));
cboFav->setField(generalSettings.qmFavorites[i], this);
connect(cboFav, &AutoComboBox::currentDataChanged, this, &GeneralFavsPanel::on_favChanged);
cboQMGrp->addCombo(cboFav);
params->append(cboFav);
AutoComboBox *cboFavTool = new AutoComboBox(this);
cboFavTool->setProperty("index", i);
cboFavTool->setModel(mdlTools);
// AutoComboBox does not support char * so use a proxy
QString *str = new QString(generalSettings.qmFavoritesTools[i]);
strFavTools->append(str);
cboFavTool->setField(*str, this);
if (generalSettings.qmFavorites[i] == GeneralSettings::QM_APP) {
if (cboFavTool->currentIndex() < 0)
cboFavTool->setCurrentIndex(0);
cboFavTool->setVisible(true);
} else {
cboFavTool->setCurrentIndex(0);
cboFavTool->setVisible(false);
}
connect(cboFavTool, &AutoComboBox::currentDataChanged, this, &GeneralFavsPanel::on_favToolChanged);
cboFavTools->append(cboFavTool);
params->append(cboFavTool);
addParams();
}
@@ -66,6 +121,7 @@ GeneralFavsPanel::GeneralFavsPanel(QWidget * parent, GeneralSettings & generalSe
params->append(reset);
addParams();
lock = false;
initComboQMGroup();
addVSpring(grid, 0, grid->rowCount());
addHSpring(grid, grid->columnCount(), 0);
@@ -74,7 +130,25 @@ GeneralFavsPanel::GeneralFavsPanel(QWidget * parent, GeneralSettings & generalSe
GeneralFavsPanel::~GeneralFavsPanel()
{
if (cboFavTools) {
delete cboFavTools; // dialog destructor will delete members
}
if (strFavTools) {
for (auto it = strFavTools->begin(); it != strFavTools->end(); ++it) {
delete *it;
}
delete strFavTools;
}
if (params) {
for (auto it = params->begin(); it != params->end(); ++it) {
delete *it;
}
delete params;
}
}
void GeneralFavsPanel::addLabel(QString text)
@@ -122,3 +196,42 @@ void GeneralFavsPanel::initComboQMGroup()
cboQMGrp->handleActivated(cbo, cbo->currentIndex());
}
}
void GeneralFavsPanel::on_favChanged()
{
if (!lock) {
const int idx = sender()->property("index").toInt();
const int i = cboFavTools->at(idx)->currentIndex();
cboFavTools->at(idx)->setCurrentIndex(0);
if (i == cboFavTools->at(idx)->currentIndex())
setToolName(idx); // force update
cboFavTools->at(idx)->setVisible(generalSettings.qmFavorites[idx] == GeneralSettings::QM_APP);
}
}
void GeneralFavsPanel::on_favToolChanged()
{
if (!lock) {
bool ok;
const int index = sender()->property("index").toInt(&ok);
if (ok) setToolName(index);
}
}
void GeneralFavsPanel::setToolName(int index)
{
if (generalSettings.qmFavoritesTools[index])
delete generalSettings.qmFavoritesTools[index];
if (generalSettings.qmFavorites[index] == GeneralSettings::QM_APP) {
// obtain current value from proxy
std::string str = strFavTools->at(index)->toStdString();
generalSettings.qmFavoritesTools[index] = new char[str.size() + 1];
strncpy(generalSettings.qmFavoritesTools[index], str.c_str(), str.size());
generalSettings.qmFavoritesTools[index][str.size()] = 0;
} else {
generalSettings.qmFavoritesTools[index] = nullptr;
}
}
@@ -22,6 +22,7 @@
#pragma once
#include "generaledit.h"
#include "autocombobox.h"
class ExclusiveComboGroup;
class QGridLayout;
@@ -34,17 +35,25 @@ class GeneralFavsPanel : public GeneralPanel
GeneralFavsPanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware);
virtual ~GeneralFavsPanel();
private slots:
void on_favChanged();
void on_favToolChanged();
private:
Board::Type board;
QGridLayout *grid;
QList<QWidget *> *params;
int row;
int col;
bool lock;
ExclusiveComboGroup *cboQMGrp;
QList<AutoComboBox *> *cboFavTools;
QList<QString *> *strFavTools;
void addLabel(QString text);
void addLine();
void addParams();
void addSection(QString text);
void initComboQMGroup();
void setToolName(int index);
};
+142 -14
View File
@@ -20,9 +20,9 @@
*/
#include "generalkeyshortcuts.h"
#include "autocombobox.h"
#include "compounditemmodels.h"
#include "exclusivecombogroup.h"
#include "helpers.h"
#include <QLabel>
#include <QGridLayout>
@@ -32,32 +32,79 @@ GeneralKeysPanel::GeneralKeysPanel(QWidget * parent, GeneralSettings & generalSe
board(firmware->getBoard()),
params(new QList<QWidget *>),
row(0),
col(0)
col(0),
lock(true),
cboShortcuts(new QList<AutoComboBox *>),
cboShortcutTools(new QList<AutoComboBox *>),
strKeyShortcutTools(new QList<QString *>)
{
grid = new QGridLayout(this);
// All values except QM_NONE are mutually exclusive
// All values except QM_NONE and QM_APP are mutually exclusive
cboQMGrp = new ExclusiveComboGroup(this,
[=](const QVariant &value) { return value == GeneralSettings::QM_NONE; });
[=](const QVariant &value) { return value == GeneralSettings::QM_NONE ||
value == GeneralSettings::QM_APP; });
const int cnt = firmware->getCapability(KeyShortcuts);
// add lua tool scripts from radio profile sdcard
QStringList toolsSet = getListLuaTools();
QStandardItemModel *mdl = new QStandardItemModel(this);
for (int i = 0; i < toolsSet.size(); i++) {
QStandardItem *item = new QStandardItem(toolsSet[i]);
mdl->appendRow(item);
}
// Ensure existing configured tool is included in toolsSet as the radio profile
// sdcard contents may not match radio
for (int i = 0; i < cnt; i++) {
if (generalSettings.qmFavorites[i] == GeneralSettings::QM_APP) {
QString temp(generalSettings.qmFavoritesTools[i]);
if (!temp.isEmpty() && mdl->findItems(temp).size() < 1) {
QStandardItem *item = new QStandardItem(temp);
mdl->appendRow(item);
}
}
}
QSortFilterProxyModel *mdlTools = new QSortFilterProxyModel(this);
mdlTools->setSourceModel(mdl);
mdlTools->setSortCaseSensitivity(Qt::CaseInsensitive);
mdlTools->setFilterKeyColumn(0);
mdlTools->sort(0);
const int split = 2;
for (int i = 0; i < split; i++) {
if (i == 0) {
addSection(tr("Short Press"));
addSection(tr("Short Press"));
} else {
addLine();
addSection(tr("Long Press"));
}
for (int j = 0; j < (cnt / split); j++) {
const int idx = (i * (split + 1)) + j;
addLabel(j == 0 ? tr("MDL") : (j == 1 ? tr("SYS") : tr("TELE")));
AutoComboBox *cbo = new AutoComboBox(this);
AutoComboBox *cboShortcut = new AutoComboBox(this);
cboShortcut->setProperty("index", idx);
// separate item model per combo box due to mutual exclusivity
cbo->setModel(generalSettings.quickMenuItemModel(true));
cbo->setField(generalSettings.keyShortcuts[(i * (split + 1)) + j], this);
cboQMGrp->addCombo(cbo);
params->append(cbo);
cboShortcut->setModel(generalSettings.quickMenuItemModel(true));
cboShortcut->setField(generalSettings.keyShortcuts[idx], this);
connect(cboShortcut, &AutoComboBox::currentDataChanged, this, &GeneralKeysPanel::on_shortcutChanged);
cboShortcuts->append(cboShortcut);
cboQMGrp->addCombo(cboShortcut);
params->append(cboShortcut);
AutoComboBox *cboShortcutTool = new AutoComboBox(this);
cboShortcutTool->setProperty("index", idx);
cboShortcutTool->setModel(mdlTools);
// AutoComboBox does not support char * so use a proxy
QString *str = new QString(generalSettings.keyShortcutTools[idx]);
strKeyShortcutTools->append(str);
cboShortcutTool->setField(*str, this);
connect(cboShortcutTool, &AutoComboBox::currentDataChanged, this, &GeneralKeysPanel::on_shortcutToolChanged);
cboShortcutTools->append(cboShortcutTool);
params->append(cboShortcutTool);
addParams();
}
}
@@ -68,23 +115,45 @@ GeneralKeysPanel::GeneralKeysPanel(QWidget * parent, GeneralSettings & generalSe
connect(reset, &QPushButton::clicked, [&] ()
{
generalSettings.setDefaultKeyShortcuts();
foreach(AutoComboBox *cb, findChildren<AutoComboBox*>())
cb->updateValue();
update();
initComboQMGroup();
});
params->append(reset);
addParams();
update();
initComboQMGroup();
addVSpring(grid, 0, grid->rowCount());
addHSpring(grid, grid->columnCount(), 0);
disableMouseScrolling();
lock = false;
}
GeneralKeysPanel::~GeneralKeysPanel()
{
if (cboShortcutTools) {
delete cboShortcutTools; // dialog destructor will delete members
}
if (cboShortcuts) {
delete cboShortcuts; // dialog destructor will delete members
}
if (strKeyShortcutTools) {
for (auto it = strKeyShortcutTools->begin(); it != strKeyShortcutTools->end(); ++it) {
delete *it;
}
delete strKeyShortcutTools;
}
if (params) {
for (auto it = params->begin(); it != params->end(); ++it) {
delete *it;
}
delete params;
}
}
void GeneralKeysPanel::addLabel(QString text)
@@ -132,3 +201,62 @@ void GeneralKeysPanel::initComboQMGroup()
cboQMGrp->handleActivated(cbo, cbo->currentIndex());
}
}
void GeneralKeysPanel::on_shortcutChanged()
{
if (!lock) {
const int idx = sender()->property("index").toInt();
if (generalSettings.keyShortcuts[idx] == GeneralSettings::QM_APP)
cboShortcutTools->at(idx)->setCurrentIndex(0);
setToolName(idx);
updateRow(idx);
}
}
void GeneralKeysPanel::on_shortcutToolChanged()
{
if (!lock) {
bool ok;
const int index = sender()->property("index").toInt(&ok);
if (ok) setToolName(index);
}
}
void GeneralKeysPanel::setToolName(int index)
{
if (generalSettings.keyShortcutTools[index])
delete generalSettings.keyShortcutTools[index];
if (generalSettings.keyShortcuts[index] == GeneralSettings::QM_APP) {
// obtain current value from proxy
std::string str = strKeyShortcutTools->at(index)->toStdString();
generalSettings.keyShortcutTools[index] = new char[str.size() + 1];
strncpy(generalSettings.keyShortcutTools[index], str.c_str(), str.size());
generalSettings.keyShortcutTools[index][str.size()] = 0;
} else {
generalSettings.keyShortcutTools[index] = nullptr;
}
}
void GeneralKeysPanel::update()
{
const int cnt = cboShortcuts->count();
for (int i = 0; i < cnt; i++)
updateRow(i);
}
void GeneralKeysPanel::updateRow(const int index)
{
lock = true;
cboShortcuts->at(index)->updateValue();
if (generalSettings.keyShortcuts[index] == GeneralSettings::QM_APP) {
cboShortcutTools->at(index)->updateValue();
cboShortcutTools->at(index)->setVisible(true);
} else {
cboShortcutTools->at(index)->setVisible(false);
}
lock = false;
}
@@ -22,6 +22,7 @@
#pragma once
#include "generaledit.h"
#include "autocombobox.h"
class ExclusiveComboGroup;
class QGridLayout;
@@ -34,17 +35,28 @@ class GeneralKeysPanel : public GeneralPanel
GeneralKeysPanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware);
virtual ~GeneralKeysPanel();
private slots:
void on_shortcutChanged();
void on_shortcutToolChanged();
private:
Board::Type board;
QGridLayout *grid;
QList<QWidget *> *params;
int row;
int col;
bool lock;
ExclusiveComboGroup *cboQMGrp;
QList<AutoComboBox *> *cboShortcuts;
QList<AutoComboBox *> *cboShortcutTools;
QList<QString *> *strKeyShortcutTools;
void addLabel(QString text);
void addLine();
void addParams();
void addSection(QString text);
void initComboQMGroup();
void setToolName(int index);
void update();
void updateRow(const int index);
};
+62
View File
@@ -42,6 +42,7 @@
#include <QRegularExpression>
#include <QProcess>
#include <QtGlobal>
#include <QFile>
using namespace Helpers;
@@ -541,6 +542,67 @@ QSet<QString> getFilesSet(const QString &path, const QStringList &filter, int ma
return result;
}
// based on /src/repos/edgetx/edgetx/radio/src/gui/colorlcd/radio/radio_tools.cpp
// loadLuaTools()
QStringList getListLuaTools()
{
const QString tdir = g.profile[g.id()].sdPath() + "/SCRIPTS/TOOLS";
QStringList result;
QDir dir(tdir);
if (dir.exists()) {
foreach (QString name, dir.entryList(QStringList() << "*.lua",
QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot | QDir::NoSymLinks)) {
QString path = tdir % "/" % name;
QFileInfo fi(path);
bool inFolder = fi.isDir();
QString toolname;
if (inFolder) {
// check if .lua with same name exists - skip folder to avoid duplicate entries
if (QFileInfo::exists(path % ".lua"))
continue;
// Default name is folder name
toolname = QDir(path).dirName();
// must have main.lua
path.append("/main.lua");
if (!QFileInfo::exists(path))
continue;
} else {
// Default name is file name
toolname = QFileInfo(path).completeBaseName();
}
// look for tool name in lua file to override default name
QFile file(path);
if (file.open(QFile::ReadOnly)) {
QByteArray ba = file.read(1024);
file.close();
if (ba.size() > 0) {
QByteArrayView view("TNS|");
int startpos = ba.indexOf(view);
if (startpos > -1) {
view = "|TNE";
int endpos = ba.indexOf(view, startpos + 1);
if (endpos > -1) {
toolname = ba.mid(startpos + 4, endpos - (startpos + 4)).data();
}
}
}
}
result.append(toolname);
}
}
return result;
}
bool GpsGlitchFilter::isGlitch(GpsCoord coord)
{
if ((fabs(coord.latitude) < 0.1) && (fabs(coord.longitude) < 0.1)) {
+1
View File
@@ -142,6 +142,7 @@ bool isTempFileName(const QString & fileName);
QString getSoundsPath(const GeneralSettings &generalSettings);
QSet<QString> getFilesSet(const QString &path, const QStringList &filter, int maxLen);
QStringList getListLuaTools();
class QTimeS : public QTime
+34 -2
View File
@@ -43,6 +43,8 @@ void AutoComboBox::initField()
m_curveType = nullptr;
m_flexType = nullptr;
m_switchType = nullptr;
m_qString = nullptr;
m_stdString = nullptr;
}
void AutoComboBox::clear()
@@ -129,6 +131,20 @@ void AutoComboBox::setField(Board::SwitchType & field, GenericPanel * panel)
updateValue();
}
void AutoComboBox::setField(QString & field, GenericPanel * panel)
{
setFieldInit(panel);
m_qString = &field;
updateValue();
}
void AutoComboBox::setField(std::string & field, GenericPanel * panel)
{
setFieldInit(panel);
m_stdString = &field;
updateValue();
}
void AutoComboBox::setFieldInit(GenericPanel * panel)
{
initField();
@@ -170,17 +186,29 @@ void AutoComboBox::updateValue()
setCurrentIndex(findData(*m_flexType));
else if (m_switchType)
setCurrentIndex(findData(*m_switchType));
else if (m_qString)
setCurrentIndex(findText(*m_qString));
else if (m_stdString)
setCurrentIndex(findText(QString(m_stdString->c_str())));
setLock(false);
}
void AutoComboBox::onCurrentIndexChanged(int index)
{
if (lock() || index < 0)
if (lock() || index < 0 || index >= count())
return;
bool ok;
const int val = itemData(index).toInt(&ok);
int val = 0;
QString str;
if (m_qString || m_stdString) {
str = itemText(index);
ok = true;
} else {
val = itemData(index).toInt(&ok);
}
if (ok) {
if (m_field && *m_field != val)
@@ -195,6 +223,10 @@ void AutoComboBox::onCurrentIndexChanged(int index)
*m_flexType = (Board::FlexType)val;
else if (m_switchType && *m_switchType != val)
*m_switchType = (Board::SwitchType)val;
else if (m_qString && *m_qString != str)
*m_qString = str;
else if (m_stdString && *m_stdString != str.toStdString())
*m_stdString = str.toStdString();
else
return;
+6
View File
@@ -29,6 +29,8 @@
#include <QComboBox>
#include <string.h>
/*
NOTE: Q_OBJECT classes cannot be templated and since we use signals we have no choice but to
take this approach or create a class per data type
@@ -57,6 +59,8 @@ class AutoComboBox : public QComboBox, public AutoWidget
void setField(CurveData::CurveType & field, GenericPanel * panel = nullptr);
void setField(Board::FlexType & field, GenericPanel * panel = nullptr);
void setField(Board::SwitchType & field, GenericPanel * panel = nullptr);
void setField(QString & field, GenericPanel * panel = nullptr);
void setField(std::string & field, GenericPanel * panel = nullptr);
void setAutoIndexes();
void setModel(QAbstractItemModel * model) override;
@@ -76,6 +80,8 @@ class AutoComboBox : public QComboBox, public AutoWidget
CurveData::CurveType *m_curveType;
Board::FlexType *m_flexType;
Board::SwitchType *m_switchType;
QString *m_qString;
std::string *m_stdString;
void initField();
void setFieldInit(GenericPanel * panel);
+17 -6
View File
@@ -1002,8 +1002,13 @@ PACK(struct switchDef {
#if defined(COLORLCD)
#define MAX_KEY_SHORTCUTS 6
#define MAX_QM_FAVORITES 12
PACK(struct QuickMenuPage {
uint8_t shortcut ENUM(QMPage);
PACK(struct KeyShortcut {
CUST_ATTR(shortcut, r_keyShortcut, w_keyShortcut);
uint8_t shortcut ENUM(QMPage) SKIP;
});
PACK(struct QMFavorite {
CUST_ATTR(shortcut, r_qmFavorite, w_qmFavorite);
uint8_t shortcut ENUM(QMPage) SKIP;
});
#endif
@@ -1167,8 +1172,8 @@ PACK(struct RadioData {
NOBACKUP(uint8_t pwrOffIfInactive);
#if defined(COLORLCD)
NOBACKUP(QuickMenuPage keyShortcuts[MAX_KEY_SHORTCUTS]);
NOBACKUP(QuickMenuPage qmFavorites[MAX_QM_FAVORITES]);
NOBACKUP(KeyShortcut keyShortcuts[MAX_KEY_SHORTCUTS]);
NOBACKUP(QMFavorite qmFavorites[MAX_QM_FAVORITES]);
#endif
NOBACKUP(uint8_t getBrightness() const
@@ -1199,11 +1204,17 @@ PACK(struct RadioData {
#endif
#endif
#if defined(COLORLCD)
#if defined(COLORLCD) && !defined(BACKUP)
int getKeyShortcutNum(event_t event);
event_t getKeyShortcutEvent(int n);
QMPage getKeyShortcut(event_t event);
bool hasKeyShortcut(QMPage shortcut);
bool hasKeyShortcut(QMPage shortcut, event_t event);
void setKeyShortcut(event_t event, QMPage shortcut);
void defaultKeyShortcuts();
void setKeyToolName(event_t event, const std::string name);
const std::string getKeyToolName(event_t event);
void setFavoriteToolName(int fav, const std::string name);
const std::string getFavoriteToolName(int fav);
#endif
});
+75 -48
View File
@@ -25,6 +25,7 @@
#include "tasks/mixer_task.h"
#if defined(COLORLCD)
#include "radio_tools.h"
#include "quick_menu_def.h"
#include "view_main.h"
#endif
@@ -92,6 +93,34 @@ void RadioData::cfsSetOffColorLuaOverride(uint8_t n, bool v) {
#endif
#if defined(COLORLCD)
int RadioData::getKeyShortcutNum(event_t event)
{
switch(event) {
case EVT_KEY_BREAK(KEY_MODEL): return 0;
case EVT_KEY_BREAK(KEY_SYS): return 1;
case EVT_KEY_BREAK(KEY_TELE): return 2;
case EVT_KEY_LONG(KEY_MODEL): return 3;
case EVT_KEY_LONG(KEY_SYS): return 4;
case EVT_KEY_LONG(KEY_TELE): return 5;
default:
return -1;
}
}
event_t RadioData::getKeyShortcutEvent(int n)
{
switch(n) {
case 0: return EVT_KEY_BREAK(KEY_MODEL);
case 1: return EVT_KEY_BREAK(KEY_SYS);
case 2: return EVT_KEY_BREAK(KEY_TELE);
case 3: return EVT_KEY_LONG(KEY_MODEL);
case 4: return EVT_KEY_LONG(KEY_SYS);
case 5: return EVT_KEY_LONG(KEY_TELE);
default:
return 0;
}
}
QMPage RadioData::getKeyShortcut(event_t event)
{
QMPage page = QM_NONE;
@@ -119,28 +148,8 @@ QMPage RadioData::getKeyShortcut(event_t event)
break;
}
#else
switch(event) {
case EVT_KEY_BREAK(KEY_MODEL):
page = (QMPage)keyShortcuts[0].shortcut;
break;
case EVT_KEY_BREAK(KEY_SYS):
page = (QMPage)keyShortcuts[1].shortcut;
break;
case EVT_KEY_BREAK(KEY_TELE):
page = (QMPage)keyShortcuts[2].shortcut;
break;
case EVT_KEY_LONG(KEY_MODEL):
page = (QMPage)keyShortcuts[3].shortcut;
break;
case EVT_KEY_LONG(KEY_SYS):
page = (QMPage)keyShortcuts[4].shortcut;
break;
case EVT_KEY_LONG(KEY_TELE):
page = (QMPage)keyShortcuts[5].shortcut;
break;
default:
break;
}
int n = getKeyShortcutNum(event);
if (n >= 0) page = (QMPage)keyShortcuts[n].shortcut;
#endif
if (page >= QM_UI_SCREEN1 && page <= QM_UI_SCREEN10)
page = (QMPage)(QM_UI_SCREEN1 + ViewMain::instance()->getCurrentMainView());
@@ -149,35 +158,26 @@ QMPage RadioData::getKeyShortcut(event_t event)
void RadioData::setKeyShortcut(event_t event, QMPage shortcut)
{
switch(event) {
case EVT_KEY_BREAK(KEY_MODEL):
keyShortcuts[0].shortcut = shortcut;
break;
case EVT_KEY_BREAK(KEY_SYS):
keyShortcuts[1].shortcut = shortcut;
break;
case EVT_KEY_BREAK(KEY_TELE):
keyShortcuts[2].shortcut = shortcut;
break;
case EVT_KEY_LONG(KEY_MODEL):
keyShortcuts[3].shortcut = shortcut;
break;
case EVT_KEY_LONG(KEY_SYS):
keyShortcuts[4].shortcut = shortcut;
break;
case EVT_KEY_LONG(KEY_TELE):
keyShortcuts[5].shortcut = shortcut;
break;
default:
break;
}
int n = getKeyShortcutNum(event);
if (n >= 0) keyShortcuts[n].shortcut = shortcut;
}
bool RadioData::hasKeyShortcut(QMPage shortcut)
bool RadioData::hasKeyShortcut(QMPage shortcut, event_t event)
{
for (int i = 0; i < MAX_KEY_SHORTCUTS; i += 1)
if (keyShortcuts[i].shortcut == shortcut)
return true;
// Returns true if the shortcut is defined on any other key except 'event' key
for (int i = 0; i < MAX_KEY_SHORTCUTS; i += 1) {
auto ev = getKeyShortcutEvent(i);
if (shortcut < QM_APP) {
if (keyShortcuts[i].shortcut == shortcut)
return ev != event;
} else {
if (keyShortcuts[i].shortcut == QM_APP) {
int idx = getLuaToolId(getKeyToolName(ev)) + QM_APP;
if (idx == shortcut)
return ev != event;
}
}
}
return false;
}
@@ -190,4 +190,31 @@ void RadioData::defaultKeyShortcuts()
setKeyShortcut(EVT_KEY_BREAK(KEY_TELE), QM_UI_SCREEN1);
setKeyShortcut(EVT_KEY_LONG(KEY_TELE), QM_TOOLS_CHAN_MON);
}
static std::string _keyToolNames[MAX_KEY_SHORTCUTS];
void RadioData::setKeyToolName(event_t event, const std::string name)
{
int n = getKeyShortcutNum(event);
if (n >= 0) _keyToolNames[n] = name;
}
const std::string RadioData::getKeyToolName(event_t event)
{
int n = getKeyShortcutNum(event);
if (n >= 0) return _keyToolNames[n];
return "";
}
static std::string _favoriteToolNames[MAX_QM_FAVORITES];
void RadioData::setFavoriteToolName(int fav, const std::string name)
{
_favoriteToolNames[fav] = name;
}
const std::string RadioData::getFavoriteToolName(int fav)
{
return _favoriteToolNames[fav];
}
#endif
+2
View File
@@ -1165,6 +1165,8 @@ void edgeTxClose(uint8_t shutdown)
cancelShutdownAnimation(); // To prevent simulator crash
MainWindow::instance()->shutdown();
#if defined(LUA)
extern void unloadLuaTools();
unloadLuaTools();
luaUnregisterWidgets();
#endif
#endif
+32 -49
View File
@@ -606,21 +606,44 @@ constexpr uint8_t TEXT_FILENAME_MAXLEN = 40;
// Re-useable byte array to save having multiple buffers
union ReusableBuffer
{
struct {
#if !defined(COLORLCD)
struct {
char menu_bss[POPUP_MENU_MAX_LINES][MENU_LINE_LENGTH];
char mainname[45]; // because reused for SD backup / restore, max backup filename 44 chars: "/MODELS/MODEL0134353-2014-06-19-04-51-27.bin"
#elif !defined(COLORLCD)
char mainname[LEN_MODEL_NAME];
#endif
} modelsel;
struct {
char filename[TEXT_FILENAME_MAXLEN];
char lines[NUM_BODY_LINES][LCD_COLS + 1];
int linesCount;
bool checklistComplete;
bool pushMenu;
} viewText;
struct {
int8_t preset;
} curveEdit;
struct {
int8_t antennaMode;
} radioHardware;
struct {
uint8_t stickMode;
#if defined(ROTARY_ENCODER_NAVIGATION)
uint8_t rotaryEncoderMode;
#endif
} generalSettings;
#endif
struct {
char msg[64];
#if !defined(COLORLCD)
uint8_t r9mPower;
int8_t antennaMode;
uint8_t previousType;
uint8_t newType;
#endif
#if defined(PXX2)
BindInformation bindInformation;
PXX2ModuleSetup pxx2;
@@ -651,29 +674,23 @@ union ReusableBuffer
} calib;
struct {
#if defined(NUM_BODY_LINES)
#if !defined(COLORLCD)
char lines[NUM_BODY_LINES][SD_SCREEN_FILE_LENGTH+1+1]; // the last char is used to store the flags (directory) of the line
#endif
uint32_t available;
uint16_t offset;
uint16_t count;
char originalName[SD_SCREEN_FILE_LENGTH+1];
#endif
#if defined(PXX2)
OtaUpdateInformation otaUpdateInformation;
char otaReceiverVersion[64]; // Large enough for TR_CURRENT_VERSION string plus version number
#endif
} sdManager;
struct
{
char id[27];
} version;
#if defined(PXX2)
PXX2HardwareAndSettings hardwareAndSettings; // radio_version
#endif
#if defined(NUM_BODY_LINES)
#if !defined(COLORLCD)
#define TOOL_NAME_MAX_LEN (LCD_W / FW)
#define TOOL_PATH_MAX_LEN 40
struct scriptInfo{
@@ -686,30 +703,16 @@ union ReusableBuffer
#endif
struct {
#if defined(NUM_BODY_LINES)
#if !defined(COLORLCD)
scriptInfo script[NUM_BODY_LINES];
uint8_t oldOffset;
uint8_t linesCount;
#endif
#if defined(PXX2)
ModuleInformation modules[NUM_MODULES];
#endif
char msg[64];
#if !defined(COLORLCD)
uint8_t linesCount;
#endif
} radioTools;
struct {
int8_t antennaMode;
} radioHardware;
struct {
uint8_t stickMode;
#if defined(ROTARY_ENCODER_NAVIGATION)
uint8_t rotaryEncoderMode;
#endif
} generalSettings;
struct {
uint8_t bars[LCD_W];
uint8_t max[LCD_W];
@@ -744,29 +747,9 @@ union ReusableBuffer
uint8_t dirty;
} powerMeter;
struct {
int8_t preset;
} curveEdit;
#if !defined(COLORLCD)
struct {
char filename[TEXT_FILENAME_MAXLEN];
char lines[NUM_BODY_LINES][LCD_COLS + 1];
int linesCount;
bool checklistComplete;
bool pushMenu;
} viewText;
#endif
struct {
uint8_t maxNameLen;
} modelFailsafe;
struct {
#if defined(PXX2)
ModuleInformation internalModule;
#endif
} viewMain;
};
extern ReusableBuffer reusableBuffer;
@@ -21,13 +21,9 @@
#include "sourcechoice.h"
#include "dataconstants.h"
#include "lcd.h"
#include "menu.h"
#include "menutoolbar.h"
#include "edgetx.h"
#include "strhelpers.h"
#include "switches.h"
class SourceChoiceMenuToolbar : public MenuToolbar
{
@@ -26,8 +26,6 @@
class SourceChoiceMenuToolbar;
bool isSourceAvailable(int source);
class SourceChoice : public Choice
{
public:
@@ -20,12 +20,9 @@
*/
#include "switchchoice.h"
#include "dataconstants.h"
#include "menu.h"
#include "menutoolbar.h"
#include "edgetx.h"
#include "strhelpers.h"
#include "switches.h"
class SwitchChoiceMenuToolbar : public MenuToolbar
{
+1 -1
View File
@@ -294,7 +294,7 @@ class MenuWindowContent : public NavWindow
{
setWindowFlag(OPAQUE);
coord_t w = (popupWidth > MENUS_WIDTH) ? popupWidth : MENUS_WIDTH;
coord_t w = (popupWidth > 0) ? popupWidth : MENUS_WIDTH;
lv_obj_center(lvobj);
setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO, w, LV_SIZE_CONTENT);
@@ -25,6 +25,7 @@
#include "mainwindow.h"
#include "model_select.h"
#include "quick_menu.h"
#include "radio_tools.h"
#include "screen_setup.h"
#include "topbar.h"
#include "view_channels.h"
@@ -227,7 +228,9 @@ void ViewMain::updateTopbarVisibility()
void ViewMain::doKeyShortcut(event_t event)
{
QMPage pg = g_eeGeneral.getKeyShortcut(event);
if (pg == QM_OPEN_QUICK_MENU) {
if (pg == QM_APP) {
runLuaTool(g_eeGeneral.getKeyToolName(event));
} else if (pg == QM_OPEN_QUICK_MENU) {
QuickMenu::openQuickMenu();
} else {
QuickMenu::openPage(pg);
+200 -142
View File
@@ -33,7 +33,206 @@
#include "etx_lv_theme.h"
#include "lib_file.h"
extern uint8_t g_moduleIdx;
//-----------------------------------------------------------------------------
inline bool tool_compare_nocase(const ToolEntry& first, const ToolEntry& second)
{
return strcasecmp(first.label.c_str(), second.label.c_str()) < 0;
}
#if defined(LUA)
std::vector<ToolEntry> luaTools;
static bool luaToolsLoaded = false;
static void run_lua_tool(const std::string& path)
{
char toolPath[FF_MAX_LFN + 1];
strncpy(toolPath, path.c_str(), sizeof(toolPath) - 1);
*((char*)getBasename(toolPath) - 1) = '\0';
f_chdir(toolPath);
luaExecStandalone(path.c_str());
}
void unloadLuaTools()
{
luaTools.clear();
luaToolsLoaded = false;
}
// LUA scripts in TOOLS
void loadLuaTools()
{
if (!luaToolsLoaded) {
luaToolsLoaded = true;
FILINFO fno;
DIR dir;
FRESULT res = f_opendir(&dir, SCRIPTS_TOOLS_PATH);
if (res == FR_OK) {
for (;;) {
res = f_readdir(&dir, &fno); /* Read a directory item */
if (res != FR_OK || fno.fname[0] == 0)
break; /* Break on error or end of dir */
if (fno.fattrib & (AM_HID | AM_SYS))
continue; // skip hidden files and system files
if (fno.fname[0] == '.') continue; /* Ignore UNIX hidden files */
bool inFolder = (fno.fattrib & AM_DIR);
char path[FF_MAX_LFN + 1] = SCRIPTS_TOOLS_PATH "/";
strcat(path, fno.fname);
if (inFolder) {
// check if .lua with same name exists - skip folder to avoid duplicate entries
auto plen = strlen(path);
strcat(path, ".lua");
if (f_stat(path, nullptr) == FR_OK)
continue;
path[plen] = 0;
strcat(path, "/main.lua");
if (f_stat(path, nullptr) != FR_OK)
continue;
}
if (isRadioScriptTool(path)) {
char toolName[RADIO_TOOL_NAME_MAXLEN + 1] = {0};
const char* label;
if (readToolName(toolName, path)) {
label = toolName;
} else {
if (!inFolder) {
char* ext = (char*)getFileExtension(fno.fname);
if (ext) *ext = '\0';
}
label = fno.fname;
}
luaTools.emplace_back(ToolEntry{label, path, run_lua_tool});
}
}
}
std::sort(luaTools.begin(), luaTools.end(), tool_compare_nocase);
}
}
// LUA scripts in TOOLS
static void scanLuaTools(std::list<ToolEntry>& scripts)
{
loadLuaTools();
for (auto t : luaTools)
scripts.emplace_back(t);
}
#endif
const ToolEntry* getLuaTool(int n)
{
if (n >= 0 && n < (int)luaTools.size())
return &luaTools[n];
return nullptr;
}
int getLuaToolId(const std::string name)
{
int id = 0;
for (auto t : luaTools) {
if (t.label == name)
return id;
id += 1;
}
return -1;
}
void runLuaTool(const std::string name)
{
for (auto t : luaTools) {
if (t.label == name) {
t.exec(t.path);
return;
}
}
}
void getLuaToolNames(std::vector<std::string>& nameList)
{
loadLuaTools();
std::string s(STR_QM_APPS);
s += " - ";
for (size_t i = 0; i < luaTools.size(); i += 1) {
nameList.emplace_back(s + luaTools[i].label);
}
}
//-----------------------------------------------------------------------------
static bool isModelGPSSensorPresent()
{
for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) {
if (isGPSSensor(i+1)) return true;
}
return false;
}
static void run_gpstool(const std::string&)
{
new RadioGpsTool();
}
#if defined(PXX2) || defined(MULTIMODULE)
#if defined(HARDWARE_INTERNAL_MODULE)
static void run_spektrum_int(const std::string&)
{
new RadioSpectrumAnalyser(INTERNAL_MODULE);
}
#endif
#if defined(HARDWARE_EXTERNAL_MODULE)
static void run_spektrum_ext(const std::string&)
{
new RadioSpectrumAnalyser(EXTERNAL_MODULE);
}
#endif
#endif // defined(PXX2) || defined(MULTIMODULE)
#if defined(INTERNAL_MODULE_PXX2)
static void run_pxx2_power(const std::string&)
{
#if 0 // disabled Power Meter: not yet implemented
new RadioPowerMeter(INTERNAL_MODULE);
#endif
}
#endif
#if defined(GHOST)
static void run_ghost_config(const std::string&)
{
new RadioGhostModuleConfig(EXTERNAL_MODULE);
}
#endif
//-----------------------------------------------------------------------------
struct ToolButton : public TextButton {
ToolButton(Window* parent, const ToolEntry& tool) :
TextButton(parent, rect_t{}, tool.label, [=]() {
tool.exec(tool.path);
return 0;
})
{
setWidth(TOOLS_BTN_W);
setHeight(TOOLS_BTN_H);
lv_obj_set_width(label, lv_pct(100));
etx_obj_add_style(label, styles->text_align_center, LV_PART_MAIN);
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
}
static LAYOUT_ORIENTATION(TOOLS_BTN_W, (LCD_W - PAD_LARGE * 3) / 3, (LCD_W - PAD_LARGE * 2) / 2)
static LAYOUT_VAL_SCALED(TOOLS_BTN_H, 48)
};
//-----------------------------------------------------------------------------
RadioToolsPage::RadioToolsPage(const PageDef& pageDef) : PageGroupItem(pageDef) {}
@@ -81,147 +280,6 @@ void RadioToolsPage::checkEvents()
PageGroupItem::checkEvents();
}
typedef void (*ToolExec)(Window* parent, const std::string& path);
struct ToolEntry {
std::string label;
std::string path;
ToolExec exec;
};
inline bool tool_compare_nocase(const ToolEntry& first, const ToolEntry& second)
{
return strcasecmp(first.label.c_str(), second.label.c_str()) < 0;
}
#if defined(LUA)
static void run_lua_tool(Window* parent, const std::string& path)
{
char toolPath[FF_MAX_LFN + 1];
strncpy(toolPath, path.c_str(), sizeof(toolPath) - 1);
*((char*)getBasename(toolPath) - 1) = '\0';
f_chdir(toolPath);
luaExecStandalone(path.c_str());
}
// LUA scripts in TOOLS
static void scanLuaTools(std::list<ToolEntry>& scripts)
{
FILINFO fno;
DIR dir;
FRESULT res = f_opendir(&dir, SCRIPTS_TOOLS_PATH);
if (res == FR_OK) {
for (;;) {
res = f_readdir(&dir, &fno); /* Read a directory item */
if (res != FR_OK || fno.fname[0] == 0)
break; /* Break on error or end of dir */
if (fno.fattrib & (AM_HID | AM_SYS))
continue; // skip hidden files and system files
if (fno.fname[0] == '.') continue; /* Ignore UNIX hidden files */
bool inFolder = (fno.fattrib & AM_DIR);
char path[FF_MAX_LFN + 1] = SCRIPTS_TOOLS_PATH "/";
strcat(path, fno.fname);
if (inFolder) {
// check if .lua with same name exists - skip folder to avoid duplicate entries
auto plen = strlen(path);
strcat(path, ".lua");
if (f_stat(path, nullptr) == FR_OK)
continue;
path[plen] = 0;
strcat(path, "/main.lua");
if (f_stat(path, nullptr) != FR_OK)
continue;
}
if (isRadioScriptTool(path)) {
char toolName[RADIO_TOOL_NAME_MAXLEN + 1] = {0};
const char* label;
if (readToolName(toolName, path)) {
label = toolName;
} else {
if (!inFolder) {
char* ext = (char*)getFileExtension(fno.fname);
if (ext) *ext = '\0';
}
label = fno.fname;
}
scripts.emplace_back(ToolEntry{label, path, run_lua_tool});
}
}
}
}
#endif
static bool isModelGPSSensorPresent()
{
for (int i = 0; i < MAX_TELEMETRY_SENSORS; i++) {
if (isGPSSensor(i+1)) return true;
}
return false;
}
static void run_gpstool(Window* parent, const std::string&)
{
new RadioGpsTool();
}
#if defined(PXX2) || defined(MULTIMODULE)
#if defined(HARDWARE_INTERNAL_MODULE)
static void run_spektrum_int(Window* parent, const std::string&)
{
new RadioSpectrumAnalyser(INTERNAL_MODULE);
}
#endif
#if defined(HARDWARE_EXTERNAL_MODULE)
static void run_spektrum_ext(Window* parent, const std::string&)
{
new RadioSpectrumAnalyser(EXTERNAL_MODULE);
}
#endif
#endif // defined(PXX2) || defined(MULTIMODULE)
#if defined(INTERNAL_MODULE_PXX2)
static void run_pxx2_power(Window* parent, const std::string&)
{
#if 0 // disabled Power Meter: not yet implemented
new RadioPowerMeter(INTERNAL_MODULE);
#endif
}
#endif
#if defined(GHOST)
static void run_ghost_config(Window* parent, const std::string&)
{
new RadioGhostModuleConfig(EXTERNAL_MODULE);
}
#endif
struct ToolButton : public TextButton {
ToolButton(Window* parent, const ToolEntry& tool) :
TextButton(parent, rect_t{}, tool.label, [=]() {
tool.exec(parent, tool.path);
return 0;
})
{
setWidth(TOOLS_BTN_W);
setHeight(TOOLS_BTN_H);
lv_obj_set_width(label, lv_pct(100));
etx_obj_add_style(label, styles->text_align_center, LV_PART_MAIN);
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
}
static LAYOUT_ORIENTATION(TOOLS_BTN_W, (LCD_W - PAD_LARGE * 3) / 3, (LCD_W - PAD_LARGE * 2) / 2)
static LAYOUT_VAL_SCALED(TOOLS_BTN_H, 48)
};
void RadioToolsPage::rebuild(Window* window)
{
window->clear();
@@ -23,6 +23,20 @@
#include "pagegroup.h"
typedef void (*ToolExec)(const std::string& path);
struct ToolEntry {
std::string label;
std::string path;
ToolExec exec;
};
extern void loadLuaTools();
extern void getLuaToolNames(std::vector<std::string>& nameList);
extern const ToolEntry* getLuaTool(int n);
extern int getLuaToolId(const std::string nm);
extern void runLuaTool(const std::string nm);
class RadioToolsPage : public PageGroupItem
{
public:
@@ -26,6 +26,8 @@
#include "edgetx.h"
#include "getset_helpers.h"
#include "pagegroup.h"
#include "qmpagechoice.h"
#include "radio_tools.h"
#define SET_DIRTY() storageDirty(EE_GENERAL)
@@ -46,21 +48,35 @@ void QMKeyShortcutsPage::addKey(event_t event, std::vector<std::string> qmPages,
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)),
auto c = new QMPageChoice(
parent, {LCD_W / 4, y, LCD_W * 2 / 3, 0}, qmPages, QM_NONE, qmPages.size() - 1,
[=]() -> int {
auto pg = g_eeGeneral.getKeyShortcut(event);
if (pg < QM_APP)
return pg;
std::string nm = g_eeGeneral.getKeyToolName(event);
int idx = getLuaToolId(nm);
if (idx >= 0)
return pg + idx;
return QM_NONE;
},
[=](int32_t newValue) {
g_eeGeneral.setKeyShortcut(event, (QMPage)newValue);
if (newValue < QM_APP) {
g_eeGeneral.setKeyShortcut(event, (QMPage)newValue);
g_eeGeneral.setKeyToolName(event, "");
} else {
g_eeGeneral.setKeyShortcut(event, QM_APP);
g_eeGeneral.setKeyToolName(event, getLuaTool(newValue - QM_APP)->label);
}
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))
[=](int pg) {
if (pg == QM_NONE) return true;
if (g_eeGeneral.hasKeyShortcut((QMPage)pg, event))
return false;
return newValue <= QM_UI_SCREEN1 || newValue > QM_UI_ADD_PG; }
return pg <= QM_UI_SCREEN1 || pg > QM_UI_ADD_PG; }
);
});
}
@@ -69,7 +85,7 @@ void QMKeyShortcutsPage::addKey(event_t event, std::vector<std::string> qmPages,
QMKeyShortcutsPage::QMKeyShortcutsPage():
SubPage(ICON_RADIO, STR_MAIN_MENU_RADIO_SETTINGS, STR_KEY_SHORTCUTS, true)
{
std::vector<std::string> qmPages = QuickMenu::menuPageNames(false);
auto qmPages = QuickMenu::menuPageNames(false);
setupLine(STR_SHORT_PRESS, nullptr);
addKey(EVT_KEY_BREAK(KEY_SYS), qmPages, "SYS");
@@ -26,6 +26,7 @@
#include "mainwindow.h"
#include "model_select.h"
#include "os/time.h"
#include "radio_tools.h"
#include "screen_setup.h"
#include "theme_manager.h"
#include "topbar.h"
@@ -393,7 +394,10 @@ void PageGroupBase::setCurrentTab(unsigned index)
void PageGroupBase::doKeyShortcut(event_t event)
{
QMPage pg = g_eeGeneral.getKeyShortcut(event);
if (pg == QM_OPEN_QUICK_MENU) {
if (pg == QM_APP) {
onCancel();
runLuaTool(g_eeGeneral.getKeyToolName(event));
} else if (pg == QM_OPEN_QUICK_MENU) {
QuickMenu::openQuickMenu();
} else {
if (QuickMenu::subMenuIcon(pg) == icon) {
@@ -0,0 +1,70 @@
/*
* 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 "qmpagechoice.h"
#include "edgetx.h"
#include "menu.h"
#include "menutoolbar.h"
class QMPageChoiceMenuToolbar : public MenuToolbar
{
public:
QMPageChoiceMenuToolbar(Choice* choice, Menu* menu) :
MenuToolbar(choice, menu, 3)
{
addButton(STR_MAIN_MENU_MODEL_SETTINGS, QM_MODEL_SETUP, QM_MODEL_NOTES, nullptr, STR_MAIN_MENU_MODEL_SETTINGS, true);
addButton(STR_MAIN_MENU_RADIO_SETTINGS, QM_RADIO_SETUP, QM_RADIO_VERSION, nullptr, STR_MAIN_MENU_RADIO_SETTINGS, true);
addButton(STR_MAIN_MENU_SCREEN_SETTINGS, QM_UI_THEMES, QM_UI_ADD_PG, nullptr, STR_MAIN_MENU_SCREEN_SETTINGS, true);
addButton(STR_QM_TOOLS, QM_TOOLS_APPS, QM_TOOLS_DEBUG, nullptr, STR_QM_TOOLS, true);
addButton(STR_MAIN_MENU_APPS, QM_APP, QM_APP+9999, nullptr, STR_MAIN_MENU_APPS, true);
addButton(STR_SELECT_MENU_CLR, 0, 0, nullptr, nullptr, true);
}
protected:
};
QMPageChoice::QMPageChoice(Window* parent, const rect_t& rect,
std::vector<std::string> values,
int16_t vmin, int16_t vmax,
std::function<int16_t()> getValue,
std::function<void(int16_t)> setValue,
const char *title) :
Choice(parent, rect, values, vmin, vmax, getValue, setValue, title)
{
setPopupWidth(TABLE_WIDTH);
}
void QMPageChoice::openMenu()
{
setEditMode(true); // this needs to be done first before menu is created.
auto menu = new Menu(false, popupWidth);
if (menuTitle) menu->setTitle(menuTitle);
auto tb = new QMPageChoiceMenuToolbar(this, menu);
menu->setToolbar(tb);
// fillMenu(menu); - called by MenuToolbar
menu->setCloseHandler([=]() { setEditMode(false); });
}
@@ -0,0 +1,49 @@
/*
* 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 "choice.h"
#include "form.h"
class QMPageChoiceMenuToolbar;
class QMPageChoice : public Choice
{
public:
QMPageChoice(Window* parent, const rect_t& rect,
std::vector<std::string> values,
int16_t vmin, int16_t vmax,
std::function<int16_t()> getValue,
std::function<void(int16_t)> setValue,
const char *title);
static LAYOUT_ORIENTATION(TABLE_WIDTH, LCD_W * 5 / 8, LCD_W / 2 + PAD_LARGE * 3)
protected:
friend QMPageChoiceMenuToolbar;
void openMenu() override;
#if defined(DEBUG_WINDOWS)
std::string getName() const override { return "QMPageChoice"; }
#endif
};
@@ -26,6 +26,7 @@
#include "mainwindow.h"
#include "model_select.h"
#include "quick_menu_group.h"
#include "radio_tools.h"
#include "screen_setup.h"
#include "theme_manager.h"
#include "view_channels.h"
@@ -145,7 +146,14 @@ class QuickSubMenu
subMenu = new QuickMenuGroup(parent);
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),
auto pg = mainDef->subMenuItems[i].qmPage;
const char* title;
if (pg < QM_APP) {
title = STR_VAL(mainDef->subMenuItems[i].qmTitle);
} else {
title = getLuaTool(pg - QM_APP)->label.c_str();
}
subMenu->addButton(mainDef->subMenuItems[i].icon, title,
std::bind(&QuickSubMenu::onPress, this, i),
mainDef->subMenuItems[i].enabled,
[=](bool focus) { if (focus) QuickMenu::setCurrentPage(mainDef->subMenuItems[i].qmPage, mainDef->icon); });
@@ -430,10 +438,11 @@ std::string replaceAll(std::string str, const std::string& from, const std::stri
return str;
}
std::vector<std::string> QuickMenu::menuPageNames(bool forFavorites)
std::vector<std::string>& QuickMenu::menuPageNames(bool forFavorites)
{
std::vector<std::string> qmPages;
static std::vector<std::string> qmPages;
qmPages.clear();
qmPages.emplace_back(STR_NONE);
qmPages.emplace_back(STR_OPEN_QUICK_MENU);
@@ -455,6 +464,10 @@ std::vector<std::string> QuickMenu::menuPageNames(bool forFavorites)
}
}
#if defined(LUA)
getLuaToolNames(qmPages);
#endif
return qmPages;
}
@@ -467,12 +480,12 @@ void QuickMenu::resetFavorites()
void QuickMenu::updateFavorites()
{
loadLuaTools();
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);
if (setupFavorite(i, f))
f += 1;
}
}
favoritesMenuItems[f].icon = EDGETX_ICONS_COUNT;
@@ -480,9 +493,30 @@ void QuickMenu::updateFavorites()
subMenus[0]->clearSubMenu();
}
void QuickMenu::setupFavorite(QMPage page, int f)
bool QuickMenu::setupFavorite(int favIdx, int favBtn)
{
PageDef& fav = favoritesMenuItems[f];
auto page = g_eeGeneral.qmFavorites[favIdx].shortcut;
PageDef& fav = favoritesMenuItems[favBtn];
if (page == QM_NONE)
return false;
if (page == QM_APP) {
std::string nm = g_eeGeneral.getFavoriteToolName(favIdx);
int idx = getLuaToolId(nm);
if (idx >= 0) {
fav.icon = ICON_TOOLS_APPS;
fav.qmTitle = nullptr; // retreived on use (no translation strings)
fav.title = nullptr; // retrieved on use (no translation strings)
fav.pageAction = PAGE_ACTION;
fav.qmPage = (QMPage)(page + idx);
fav.create = nullptr;
fav.enabled = nullptr;
fav.action = [=]() { runLuaTool(nm); };
return true;
}
return false;
}
for (int i = FIRST_SEARCH_IDX; qmTopItems[i].icon != EDGETX_ICONS_COUNT; i += 1) {
if (qmTopItems[i].pageAction == QM_ACTION) {
@@ -495,7 +529,7 @@ void QuickMenu::setupFavorite(QMPage page, int f)
fav.create = nullptr;
fav.enabled = nullptr;
fav.action = qmTopItems[i].action;
return;
return true;
}
} else {
const PageDef* sub = qmTopItems[i].subMenuItems;
@@ -509,11 +543,13 @@ void QuickMenu::setupFavorite(QMPage page, int f)
fav.create = sub[j].create;
fav.enabled = sub[j].enabled;
fav.action = sub[j].action;
return;
return true;
}
}
}
}
return false;
}
#endif
@@ -580,7 +616,10 @@ void QuickMenu::enableSubMenu()
void QuickMenu::doKeyShortcut(event_t event)
{
QMPage pg = g_eeGeneral.getKeyShortcut(event);
if (pg == QM_OPEN_QUICK_MENU) {
if (pg == QM_APP) {
closeQM();
runLuaTool(g_eeGeneral.getKeyToolName(event));
} else if (pg == QM_OPEN_QUICK_MENU) {
closeQM();
} else {
onSelect(true);
@@ -96,7 +96,7 @@ class QuickMenu : public NavWindow
static void openPage(QMPage page);
static EdgeTxIcon subMenuIcon(QMPage page);
static int pageIndex(QMPage page);
static std::vector<std::string> menuPageNames(bool forFavorites);
static std::vector<std::string>& menuPageNames(bool forFavorites);
#if VERSION_MAJOR > 2
static void resetFavorites();
@@ -168,7 +168,7 @@ class QuickMenu : public NavWindow
#if VERSION_MAJOR > 2
void updateFavorites();
void setupFavorite(QMPage page, int f);
bool setupFavorite(int fav, int favBtn);
#endif
};
@@ -68,4 +68,6 @@ enum QMPage {
QM_TOOLS_LS_MON,
QM_TOOLS_STATS,
QM_TOOLS_DEBUG,
// Key shortcut & Favorites APP
QM_APP,
};
@@ -25,34 +25,59 @@
#include "edgetx.h"
#include "getset_helpers.h"
#include "pagegroup.h"
#include "qmpagechoice.h"
#include "radio_tools.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);
auto 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),
auto c = new QMPageChoice(
parent, {LCD_W / 4, y, LCD_W * 2 / 3, 0}, qmPages, QM_NONE, qmPages.size() - 1,
[=]() -> int {
auto pg = g_eeGeneral.qmFavorites[i].shortcut;
if (pg < QM_APP)
return pg;
std::string nm = g_eeGeneral.getFavoriteToolName(i);
int idx = getLuaToolId(nm);
if (idx >= 0)
return pg + idx;
return QM_NONE;
},
[=](int32_t pg) {
g_eeGeneral.qmFavorites[i].shortcut = (QMPage)pg;
if (pg < QM_APP) {
g_eeGeneral.qmFavorites[i].shortcut = (QMPage)pg;
g_eeGeneral.setFavoriteToolName(i, "");
} else {
g_eeGeneral.qmFavorites[i].shortcut = QM_APP;
g_eeGeneral.setFavoriteToolName(i, getLuaTool(pg - QM_APP)->label);
}
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;
if (pg < QM_APP) {
for (int n = 0; n < MAX_QM_FAVORITES; n += 1)
if (g_eeGeneral.qmFavorites[n].shortcut == (QMPage)pg)
return n == i;
} else {
for (int n = 0; n < MAX_QM_FAVORITES; n += 1)
if (g_eeGeneral.qmFavorites[n].shortcut == QM_APP) {
int idx = getLuaToolId(g_eeGeneral.getFavoriteToolName(n)) + QM_APP;
if (idx == pg)
return n == i;
}
}
return pg != QM_OPEN_QUICK_MENU; }
);
});
@@ -188,6 +188,9 @@ void QuickMenuGroup::deleteLater()
void QuickMenuGroup::setFocus()
{
if (!curBtn && btns.size() > 0)
curBtn = btns[0];
if (curBtn) {
lv_event_send(curBtn->getLvObj(), LV_EVENT_FOCUSED, nullptr);
lv_group_focus_obj(curBtn->getLvObj());
@@ -142,6 +142,7 @@ const struct YamlIdStr enum_QMPage[] = {
{ QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ QM_TOOLS_STATS, "TOOLS_STATS" },
{ QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ QM_APP, "APP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
@@ -333,9 +334,16 @@ static const struct YamlNode struct_switchDef[] = {
YAML_PADDING( 5 ),
YAML_END
};
static const struct YamlNode struct_QuickMenuPage[] = {
static const struct YamlNode struct_KeyShortcut[] = {
YAML_IDX,
YAML_ENUM("shortcut", 8, enum_QMPage, NULL),
YAML_CUSTOM("shortcut",r_keyShortcut,w_keyShortcut),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_QMFavorite[] = {
YAML_IDX,
YAML_CUSTOM("shortcut",r_qmFavorite,w_qmFavorite),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
@@ -450,8 +458,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
@@ -34,6 +34,10 @@
#include "hal/adc_driver.h"
#include "hal/audio_driver.h"
#if defined(COLORLCD)
#include "radio_tools.h"
#endif
//
// WARNING:
// ========
@@ -926,6 +930,70 @@ bool w_lov_color(void* user, uint8_t* data, uint32_t bitoffs,
return set_color(layoutData->options[option].value.unsignedValue, wf, opaque);
}
extern const struct YamlIdStr enum_QMPage[];
void r_keyShortcut(void* user, uint8_t* data, uint32_t bitoffs,
const char* val, uint8_t val_len)
{
auto tw = reinterpret_cast<YamlTreeWalker*>(user);
event_t ev = g_eeGeneral.getKeyShortcutEvent(tw->getElmts(1));
bool isApp = (strncmp(val, "APP,", 4) == 0);
QMPage pg = isApp ? QM_APP : (QMPage)yaml_parse_enum(enum_QMPage, val, val_len);
g_eeGeneral.setKeyShortcut(ev, pg);
if (isApp)
g_eeGeneral.setKeyToolName(ev, val+4);
}
bool w_keyShortcut(void* user, uint8_t* data, uint32_t bitoffs,
yaml_writer_func wf, void* opaque)
{
auto tw = reinterpret_cast<YamlTreeWalker*>(user);
event_t ev = g_eeGeneral.getKeyShortcutEvent(tw->getElmts(1));
QMPage pg = g_eeGeneral.getKeyShortcut(ev);
const char* str = yaml_output_enum(pg, enum_QMPage);
if (!wf(opaque, str, strlen(str))) return false;
if (pg == QM_APP) {
auto s = g_eeGeneral.getKeyToolName(ev);
if (!wf(opaque, ",", 1)) return false;
return wf(opaque, s.c_str(), s.size());
}
return true;
}
void r_qmFavorite(void* user, uint8_t* data, uint32_t bitoffs,
const char* val, uint8_t val_len)
{
auto tw = reinterpret_cast<YamlTreeWalker*>(user);
int idx = tw->getElmts(1);
bool isApp = (strncmp(val, "APP,", 4) == 0);
QMPage pg = isApp ? QM_APP : (QMPage)yaml_parse_enum(enum_QMPage, val, val_len);
g_eeGeneral.qmFavorites[idx].shortcut = pg;
if (isApp)
g_eeGeneral.setFavoriteToolName(idx, val+4);
}
bool w_qmFavorite(void* user, uint8_t* data, uint32_t bitoffs,
yaml_writer_func wf, void* opaque)
{
auto tw = reinterpret_cast<YamlTreeWalker*>(user);
int idx = tw->getElmts(1);
QMPage pg = (QMPage)g_eeGeneral.qmFavorites[idx].shortcut;
const char* str = yaml_output_enum(pg, enum_QMPage);
if (!wf(opaque, str, strlen(str))) return false;
if (pg == QM_APP) {
auto s = g_eeGeneral.getFavoriteToolName(idx);
if (!wf(opaque, ",", 1)) return false;
return wf(opaque, s.c_str(), s.size());
}
return true;
}
#endif
static uint8_t select_mod_type(void* user, uint8_t* data, uint32_t bitoffs)
@@ -141,6 +141,7 @@ const struct YamlIdStr enum_QMPage[] = {
{ QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ QM_TOOLS_STATS, "TOOLS_STATS" },
{ QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ QM_APP, "APP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
@@ -324,9 +325,16 @@ static const struct YamlNode struct_switchDef[] = {
YAML_PADDING( 5 ),
YAML_END
};
static const struct YamlNode struct_QuickMenuPage[] = {
static const struct YamlNode struct_KeyShortcut[] = {
YAML_IDX,
YAML_ENUM("shortcut", 8, enum_QMPage, NULL),
YAML_CUSTOM("shortcut",r_keyShortcut,w_keyShortcut),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_QMFavorite[] = {
YAML_IDX,
YAML_CUSTOM("shortcut",r_qmFavorite,w_qmFavorite),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
@@ -441,8 +449,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
@@ -148,6 +148,7 @@ const struct YamlIdStr enum_QMPage[] = {
{ QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ QM_TOOLS_STATS, "TOOLS_STATS" },
{ QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ QM_APP, "APP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
@@ -331,9 +332,16 @@ static const struct YamlNode struct_switchDef[] = {
YAML_PADDING( 5 ),
YAML_END
};
static const struct YamlNode struct_QuickMenuPage[] = {
static const struct YamlNode struct_KeyShortcut[] = {
YAML_IDX,
YAML_ENUM("shortcut", 8, enum_QMPage, NULL),
YAML_CUSTOM("shortcut",r_keyShortcut,w_keyShortcut),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_QMFavorite[] = {
YAML_IDX,
YAML_CUSTOM("shortcut",r_qmFavorite,w_qmFavorite),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
@@ -448,8 +456,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
@@ -154,6 +154,7 @@ const struct YamlIdStr enum_QMPage[] = {
{ QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ QM_TOOLS_STATS, "TOOLS_STATS" },
{ QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ QM_APP, "APP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
@@ -356,9 +357,16 @@ static const struct YamlNode struct_switchDef[] = {
YAML_STRUCT("offColor", 24, struct_RGBLedColor, switch_is_cfs),
YAML_END
};
static const struct YamlNode struct_QuickMenuPage[] = {
static const struct YamlNode struct_KeyShortcut[] = {
YAML_IDX,
YAML_ENUM("shortcut", 8, enum_QMPage, NULL),
YAML_CUSTOM("shortcut",r_keyShortcut,w_keyShortcut),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_QMFavorite[] = {
YAML_IDX,
YAML_CUSTOM("shortcut",r_qmFavorite,w_qmFavorite),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
@@ -473,8 +481,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
@@ -148,6 +148,7 @@ const struct YamlIdStr enum_QMPage[] = {
{ QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ QM_TOOLS_STATS, "TOOLS_STATS" },
{ QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ QM_APP, "APP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
@@ -331,9 +332,16 @@ static const struct YamlNode struct_switchDef[] = {
YAML_PADDING( 5 ),
YAML_END
};
static const struct YamlNode struct_QuickMenuPage[] = {
static const struct YamlNode struct_KeyShortcut[] = {
YAML_IDX,
YAML_ENUM("shortcut", 8, enum_QMPage, NULL),
YAML_CUSTOM("shortcut",r_keyShortcut,w_keyShortcut),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_QMFavorite[] = {
YAML_IDX,
YAML_CUSTOM("shortcut",r_qmFavorite,w_qmFavorite),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
@@ -448,8 +456,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
@@ -141,6 +141,7 @@ const struct YamlIdStr enum_QMPage[] = {
{ QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ QM_TOOLS_STATS, "TOOLS_STATS" },
{ QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ QM_APP, "APP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
@@ -324,9 +325,16 @@ static const struct YamlNode struct_switchDef[] = {
YAML_PADDING( 5 ),
YAML_END
};
static const struct YamlNode struct_QuickMenuPage[] = {
static const struct YamlNode struct_KeyShortcut[] = {
YAML_IDX,
YAML_ENUM("shortcut", 8, enum_QMPage, NULL),
YAML_CUSTOM("shortcut",r_keyShortcut,w_keyShortcut),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_QMFavorite[] = {
YAML_IDX,
YAML_CUSTOM("shortcut",r_qmFavorite,w_qmFavorite),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
@@ -441,8 +449,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
@@ -154,6 +154,7 @@ const struct YamlIdStr enum_QMPage[] = {
{ QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ QM_TOOLS_STATS, "TOOLS_STATS" },
{ QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ QM_APP, "APP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
@@ -356,9 +357,16 @@ static const struct YamlNode struct_switchDef[] = {
YAML_STRUCT("offColor", 24, struct_RGBLedColor, switch_is_cfs),
YAML_END
};
static const struct YamlNode struct_QuickMenuPage[] = {
static const struct YamlNode struct_KeyShortcut[] = {
YAML_IDX,
YAML_ENUM("shortcut", 8, enum_QMPage, NULL),
YAML_CUSTOM("shortcut",r_keyShortcut,w_keyShortcut),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_QMFavorite[] = {
YAML_IDX,
YAML_CUSTOM("shortcut",r_qmFavorite,w_qmFavorite),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
@@ -473,8 +481,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
@@ -149,6 +149,7 @@ const struct YamlIdStr enum_QMPage[] = {
{ QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ QM_TOOLS_STATS, "TOOLS_STATS" },
{ QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ QM_APP, "APP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
@@ -341,9 +342,16 @@ static const struct YamlNode struct_switchDef[] = {
YAML_PADDING( 3 ),
YAML_END
};
static const struct YamlNode struct_QuickMenuPage[] = {
static const struct YamlNode struct_KeyShortcut[] = {
YAML_IDX,
YAML_ENUM("shortcut", 8, enum_QMPage, NULL),
YAML_CUSTOM("shortcut",r_keyShortcut,w_keyShortcut),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_QMFavorite[] = {
YAML_IDX,
YAML_CUSTOM("shortcut",r_qmFavorite,w_qmFavorite),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
@@ -458,8 +466,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
@@ -154,6 +154,7 @@ const struct YamlIdStr enum_QMPage[] = {
{ QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ QM_TOOLS_STATS, "TOOLS_STATS" },
{ QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ QM_APP, "APP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
@@ -356,9 +357,16 @@ static const struct YamlNode struct_switchDef[] = {
YAML_STRUCT("offColor", 24, struct_RGBLedColor, switch_is_cfs),
YAML_END
};
static const struct YamlNode struct_QuickMenuPage[] = {
static const struct YamlNode struct_KeyShortcut[] = {
YAML_IDX,
YAML_ENUM("shortcut", 8, enum_QMPage, NULL),
YAML_CUSTOM("shortcut",r_keyShortcut,w_keyShortcut),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_QMFavorite[] = {
YAML_IDX,
YAML_CUSTOM("shortcut",r_qmFavorite,w_qmFavorite),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
@@ -473,8 +481,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
@@ -154,6 +154,7 @@ const struct YamlIdStr enum_QMPage[] = {
{ QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ QM_TOOLS_STATS, "TOOLS_STATS" },
{ QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ QM_APP, "APP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
@@ -356,9 +357,16 @@ static const struct YamlNode struct_switchDef[] = {
YAML_STRUCT("offColor", 24, struct_RGBLedColor, switch_is_cfs),
YAML_END
};
static const struct YamlNode struct_QuickMenuPage[] = {
static const struct YamlNode struct_KeyShortcut[] = {
YAML_IDX,
YAML_ENUM("shortcut", 8, enum_QMPage, NULL),
YAML_CUSTOM("shortcut",r_keyShortcut,w_keyShortcut),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_QMFavorite[] = {
YAML_IDX,
YAML_CUSTOM("shortcut",r_qmFavorite,w_qmFavorite),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
@@ -473,8 +481,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
@@ -154,6 +154,7 @@ const struct YamlIdStr enum_QMPage[] = {
{ QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ QM_TOOLS_STATS, "TOOLS_STATS" },
{ QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ QM_APP, "APP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
@@ -357,9 +358,16 @@ static const struct YamlNode struct_switchDef[] = {
YAML_STRUCT("offColor", 24, struct_RGBLedColor, switch_is_cfs),
YAML_END
};
static const struct YamlNode struct_QuickMenuPage[] = {
static const struct YamlNode struct_KeyShortcut[] = {
YAML_IDX,
YAML_ENUM("shortcut", 8, enum_QMPage, NULL),
YAML_CUSTOM("shortcut",r_keyShortcut,w_keyShortcut),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_QMFavorite[] = {
YAML_IDX,
YAML_CUSTOM("shortcut",r_qmFavorite,w_qmFavorite),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
@@ -474,8 +482,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
@@ -141,6 +141,7 @@ const struct YamlIdStr enum_QMPage[] = {
{ QM_TOOLS_LS_MON, "TOOLS_LS_MON" },
{ QM_TOOLS_STATS, "TOOLS_STATS" },
{ QM_TOOLS_DEBUG, "TOOLS_DEBUG" },
{ QM_APP, "APP" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
@@ -332,9 +333,16 @@ static const struct YamlNode struct_switchDef[] = {
YAML_PADDING( 5 ),
YAML_END
};
static const struct YamlNode struct_QuickMenuPage[] = {
static const struct YamlNode struct_KeyShortcut[] = {
YAML_IDX,
YAML_ENUM("shortcut", 8, enum_QMPage, NULL),
YAML_CUSTOM("shortcut",r_keyShortcut,w_keyShortcut),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_QMFavorite[] = {
YAML_IDX,
YAML_CUSTOM("shortcut",r_qmFavorite,w_qmFavorite),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
@@ -449,8 +457,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {