Input & Mixer edit pages: flex layout rework

This commit is contained in:
Raphael Coeffic
2022-06-11 15:38:08 +02:00
committed by Raphael Coeffic
parent c418758863
commit e31a1cc1fc
26 changed files with 1093 additions and 598 deletions
+6
View File
@@ -167,8 +167,14 @@ add_gui_src(curve.cpp)
add_gui_src(sourcechoice.cpp)
add_gui_src(switchchoice.cpp)
add_gui_src(curveedit.cpp)
add_gui_src(gvar_numberedit.cpp)
add_gui_src(curve_param.cpp)
add_gui_src(fm_matrix.cpp)
add_gui_src(input_source.cpp)
add_gui_src(input_edit.cpp)
add_gui_src(input_edit_adv.cpp)
add_gui_src(mixer_edit.cpp)
add_gui_src(mixer_edit_adv.cpp)
add_gui_src(output_edit.cpp)
add_gui_src(input_mix_group.cpp)
add_gui_src(input_mix_button.cpp)
+6 -1
View File
@@ -51,7 +51,11 @@ class Curve: public Window
{
// will always force a full window refresh
if (position) {
invalidate();
// int pos = position();
// if (pos != lastPos) {
// lastPos = pos;
invalidate();
// }
}
Window::checkEvents();
@@ -64,6 +68,7 @@ class Curve: public Window
void paint(BitmapBuffer * dc) override;
protected:
// int lastPos = 0;
std::function<int(int)> function;
std::function<int()> position;
std::list<CurvePoint> points;
+123
View File
@@ -0,0 +1,123 @@
/*
* 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 "curve_param.h"
#include "gvar_numberedit.h"
#include "model_curves.h"
#include "opentx.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
static const char *_curve_type[] = {"Diff", "Expo", "Func", "Cstm"};
void CurveParam::value_changed(lv_event_t* e)
{
auto obj = lv_event_get_target(e);
auto param = (CurveParam*)lv_obj_get_user_data(obj);
if (!param) return;
param->update();
}
CurveParam::CurveParam(Window* parent, const rect_t& rect, CurveRef* ref) :
Window(parent, rect),
ref(ref)
{
lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW_WRAP);
lv_obj_set_style_pad_column(lvobj, lv_dpx(4), 0);
lv_obj_set_style_flex_cross_place(lvobj, LV_FLEX_ALIGN_CENTER, 0);
lv_obj_set_size(lvobj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
new Choice(this, rect_t{}, _curve_type, 0,
CURVE_REF_CUSTOM, GET_DEFAULT(ref->type),
[=](int32_t newValue) {
ref->type = newValue;
ref->value = 0;
SET_DIRTY();
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
});
lv_obj_add_event_cb(lvobj, CurveParam::value_changed, LV_EVENT_VALUE_CHANGED,
nullptr);
// CURVE_REF_DIFF
// CURVE_REF_EXPO
value_edit = new GVarNumberEdit(this, rect_t{}, -100, 100,
GET_SET_DEFAULT(ref->value));
value_edit->setSuffix("%");
// CURVE_REF_FUNC
func_choice = new Choice(this, rect_t{}, STR_VCURVEFUNC, 0, CURVE_BASE - 1,
GET_SET_DEFAULT(ref->value));
// CURVE_REF_CUSTOM
cust_choice = new ChoiceEx(this, rect_t{}, -MAX_CURVES, MAX_CURVES,
GET_SET_DEFAULT(ref->value));
cust_choice->setTextHandler([](int value) { return getCurveString(value); });
cust_choice->setLongPressHandler([ref](event_t event) {
// if no curve is specified then dont link to curve page
if (ref->value != 0) ModelCurvesPage::pushEditCurve(abs(ref->value) - 1);
});
update();
}
void CurveParam::update()
{
bool has_focus = act_field && act_field->hasFocus();
auto value_obj = value_edit->getLvObj();
auto func_obj = func_choice->getLvObj();
auto cust_obj = cust_choice->getLvObj();
lv_obj_add_flag(value_obj, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(func_obj, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(cust_obj, LV_OBJ_FLAG_HIDDEN);
switch(ref->type) {
case CURVE_REF_DIFF:
case CURVE_REF_EXPO:
lv_obj_clear_flag(value_obj, LV_OBJ_FLAG_HIDDEN);
act_field = value_edit;
break;
case CURVE_REF_FUNC:
lv_obj_clear_flag(func_obj, LV_OBJ_FLAG_HIDDEN);
act_field = func_choice;
break;
case CURVE_REF_CUSTOM:
lv_obj_clear_flag(cust_obj, LV_OBJ_FLAG_HIDDEN);
act_field = cust_choice;
break;
default:
return;
}
auto act_obj = act_field->getLvObj();
if (has_focus) {
lv_group_focus_obj(act_obj);
}
lv_event_send(act_obj, LV_EVENT_VALUE_CHANGED, nullptr);
}
+49
View File
@@ -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 "window.h"
struct CurveRef;
class GVarNumberEdit;
class Choice;
class ChoiceEx;
class CurveParam : public Window
{
// Curve
CurveRef* ref;
// Controls
GVarNumberEdit* value_edit;
Choice* func_choice;
ChoiceEx* cust_choice;
Window* act_field = nullptr;
void update();
static void value_changed(lv_event_t* e);
public:
CurveParam(Window* parent, const rect_t& rect, CurveRef* ref);
};
+67
View File
@@ -0,0 +1,67 @@
/*
* 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 "fm_matrix.h"
#include "opentx.h"
template<class T>
FMMatrix<T>::FMMatrix(Window* parent, const rect_t& r, T* input) :
ButtonMatrix(parent, r), input(input)
{
initBtnMap(3, MAX_FLIGHT_MODES);
for (int i = 0; i < MAX_FLIGHT_MODES; i++) {
setText(i, std::to_string(i).c_str());
}
update();
lv_obj_set_width(lvobj, LV_DPI_DEF * 2);
lv_obj_set_width(lvobj, LV_DPI_DEF);
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);
}
template<class T>
void FMMatrix<T>::onPress(uint8_t btn_id)
{
if (btn_id >= MAX_FLIGHT_MODES) return;
BFBIT_FLIP(input->flightModes, bfBit<uint32_t>(btn_id));
storageDirty(EE_MODEL);
}
template<class T>
bool FMMatrix<T>::isActive(uint8_t btn_id)
{
if (btn_id >= MAX_FLIGHT_MODES) return false;
return !bfSingleBitGet(input->flightModes, btn_id);
}
// explicit instantiation
template struct FMMatrix<ExpoData>;
template struct FMMatrix<MixData>;
+38
View File
@@ -0,0 +1,38 @@
/*
* 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 "button_matrix.h"
struct ExpoData;
struct MixData;
template<class T>
struct FMMatrix : public ButtonMatrix {
T* input;
FMMatrix(Window* parent, const rect_t& rect, T* input);
void onPress(uint8_t btn_id);
bool isActive(uint8_t btn_id);
};
extern template struct FMMatrix<ExpoData>;
extern template struct FMMatrix<MixData>;
+146
View File
@@ -0,0 +1,146 @@
/*
* 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 "gvar_numberedit.h"
#include "opentx.h"
void GVarNumberEdit::value_changed(lv_event_t* e)
{
auto obj = lv_event_get_target(e);
auto edit = (GVarNumberEdit*)lv_obj_get_user_data(obj);
if (!edit) return;
edit->update();
}
GVarNumberEdit::GVarNumberEdit(Window* parent, const rect_t& rect, int32_t vmin,
int32_t vmax, std::function<int32_t()> getValue,
std::function<void(int32_t)> setValue,
LcdFlags textFlags, int32_t voffset) :
Window(parent, rect),
vmin(vmin),
vmax(vmax),
getValue(getValue),
setValue(setValue),
textFlags(textFlags),
voffset(voffset)
{
lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW_WRAP);
lv_obj_set_style_pad_column(lvobj, lv_dpx(4), 0);
lv_obj_set_style_flex_cross_place(lvobj, LV_FLEX_ALIGN_CENTER, 0);
lv_obj_set_size(lvobj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
// GVAR field
gvar_field = new Choice(
this, rect_t{}, -MAX_GVARS, MAX_GVARS - 1,
[=]() {
uint16_t gvar1 = GV_GET_GV1_VALUE(vmin, vmax);
return GV_INDEX_CALC_DELTA(getValue(), gvar1);
},
[=](int idx) {
uint16_t gvar1 = GV_GET_GV1_VALUE(vmin, vmax);
if (idx < 0)
setValue(GV_CALC_VALUE_IDX_NEG(idx, gvar1));
else
setValue(GV_CALC_VALUE_IDX_POS(idx, gvar1));
});
gvar_field->setTextHandler(
[=](int32_t value) { return getGVarString(value); });
num_field = new NumberEdit(
this, rect_t{}, vmin, vmax, [=]() { return getValue() + voffset; },
[=](int32_t newValue) { return setValue(newValue - voffset); },
windowFlags, textFlags);
#if defined(GVARS)
// The GVAR button
auto btn = new TextButton(this, rect_t{}, STR_GV, [=]() {
switchGVarMode();
return 0;
});
lv_obj_set_height(btn->getLvObj(), lv_obj_get_height(gvar_field->getLvObj()));
#endif
lv_obj_add_event_cb(lvobj, GVarNumberEdit::value_changed,
LV_EVENT_VALUE_CHANGED, nullptr);
// update field type based on value
update();
}
void GVarNumberEdit::switchGVarMode()
{
int32_t value = getValue();
setValue(
GV_IS_GV_VALUE(value, vmin, vmax)
? ((textFlags & PREC1)
? GET_GVAR_PREC1(value, vmin, vmax, mixerCurrentFlightMode)
: GET_GVAR(value, vmin, vmax, mixerCurrentFlightMode))
: GV_GET_GV1_VALUE(vmin, vmax));
// update field type based on value
update();
}
void GVarNumberEdit::setSuffix(std::string value)
{
num_field->setSuffix(value);
}
void GVarNumberEdit::onEvent(event_t event)
{
if (event == EVT_KEY_LONG(KEY_ENTER)) {
// TODO: check this...
// killEvents(event);
switchGVarMode();
} else {
Window::onEvent(event);
}
}
void GVarNumberEdit::update()
{
bool has_focus = act_field && act_field->hasFocus();
auto gvar_obj = gvar_field->getLvObj();
auto num_obj = num_field->getLvObj();
lv_obj_add_flag(gvar_obj, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(num_obj, LV_OBJ_FLAG_HIDDEN);
int32_t value = getValue();
if (GV_IS_GV_VALUE(value, vmin, vmax)) {
// GVAR mode
act_field = gvar_field;
lv_obj_clear_flag(gvar_obj, LV_OBJ_FLAG_HIDDEN);
lv_event_send(gvar_obj, LV_EVENT_VALUE_CHANGED, nullptr);
} else {
// number edit mode
act_field = num_field;
lv_obj_clear_flag(num_obj, LV_OBJ_FLAG_HIDDEN);
num_field->setValue(value);
}
if (has_focus) {
auto act_obj = act_field->getLvObj();
lv_group_focus_obj(act_obj);
}
}
+14 -98
View File
@@ -29,117 +29,33 @@
constexpr coord_t GVAR_BUTTON_WIDTH = 30;
class GVarNumberEdit : public FormGroup
class GVarNumberEdit : public Window
{
public:
GVarNumberEdit(FormGroup* parent, const rect_t& rect, int32_t vmin,
int32_t vmax, std::function<int32_t()> getValue,
GVarNumberEdit(Window* parent, const rect_t& rect, int32_t vmin, int32_t vmax,
std::function<int32_t()> getValue,
std::function<void(int32_t)> setValue,
WindowFlags windowFlags = 0, LcdFlags textFlags = 0,
int32_t voffset = 0) :
FormGroup(parent, rect, FORWARD_SCROLL /*| FORM_FORWARD_FOCUS*/),
vmin(vmin),
vmax(vmax),
voffset(voffset),
getValue(getValue),
setValue(setValue),
windowFlags(windowFlags),
textFlags(textFlags)
{
update();
}
LcdFlags textFlags = 0, int32_t voffset = 0);
void switchGVarMode()
{
int32_t value = getValue();
setValue(
GV_IS_GV_VALUE(value, vmin, vmax)
? ((textFlags & PREC1)
? GET_GVAR_PREC1(value, vmin, vmax, mixerCurrentFlightMode)
: GET_GVAR(value, vmin, vmax, mixerCurrentFlightMode))
: GV_GET_GV1_VALUE(vmin, vmax));
update();
}
void setSuffix(std::string value)
{
suffix = std::move(value);
update();
}
#if defined(HARDWARE_KEYS)
void onEvent(event_t event) override
{
if (event == EVT_KEY_LONG(KEY_ENTER)) {
// TODO: check this...
// killEvents(event);
switchGVarMode();
// field->setFocus(SET_FOCUS_DEFAULT);
} else {
FormGroup::onEvent(event);
}
}
#endif
void switchGVarMode();
void setSuffix(std::string value);
protected:
FormField* field = nullptr;
Choice* gvar_field = nullptr;
NumberEdit* num_field = nullptr;
FormField* act_field = nullptr;
int32_t vmin;
int32_t vmax;
int32_t voffset;
std::function<int32_t()> getValue;
std::function<void(int32_t)> setValue;
WindowFlags windowFlags;
LcdFlags textFlags;
std::string suffix;
int32_t voffset;
void update()
{
clear();
void onEvent(event_t event) override;
void update();
// The main field
int32_t value = getValue();
if (GV_IS_GV_VALUE(value, vmin, vmax)) {
auto result = new Choice(
this, {0, 0, width() - GVAR_BUTTON_WIDTH, height()}, -MAX_GVARS,
MAX_GVARS - 1,
[=]() {
uint16_t gvar1 = GV_GET_GV1_VALUE(vmin, vmax);
return GV_INDEX_CALC_DELTA(getValue(), gvar1);
},
[=](int idx) {
uint16_t gvar1 = GV_GET_GV1_VALUE(vmin, vmax);
if (idx < 0)
setValue(GV_CALC_VALUE_IDX_NEG(idx, gvar1));
else
setValue(GV_CALC_VALUE_IDX_POS(idx, gvar1));
});
result->setTextHandler(
[=](int32_t value) { return getGVarString(value); });
field = result;
} else {
auto result = new NumberEdit(
this, {0, 0, width() - GVAR_BUTTON_WIDTH, height()}, vmin, vmax,
[=]() { return getValue() + voffset; },
[=](int32_t newValue) { return setValue(newValue - voffset); },
windowFlags, textFlags);
result->setSuffix(suffix);
field = result;
}
#if defined(GVARS)
// The GVAR button
new TextButton(
this, {width() - GVAR_BUTTON_WIDTH, 0, GVAR_BUTTON_WIDTH, height()},
STR_GV,
[=]() {
switchGVarMode();
return 0;
},
BUTTON_BACKGROUND | OPAQUE | FORM_DETACHED);
#endif
}
static void value_changed(lv_event_t* e);
};
#endif // _GVAR_NUMBEREDIT_H_
+93 -264
View File
@@ -20,296 +20,125 @@
*/
#include "input_edit.h"
#include "model_curves.h"
#include "input_edit_adv.h"
#include "curve_param.h"
#include "gvar_numberedit.h"
#include "input_source.h"
#include "opentx.h"
#include "gvar_numberedit.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
class SensorValue : Window
{
public:
SensorValue(Window *parent, const rect_t &rect, ExpoData *expoData) :
Window(parent, rect), expoData(expoData)
{
}
void paint(BitmapBuffer *dc) override
{
if (isTelemetryValue()) {
uint8_t sensorIndex = (expoData->srcRaw - MIXSRC_FIRST_TELEM) / 3;
#if defined(SIMU)
if (true) {
#else
TelemetryItem &telemetryItem = telemetryItems[sensorIndex];
if (telemetryItem.isAvailable()) {
#endif
LcdFlags flags = LEFT | COLOR_THEME_PRIMARY1;
drawSensorCustomValue(dc, 3, 2, sensorIndex, lastSensorVal, flags);
} else {
dc->drawText(3, 2, "---", COLOR_THEME_PRIMARY1);
}
}
}
bool isTelemetryValue()
{
return expoData->srcRaw >= MIXSRC_FIRST_TELEM &&
expoData->srcRaw <= MIXSRC_LAST_TELEM;
}
void checkEvents() override
{
getvalue_t sensorVal = -1;
if (isTelemetryValue()) {
sensorVal = getValue(expoData->srcRaw);
}
if (lastSensorVal != sensorVal) {
lastSensorVal = sensorVal;
invalidate();
}
}
LcdFlags getSensorPrec()
{
LcdFlags prec = 0;
if (isTelemetryValue()) {
uint8_t sensorIndex = (expoData->srcRaw - MIXSRC_FIRST_TELEM) / 3;
TelemetrySensor sensor = g_model.telemetrySensors[sensorIndex];
if (sensor.prec > 0) {
prec |= (sensor.prec == 1 ? PREC1 : PREC2);
}
}
return prec;
}
protected:
getvalue_t lastSensorVal;
ExpoData *expoData;
};
InputEditWindow::InputEditWindow(int8_t input, uint8_t index) :
Page(ICON_MODEL_INPUTS),
input(input),
index(index),
preview(
this,
{INPUT_EDIT_CURVE_LEFT, INPUT_EDIT_CURVE_TOP, INPUT_EDIT_CURVE_WIDTH,
INPUT_EDIT_CURVE_HEIGHT},
[=](int x) -> int {
ExpoData *line = expoAddress(index);
int16_t anas[MAX_INPUTS] = {0};
applyExpos(anas, e_perout_mode_inactive_flight_mode, line->srcRaw, x);
return anas[line->chn];
},
[=]() -> int { return getValue(expoAddress(index)->srcRaw); })
index(index)
{
#if LCD_W > LCD_H
auto BODY_WIDTH = LCD_W - preview.width() - PAGE_PADDING;
body.setWidth(BODY_WIDTH);
body.setLeft(preview.width() + PAGE_PADDING);
#else
body.setRect({0, INPUT_EDIT_CURVE_TOP + INPUT_EDIT_CURVE_HEIGHT, LCD_W,
LCD_H - INPUT_EDIT_CURVE_TOP - INPUT_EDIT_CURVE_HEIGHT});
std::string title(STR_MENUINPUTS);
title += "\n";
title += getSourceString(MIXSRC_FIRST_INPUT + input);
header.setTitle(title);
auto body_obj = body.getLvObj();
#if LCD_H > LCD_W // portrait
lv_obj_set_flex_flow(body_obj, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(body_obj, lv_dpx(8), 0);
#else // landscape
lv_obj_set_flex_flow(body_obj, LV_FLEX_FLOW_ROW);
lv_obj_set_style_pad_column(body_obj, lv_dpx(8), 0);
#endif
buildBody(&body);
buildHeader(&header);
}
lv_obj_set_style_flex_cross_place(body_obj, LV_FLEX_ALIGN_CENTER, 0);
// TODO: would be better to set the padding on the preview window...
// ...but it doesn't support it yet.
lv_obj_set_style_pad_all(body_obj, lv_dpx(8), 0);
void InputEditWindow::deleteLater(bool detach, bool trash)
{
if (_deleted) return;
auto box = new Window(&body, rect_t{});
auto box_obj = box->getLvObj();
lv_obj_set_flex_grow(box_obj, 2);
preview.deleteLater(true, false);
Page::deleteLater(detach, trash);
}
void InputEditWindow::buildHeader(Window *window)
{
new StaticText(window,
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
PAGE_LINE_HEIGHT},
STR_MENUINPUTS, 0, COLOR_THEME_PRIMARY2);
new StaticText(window,
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
getSourceString(MIXSRC_FIRST_INPUT + input), 0,
COLOR_THEME_PRIMARY2);
}
// TODO share this code with MIXER
void InputEditWindow::updateCurveParamField(ExpoData *line)
{
curveParamField->clear();
const rect_t rect = {0, 0, curveParamField->width(),
curveParamField->height()};
switch (line->curve.type) {
case CURVE_REF_DIFF:
case CURVE_REF_EXPO: {
GVarNumberEdit *edit = new GVarNumberEdit(
curveParamField, rect, -100, 100, GET_SET_DEFAULT(line->curve.value));
edit->setSuffix("%");
break;
}
case CURVE_REF_FUNC:
new Choice(curveParamField, rect, STR_VCURVEFUNC, 0, CURVE_BASE - 1,
GET_SET_DEFAULT(line->curve.value));
break;
case CURVE_REF_CUSTOM: {
auto choice = new ChoiceEx(curveParamField, rect, -MAX_CURVES, MAX_CURVES,
GET_SET_DEFAULT(line->curve.value));
choice->setTextHandler([](int value) { return getCurveString(value); });
choice->setLongPressHandler([this](event_t event) {
ExpoData *line = expoAddress(index);
// if no curve is specified then dont link to curve page
if (line->curve.value != 0)
ModelCurvesPage::pushEditCurve(abs(line->curve.value) - 1);
});
break;
}
}
}
void InputEditWindow::buildBody(FormWindow *window)
{
FormGridLayout grid;
grid.setLabelWidth(INPUT_EDIT_LABELS_WIDTH);
grid.spacer(PAGE_PADDING);
ExpoData *line = expoAddress(index);
#if LCD_W > LCD_H
grid.setMarginRight(180);
#if LCD_H > LCD_W // portrait
box->setWidth(body.width() - 2*lv_dpx(8));
#else // landscape
box->setHeight(body.height() - 2*lv_dpx(8));
#endif
auto form = new FormWindow(box, rect_t{});
auto form_obj = form->getLvObj();
lv_obj_set_style_pad_all(form_obj, lv_dpx(8), 0);
buildBody(form);
preview = new Curve(&body, rect_t{},
[=](int x) -> int {
ExpoData* line = expoAddress(index);
int16_t anas[MAX_INPUTS] = {0};
applyExpos(anas, e_perout_mode_inactive_flight_mode, line->srcRaw, x);
return anas[line->chn];
},
[=]() -> int { return getValue(expoAddress(index)->srcRaw); });
preview->setWidth(INPUT_EDIT_CURVE_WIDTH);
preview->setHeight(INPUT_EDIT_CURVE_HEIGHT);
}
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2),
LV_GRID_TEMPLATE_LAST};
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
void InputEditWindow::buildBody(FormWindow* form)
{
FlexGridLayout grid(col_dsc, row_dsc, 2);
form->setFlexLayout();
ExpoData* input = expoAddress(index);
// Input Name
new StaticText(window, grid.getLabelSlot(), STR_INPUTNAME, 0,
COLOR_THEME_PRIMARY1);
new ModelTextEdit(window, grid.getFieldSlot(), g_model.inputNames[line->chn],
sizeof(g_model.inputNames[line->chn]));
grid.nextLine();
auto line = form->newLine(&grid);
auto inputName = g_model.inputNames[input->chn];
new StaticText(line, rect_t{}, STR_INPUTNAME, 0, COLOR_THEME_PRIMARY1);
new ModelTextEdit(line, rect_t{}, inputName, sizeof(inputName));
// Switch
new StaticText(window, grid.getLabelSlot(), STR_SWITCH, 0,
COLOR_THEME_PRIMARY1);
new SwitchChoice(window, grid.getFieldSlot(), SWSRC_FIRST_IN_MIXES,
SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(line->swtch));
grid.nextLine();
// Side
new StaticText(window, grid.getLabelSlot(), STR_SIDE, 0,
COLOR_THEME_PRIMARY1);
new Choice(
window, grid.getFieldSlot(), STR_VCURVEFUNC, 1, 3,
[=]() -> int16_t { return 4 - line->mode; },
[=](int16_t newValue) {
line->mode = 4 - newValue;
SET_DIRTY();
});
grid.nextLine();
// Name
new StaticText(window, grid.getLabelSlot(), STR_EXPONAME, 0,
COLOR_THEME_PRIMARY1);
new ModelTextEdit(window, grid.getFieldSlot(), line->name,
sizeof(line->name));
grid.nextLine();
// Line Name
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_EXPONAME, 0, COLOR_THEME_PRIMARY1);
new ModelTextEdit(line, rect_t{}, input->name, sizeof(input->name));
// Source
new StaticText(window, grid.getLabelSlot(), STR_SOURCE, 0,
COLOR_THEME_PRIMARY1);
new SourceChoice(
window, grid.getFieldSlot(2, 0), INPUTSRC_FIRST, INPUTSRC_LAST,
GET_DEFAULT(line->srcRaw), [=](int32_t newValue) {
line->srcRaw = newValue;
if (line->srcRaw > MIXSRC_Ail && line->carryTrim == TRIM_ON) {
line->carryTrim = TRIM_OFF;
trimChoice->invalidate();
}
window->clear();
buildBody(window);
SET_DIRTY();
});
SensorValue *sensor = nullptr;
if (line->srcRaw >= MIXSRC_FIRST_TELEM) {
sensor = new SensorValue(window, grid.getFieldSlot(2, 1), line);
grid.nextLine();
// Scale
new StaticText(window, grid.getLabelSlot(), STR_SCALE, 0,
COLOR_THEME_PRIMARY1);
new NumberEdit(window, grid.getFieldSlot(), 0,
maxTelemValue(line->srcRaw - MIXSRC_FIRST_TELEM + 1),
GET_SET_DEFAULT(line->scale), 0, sensor->getSensorPrec());
adjustHeight();
}
grid.nextLine();
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_SOURCE, 0, COLOR_THEME_PRIMARY1);
auto src = new InputSource(line, input);
lv_obj_set_style_grid_cell_x_align(src->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);
// Weight
new StaticText(window, grid.getLabelSlot(), STR_WEIGHT, 0,
COLOR_THEME_PRIMARY1);
auto gvar = new GVarNumberEdit(window, grid.getFieldSlot(), -100, 100,
GET_SET_DEFAULT(line->weight));
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_WEIGHT, 0, COLOR_THEME_PRIMARY1);
auto gvar = new GVarNumberEdit(line, rect_t{}, -100, 100, GET_SET_DEFAULT(input->weight));
gvar->setSuffix("%");
grid.nextLine();
// Offset
new StaticText(window, grid.getLabelSlot(), STR_OFFSET, 0,
COLOR_THEME_PRIMARY1);
gvar = new GVarNumberEdit(window, grid.getFieldSlot(), -100, 100,
GET_SET_DEFAULT(line->offset));
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_OFFSET, 0, COLOR_THEME_PRIMARY1);
gvar = new GVarNumberEdit(line, rect_t{}, -100, 100, GET_SET_DEFAULT(input->offset));
gvar->setSuffix("%");
grid.nextLine();
// Trim
new StaticText(window, grid.getLabelSlot(), STR_TRIM, 0,
COLOR_THEME_PRIMARY1);
trimChoice = new Choice(window, grid.getFieldSlot(), STR_VMIXTRIMS, -TRIM_OFF,
-TRIM_LAST, GET_VALUE(-line->carryTrim),
SET_VALUE(line->carryTrim, -newValue));
trimChoice->setAvailableHandler([=](int value) {
return value != TRIM_ON || line->srcRaw <= MIXSRC_Ail;
});
grid.nextLine();
// Switch
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_SWITCH, 0, COLOR_THEME_PRIMARY1);
new SwitchChoice(line, rect_t{}, SWSRC_FIRST_IN_MIXES,
SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(input->swtch));
// Curve
new StaticText(&body, grid.getLabelSlot(), STR_CURVE, 0,
COLOR_THEME_PRIMARY1);
new Choice(&body, grid.getFieldSlot(2, 0), "\004DiffExpoFuncCstm", 0,
CURVE_REF_CUSTOM, GET_DEFAULT(line->curve.type),
[=](int32_t newValue) {
line->curve.type = newValue;
line->curve.value = 0;
SET_DIRTY();
updateCurveParamField(line);
});
curveParamField = new FormGroup(&body, grid.getFieldSlot(2, 1)
// , FORM_FORWARD_FOCUS
);
updateCurveParamField(line);
grid.nextLine();
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_CURVE, 0, COLOR_THEME_PRIMARY1);
auto param = new CurveParam(line, rect_t{}, &input->curve);
lv_obj_set_style_grid_cell_x_align(param->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);
#if defined(FLIGHT_MODES)
// Flight modes
new StaticText(window, grid.getLabelSlot(), STR_FLMODE, 0,
COLOR_THEME_PRIMARY1);
for (uint32_t i = 0; i < MAX_FLIGHT_MODES; i++) {
char fm[2] = {char('0' + i), '\0'};
if (i > 0 && (i % 4) == 0) grid.nextLine();
new TextButton(
window, grid.getFieldSlot(4, i % 4), fm,
[=]() -> uint32_t {
BFBIT_FLIP(line->flightModes, bfBit<uint32_t>(i));
SET_DIRTY();
return !(bfSingleBitGet(line->flightModes, i));
},
OPAQUE | (bfSingleBitGet(line->flightModes, i) ? 0 : BUTTON_CHECKED));
}
grid.nextLine();
#endif
line = form->newLine();
lv_obj_set_style_pad_all(line->getLvObj(), lv_dpx(8), 0);
auto btn = new TextButton(line, rect_t{}, LV_SYMBOL_SETTINGS, [=]() -> uint8_t {
new InputEditAdvanced(this->input, index);
return 0;
});
lv_obj_set_width(btn->getLvObj(), lv_pct(100));
}
+1 -6
View File
@@ -31,16 +31,11 @@ class InputEditWindow : public Page
{
public:
InputEditWindow(int8_t input, uint8_t index);
void deleteLater(bool detach = true, bool trash = true) override;
protected:
uint8_t input;
uint8_t index;
Curve preview;
Choice *trimChoice = nullptr;
FormGroup *curveParamField = nullptr;
Curve* preview;
void buildHeader(Window *window);
void updateCurveParamField(ExpoData *line);
void buildBody(FormWindow *window);
};
+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 "input_edit_adv.h"
#include "fm_matrix.h"
#include "opentx.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
LV_GRID_TEMPLATE_LAST};
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
InputEditAdvanced::InputEditAdvanced(uint8_t input_n, uint8_t index) :
Page(ICON_MODEL_INPUTS)
{
std::string title(STR_MENUINPUTS);
title += "\n";
title += getSourceString(MIXSRC_FIRST_INPUT + input_n);
header.setTitle(title);
rect_t r = rect_t{0, 0, body.width(), body.height()};
auto form = new FormWindow(&body, r);
FlexGridLayout grid(col_dsc, row_dsc, 2);
form->setFlexLayout();
ExpoData* input = expoAddress(index);
// Side
auto line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_SIDE, 0, COLOR_THEME_PRIMARY1);
new Choice(
line, rect_t{}, STR_VCURVEFUNC, 1, 3,
[=]() -> int16_t { return 4 - input->mode; },
[=](int16_t newValue) {
input->mode = 4 - newValue;
SET_DIRTY();
});
// Trim
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_TRIM, 0, COLOR_THEME_PRIMARY1);
auto c = new Choice(line, rect_t{}, STR_VMIXTRIMS, -TRIM_OFF,
-TRIM_LAST, GET_VALUE(-input->carryTrim),
SET_VALUE(input->carryTrim, -newValue));
c->setAvailableHandler([=](int value) {
return value != TRIM_ON || input->srcRaw <= MIXSRC_Ail;
});
// Flight modes
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_FLMODE, 0, COLOR_THEME_PRIMARY1);
new FMMatrix<ExpoData>(line, rect_t{}, input);
}
+33
View File
@@ -0,0 +1,33 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#pragma once
#include "page.h"
#include "button_matrix.h"
struct ExpoData;
class InputEditAdvanced : public Page
{
public:
InputEditAdvanced(uint8_t input_n, uint8_t index);
};
+160
View File
@@ -0,0 +1,160 @@
/*
* 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 "input_source.h"
#include "opentx.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
class SensorValue : public StaticText
{
public:
SensorValue(Window *parent, const rect_t &rect, ExpoData *input) :
StaticText(parent, rect), input(input)
{
}
// void paint(BitmapBuffer *dc) override
// {
// if (isTelemetryValue()) {
// uint8_t sensorIndex = (input->srcRaw - MIXSRC_FIRST_TELEM) / 3;
// #if defined(SIMU)
// if (true) {
// #else
// TelemetryItem &telemetryItem = telemetryItems[sensorIndex];
// if (telemetryItem.isAvailable()) {
// #endif
// LcdFlags flags = LEFT | COLOR_THEME_PRIMARY1;
// drawSensorCustomValue(dc, 3, 2, sensorIndex, lastSensorVal, flags);
// } else {
// dc->drawText(3, 2, "---", COLOR_THEME_PRIMARY1);
// }
// }
// }
bool isTelemetryValue()
{
return input->srcRaw >= MIXSRC_FIRST_TELEM &&
input->srcRaw <= MIXSRC_LAST_TELEM;
}
void checkEvents() override
{
if (lv_obj_has_flag(lvobj, LV_OBJ_FLAG_HIDDEN))
return;
// TODO: check for telemetry available
if (isTelemetryValue()) {
getvalue_t sensorVal = getValue(input->srcRaw);
if (lastSensorVal != sensorVal) {
lastSensorVal = sensorVal;
setText(std::to_string(lastSensorVal));
}
} else {
setText("---");
}
}
LcdFlags getSensorPrec()
{
LcdFlags prec = 0;
if (isTelemetryValue()) {
uint8_t sensorIndex = (input->srcRaw - MIXSRC_FIRST_TELEM) / 3;
TelemetrySensor sensor = g_model.telemetrySensors[sensorIndex];
if (sensor.prec > 0) {
prec |= (sensor.prec == 1 ? PREC1 : PREC2);
}
}
return prec;
}
protected:
getvalue_t lastSensorVal;
ExpoData *input;
};
void InputSource::value_changed(lv_event_t *e)
{
auto obj = lv_event_get_target(e);
auto src = (InputSource*)lv_obj_get_user_data(obj);
if (!src) return;
src->update();
}
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
LV_GRID_TEMPLATE_LAST};
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
InputSource::InputSource(Window* parent, ExpoData* input) :
Window(parent, rect_t{}), input(input)
{
lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(lvobj, lv_dpx(4), 0);
lv_obj_set_size(lvobj, lv_pct(100), LV_SIZE_CONTENT);
new SourceChoice(
this, rect_t{}, INPUTSRC_FIRST, INPUTSRC_LAST, GET_DEFAULT(input->srcRaw),
[=](int32_t newValue) {
input->srcRaw = newValue;
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
SET_DIRTY();
});
lv_obj_add_event_cb(lvobj, InputSource::value_changed, LV_EVENT_VALUE_CHANGED, nullptr);
sensor_form = new FormGroup(this, rect_t{});
sensor_form->setFlexLayout();
auto sensor_form_obj = sensor_form->getLvObj();
FlexGridLayout grid(col_dsc, row_dsc);
auto line = sensor_form->newLine(&grid);
// Value
Window* w = new StaticText(line, rect_t{}, STR_VALUE, 0, COLOR_THEME_PRIMARY1);
auto sensor = new SensorValue(line, rect_t{}, input);
// Scale
line = sensor_form->newLine(&grid);
w = new StaticText(line, rect_t{}, STR_SCALE, 0, COLOR_THEME_PRIMARY1);
w = new NumberEdit(line, rect_t{}, 0,
maxTelemValue(input->srcRaw - MIXSRC_FIRST_TELEM + 1),
GET_SET_DEFAULT(input->scale), 0, sensor->getSensorPrec());
update();
}
void InputSource::update()
{
if (input->srcRaw > MIXSRC_Ail && input->carryTrim == TRIM_ON) {
input->carryTrim = TRIM_OFF;
}
if (!sensor_form) return;
auto sensor_form_obj = sensor_form->getLvObj();
if (input->srcRaw >= MIXSRC_FIRST_TELEM &&
input->srcRaw <= MIXSRC_LAST_TELEM) {
lv_obj_clear_flag(sensor_form_obj, LV_OBJ_FLAG_HIDDEN);
} else {
lv_obj_add_flag(sensor_form_obj, LV_OBJ_FLAG_HIDDEN);
}
}
+39
View File
@@ -0,0 +1,39 @@
/*
* 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 "window.h"
struct ExpoData;
class FormGroup;
class InputSource : public Window
{
ExpoData* input;
FormGroup* sensor_form;
void update();
static void value_changed(lv_event_t* e);
public:
InputSource(Window* parent, ExpoData* input);
};
+67 -188
View File
@@ -20,9 +20,10 @@
*/
#include "mixer_edit.h"
#include "mixer_edit_adv.h"
#include "channel_bar.h"
#include "gvar_numberedit.h"
#include "model_curves.h"
#include "curve_param.h"
#include "opentx.h"
@@ -40,223 +41,101 @@
class MixerEditStatusBar : public Window
{
public:
MixerEditStatusBar(Window *parent, const rect_t &rect, int8_t channel) :
Window(parent, rect),
_channel(channel)
{
channelBar = new ComboChannelBar(this, {MIX_STATUS_BAR_MARGIN, 0, rect.w - (MIX_STATUS_BAR_MARGIN * 2), rect.h}, channel);
channelBar->setLeftMargin(0);
channelBar->setTextColor(COLOR_THEME_PRIMARY2);
channelBar->setOutputChannelBarLimitColor(COLOR_THEME_EDIT);
}
public:
MixerEditStatusBar(Window *parent, const rect_t &rect, int8_t channel) :
Window(parent, rect), _channel(channel)
{
channelBar =
new ComboChannelBar(this,
{MIX_STATUS_BAR_MARGIN, 0,
rect.w - (MIX_STATUS_BAR_MARGIN * 2), rect.h},
channel);
channelBar->setLeftMargin(0);
channelBar->setTextColor(COLOR_THEME_PRIMARY2);
channelBar->setOutputChannelBarLimitColor(COLOR_THEME_EDIT);
}
void paint(BitmapBuffer *dc) override
{
// dc->clear(COLOR_THEME_SECONDARY2);
}
protected:
ComboChannelBar *channelBar;
int8_t _channel;
protected:
ComboChannelBar *channelBar;
int8_t _channel;
};
MixEditWindow::MixEditWindow(int8_t channel, uint8_t mixIndex) :
Page(ICON_MODEL_MIXER), channel(channel), mixIndex(mixIndex)
MixEditWindow::MixEditWindow(int8_t channel, uint8_t index) :
Page(ICON_MODEL_MIXER), channel(channel), index(index)
{
buildBody(&body);
auto form = new FormWindow(&body, rect_t{});
lv_obj_set_style_pad_all(form->getLvObj(), lv_dpx(8), 0);
buildBody(form);
buildHeader(&header);
}
void MixEditWindow::buildHeader(Window *window)
{
new StaticText(window,
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
PAGE_LINE_HEIGHT},
STR_MIXES, 0, COLOR_THEME_PRIMARY2);
new StaticText(window,
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
getSourceString(MIXSRC_CH1 + channel), 0,
COLOR_THEME_PRIMARY2);
std::string title(STR_MIXES);
title += "\n";
title += getSourceString(MIXSRC_CH1 + channel);
header.setTitle(title);
statusBar = new MixerEditStatusBar(
new MixerEditStatusBar(
window,
{window->getRect().w - MIX_STATUS_BAR_WIDTH - MIX_RIGHT_MARGIN, 0,
MIX_STATUS_BAR_WIDTH, MENU_HEADER_HEIGHT + 3},
channel);
}
void MixEditWindow::buildBody(FormWindow *window)
{
FormGridLayout grid;
grid.spacer(8);
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2),
LV_GRID_TEMPLATE_LAST};
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
MixData *mix = mixAddress(mixIndex);
void MixEditWindow::buildBody(FormWindow* form)
{
FlexGridLayout grid(col_dsc, row_dsc, 2);
form->setFlexLayout();
MixData *mix = mixAddress(index);
// Mix name
new StaticText(window, grid.getLabelSlot(), STR_MIXNAME, 0,
COLOR_THEME_PRIMARY1);
new ModelTextEdit(window, grid.getFieldSlot(), mix->name, sizeof(mix->name));
grid.nextLine();
auto line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_MIXNAME, 0, COLOR_THEME_PRIMARY1);
new ModelTextEdit(line, rect_t{}, mix->name, sizeof(mix->name));
// Source
new StaticText(window, grid.getLabelSlot(), STR_SOURCE, 0,
COLOR_THEME_PRIMARY1);
new SourceChoice(window, grid.getFieldSlot(), 0, MIXSRC_LAST,
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_SOURCE, 0, COLOR_THEME_PRIMARY1);
new SourceChoice(line, rect_t{}, 0, MIXSRC_LAST,
GET_SET_DEFAULT(mix->srcRaw));
grid.nextLine();
// Weight
new StaticText(window, grid.getLabelSlot(), STR_WEIGHT, 0,
COLOR_THEME_PRIMARY1);
auto gvar = new GVarNumberEdit(window, grid.getFieldSlot(), MIX_WEIGHT_MIN,
MIX_WEIGHT_MAX, GET_SET_DEFAULT(mix->weight));
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_WEIGHT, 0, COLOR_THEME_PRIMARY1);
auto gvar = new GVarNumberEdit(line, rect_t{}, MIX_WEIGHT_MIN, MIX_WEIGHT_MAX,
GET_SET_DEFAULT(mix->weight));
gvar->setSuffix("%");
grid.nextLine();
// Offset
new StaticText(window, grid.getLabelSlot(), STR_OFFSET, 0,
COLOR_THEME_PRIMARY1);
gvar = new GVarNumberEdit(window, grid.getFieldSlot(), MIX_OFFSET_MIN,
MIX_OFFSET_MAX, GET_SET_DEFAULT(mix->offset));
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_OFFSET, 0, COLOR_THEME_PRIMARY1);
gvar = new GVarNumberEdit(line, rect_t{}, MIX_OFFSET_MIN, MIX_OFFSET_MAX,
GET_SET_DEFAULT(mix->offset));
gvar->setSuffix("%");
grid.nextLine();
// Trim
new StaticText(window, grid.getLabelSlot(), STR_TRIM, 0,
COLOR_THEME_PRIMARY1);
new CheckBox(window, grid.getFieldSlot(), GET_SET_INVERTED(mix->carryTrim));
grid.nextLine();
// Curve
new StaticText(&body, grid.getLabelSlot(), STR_CURVE, 0,
COLOR_THEME_PRIMARY1);
new Choice(&body, grid.getFieldSlot(2, 0), "\004DiffExpoFuncCstm", 0,
CURVE_REF_CUSTOM, GET_DEFAULT(mix->curve.type),
[=](int32_t newValue) {
mix->curve.type = newValue;
mix->curve.value = 0;
SET_DIRTY();
updateCurveParamField(mix);
});
curveParamField =
new FormGroup(&body, grid.getFieldSlot(2, 1) // , FORM_FORWARD_FOCUS
);
updateCurveParamField(mix);
grid.nextLine();
#if defined(FLIGHT_MODES)
// Flight modes
new StaticText(window, grid.getLabelSlot(), STR_FLMODE, 0,
COLOR_THEME_PRIMARY1);
for (uint32_t i = 0; i < MAX_FLIGHT_MODES; i++) {
char fm[2] = {char('0' + i), '\0'};
if (i > 0 && (i % 4) == 0) grid.nextLine();
new TextButton(
window, grid.getFieldSlot(4, i % 4), fm,
[=]() -> uint32_t {
BFBIT_FLIP(mix->flightModes, bfBit<uint32_t>(i));
SET_DIRTY();
return !(bfSingleBitGet(mix->flightModes, i));
},
OPAQUE | (bfSingleBitGet(mix->flightModes, i) ? 0 : BUTTON_CHECKED));
}
grid.nextLine();
#endif
// Switch
new StaticText(window, grid.getLabelSlot(), STR_SWITCH, 0,
COLOR_THEME_PRIMARY1);
new SwitchChoice(window, grid.getFieldSlot(), SWSRC_FIRST_IN_MIXES,
SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(mix->swtch));
grid.nextLine();
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_SWITCH, 0, COLOR_THEME_PRIMARY1);
new SwitchChoice(line, rect_t{}, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES,
GET_SET_DEFAULT(mix->swtch));
// Warning
new StaticText(window, grid.getLabelSlot(), STR_MIXWARNING, 0,
COLOR_THEME_PRIMARY1);
auto edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, 3,
GET_SET_DEFAULT(mix->mixWarn));
edit->setZeroText(STR_OFF);
grid.nextLine();
// Curve
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_CURVE, 0, COLOR_THEME_PRIMARY1);
new CurveParam(line, rect_t{}, &mix->curve);
// Multiplex
new StaticText(window, grid.getLabelSlot(), STR_MULTPX, 0,
COLOR_THEME_PRIMARY1);
new Choice(window, grid.getFieldSlot(), STR_VMLTPX, 0, 2,
GET_SET_DEFAULT(mix->mltpx));
grid.nextLine();
// Delay up
new StaticText(window, grid.getLabelSlot(), STR_DELAYUP, 0,
COLOR_THEME_PRIMARY1);
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
GET_DEFAULT(mix->delayUp),
SET_VALUE(mix->delayUp, newValue), 0, PREC1);
edit->setSuffix("s");
grid.nextLine();
// Delay down
new StaticText(window, grid.getLabelSlot(), STR_DELAYDOWN, 0,
COLOR_THEME_PRIMARY1);
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
GET_DEFAULT(mix->delayDown),
SET_VALUE(mix->delayDown, newValue), 0, PREC1);
edit->setSuffix("s");
grid.nextLine();
// Slow up
new StaticText(window, grid.getLabelSlot(), STR_SLOWUP, 0,
COLOR_THEME_PRIMARY1);
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
GET_DEFAULT(mix->speedUp),
SET_VALUE(mix->speedUp, newValue), 0, PREC1);
edit->setSuffix("s");
grid.nextLine();
// Slow down
new StaticText(window, grid.getLabelSlot(), STR_SLOWDOWN, 0,
COLOR_THEME_PRIMARY1);
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
GET_DEFAULT(mix->speedDown),
SET_VALUE(mix->speedDown, newValue), 0, PREC1);
edit->setSuffix("s");
grid.nextLine();
}
// TODO share this code with INPUT
void MixEditWindow::updateCurveParamField(MixData *line)
{
curveParamField->clear();
const rect_t rect = {0, 0, curveParamField->width(),
curveParamField->height()};
switch (line->curve.type) {
case CURVE_REF_DIFF:
case CURVE_REF_EXPO: {
GVarNumberEdit *edit = new GVarNumberEdit(
curveParamField, rect, -100, 100, GET_SET_DEFAULT(line->curve.value));
edit->setSuffix("%");
break;
}
case CURVE_REF_FUNC:
new Choice(curveParamField, rect, STR_VCURVEFUNC, 0, CURVE_BASE - 1,
GET_SET_DEFAULT(line->curve.value));
break;
case CURVE_REF_CUSTOM: {
auto choice = new ChoiceEx(curveParamField, rect, -MAX_CURVES, MAX_CURVES,
GET_SET_DEFAULT(line->curve.value));
choice->setTextHandler([](int value) { return getCurveString(value); });
choice->setLongPressHandler([this](event_t event) {
MixData *mix = mixAddress(mixIndex);
// if no curve is specified then dont link to curve page
if (mix->curve.value != 0)
ModelCurvesPage::pushEditCurve(abs(mix->curve.value) - 1);
});
break;
}
}
line = form->newLine();
lv_obj_set_style_pad_all(line->getLvObj(), lv_dpx(8), 0);
auto btn = new TextButton(line, rect_t{}, LV_SYMBOL_SETTINGS, [=]() -> uint8_t {
new MixEditAdvanced(channel, index);
return 0;
});
lv_obj_set_width(btn->getLvObj(), lv_pct(100));
}
+2 -9
View File
@@ -25,24 +25,17 @@
#include "form.h"
#include "curve.h"
struct MixData;
class FormGroup;
class MixerEditStatusBar;
class MixEditWindow : public Page
{
public:
MixEditWindow(int8_t channel, uint8_t mixIndex);
MixEditWindow(int8_t channel, uint8_t index);
protected:
uint8_t channel;
uint8_t mixIndex;
FormGroup *curveParamField = nullptr;
MixerEditStatusBar *statusBar = nullptr;
uint8_t index;
void buildHeader(Window *window);
void buildBody(FormWindow *window);
// TODO share this code with INPUT
void updateCurveParamField(MixData *line);
};
+107
View File
@@ -0,0 +1,107 @@
/*
* 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 "mixer_edit_adv.h"
#include "numberedit.h"
#include "fm_matrix.h"
#include "opentx.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
MixEditAdvanced::MixEditAdvanced(int8_t channel, uint8_t index) :
Page(ICON_MODEL_MIXER), channel(channel), index(index)
{
std::string title(STR_MIXES);
title += "\n";
title += getSourceString(MIXSRC_CH1 + channel);
header.setTitle(title);
auto form = new FormWindow(&body, rect_t{});
lv_obj_set_style_pad_all(form->getLvObj(), lv_dpx(8), 0);
buildBody(form);
}
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2),
LV_GRID_TEMPLATE_LAST};
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
void MixEditAdvanced::buildBody(FormWindow* form)
{
FlexGridLayout grid(col_dsc, row_dsc, 2);
form->setFlexLayout();
MixData *mix = mixAddress(index);
// Advanced...
// Multiplex
auto line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_MULTPX, 0, COLOR_THEME_PRIMARY1);
new Choice(line, rect_t{}, STR_VMLTPX, 0, 2, GET_SET_DEFAULT(mix->mltpx));
// Flight modes
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_FLMODE, 0, COLOR_THEME_PRIMARY1);
new FMMatrix<MixData>(line, rect_t{}, mix);
// Trim
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_TRIM, 0, COLOR_THEME_PRIMARY1);
new CheckBox(line, rect_t{}, GET_SET_INVERTED(mix->carryTrim));
// Warning
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_MIXWARNING, 0, COLOR_THEME_PRIMARY1);
auto edit = new NumberEdit(line, rect_t{}, 0, 3, GET_SET_DEFAULT(mix->mixWarn));
edit->setZeroText(STR_OFF);
// Delay up
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_DELAYUP, 0, COLOR_THEME_PRIMARY1);
edit = new NumberEdit(line, rect_t{}, 0, DELAY_MAX, GET_DEFAULT(mix->delayUp),
SET_VALUE(mix->delayUp, newValue), 0, PREC1);
edit->setSuffix("s");
// Delay down
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_DELAYDOWN, 0, COLOR_THEME_PRIMARY1);
edit =
new NumberEdit(line, rect_t{}, 0, DELAY_MAX, GET_DEFAULT(mix->delayDown),
SET_VALUE(mix->delayDown, newValue), 0, PREC1);
edit->setSuffix("s");
// Slow up
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_SLOWUP, 0, COLOR_THEME_PRIMARY1);
edit = new NumberEdit(line, rect_t{}, 0, DELAY_MAX, GET_DEFAULT(mix->speedUp),
SET_VALUE(mix->speedUp, newValue), 0, PREC1);
edit->setSuffix("s");
// Slow down
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_SLOWDOWN, 0, COLOR_THEME_PRIMARY1);
edit =
new NumberEdit(line, rect_t{}, 0, DELAY_MAX, GET_DEFAULT(mix->speedDown),
SET_VALUE(mix->speedDown, newValue), 0, PREC1);
edit->setSuffix("s");
}
+41
View File
@@ -0,0 +1,41 @@
/*
* 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"
#include "form.h"
#include "curve.h"
class FormGroup;
class MixEditAdvanced : public Page
{
public:
MixEditAdvanced(int8_t channel, uint8_t index);
protected:
uint8_t channel;
uint8_t index;
void buildHeader(Window *window);
void buildBody(FormWindow *window);
};
+1 -1
View File
@@ -158,8 +158,8 @@ class InputLineButton : public InputMixButton
}
// second line ...
y += line_h;
if (line.swtch || line.curve.value) {
y += line_h;
if (line.swtch) {
dc->drawMask(x, y, mixerSetupSwitchIcon, textColor);
drawSwitch(dc, x + 21, y, line.swtch, textColor);
+3 -3
View File
@@ -124,7 +124,7 @@ void OutputEditWindow::buildBody(FormWindow *window)
new StaticText(window, grid.getLabelSlot(), TR_LIMITS_HEADERS_SUBTRIM, 0,
COLOR_THEME_PRIMARY1);
new GVarNumberEdit(window, grid.getFieldSlot(), -LIMIT_STD_MAX,
+LIMIT_STD_MAX, GET_SET_DEFAULT(output->offset), 0, PREC1);
+LIMIT_STD_MAX, GET_SET_DEFAULT(output->offset), PREC1);
grid.nextLine();
// TRACE("ch=%d cV=%d zero=%d", channel, chanVal, chanZero);
@@ -133,14 +133,14 @@ void OutputEditWindow::buildBody(FormWindow *window)
minText = new StaticText(window, grid.getLabelSlot(), TR_MIN, 0,
COLOR_THEME_PRIMARY1);
new GVarNumberEdit(window, grid.getFieldSlot(), -limit, 0,
GET_SET_DEFAULT(output->min), 0, PREC1, -LIMIT_STD_MAX);
GET_SET_DEFAULT(output->min), PREC1, -LIMIT_STD_MAX);
grid.nextLine();
// Max
maxText = new StaticText(window, grid.getLabelSlot(), TR_MAX, 0,
COLOR_THEME_PRIMARY1);
new GVarNumberEdit(window, grid.getFieldSlot(), 0, +limit,
GET_SET_DEFAULT(output->max), 0, PREC1, +LIMIT_STD_MAX);
GET_SET_DEFAULT(output->max), PREC1, +LIMIT_STD_MAX);
grid.nextLine();
// Direction
+10 -7
View File
@@ -27,14 +27,17 @@
PageHeader::PageHeader(Page * parent, uint8_t icon):
FormGroup(parent, { 0, 0, LCD_W, MENU_HEADER_HEIGHT }, OPAQUE),
icon(icon)
#if defined(HARDWARE_TOUCH)
, back(this, { 0, 0, MENU_HEADER_BACK_BUTTON_WIDTH, MENU_HEADER_BACK_BUTTON_HEIGHT },
[=]() -> uint8_t {
parent->deleteLater();
return 0;
}, NO_FOCUS | FORM_NO_BORDER)
#endif
{
#if defined(HARDWARE_TOUCH)
new Button(this, { 0, 0, MENU_HEADER_BACK_BUTTON_WIDTH, MENU_HEADER_BACK_BUTTON_HEIGHT },
[=]() -> uint8_t {
parent->deleteLater();
return 0;
}, NO_FOCUS | FORM_NO_BORDER);
#endif
title = new StaticText(this, rect_t{}, "", 0, COLOR_THEME_PRIMARY2);
title->setTop(PAGE_TITLE_TOP);
title->setLeft(PAGE_TITLE_LEFT);
}
void PageHeader::paint(BitmapBuffer * dc)
+5 -15
View File
@@ -24,6 +24,7 @@
#include "window.h"
#include "button.h"
#include "static.h"
class Page;
@@ -32,24 +33,14 @@ class PageHeader : public FormGroup
public:
PageHeader(Page* parent, uint8_t icon);
#if defined(HARDWARE_TOUCH)
void deleteLater(bool detach = true, bool trash = true) override
{
if (_deleted) return;
back.deleteLater(true, false);
FormGroup::deleteLater(detach, trash);
}
#endif
uint8_t getIcon() const { return icon; }
void setTitle(std::string txt) { title->setText(std::move(txt)); }
void paint(BitmapBuffer* dc) override;
uint8_t getIcon() const { return icon; }
protected:
uint8_t icon;
#if defined(HARDWARE_TOUCH)
Button back;
#endif
StaticText* title;
};
class Page : public Window
@@ -57,8 +48,6 @@ class Page : public Window
public:
explicit Page(unsigned icon);
void deleteLater(bool detach = true, bool trash = true) override;
#if defined(DEBUG_WINDOWS)
std::string getName() const override { return "Page"; }
#endif
@@ -67,6 +56,7 @@ class Page : public Window
void onClicked() override;
void paint(BitmapBuffer* dc) override;
void deleteLater(bool detach = true, bool trash = true) override;
protected:
PageHeader header;
+2
View File
@@ -1404,6 +1404,8 @@ void opentxClose(uint8_t shutdown)
RTOS_WAIT_MS(100);
#if defined(COLORLCD)
// clear layer stack first
for (Window* w = Layer::back(); w; w = Layer::back()) w->deleteLater();
MainWindow::instance()->clear();
// this is necessary as the custom screens are not deleted
// by using deleteCustomScreens(), but here through it's parent window
+1 -1
View File
@@ -117,7 +117,7 @@ constexpr uint32_t PAGE_TITLE_LEFT = 50;
constexpr uint32_t INPUT_EDIT_LABELS_WIDTH = 120;
constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 158;
constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 132;
constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = INPUT_EDIT_CURVE_WIDTH;
constexpr coord_t INPUT_EDIT_CURVE_LEFT = PAGE_PADDING;
constexpr coord_t INPUT_EDIT_CURVE_TOP = MENU_HEADER_HEIGHT + PAGE_PADDING;
+4 -4
View File
@@ -114,10 +114,10 @@ constexpr uint32_t PAGE_TITLE_TOP = 2;
constexpr uint32_t PAGE_TITLE_LEFT = 50;
constexpr uint32_t INPUT_EDIT_LABELS_WIDTH = 80;
constexpr coord_t INPUT_EDIT_CURVE_WIDTH = LCD_W;
constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = 158;
constexpr coord_t INPUT_EDIT_CURVE_LEFT = 0;
constexpr coord_t INPUT_EDIT_CURVE_TOP = MENU_HEADER_HEIGHT;
constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 176;
constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = 132;
constexpr coord_t INPUT_EDIT_CURVE_LEFT = PAGE_PADDING;
constexpr coord_t INPUT_EDIT_CURVE_TOP = MENU_HEADER_HEIGHT + PAGE_PADDING;
constexpr coord_t MENUS_LINE_HEIGHT = 40;
constexpr coord_t MENUS_WIDTH = 200;
constexpr coord_t POPUP_HEADER_HEIGHT = 30;