simplify model setup screen

This commit is contained in:
Raphael Coeffic
2022-06-11 15:38:08 +02:00
committed by Raphael Coeffic
parent 009018be3a
commit ace7cfbe9d
19 changed files with 826 additions and 369 deletions
+3
View File
@@ -56,6 +56,9 @@ set(GUI_SRC
custom_failsafe.cpp
module_setup.cpp
timer_setup.cpp
trims_setup.cpp
throttle_params.cpp
preflight_checks.cpp
model_setup.cpp
model_flightmodes.cpp
model_inputs.cpp
+7 -2
View File
@@ -51,8 +51,13 @@ TouchState getLastTochState()
extern "C" void keyboardDriverRead(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
// if there is a keyboard event then call checkevents
if (isEvent())
MainWindow::instance()->checkEvents();
if (isEvent()) {
event_t evt = getWindowEvent();
auto focusWindow = Window::getFocus();
if (focusWindow) {
focusWindow->onEvent(evt);
}
}
}
static void copy_ts_to_indev_data(const TouchState &st, lv_indev_data_t *data)
+115 -285
View File
@@ -23,30 +23,20 @@
#include "opentx.h"
#include "libopenui.h"
#include "button_matrix.h"
#include "storage/modelslist.h"
#include "trainer_setup.h"
#include "module_setup.h"
#include "timer_setup.h"
#include "trims_setup.h"
#include "throttle_params.h"
#include "preflight_checks.h"
#include <algorithm>
#define SET_DIRTY() storageDirty(EE_MODEL)
std::string switchWarninglabel(swsrc_t index)
{
static const char *switchPositions[] = {
" ",
STR_CHAR_UP,
"-",
STR_CHAR_DOWN,
};
return TEXT_AT_INDEX(STR_VSRCRAW,
(index + MIXSRC_FIRST_SWITCH - MIXSRC_Rud + 1)) +
std::string(
switchPositions[g_model.switchWarningState >> (3 * index) & 0x07]);
}
ModelSetupPage::ModelSetupPage() :
PageTab(STR_MENU_MODEL_SETUP, ICON_MODEL_SETUP)
{
@@ -87,293 +77,133 @@ static void setModelBitmap(std::string newValue)
}
struct ModelBitmapEdit : public FileChoice {
ModelBitmapEdit(FormGroup *parent, const rect_t &rect) :
ModelBitmapEdit(Window *parent, const rect_t &rect) :
FileChoice(parent, rect, BITMAPS_PATH, BITMAPS_EXT,
sizeof(g_model.header.bitmap), getModelBitmap, setModelBitmap)
{
}
};
struct SubScreenButtonMatrix : public ButtonMatrix {
SubScreenButtonMatrix(Window* parent, const rect_t& rect);
void onPress(uint8_t btn_id) override;
bool isActive(uint8_t btn_id) override;
};
static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
LV_GRID_TEMPLATE_LAST};
static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT,
LV_GRID_TEMPLATE_LAST};
void ModelSetupPage::build(FormWindow * window)
{
FormGridLayout grid;
grid.spacer(PAGE_PADDING);
window->setFlexLayout();
FlexGridLayout grid(line_col_dsc, line_row_dsc, 2);
// Model name
new StaticText(window, grid.getLabelSlot(), STR_MODELNAME, 0, COLOR_THEME_PRIMARY1);
new ModelNameEdit(window, grid.getFieldSlot());
grid.nextLine();
auto line = window->newLine(&grid);
new StaticText(line, rect_t{}, STR_MODELNAME, 0, COLOR_THEME_PRIMARY1);
new ModelNameEdit(line, rect_t{});
// Bitmap
new StaticText(window, grid.getLabelSlot(), STR_BITMAP, 0, COLOR_THEME_PRIMARY1);
new ModelBitmapEdit(window, grid.getFieldSlot());
grid.nextLine();
for (uint8_t i = 0; i < TIMERS; i++)
new TimerButton(window, grid.getSlot(3, i), i);
grid.nextLine();
line = window->newLine(&grid);
new StaticText(line, rect_t{}, STR_BITMAP, 0, COLOR_THEME_PRIMARY1);
// TODO: show bitmap thumbnail instead?
new ModelBitmapEdit(line, rect_t{});
// Extended limits
new StaticText(window, grid.getLabelSlot(), STR_ELIMITS, 0, COLOR_THEME_PRIMARY1);
new CheckBox(window, grid.getFieldSlot(), GET_SET_DEFAULT(g_model.extendedLimits));
grid.nextLine();
// Extended trims
new StaticText(window, grid.getLabelSlot(), STR_ETRIMS, 0, COLOR_THEME_PRIMARY1);
new CheckBox(window, grid.getFieldSlot(2, 0), GET_SET_DEFAULT(g_model.extendedTrims));
new TextButton(window, grid.getFieldSlot(2, 1), STR_RESET_BTN,
[]() -> uint8_t {
for (auto &flightModeData : g_model.flightModeData) {
memclear(&flightModeData, TRIMS_ARRAY_SIZE);
}
SET_DIRTY();
AUDIO_WARNING1();
return 0;
});
grid.nextLine();
// Display trims
new StaticText(window, grid.getLabelSlot(), STR_DISPLAY_TRIMS, 0, COLOR_THEME_PRIMARY1);
new Choice(window, grid.getFieldSlot(), "\006No\0 ChangeYes", 0, 2, GET_SET_DEFAULT(g_model.displayTrims));
grid.nextLine();
// Trim step
new StaticText(window, grid.getLabelSlot(), STR_TRIMINC, 0, COLOR_THEME_PRIMARY1);
new Choice(window, grid.getFieldSlot(), STR_VTRIMINC, -2, 2, GET_SET_DEFAULT(g_model.trimInc));
grid.nextLine();
// Throttle parameters
{
new Subtitle(window, grid.getLineSlot(), STR_THROTTLE_LABEL, 0, COLOR_THEME_PRIMARY1);
grid.nextLine();
// Throttle reversed
new StaticText(window, grid.getLabelSlot(true), STR_THROTTLEREVERSE, 0, COLOR_THEME_PRIMARY1);
new CheckBox(window, grid.getFieldSlot(), GET_SET_DEFAULT(g_model.throttleReversed));
grid.nextLine();
// Throttle source
new StaticText(window, grid.getLabelSlot(true), STR_TTRACE, 0, COLOR_THEME_PRIMARY1);
auto sc = new SourceChoice(
window, grid.getFieldSlot(), 0, MIXSRC_LAST_CH,
[=]() { return throttleSource2Source(g_model.thrTraceSrc); },
[=](int16_t src) {
int16_t val = source2ThrottleSource(src);
if (val >= 0) {
g_model.thrTraceSrc = val;
SET_DIRTY();
}
}, 0, COLOR_THEME_PRIMARY1);
sc->setAvailableHandler(isThrottleSourceAvailable);
grid.nextLine();
// Throttle trim
new StaticText(window, grid.getLabelSlot(true), STR_TTRIM, 0, COLOR_THEME_PRIMARY1);
new CheckBox(window, grid.getFieldSlot(), GET_SET_DEFAULT(g_model.thrTrim));
grid.nextLine();
// Throttle trim source
new StaticText(window, grid.getLabelSlot(true), STR_TTRIM_SW, 0, COLOR_THEME_PRIMARY1);
new SourceChoice(
window, grid.getFieldSlot(), MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM,
[=]() { return g_model.getThrottleStickTrimSource(); },
[=](int16_t src) { g_model.setThrottleStickTrimSource(src); }, 0, COLOR_THEME_PRIMARY1);
grid.nextLine();
}
// Preflight parameters
{
new Subtitle(window, grid.getLineSlot(), STR_PREFLIGHT, 0, COLOR_THEME_PRIMARY1);
grid.nextLine();
// Display checklist
new StaticText(window, grid.getLabelSlot(true), STR_CHECKLIST, 0, COLOR_THEME_PRIMARY1);
new CheckBox(window, grid.getFieldSlot(), GET_SET_DEFAULT(g_model.displayChecklist));
grid.nextLine();
// Throttle warning
new StaticText(window, grid.getLabelSlot(true), STR_THROTTLE_WARNING, 0, COLOR_THEME_PRIMARY1);
new CheckBox(window, grid.getFieldSlot(), GET_SET_INVERTED(g_model.disableThrottleWarning));
grid.nextLine();
// Custom Throttle warning
new StaticText(window, grid.getLabelSlot(true), STR_CUSTOM_THROTTLE_WARNING, 0, COLOR_THEME_PRIMARY1);
new CheckBox(window, grid.getFieldSlot(), GET_SET_DEFAULT(g_model.enableCustomThrottleWarning));
grid.nextLine();
// Custom Throttle warning value
new StaticText(window, grid.getLabelSlot(true), STR_CUSTOM_THROTTLE_WARNING_VAL, 0, COLOR_THEME_PRIMARY1);
new NumberEdit(window, grid.getFieldSlot(), -100, 100, GET_SET_DEFAULT(g_model.customThrottleWarningPosition));
grid.nextLine();
// Switches warning
new StaticText(window, grid.getLabelSlot(true), STR_SWITCHWARNING, 0, COLOR_THEME_PRIMARY1);
auto group = new FormGroup(window, grid.getFieldSlot(), FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST);
GridLayout switchesGrid(group);
for (int i = 0, j = 0; i < NUM_SWITCHES; i++) {
if (SWITCH_EXISTS(i)) {
if (j > 0 && (j % 3) == 0)
switchesGrid.nextLine();
auto button = new TextButton(group, switchesGrid.getSlot(3, j % 3), switchWarninglabel(i), nullptr,
OPAQUE | (bfGet(g_model.switchWarningState, 3 * i, 3) == 0 ? 0 : BUTTON_CHECKED));
button->setPressHandler([button, i] {
swarnstate_t newstate = bfGet(g_model.switchWarningState, 3 * i, 3);
if (newstate == 1 && SWITCH_CONFIG(i) != SWITCH_3POS)
newstate = 3;
else
newstate = (newstate + 1) % 4;
g_model.switchWarningState = bfSet(g_model.switchWarningState, newstate, 3 * i, 3);
SET_DIRTY();
button->setText(switchWarninglabel(i));
return newstate > 0;
});
j++;
}
}
grid.addWindow(group);
// Pots and sliders warning
#if NUM_POTS + NUM_SLIDERS
{
new StaticText(window, grid.getLabelSlot(true), STR_POTWARNINGSTATE, 0, COLOR_THEME_PRIMARY1);
new Choice(window, grid.getFieldSlot(), {"OFF", "ON", "AUTO"}, 0, 2,
GET_SET_DEFAULT(g_model.potsWarnMode));
grid.nextLine();
#if (NUM_POTS)
{
new StaticText(window, grid.getLabelSlot(true), STR_POTWARNING, 0, COLOR_THEME_PRIMARY1);
auto group =
new FormGroup(window, grid.getFieldSlot(),
FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST);
GridLayout centerGrid(group);
for (int i = POT_FIRST, j = 0, k = 0; i <= POT_LAST; i++, k++) {
char s[8];
if ((IS_POT(i) || IS_POT_MULTIPOS(i)) && IS_POT_AVAILABLE(i)) {
if (j > 0 && ((j % 4) == 0)) centerGrid.nextLine();
auto button = new TextButton(
group, centerGrid.getSlot(4, j % 4),
getStringAtIndex(s, STR_VSRCRAW, i + 1), nullptr,
OPAQUE | ((g_model.potsWarnEnabled & (1 << k)) ? BUTTON_CHECKED
: 0));
button->setPressHandler([button, k] {
g_model.potsWarnEnabled ^= (1 << k);
if ((g_model.potsWarnMode == POTS_WARN_MANUAL) &&
(g_model.potsWarnEnabled & (1 << k))) {
SAVE_POT_POSITION(k);
}
button->check(g_model.potsWarnEnabled & (1 << k) ? true : false);
SET_DIRTY();
return (g_model.potsWarnEnabled & (1 << k) ? 1 : 0);
});
j++;
} else {
g_model.potsWarnEnabled &= ~(1 << k);
}
}
grid.addWindow(group);
}
#endif
#if (NUM_SLIDERS)
{
new StaticText(window, grid.getLabelSlot(true), STR_SLIDERWARNING, 0, COLOR_THEME_PRIMARY1);
auto group =
new FormGroup(window, grid.getFieldSlot(),
FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST);
GridLayout centerGrid(group);
for (int i = SLIDER_FIRST, j = 0, k = NUM_POTS; i <= SLIDER_LAST; i++, k++) {
char s[8];
if ((IS_SLIDER(i))) {
if (j > 0 && ((j % 4) == 0)) centerGrid.nextLine();
auto *button = new TextButton(
group, centerGrid.getSlot(4, j % 4),
getStringAtIndex(s, STR_VSRCRAW, i + 1), nullptr,
OPAQUE | ((g_model.potsWarnEnabled & (1 << k)) ? BUTTON_CHECKED
: 0));
button->setPressHandler([button, k] {
g_model.potsWarnEnabled ^= (1 << (k));
if ((g_model.potsWarnMode == POTS_WARN_MANUAL) &&
(g_model.potsWarnEnabled & (1 << k))) {
SAVE_POT_POSITION(k);
}
button->check(g_model.potsWarnEnabled & (1 << k) ? true : false);
SET_DIRTY();
return (g_model.potsWarnEnabled & (1 << k) ? 1 : 0);
});
j++;
}
}
grid.addWindow(group);
}
#endif
}
#endif
}
grid.nextLine();
// Center beeps
{
new StaticText(window, grid.getLabelSlot(false), STR_BEEPCTR, 0, COLOR_THEME_PRIMARY1);
auto group = new FormGroup(window, grid.getFieldSlot(), FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST);
GridLayout centerGrid(group);
for (int i = 0, j = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++) {
char s[2];
if (i < NUM_STICKS || (IS_POT_SLIDER_AVAILABLE(i) && !IS_POT_MULTIPOS(i))) { // multipos cannot be centered
if (j > 0 && (j % 6) == 0)
centerGrid.nextLine();
new TextButton(
group, centerGrid.getSlot(6, j % 6),
getStringAtIndex(s, STR_RETA123, i),
[=]() -> uint8_t {
BFBIT_FLIP(g_model.beepANACenter, bfBit<BeepANACenter>(i));
SET_DIRTY();
return (bfSingleBitGet<BeepANACenter>(g_model.beepANACenter, i) ? 1 : 0);
},
OPAQUE | (bfSingleBitGet<BeepANACenter>(g_model.beepANACenter, i)
? BUTTON_CHECKED
: 0));
j++;
}
}
grid.addWindow(group);
}
// TODO: move to "Outputs" screen ?
line = window->newLine(&grid);
new StaticText(line, rect_t{}, STR_ELIMITS, 0, COLOR_THEME_PRIMARY1);
new CheckBox(line, rect_t{}, GET_SET_DEFAULT(g_model.extendedLimits));
// Global functions
new StaticText(window, grid.getLabelSlot(), STR_USE_GLOBAL_FUNCS, 0, COLOR_THEME_PRIMARY1);
new CheckBox(window, grid.getFieldSlot(), GET_SET_INVERTED(g_model.noGlobalFunctions));
grid.nextLine();
line = window->newLine(&grid);
new StaticText(line, rect_t{}, STR_USE_GLOBAL_FUNCS, 0, COLOR_THEME_PRIMARY1);
new CheckBox(line, rect_t{}, GET_SET_INVERTED(g_model.noGlobalFunctions));
{
// Model ADC jitter filter
new StaticText(window, grid.getLabelSlot(), STR_JITTER_FILTER, 0, COLOR_THEME_PRIMARY1);
new Choice(window, grid.getFieldSlot(), STR_ADCFILTERVALUES, 0, 2, GET_SET_DEFAULT(g_model.jitterFilter));
grid.nextLine();
}
// Internal module
{
new Subtitle(window, grid.getLineSlot(), TR_INTERNALRF, 0, COLOR_THEME_PRIMARY1);
grid.nextLine();
grid.addWindow(new ModuleWindow(window, {0, grid.getWindowHeight(), LCD_W, 0}, INTERNAL_MODULE));
}
// External module
{
new Subtitle(window, grid.getLineSlot(), TR_EXTERNALRF, 0, COLOR_THEME_PRIMARY1);
grid.nextLine();
grid.addWindow(new ModuleWindow(window, {0, grid.getWindowHeight(), LCD_W, 0}, EXTERNAL_MODULE));
}
// Trainer
{
new Subtitle(window, grid.getLineSlot(), STR_TRAINER, 0, COLOR_THEME_PRIMARY1);
grid.nextLine();
grid.addWindow(new TrainerModuleWindow(window, {0, grid.getWindowHeight(), LCD_W, 0}));
}
// Model ADC jitter filter
line = window->newLine(&grid);
new StaticText(line, rect_t{}, STR_JITTER_FILTER, 0, COLOR_THEME_PRIMARY1);
new Choice(line, rect_t{}, STR_ADCFILTERVALUES, 0, 2,
GET_SET_DEFAULT(g_model.jitterFilter));
// Sub-screens
new SubScreenButtonMatrix(window, rect_t{});
}
#define MAX_SUBSCREEN_BTNS 9
SubScreenButtonMatrix::SubScreenButtonMatrix(Window* parent, const rect_t& r) :
ButtonMatrix(parent, r)
{
initBtnMap(3, MAX_SUBSCREEN_BTNS);
setText(0, STR_INTERNALRF);
setText(1, STR_EXTERNALRF);
setText(2, STR_TRAINER);
setText(3, STR_PREFLIGHT);
setText(4, STR_TRIMS);
setText(5, STR_THROTTLE_LABEL);
setText(6, TR_TIMER "1");
setText(7, TR_TIMER "2");
setText(8, TR_TIMER "3");
update();
lv_btnmatrix_set_btn_width(lvobj, 3, 2);
lv_obj_set_width(lvobj, lv_pct(100));
lv_obj_set_height(lvobj, (4 * LV_DPI_DEF) / 3);
lv_obj_set_style_bg_opa(lvobj, LV_OPA_0, LV_PART_MAIN);
lv_obj_set_style_pad_all(lvobj, LV_DPI_DEF / 10, LV_PART_MAIN);
lv_obj_remove_style(lvobj, nullptr, LV_PART_MAIN | LV_STATE_FOCUSED);
lv_obj_remove_style(lvobj, nullptr, LV_PART_MAIN | LV_STATE_EDITED);
}
void SubScreenButtonMatrix::onPress(uint8_t btn_id)
{
if (btn_id >= MAX_SUBSCREEN_BTNS) return;
Window* w = nullptr;
switch (btn_id) {
case 0:
w = new ModulePage(INTERNAL_MODULE);
break;
case 1:
w = new ModulePage(EXTERNAL_MODULE);
break;
case 2:
w = new TrainerPage();
break;
case 3:
w = new PreflightChecks();
break;
case 4:
w = new TrimsSetup();
break;
case 5:
w = new ThrottleParams();
break;
default:
w = new TimerWindow((uint8_t)(btn_id - 6));
break;
}
if (w) w->setFocus();
}
bool SubScreenButtonMatrix::isActive(uint8_t btn_id)
{
if (btn_id == 0)
return g_model.moduleData[INTERNAL_MODULE].type > 0;
if (btn_id == 1)
return g_model.moduleData[EXTERNAL_MODULE].type > 0;
if (btn_id == 2)
return g_model.trainerData.mode > 0;
return false;
}
+41
View File
@@ -22,6 +22,11 @@
#include "module_setup.h"
#include "opentx.h"
#include "form.h"
#include "choice.h"
#include "button.h"
#include "gridlayout.h"
#include "mixer_scheduler.h"
#include "multi_rfprotos.h"
#include "io/multi_protolist.h"
@@ -35,6 +40,29 @@
#define SET_DIRTY() storageDirty(EE_MODEL)
class ModuleWindow : public FormGroup
{
public:
ModuleWindow(FormWindow *parent, const rect_t &rect, uint8_t moduleIdx);
protected:
uint8_t moduleIdx;
bool hasFailsafe = false;
Choice *moduleChoice = nullptr;
Choice *rfChoice = nullptr;
TextButton *bindButton = nullptr;
TextButton *rangeButton = nullptr;
TextButton *registerButton = nullptr;
Choice *failSafeChoice = nullptr;
void addChannelRange(FormGridLayout &grid);
void startRSSIDialog(std::function<void()> closeHandler = nullptr);
void update();
void checkEvents() override;
};
ModuleWindow::ModuleWindow(FormWindow *parent, const rect_t &rect,
uint8_t moduleIdx) :
FormGroup(parent, rect, FORWARD_SCROLL | NO_FOCUS | FORM_FORWARD_FOCUS),
@@ -882,3 +910,16 @@ void ModuleWindow::checkEvents()
FormGroup::checkEvents();
}
ModulePage::ModulePage(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP)
{
const char* title = moduleIdx == INTERNAL_MODULE ?
STR_INTERNALRF : STR_EXTERNALRF;
new StaticText(&header,
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
PAGE_LINE_HEIGHT},
title, 0, COLOR_THEME_PRIMARY2);
new ModuleWindow(&body, {0, 0, width(), 0}, moduleIdx);
}
+3 -25
View File
@@ -21,30 +21,8 @@
#pragma once
#include "form.h"
#include "choice.h"
#include "button.h"
#include "gridlayout.h"
#include "page.h"
class ModuleWindow : public FormGroup
{
public:
ModuleWindow(FormWindow *parent, const rect_t &rect, uint8_t moduleIdx);
protected:
uint8_t moduleIdx;
bool hasFailsafe = false;
Choice *moduleChoice = nullptr;
Choice *rfChoice = nullptr;
TextButton *bindButton = nullptr;
TextButton *rangeButton = nullptr;
TextButton *registerButton = nullptr;
Choice *failSafeChoice = nullptr;
void addChannelRange(FormGridLayout &grid);
void startRSSIDialog(std::function<void()> closeHandler = nullptr);
void update();
void checkEvents() override;
struct ModulePage : public Page {
ModulePage(uint8_t moduleIdx);
};
+5
View File
@@ -67,6 +67,11 @@ void Page::deleteLater(bool detach, bool trash)
Window::deleteLater(detach, trash);
}
void Page::setFocus(uint8_t flag, Window * from)
{
body.setFocus(flag, from);
}
void Page::paint(BitmapBuffer * dc)
{
dc->clear(COLOR_THEME_SECONDARY3);
+2
View File
@@ -114,6 +114,8 @@ class Page: public Window
}
#endif
void setFocus(uint8_t flag = SET_FOCUS_DEFAULT, Window * from = nullptr) override;
void paint(BitmapBuffer * dc) override;
protected:
+343
View File
@@ -0,0 +1,343 @@
/*
* 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 "preflight_checks.h"
#include "button_matrix.h"
#include "opentx.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
LV_GRID_TEMPLATE_LAST};
static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT,
LV_GRID_TEMPLATE_LAST};
static void cb_changed(lv_event_t* e)
{
auto target = lv_event_get_target(e);
auto obj = (lv_obj_t*)lv_event_get_user_data(e);
if (lv_obj_has_state(target, LV_STATE_CHECKED)) {
lv_obj_clear_flag(obj, LV_OBJ_FLAG_HIDDEN);
} else {
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
}
}
static void make_conditional(Window* w, CheckBox* cb)
{
lv_obj_t* w_obj = w->getLvObj();
if (!cb->getValue()) { lv_obj_add_flag(w_obj, LV_OBJ_FLAG_HIDDEN); }
lv_obj_t* cb_obj = cb->getLvObj();
lv_obj_add_event_cb(cb_obj, cb_changed, LV_EVENT_VALUE_CHANGED, w_obj);
}
static void choice_changed(lv_event_t* e)
{
auto target = lv_event_get_target(e);
auto choice = (Choice*)lv_obj_get_user_data(target);
auto obj = (lv_obj_t*)lv_event_get_user_data(e);
if (choice->getIntValue() != 0) {
lv_obj_clear_flag(obj, LV_OBJ_FLAG_HIDDEN);
} else {
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
}
}
static void make_conditional(Window* w, Choice* choice)
{
lv_obj_t* w_obj = w->getLvObj();
if (choice->getIntValue() == 0) { lv_obj_add_flag(w_obj, LV_OBJ_FLAG_HIDDEN); }
lv_obj_t* choice_obj = choice->getLvObj();
lv_obj_add_event_cb(choice_obj, choice_changed, LV_EVENT_VALUE_CHANGED, w_obj);
}
struct SwitchWarnMatrix : public ButtonMatrix {
SwitchWarnMatrix(Window* parent, const rect_t& rect);
void onPress(uint8_t btn_id);
bool isActive(uint8_t btn_id);
};
struct PotWarnMatrix : public ButtonMatrix {
PotWarnMatrix(Window* parent, const rect_t& rect);
void onPress(uint8_t btn_id);
bool isActive(uint8_t btn_id);
};
PreflightChecks::PreflightChecks() : Page(ICON_MODEL_SETUP)
{
new StaticText(&header,
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
PAGE_LINE_HEIGHT},
STR_PREFLIGHT, 0, COLOR_THEME_PRIMARY2);
auto form = new FormWindow(&body, rect_t{0, 0, body.width(), body.height()},
NO_FOCUS | FORM_FORWARD_FOCUS);
form->setFlexLayout();
FlexGridLayout grid(line_col_dsc, line_row_dsc, 2);
// Display checklist
auto line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_CHECKLIST, 0, COLOR_THEME_PRIMARY1);
new CheckBox(line, rect_t{}, GET_SET_DEFAULT(g_model.displayChecklist));
// Throttle warning
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_THROTTLE_WARNING, 0, COLOR_THEME_PRIMARY1);
auto tw = new CheckBox(line, rect_t{}, GET_SET_INVERTED(g_model.disableThrottleWarning));
// Custom Throttle warning (conditional on previous field)
line = form->newLine(&grid);
make_conditional(line, tw);
new StaticText(line, rect_t{}, STR_CUSTOM_THROTTLE_WARNING, 0, COLOR_THEME_PRIMARY1);
auto box = new FormGroup::Line(line, lv_obj_create(line->getLvObj()), nullptr, form);
lv_obj_set_layout(box->getLvObj(), LV_LAYOUT_FLEX);
auto cst_tw = new CheckBox(
box, rect_t{}, GET_SET_DEFAULT(g_model.enableCustomThrottleWarning));
// Custom Throttle warning value
auto cst_val =
new NumberEdit(box, rect_t{}, -100, 100,
GET_SET_DEFAULT(g_model.customThrottleWarningPosition));
make_conditional(cst_val, cst_tw);
// Switch warnings (TODO: add display switch?)
new SwitchWarnMatrix(form, rect_t{});
// Pots and sliders warning
#if NUM_POTS + NUM_SLIDERS
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_POTWARNINGSTATE, 0, COLOR_THEME_PRIMARY1);
auto pots_wm = new Choice(line, rect_t{}, {"OFF", "ON", "AUTO"}, 0, 2,
GET_SET_DEFAULT(g_model.potsWarnMode));
#if (NUM_POTS)
// Pot warnings
auto pwm = new PotWarnMatrix(form, rect_t{});
make_conditional(pwm, pots_wm);
#endif
// #if (NUM_SLIDERS)
// {
// new StaticText(window, grid.getLabelSlot(true), STR_SLIDERWARNING, 0,
// COLOR_THEME_PRIMARY1);
// auto group = new FormGroup(window, grid.getFieldSlot(),
// FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST);
// GridLayout centerGrid(group);
// for (int i = SLIDER_FIRST, j = 0, k = NUM_POTS; i <= SLIDER_LAST;
// i++, k++) {
// char s[8];
// if ((IS_SLIDER(i))) {
// if (j > 0 && ((j % 4) == 0)) centerGrid.nextLine();
// auto *button = new TextButton(
// group, centerGrid.getSlot(4, j % 4),
// getStringAtIndex(s, STR_VSRCRAW, i + 1), nullptr,
// OPAQUE |
// ((g_model.potsWarnEnabled & (1 << k)) ? BUTTON_CHECKED : 0));
// button->setPressHandler([button, k] {
// g_model.potsWarnEnabled ^= (1 << (k));
// if ((g_model.potsWarnMode == POTS_WARN_MANUAL) &&
// (g_model.potsWarnEnabled & (1 << k))) {
// SAVE_POT_POSITION(k);
// }
// button->check(g_model.potsWarnEnabled & (1 << k) ? true : false);
// SET_DIRTY();
// return (g_model.potsWarnEnabled & (1 << k) ? 1 : 0);
// });
// j++;
// }
// }
// grid.addWindow(group);
// }
// #endif
// }
#endif
// // Center beeps
// {
// new StaticText(window, grid.getLabelSlot(false), STR_BEEPCTR, 0,
// COLOR_THEME_PRIMARY1);
// auto group = new FormGroup(window, grid.getFieldSlot(),
// FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST);
// GridLayout centerGrid(group);
// for (int i = 0, j = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++) {
// char s[2];
// if (i < NUM_STICKS ||
// (IS_POT_SLIDER_AVAILABLE(i) &&
// !IS_POT_MULTIPOS(i))) { // multipos cannot be centered
// if (j > 0 && (j % 6) == 0) centerGrid.nextLine();
// new TextButton(
// group, centerGrid.getSlot(6, j % 6),
// getStringAtIndex(s, STR_RETA123, i),
// [=]() -> uint8_t {
// BFBIT_FLIP(g_model.beepANACenter, bfBit<BeepANACenter>(i));
// SET_DIRTY();
// return (bfSingleBitGet<BeepANACenter>(g_model.beepANACenter, i)
// ? 1
// : 0);
// },
// OPAQUE | (bfSingleBitGet<BeepANACenter>(g_model.beepANACenter, i)
// ? BUTTON_CHECKED
// : 0));
// j++;
// }
// }
// grid.addWindow(group);
// }
}
// // Max 12 switches
// #define MAX_SW_WARN 12
// static const char* sw_warn_map[] = {
// "0", "1", "2", "3", "\n",
// "4", "5", "6", "7", "\n",
// "8", "9", "0", "1", ""
// };
// static_assert(NUM_SWITCHES <= MAX_SW_WARN, "Max 12 switches supported");
static std::string switchWarninglabel(swsrc_t index)
{
auto warn_pos = g_model.switchWarningState >> (3 * index) & 0x07;
return TEXT_AT_INDEX(STR_VSRCRAW,
(index + MIXSRC_FIRST_SWITCH - MIXSRC_Rud + 1)) +
std::string(getSwitchWarnSymbol(warn_pos));
}
SwitchWarnMatrix::SwitchWarnMatrix(Window* parent, const rect_t& r) :
ButtonMatrix(parent, r)
{
// Setup button layout & texts
uint8_t btn_cnt = 0;
for (uint8_t i = 0; i < NUM_SWITCHES; i++)
if (SWITCH_EXISTS(i)) btn_cnt++;
initBtnMap(4, btn_cnt);
for (uint8_t i = 0; i < NUM_SWITCHES; i++) {
if (SWITCH_EXISTS(i)) {
std::string txt = switchWarninglabel(i);
setText(i, txt.c_str());
}
}
update();
lv_obj_set_width(lvobj, LV_DPI_DEF * 2);
uint8_t rows = ((btn_cnt - 1) / 4) + 1;
lv_obj_set_height(lvobj, (rows * LV_DPI_DEF) / 3);
lv_obj_set_style_bg_opa(lvobj, LV_OPA_0, LV_PART_MAIN);
lv_obj_set_style_pad_all(lvobj, 4, LV_PART_MAIN);
lv_obj_set_style_pad_left(lvobj, LV_DPI_DEF / 10, LV_PART_MAIN);
lv_obj_set_style_pad_row(lvobj, 4, LV_PART_MAIN);
lv_obj_set_style_pad_column(lvobj, 4, LV_PART_MAIN);
lv_obj_remove_style(lvobj, nullptr, LV_PART_MAIN | LV_STATE_FOCUSED);
lv_obj_remove_style(lvobj, nullptr, LV_PART_MAIN | LV_STATE_EDITED);
}
void SwitchWarnMatrix::onPress(uint8_t btn_id)
{
if (btn_id >= NUM_SWITCHES) return;
swarnstate_t newstate = bfGet(g_model.switchWarningState, 3 * btn_id, 3);
if (newstate == 1 && SWITCH_CONFIG(btn_id) != SWITCH_3POS)
newstate = 3;
else
newstate = (newstate + 1) % 4;
g_model.switchWarningState =
bfSet(g_model.switchWarningState, newstate, 3 * btn_id, 3);
SET_DIRTY();
// TODO: save state in object
std::string txt = switchWarninglabel(btn_id);
setText(btn_id, txt.c_str());
}
bool SwitchWarnMatrix::isActive(uint8_t btn_id)
{
return bfGet(g_model.switchWarningState, 3 * btn_id, 3) != 0;
}
PotWarnMatrix::PotWarnMatrix(Window* parent, const rect_t& r) :
ButtonMatrix(parent, r)
{
// Setup button layout & texts
uint8_t btn_cnt = 0;
for (uint16_t i = POT_FIRST; i <= POT_LAST; i++) {
if ((IS_POT(i) || IS_POT_MULTIPOS(i)) && IS_POT_AVAILABLE(i)) btn_cnt++;
}
initBtnMap(3, btn_cnt);
uint8_t btn_id = 0;
for (uint16_t i = POT_FIRST; i <= POT_LAST; i++) {
if ((IS_POT(i) || IS_POT_MULTIPOS(i)) && IS_POT_AVAILABLE(i)) {
setText(btn_id, STR_VSRCRAW[btn_id + POT_FIRST + 1]);
btn_id++;
}
}
update();
lv_obj_set_width(lvobj, (LV_DPI_DEF * 3) / 2);
uint8_t rows = ((btn_cnt - 1) / 4) + 1;
lv_obj_set_height(lvobj, (rows * LV_DPI_DEF) / 3);
lv_obj_set_style_bg_opa(lvobj, LV_OPA_0, LV_PART_MAIN);
lv_obj_set_style_pad_all(lvobj, 4, LV_PART_MAIN);
lv_obj_set_style_pad_left(lvobj, LV_DPI_DEF / 10, LV_PART_MAIN);
lv_obj_set_style_pad_row(lvobj, 4, LV_PART_MAIN);
lv_obj_set_style_pad_column(lvobj, 4, LV_PART_MAIN);
lv_obj_remove_style(lvobj, nullptr, LV_PART_MAIN | LV_STATE_FOCUSED);
lv_obj_remove_style(lvobj, nullptr, LV_PART_MAIN | LV_STATE_EDITED);
}
void PotWarnMatrix::onPress(uint8_t btn_id)
{
if (btn_id >= NUM_POTS) return;
g_model.potsWarnEnabled ^= (1 << btn_id);
if ((g_model.potsWarnMode == POTS_WARN_MANUAL) &&
(g_model.potsWarnEnabled & (1 << btn_id))) {
SAVE_POT_POSITION(btn_id);
}
SET_DIRTY();
}
bool PotWarnMatrix::isActive(uint8_t btn_id)
{
return (g_model.potsWarnEnabled & (1 << btn_id)) != 0;
}
+28
View File
@@ -0,0 +1,28 @@
/*
* 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"
struct PreflightChecks : public Page {
PreflightChecks();
};
@@ -0,0 +1,91 @@
/*
* 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 "throttle_params.h"
#include "opentx.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
LV_GRID_TEMPLATE_LAST};
static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT,
LV_GRID_TEMPLATE_LAST};
static int16_t getThrottleSource()
{
return throttleSource2Source(g_model.thrTraceSrc);
}
static void setThrottleSource(int16_t src)
{
int16_t val = source2ThrottleSource(src);
if (val >= 0) {
g_model.thrTraceSrc = val;
SET_DIRTY();
}
}
static int16_t getThrottleTrimSource()
{
return g_model.getThrottleStickTrimSource();
}
static void setThrottleTrimSource(int16_t src)
{
g_model.setThrottleStickTrimSource(src);
}
ThrottleParams::ThrottleParams() : Page(ICON_MODEL_SETUP)
{
new StaticText(&header,
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
PAGE_LINE_HEIGHT},
STR_THROTTLE_LABEL, 0, COLOR_THEME_PRIMARY2);
body.setFlexLayout();
FlexGridLayout grid(line_col_dsc, line_row_dsc, 2);
// Throttle reversed
auto line = body.newLine(&grid);
new StaticText(line, rect_t{}, STR_THROTTLEREVERSE, 0, COLOR_THEME_PRIMARY1);
new CheckBox(line, rect_t{}, GET_SET_DEFAULT(g_model.throttleReversed));
// Throttle source
line = body.newLine(&grid);
new StaticText(line, rect_t{}, STR_TTRACE, 0, COLOR_THEME_PRIMARY1);
auto sc = new SourceChoice(line, rect_t{}, 0, MIXSRC_LAST_CH,
getThrottleSource, setThrottleSource,
0, COLOR_THEME_PRIMARY1);
sc->setAvailableHandler(isThrottleSourceAvailable);
// Throttle trim
line = body.newLine(&grid);
new StaticText(line, rect_t{}, STR_TTRIM, 0, COLOR_THEME_PRIMARY1);
new CheckBox(line, rect_t{}, GET_SET_DEFAULT(g_model.thrTrim));
// Throttle trim source
line = body.newLine(&grid);
new StaticText(line, rect_t{}, STR_TTRIM_SW, 0, COLOR_THEME_PRIMARY1);
new SourceChoice(
line, rect_t{}, MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM,
getThrottleTrimSource, setThrottleTrimSource, 0,
COLOR_THEME_PRIMARY1);
}
+28
View File
@@ -0,0 +1,28 @@
/*
* 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"
struct ThrottleParams : public Page {
ThrottleParams();
};
-10
View File
@@ -24,16 +24,6 @@
#define SET_DIRTY() storageDirty(EE_MODEL)
TimerButton::TimerButton(Window* parent, const rect_t& rect, uint8_t timer) :
TextButton(parent, rect, std::string(STR_TIMER) + std::to_string(timer + 1))
{
// TODO: add start time
setPressHandler([=]() {
new TimerWindow(timer);
return false;
});
}
// TODO: translation
const char* STR_TIMER_MODES[] = {"OFF", "ON", "Start",
"Throttle", "Throttle %", "Throttle Start"};
-5
View File
@@ -22,11 +22,6 @@
#pragma once
#include "page.h"
#include "button.h"
struct TimerButton : public TextButton {
TimerButton(Window* parent, const rect_t& rect, uint8_t timer);
};
struct TimerWindow : public Page {
TimerWindow(uint8_t timer);
+53
View File
@@ -24,6 +24,49 @@
#define SET_DIRTY() storageDirty(EE_MODEL)
#include "form.h"
#include "menu.h"
#include "static.h"
#include "button.h"
#include "numberedit.h"
#if defined(BLUETOOTH)
#include "bluetooth.h"
#endif
class TrChoice;
class TrainerModuleWindow : public FormGroup
{
public:
TrainerModuleWindow(FormWindow *parent, const rect_t &rect);
void checkEvents() override;
void update();
protected:
TrChoice *trainerChoice = nullptr;
NumberEdit *channelStart = nullptr;
NumberEdit *channelEnd = nullptr;
bool trChoiceOpen = false;
#if defined(BLUETOOTH)
StaticText *btChannelEnd = nullptr;
StaticText *btDistAddress = nullptr;
TextButton *btMasterButton = nullptr;
Menu *btPopUpMenu = nullptr;
bool btCanceled = false;
private:
bool popupopen = false;
int devicecount = 0;
uint8_t lastbluetoothstate = BLUETOOTH_STATE_OFF;
void btDiscoverMenuItemChosen();
void btDiscoverMenuAddItem(const char *itm);
#endif
};
class TrChoice : public Choice
{
public:
@@ -283,3 +326,13 @@ void TrainerModuleWindow::btDiscoverMenuAddItem(const char *itm)
itm, std::bind(&TrainerModuleWindow::btDiscoverMenuItemChosen, this));
}
#endif
TrainerPage::TrainerPage() : Page(ICON_MODEL_SETUP)
{
new StaticText(&header,
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
PAGE_LINE_HEIGHT},
STR_TRAINER, 0, COLOR_THEME_PRIMARY2);
new TrainerModuleWindow(&body, {0, 0, width(), 0});
}
+3 -40
View File
@@ -21,45 +21,8 @@
#pragma once
#include "form.h"
#include "menu.h"
#include "static.h"
#include "button.h"
#include "numberedit.h"
#include "page.h"
#if defined(BLUETOOTH)
#include "bluetooth.h"
#endif
class TrChoice;
class TrainerModuleWindow : public FormGroup
{
public:
TrainerModuleWindow(FormWindow *parent, const rect_t &rect);
void checkEvents() override;
void update();
protected:
TrChoice *trainerChoice = nullptr;
NumberEdit *channelStart = nullptr;
NumberEdit *channelEnd = nullptr;
bool trChoiceOpen = false;
#if defined(BLUETOOTH)
StaticText *btChannelEnd = nullptr;
StaticText *btDistAddress = nullptr;
TextButton *btMasterButton = nullptr;
Menu *btPopUpMenu = nullptr;
bool btCanceled = false;
private:
bool popupopen = false;
int devicecount = 0;
uint8_t lastbluetoothstate = BLUETOOTH_STATE_OFF;
void btDiscoverMenuItemChosen();
void btDiscoverMenuAddItem(const char *itm);
#endif
struct TrainerPage: public Page {
TrainerPage();
};
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "trims_setup.h"
#include "opentx.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
LV_GRID_TEMPLATE_LAST};
static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT,
LV_GRID_TEMPLATE_LAST};
static void resetTrims()
{
for (auto &fm : g_model.flightModeData) memclear(&fm.trim, sizeof(fm.trim));
SET_DIRTY();
AUDIO_WARNING1();
}
TrimsSetup::TrimsSetup() : Page(ICON_MODEL_SETUP)
{
new StaticText(&header,
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
PAGE_LINE_HEIGHT},
STR_TRIMS, 0, COLOR_THEME_PRIMARY2);
body.setFlexLayout();
FlexGridLayout grid(line_col_dsc, line_row_dsc, 2);
// Trim step
auto line = body.newLine(&grid);
new StaticText(line, rect_t{}, STR_TRIMINC, 0,
COLOR_THEME_PRIMARY1);
new Choice(line, rect_t{}, STR_VTRIMINC, -2, 2,
GET_SET_DEFAULT(g_model.trimInc));
// Extended trims
line = body.newLine(&grid);
new StaticText(line, rect_t{}, STR_ETRIMS, 0, COLOR_THEME_PRIMARY1);
new CheckBox(line, rect_t{}, GET_SET_DEFAULT(g_model.extendedTrims));
// Reset trims
line = body.newLine(&grid);
new TextButton(line, rect_t{}, STR_RESET_BTN, []() -> uint8_t {
resetTrims();
return 0;
});
// Display trims
// TODO: move to "Screen setup" ?
line = body.newLine(&grid);
new StaticText(line, rect_t{}, STR_DISPLAY_TRIMS, 0, COLOR_THEME_PRIMARY1);
new Choice(line, rect_t{}, STR_VDISPLAYTRIMS, 0, 2,
GET_SET_DEFAULT(g_model.displayTrims));
}
+28
View File
@@ -0,0 +1,28 @@
/*
* 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"
struct TrimsSetup : public Page {
TrimsSetup();
};
+1 -1
View File
@@ -1001,7 +1001,7 @@ const char* STR_SUBTYPE_HUBSAN[] = {"H107","H301","H501"};
const char* STR_SUBTYPE_FRSKY[] = {"D16","D8","D16 8ch","V8","LBT(EU)","LBT 8ch","D8Cloned","D16Cloned"};
const char* STR_SUBTYPE_HISKY[] = {"Std","HK310"};
const char* STR_SUBTYPE_V2X2[] = {"Std","JXD506","MR101"};
const char* STR_SUBTYPE_DSM[] = {"2 1F","2 2F","X 1F,""X 2F,""Auto","R 1F"};
const char* STR_SUBTYPE_DSM[] = {"2 1F","2 2F","X 1F","X 2F","Auto","R 1F"};
const char* STR_SUBTYPE_DEVO[] = {"8ch","10ch","12ch","6ch","7ch"};
const char* STR_SUBTYPE_YD717[] = {"Std","SkyWlkr","Syma X4","XINXUN","NIHUI"};
const char* STR_SUBTYPE_KN[] = {"WLtoys","FeiLun"};