New UI continued

This commit is contained in:
Bertrand Songis
2019-10-05 19:01:57 +02:00
parent f5c60a86a9
commit ae548b9814
26 changed files with 331 additions and 196 deletions
+33 -6
View File
@@ -21,8 +21,8 @@
#include "opentx.h"
uint8_t s_curveChan;
int8_t * curveEnd[MAX_CURVES];
void loadCurves()
{
bool showWarning= false;
@@ -94,8 +94,35 @@ void resetCustomCurveX(int8_t * points, int noPoints)
}
}
void curveReset(uint8_t index)
{
CurveHeader * curve = &g_model.curves[index];
int8_t * points = curveAddress(index);
memclear(points, 5 + curve->points);
if (curve->type == CURVE_TYPE_CUSTOM)
resetCustomCurveX(points, 5 + curve->points);
memclear(curve, sizeof(CurveHeader));
}
void curveMirror(uint8_t index)
{
CurveHeader & curve = g_model.curves[index];
int8_t * points = curveAddress(index);
for (int i = 0; i < 5 + curve.points; i++)
points[i] = -points[i];
}
bool isCurveUsed(uint8_t index)
{
return !is_memclear(&g_model.curves[index], sizeof(CurveHeader)) || !is_memclear(curveAddress(index), 5);
}
#define CUSTOM_POINT_X(points, count, idx) ((idx)==0 ? -100 : (((idx)==(count)-1) ? 100 : points[(count)+(idx)-1]))
int32_t compute_tangent(CurveInfo * crv, int8_t * points, int i)
int32_t compute_tangent(CurveHeader * crv, int8_t * points, int i)
{
int32_t m=0;
uint8_t num_points = crv->points + 5;
@@ -166,7 +193,7 @@ int32_t compute_tangent(CurveInfo * crv, int8_t * points, int i)
*/
int16_t hermite_spline(int16_t x, uint8_t idx)
{
CurveInfo &crv = g_model.curves[idx];
CurveHeader &crv = g_model.curves[idx];
int8_t *points = curveAddress(idx);
uint8_t count = crv.points+5;
bool custom = (crv.type == CURVE_TYPE_CUSTOM);
@@ -211,7 +238,7 @@ int16_t hermite_spline(int16_t x, uint8_t idx)
int intpol(int x, uint8_t idx) // -100, -75, -50, -25, 0 ,25 ,50, 75, 100
{
CurveInfo & crv = g_model.curves[idx];
CurveHeader & crv = g_model.curves[idx];
int8_t * points = curveAddress(idx);
uint8_t count = crv.points+5;
bool custom = (crv.type == CURVE_TYPE_CUSTOM);
@@ -307,7 +334,7 @@ int applyCustomCurve(int x, uint8_t idx)
if (idx >= MAX_CURVES)
return 0;
CurveInfo & crv = g_model.curves[idx];
CurveHeader & crv = g_model.curves[idx];
if (crv.smooth)
return hermite_spline(x, idx);
else
@@ -322,7 +349,7 @@ point_t getPoint(uint8_t index)
point_t getPoint(uint8_t curveIndex, uint8_t index)
{
point_t result = {0, 0};
CurveInfo & crv = g_model.curves[curveIndex];
CurveHeader & crv = g_model.curves[curveIndex];
int8_t * points = curveAddress(curveIndex);
bool custom = (crv.type == CURVE_TYPE_CUSTOM);
uint8_t count = 5 + crv.points;
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* 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.
*/
#ifndef _CURVES_H_
#define _CURVES_H_
enum BaseCurves {
CURVE_NONE,
CURVE_X_GT0,
CURVE_X_LT0,
CURVE_ABS_X,
CURVE_F_GT0,
CURVE_F_LT0,
CURVE_ABS_F,
CURVE_BASE
};
void curveReset(uint8_t index);
void curveMirror(uint8_t index);
bool isCurveUsed(uint8_t index);
void loadCurves();
int8_t * curveAddress(uint8_t idx);
bool moveCurve(uint8_t index, int8_t shift);
int8_t getCurveX(int noPoints, int point);
void resetCustomCurveX(int8_t * points, int noPoints);
point_t getPoint(uint8_t i);
point_t getPoint(uint8_t curveIndex, uint8_t index);
int applyCustomCurve(int x, uint8_t idx);
int applyCurve(int x, CurveRef & curve);
int applyCurrentCurve(int x);
#endif
+7 -7
View File
@@ -190,7 +190,7 @@ PACK(struct FlightModeData {
* Curve structure
*/
PACK(struct CurveData {
PACK(struct CurveHeader {
uint8_t type:1;
uint8_t smooth:1;
int8_t points:6; // describes number of points - 5
@@ -580,7 +580,7 @@ PACK(struct ModelData {
LimitData limitData[MAX_OUTPUT_CHANNELS];
ExpoData expoData[MAX_EXPOS];
CurveData curves[MAX_CURVES];
CurveHeader curves[MAX_CURVES];
int8_t points[MAX_CURVE_POINTS];
LogicalSwitchData logicalSw[MAX_LOGICAL_SWITCHES];
@@ -849,7 +849,7 @@ static inline void check_struct()
CHKSIZE(FrSkyLineData, 4);
CHKTYPE(union TelemetryScreenData, 24);
CHKSIZE(ModelHeader, 12);
CHKSIZE(CurveData, 4);
CHKSIZE(CurveHeader, 4);
#elif defined(PCBTARANIS)
CHKSIZE(MixData, 20);
CHKSIZE(ExpoData, 17);
@@ -863,7 +863,7 @@ static inline void check_struct()
CHKSIZE(FrSkyLineData, 6);
CHKTYPE(union TelemetryScreenData, 24);
CHKSIZE(ModelHeader, 24);
CHKSIZE(CurveData, 4);
CHKSIZE(CurveHeader, 4);
#elif defined(PCBHORUS)
CHKSIZE(MixData, 20);
CHKSIZE(ExpoData, 17);
@@ -873,7 +873,7 @@ static inline void check_struct()
CHKSIZE(TimerData, 16);
CHKSIZE(SwashRingData, 8);
CHKSIZE(ModelHeader, 31);
CHKSIZE(CurveData, 4);
CHKSIZE(CurveHeader, 4);
CHKSIZE(CustomScreenData, 610);
CHKSIZE(Topbar::PersistentData, 216);
#elif defined(PCBNV14)
@@ -889,7 +889,7 @@ static inline void check_struct()
CHKSIZE(FrSkyBarData, 5);
CHKSIZE(FrSkyLineData, 2);
CHKSIZE(ModelHeader, 12);
CHKTYPE(CurveData, 4);
CHKTYPE(CurveHeader, 4);
#else
// Common for all variants
CHKSIZE(LimitData, 5);
@@ -897,7 +897,7 @@ static inline void check_struct()
CHKSIZE(FrSkyBarData, 3);
CHKSIZE(FrSkyLineData, 2);
CHKSIZE(ModelHeader, 11);
CHKTYPE(CurveData, 1);
CHKTYPE(CurveHeader, 1);
CHKSIZE(MixData, 9);
CHKSIZE(ExpoData, 4);
+4 -4
View File
@@ -50,7 +50,7 @@ void runPopupCurvePreset(event_t event)
if (warningResult) {
warningResult = 0;
CurveInfo & crv = g_model.curves[s_curveChan];
CurveHeader & crv = g_model.curves[s_curveChan];
int8_t * points = curveAddress(s_curveChan);
int k = 25 * reusableBuffer.curveEdit.preset;
int dx = 2000 / (5+crv.points-1);
@@ -71,13 +71,13 @@ void onCurveOneMenu(const char * result)
POPUP_INPUT(STR_PRESET, runPopupCurvePreset);
}
else if (result == STR_MIRROR) {
CurveInfo & crv = g_model.curves[s_curveChan];
CurveHeader & crv = g_model.curves[s_curveChan];
int8_t * points = curveAddress(s_curveChan);
for (int i=0; i<5+crv.points; i++)
points[i] = -points[i];
}
else if (result == STR_CLEAR) {
CurveInfo & crv = g_model.curves[s_curveChan];
CurveHeader & crv = g_model.curves[s_curveChan];
int8_t * points = curveAddress(s_curveChan);
for (int i=0; i<5+crv.points; i++)
points[i] = 0;
@@ -89,7 +89,7 @@ void onCurveOneMenu(const char * result)
void menuModelCurveOne(event_t event)
{
CurveData & crv = g_model.curves[s_curveChan];
CurveHeader & crv = g_model.curves[s_curveChan];
int8_t * points = curveAddress(s_curveChan);
drawStringWithIndex(PSIZE(TR_MENUCURVES)*FW+FW, 0, STR_CV, s_curveChan+1);
+4 -4
View File
@@ -52,7 +52,7 @@ void runPopupCurvePreset(event_t event)
if (warningResult) {
warningResult = 0;
CurveInfo & crv = g_model.curves[s_curveChan];
CurveHeader & crv = g_model.curves[s_curveChan];
int8_t * points = curveAddress(s_curveChan);
int k = 25 * reusableBuffer.curveEdit.preset;
int dx = 2000 / (5+crv.points-1);
@@ -73,13 +73,13 @@ void onCurveOneMenu(const char * result)
POPUP_INPUT(STR_PRESET, runPopupCurvePreset);
}
else if (result == STR_MIRROR) {
CurveInfo & crv = g_model.curves[s_curveChan];
CurveHeader & crv = g_model.curves[s_curveChan];
int8_t * points = curveAddress(s_curveChan);
for (int i=0; i<5+crv.points; i++)
points[i] = -points[i];
}
else if (result == STR_CLEAR) {
CurveInfo & crv = g_model.curves[s_curveChan];
CurveHeader & crv = g_model.curves[s_curveChan];
int8_t * points = curveAddress(s_curveChan);
for (int i=0; i<5+crv.points; i++)
points[i] = 0;
@@ -92,7 +92,7 @@ void onCurveOneMenu(const char * result)
void menuModelCurveOne(event_t event)
{
static uint8_t pointsOfs = 0;
CurveData & crv = g_model.curves[s_curveChan];
CurveHeader & crv = g_model.curves[s_curveChan];
int8_t * points = curveAddress(s_curveChan);
drawStringWithIndex(PSIZE(TR_MENUCURVES)*FW+FW, 0, "CV", s_curveChan+1);
+6 -4
View File
@@ -22,17 +22,19 @@
#ifndef _CURVE_H_
#define _CURVE_H_
#include "form.h"
#include "window.h"
struct CurvePoint {
point_t coords;
LcdFlags flags;
};
class Curve: public FormField {
class Curve: public Window {
friend class CurveEdit;
public:
Curve(Window * parent, const rect_t & rect, std::function<int(int)> function, std::function<int()> position=nullptr):
FormField(parent, rect, OPAQUE),
Window(parent, rect, OPAQUE),
function(std::move(function)),
position(std::move(position))
{
@@ -52,7 +54,7 @@ class Curve: public FormField {
invalidate();
}
FormField::checkEvents();
Window::checkEvents();
}
void addPoint(const point_t & point, LcdFlags flags);
+12 -11
View File
@@ -23,7 +23,8 @@
#include "opentx.h" // TODO for applyCustomCurve
CurveEdit::CurveEdit(Window * parent, const rect_t & rect, uint8_t index) :
Curve(parent, rect, [=](int x) -> int {
FormField(parent, rect),
preview(this, {0, 0, width(), height()}, [=](int x) -> int {
return applyCustomCurve(x, index);
}),
index(index),
@@ -34,16 +35,16 @@ CurveEdit::CurveEdit(Window * parent, const rect_t & rect, uint8_t index) :
void CurveEdit::update()
{
clearPoints();
CurveInfo & curve = g_model.curves[index];
preview.clearPoints();
CurveHeader & curve = g_model.curves[index];
for (uint8_t i = 0; i < 5 + curve.points; i++) {
if (hasFocus() && current == i) {
position = [=] () -> int {
preview.position = [=] () -> int {
return getPoint(index, i).x;
};
}
else {
addPoint(getPoint(index, i), DEFAULT_COLOR);
preview.addPoint(getPoint(index, i), DEFAULT_COLOR);
}
}
invalidate();
@@ -58,11 +59,11 @@ bool CurveEdit::onTouchEnd(coord_t x, coord_t y)
CurveKeyboard::show(this, isCustomCurve());
CurveInfo & curve = g_model.curves[index];
CurveHeader & curve = g_model.curves[index];
for (int i=0; i<5 + curve.points; i++) {
if (i != current) {
point_t point = getPoint(index, i);
if (abs(getPointX(point.x) - x) <= 10 && abs(getPointY(point.y) - y) <= 10) {
if (abs(preview.getPointX(point.x) - x) <= 10 && abs(preview.getPointY(point.y) - y) <= 10) {
current = i;
update();
break;
@@ -81,7 +82,7 @@ void CurveEdit::onFocusLost()
void CurveEdit::next()
{
if (current++ == points.size()) {
if (current++ == preview.points.size()) {
current = 0;
}
update();
@@ -90,7 +91,7 @@ void CurveEdit::next()
void CurveEdit::previous()
{
if (current-- == 0) {
current = points.size();
current = preview.points.size();
}
update();
}
@@ -113,7 +114,7 @@ void CurveEdit::down()
void CurveEdit::right()
{
CurveInfo & curve = g_model.curves[index];
CurveHeader & curve = g_model.curves[index];
if (curve.type == CURVE_TYPE_CUSTOM && current != 0 && current != curve.points + 5 - 1) {
int8_t * points = curveAddress(index);
int8_t * point = &points[5 + curve.points + current - 1];
@@ -126,7 +127,7 @@ void CurveEdit::right()
void CurveEdit::left()
{
CurveInfo & curve = g_model.curves[index];
CurveHeader & curve = g_model.curves[index];
if (curve.type == CURVE_TYPE_CUSTOM && current != 0 && current != curve.points + 5 - 1) {
int8_t * points = curveAddress(index);
int8_t * point = &points[5 + curve.points + current - 1];
+3 -6
View File
@@ -21,17 +21,13 @@
#ifndef _CURVEEDIT_H_
#define _CURVEEDIT_H_
#include "form.h"
#include "curve.h"
class CurveEdit: public Curve {
class CurveEdit: public FormField {
public:
CurveEdit(Window * parent, const rect_t & rect, uint8_t index);
void checkEvents() override
{
Curve::checkEvents();
}
void update();
void onEvent(event_t event) override;
@@ -43,6 +39,7 @@ class CurveEdit: public Curve {
#endif
protected:
Curve preview;
uint8_t index;
uint8_t current;
void next();
+141 -72
View File
@@ -24,18 +24,6 @@
#define SET_DIRTY() storageDirty(EE_MODEL)
bool isCurveFilled(uint8_t index)
{
CurveInfo &curve = g_model.curves[index];
int8_t * points = curveAddress(index);
for (int i = 0; i < 5 + curve.points; i++) {
if (points[i] != 0) {
return true;
}
}
return false;
}
class CurveEditWindow : public Page {
public:
explicit CurveEditWindow(uint8_t index):
@@ -52,12 +40,91 @@ class CurveEditWindow : public Page {
void buildHeader(Window * window)
{
new StaticText(window, {70, 4, LCD_W - 100, 20}, STR_MENUCURVE, MENU_TITLE_COLOR);
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_MENUCURVE, MENU_TITLE_COLOR);
char s[16];
strAppendStringWithIndex(s, STR_CV, index + 1);
new StaticText(window, {70, 28, LCD_W - 100, 20}, s, MENU_TITLE_COLOR);
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, s, MENU_TITLE_COLOR);
}
#if LCD_W > LCD_H
void buildBody(Window * window)
{
coord_t curveWidth = window->height() - 2 * PAGE_PADDING;
CurveHeader & curve = g_model.curves[index];
int8_t * points = curveAddress(index);
// Curve editor
curveEdit = new CurveEdit(window, { LCD_W - curveWidth - PAGE_PADDING, PAGE_PADDING, curveWidth, curveWidth}, index);
FormGridLayout grid;
grid.setLabelWidth(PAGE_PADDING);
grid.setMarginRight(curveWidth + 2 * PAGE_PADDING);
grid.spacer(PAGE_PADDING);
// Name
new StaticText(window, grid.getFieldSlot(), STR_NAME);
grid.nextLine();
new TextEdit(window, grid.getFieldSlot(), curve.name, sizeof(curve.name));
grid.nextLine();
// Type
new StaticText(window, grid.getFieldSlot(), STR_TYPE);
grid.nextLine();
new Choice(window, grid.getFieldSlot(2, 0), STR_CURVE_TYPES, 0, 1, GET_DEFAULT(g_model.curves[index].type),
[=](int32_t newValue) {
CurveHeader &curve = g_model.curves[index];
if (newValue != curve.type) {
for (int i = 1; i < 4 + curve.points; i++) {
points[i] = calcRESXto100(applyCustomCurve(calc100toRESX(-100 + i * 200 / (4 + curve.points)), index));
}
if (moveCurve(index, newValue == CURVE_TYPE_CUSTOM ? 3 + curve.points : -3 - curve.points)) {
if (newValue == CURVE_TYPE_CUSTOM) {
resetCustomCurveX(points, 5 + curve.points);
}
curve.type = newValue;
}
SET_DIRTY();
curveEdit->update();
}
});
// Points count
auto edit = new NumberEdit(window, grid.getFieldSlot(2, 1), 2, 17, GET_DEFAULT(g_model.curves[index].points + 5),
[=](int32_t newValue) {
newValue -= 5;
CurveHeader &curve = g_model.curves[index];
int newPoints[MAX_POINTS_PER_CURVE];
newPoints[0] = points[0];
newPoints[4 + newValue] = points[4 + curve.points];
for (int i = 1; i < 4 + newValue; i++)
newPoints[i] = calcRESXto100(applyCustomCurve(-RESX + (i * 2 * RESX) / (4 + newValue), index));
if (moveCurve(index, (newValue - curve.points) * (curve.type == CURVE_TYPE_CUSTOM ? 2 : 1))) {
for (int i = 0; i < 5 + newValue; i++) {
points[i] = newPoints[i];
if (curve.type == CURVE_TYPE_CUSTOM && i != 0 && i != 4 + newValue)
points[5 + newValue + i - 1] = -100 + (i * 200) / (4 + newValue);
}
curve.points = newValue;
SET_DIRTY();
curveEdit->update();
}
});
edit->setSuffix(STR_PTS);
grid.nextLine();
// Smooth
new StaticText(window, grid.getFieldSlot(), STR_SMOOTH);
grid.nextLine();
new CheckBox(window, grid.getFieldSlot(), GET_DEFAULT(g_model.curves[index].smooth),
[=](int32_t newValue) {
g_model.curves[index].smooth = newValue;
SET_DIRTY();
curveEdit->update();
});
grid.nextLine();
}
#else
void buildBody(Window * window)
{
FormGridLayout grid;
@@ -66,7 +133,7 @@ class CurveEditWindow : public Page {
grid.setLabelWidth(100);
grid.spacer(20);
CurveInfo & curve = g_model.curves[index];
CurveHeader & curve = g_model.curves[index];
int8_t * points = curveAddress(index);
// Curve editor
@@ -82,7 +149,7 @@ class CurveEditWindow : public Page {
new StaticText(window, grid.getLabelSlot(), STR_TYPE);
new Choice(window, grid.getFieldSlot(2, 0), STR_CURVE_TYPES, 0, 1, GET_DEFAULT(g_model.curves[index].type),
[=](int32_t newValue) {
CurveInfo &curve = g_model.curves[index];
CurveHeader &curve = g_model.curves[index];
if (newValue != curve.type) {
for (int i = 1; i < 4 + curve.points; i++) {
points[i] = calcRESXto100(applyCustomCurve(calc100toRESX(-100 + i * 200 / (4 + curve.points)), index));
@@ -102,7 +169,7 @@ class CurveEditWindow : public Page {
auto edit = new NumberEdit(window, grid.getFieldSlot(2, 1), 2, 17, GET_DEFAULT(g_model.curves[index].points + 5),
[=](int32_t newValue) {
newValue -= 5;
CurveInfo &curve = g_model.curves[index];
CurveHeader &curve = g_model.curves[index];
int newPoints[MAX_POINTS_PER_CURVE];
newPoints[0] = points[0];
newPoints[4 + newValue] = points[4 + curve.points];
@@ -131,8 +198,8 @@ class CurveEditWindow : public Page {
curveEdit->update();
});
grid.nextLine();
}
#endif
};
class CurveButton : public Button {
@@ -141,7 +208,7 @@ class CurveButton : public Button {
Button(parent, rect),
index(index)
{
if (isCurveFilled(index)) {
if (isCurveUsed(index)) {
setHeight(130);
new Curve(this, {5, 5, 120, 120},
[=](int x) -> int {
@@ -156,12 +223,12 @@ class CurveButton : public Button {
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, hasFocus() ? CHECKBOX_COLOR : DISABLE_COLOR);
// curve characteristics
if (isCurveFilled(index)) {
CurveInfo &curve = g_model.curves[index];
if (isCurveUsed(index)) {
CurveHeader &curve = g_model.curves[index];
dc->drawNumber(130, 5, 5 + curve.points, LEFT, 0, nullptr, STR_PTS);
dc->drawTextAtIndex(130, 25, STR_CURVE_TYPES, curve.type);
if (curve.smooth)
dc->drawText(130, 45, "Smooth");
dc->drawText(130, 45, STR_SMOOTH);
}
}
@@ -197,66 +264,68 @@ void ModelCurvesPage::build(FormWindow * window, int8_t focusIndex)
grid.setLabelWidth(66);
for (uint8_t index = 0; index < MAX_CURVES; index++) {
CurveInfo &curve = g_model.curves[index];
CurveHeader &curve = g_model.curves[index];
int8_t * points = curveAddress(index);
// Curve label
new StaticText(window, grid.getLabelSlot(), getCurveString(1 + index), BUTTON_BACKGROUND | CENTERED);
if (isCurveUsed(index)) {
// Curve label
new StaticText(window, grid.getLabelSlot(), getCurveString(1 + index), BUTTON_BACKGROUND | CENTERED);
// Curve drawing
Button * button = new CurveButton(window, grid.getFieldSlot(), index);
button->setPressHandler([=]() -> uint8_t {
Menu * menu = new Menu();
menu->addLine(STR_EDIT, [=]() {
editCurve(window, index);
});
menu->addLine(STR_CURVE_PRESET, [=]() {
Menu * menu = new Menu();
for (int angle = -45; angle <= 45; angle += 15) {
char label[16];
strAppend(strAppendSigned(label, angle), "@");
menu->addLine(label, [=]() {
int dx = 2000 / (5 + curve.points - 1);
for (uint8_t i = 0; i < 5 + curve.points; i++) {
int x = -1000 + i * dx;
points[i] = div_and_round(angle * x, 450);
}
if (curve.type == CURVE_TYPE_CUSTOM) {
resetCustomCurveX(points, 5 + curve.points);
}
storageDirty(EE_MODEL);
rebuild(window, index);
// Curve drawing
Button * button = new CurveButton(window, grid.getFieldSlot(), index);
button->setPressHandler([=]() -> uint8_t {
Menu * menu = new Menu();
menu->addLine(STR_EDIT, [=]() {
editCurve(window, index);
});
}
menu->addLine(STR_CURVE_PRESET, [=]() {
Menu * menu = new Menu();
for (int angle = -45; angle <= 45; angle += 15) {
char label[16];
strAppend(strAppendSigned(label, angle), "@");
menu->addLine(label, [=]() {
int dx = 2000 / (5 + curve.points - 1);
for (uint8_t i = 0; i < 5 + curve.points; i++) {
int x = -1000 + i * dx;
points[i] = div_and_round(angle * x, 450);
}
if (curve.type == CURVE_TYPE_CUSTOM) {
resetCustomCurveX(points, 5 + curve.points);
}
storageDirty(EE_MODEL);
rebuild(window, index);
});
}
});
menu->addLine(STR_MIRROR, [=]() {
curveMirror(index);
storageDirty(EE_MODEL);
button->invalidate();
});
menu->addLine(STR_CLEAR, [=]() {
curveReset(index);
storageDirty(EE_MODEL);
rebuild(window, index);
});
return 0;
});
if (isCurveFilled(index)) {
menu->addLine(STR_MIRROR, [=]() {
for (int i = 0; i < 5 + curve.points; i++)
points[i] = -points[i];
storageDirty(EE_MODEL);
button->invalidate();
});
menu->addLine(STR_CLEAR, [=]() {
for (int i = 0; i < 5 + curve.points; i++)
points[i] = 0;
if (curve.type == CURVE_TYPE_CUSTOM)
resetCustomCurveX(points, 5 + curve.points);
storageDirty(EE_MODEL);
rebuild(window, index);
});
if (focusIndex == index) {
button->setFocus();
}
return 0;
});
if (focusIndex == index) {
button->setFocus();
grid.spacer(button->height() + 5);
}
else {
auto button = new TextButton(window, grid.getLabelSlot(), getCurveString(1 + index));
button->setPressHandler([=]() {
editCurve(window, index);
return 0;
});
grid.spacer(button->height() + 5);
}
grid.spacer(button->height() + 5);
}
grid.nextLine();
window->setLastField();
window->setInnerHeight(grid.getWindowHeight());
}
+2 -2
View File
@@ -119,8 +119,8 @@ class InputEditWindow: public Page {
Choice * curveTypeChoice = nullptr;
void buildHeader(Window * window) {
new StaticText(window, { 50, 0, 100, 20 }, STR_MENUINPUTS, MENU_TITLE_COLOR);
new StaticText(window, { 50, FH+2, 100, 20 }, getSourceString(MIXSRC_FIRST_INPUT + input), MENU_TITLE_COLOR);
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_MENUINPUTS, MENU_TITLE_COLOR);
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), MENU_TITLE_COLOR);
}
void updateCurves() {
@@ -58,6 +58,8 @@ class LogicalSwitchEditWindow: public Page {
headerSwitchName->setFlags(isActive() ? BOLD|WARNING_COLOR : MENU_TITLE_COLOR);
active = !active;
}
Page::checkEvents();
}
protected:
@@ -183,8 +185,8 @@ class LogicalSwitchEditWindow: public Page {
}
void buildHeader(Window * window) {
new StaticText(window, { 70, 4, LCD_W - 100, 20 }, STR_MENULOGICALSWITCHES, MENU_TITLE_COLOR);
headerSwitchName = new StaticText(window, { 70, 28, LCD_W - 100, 20 }, getSwitchPositionName(SWSRC_SW1+ls), MENU_TITLE_COLOR);
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_MENULOGICALSWITCHES, MENU_TITLE_COLOR);
headerSwitchName = new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, getSwitchPositionName(SWSRC_SW1+ls), MENU_TITLE_COLOR);
}
void buildBody(Window * window) {
@@ -256,7 +258,7 @@ class LogicalSwitchButton : public Button {
Button::checkEvents();
}
virtual void paint(BitmapBuffer * dc) override
void paint(BitmapBuffer * dc) override
{
LogicalSwitchData * ls = lswAddress(lsIndex);
uint8_t lsFamily = lswFamily(ls->func);
@@ -341,15 +343,19 @@ void ModelLogicalSwitchesPage::build(FormWindow * window, int8_t focusIndex)
for (uint8_t i=0; i<MAX_LOGICAL_SWITCHES; i++) {
LogicalSwitchData * ls = lswAddress(i);
if (ls->func == LS_FUNC_NONE) {
auto label = new TextButton(window, grid.getLabelSlot(), getSwitchPositionName(SWSRC_SW1+i));
grid.spacer(label->height() + 5);
auto button = new TextButton(window, grid.getLabelSlot(), getSwitchPositionName(SWSRC_SW1+i));
button->setPressHandler([=]() {
editLogicalSwitch(window, i);
return 0;
});
grid.spacer(button->height() + 5);
}
else {
new StaticText(window, grid.getLabelSlot(), getSwitchPositionName(SWSRC_SW1 + i), BUTTON_BACKGROUND | CENTERED);
Button * button = new LogicalSwitchButton(window, grid.getFieldSlot(), i,
[=]() -> uint8_t {
Menu *menu = new Menu();
LogicalSwitchData *ls = lswAddress(i);
[=]() {
Menu * menu = new Menu();
LogicalSwitchData * ls = lswAddress(i);
menu->addLine(STR_EDIT, [=]() {
editLogicalSwitch(window, i);
});
+2 -2
View File
@@ -72,8 +72,8 @@ class MixEditWindow : public Page {
void buildHeader(Window * window)
{
new StaticText(window, {70, 4, 100, 20}, STR_MIXER, MENU_TITLE_COLOR);
new StaticText(window, {70, 28, 100, 20}, getSourceString(MIXSRC_CH1 + channel), MENU_TITLE_COLOR);
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_MIXER, MENU_TITLE_COLOR);
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, getSourceString(MIXSRC_CH1 + channel), MENU_TITLE_COLOR);
}
void updateCurves()
+2 -2
View File
@@ -39,8 +39,8 @@ class OutputEditWindow : public Page {
void buildHeader(Window * window)
{
new StaticText(window, {70, 4, 100, 20}, STR_MENULIMITS, MENU_TITLE_COLOR);
new StaticText(window, {70, 28, 100, 20}, getSourceString(MIXSRC_CH1 + channel), MENU_TITLE_COLOR);
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_MENULIMITS, MENU_TITLE_COLOR);
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, getSourceString(MIXSRC_CH1 + channel), MENU_TITLE_COLOR);
}
void buildBody(Window * window)
+1 -1
View File
@@ -125,7 +125,7 @@ class SensorEditWindow : public Page {
void buildHeader(Window * window)
{
new StaticText(window, {70, 4, 200, 20}, STR_SENSOR + std::to_string(index + 1), MENU_TITLE_COLOR);
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_SENSOR + std::to_string(index + 1), MENU_TITLE_COLOR);
// dynamic display of sensor value ?
//new StaticText(window, {70, 28, 100, 20}, "SF" + std::to_string(index), MENU_TITLE_COLOR);
}
+2 -2
View File
@@ -58,8 +58,8 @@ class SpecialFunctionEditPage : public Page {
void buildHeader(Window * window)
{
new StaticText(window, { 60, 2, 200, 20 }, functions == g_model.customFn ? STR_MENUCUSTOMFUNC : STR_MENUSPECIALFUNCS, MENU_TITLE_COLOR);
headerSF = new StaticText(window, { 60, 22, 100, 20 }, (functions == g_model.customFn ? "SF" : "GF" ) + std::to_string(index), MENU_TITLE_COLOR);
new StaticText(window, { PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, 20 }, functions == g_model.customFn ? STR_MENUCUSTOMFUNC : STR_MENUSPECIALFUNCS, MENU_TITLE_COLOR);
headerSF = new StaticText(window, { PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, 20 }, (functions == g_model.customFn ? "SF" : "GF" ) + std::to_string(index), MENU_TITLE_COLOR);
}
void updateSpecialFunctionOneWindow(FormField * previousField, FormField * nextField)
+1 -1
View File
@@ -83,7 +83,7 @@ void menuModelCurvesAll(event_t event)
#endif
{
drawStringWithIndex(0, y, STR_CV, k+1, attr);
CurveData & crv = g_model.curves[k];
CurveHeader & crv = g_model.curves[k];
editName(4*FW, y, crv.name, sizeof(crv.name), 0, 0);
#if LCD_W >= 212
lcdDrawNumber(11*FW, y, 5+crv.points, LEFT);
+30 -30
View File
@@ -829,33 +829,33 @@ static int luaModelGetCurve(lua_State *L)
{
unsigned int idx = luaL_checkunsigned(L, 1);
if (idx < MAX_CURVES) {
CurveData & curveData = g_model.curves[idx];
CurveHeader & CurveHeader = g_model.curves[idx];
lua_newtable(L);
lua_pushtablezstring(L, "name", curveData.name);
lua_pushtableinteger(L, "type", curveData.type);
lua_pushtableboolean(L, "smooth", curveData.smooth);
lua_pushtableinteger(L, "points", curveData.points + 5);
lua_pushtablezstring(L, "name", CurveHeader.name);
lua_pushtableinteger(L, "type", CurveHeader.type);
lua_pushtableboolean(L, "smooth", CurveHeader.smooth);
lua_pushtableinteger(L, "points", CurveHeader.points + 5);
lua_pushstring(L, "y");
lua_newtable(L);
int8_t * point = curveAddress(idx);
for (int i=0; i < curveData.points + 5; i++) {
for (int i=0; i < CurveHeader.points + 5; i++) {
lua_pushinteger(L, i);
lua_pushinteger(L, *point++);
lua_settable(L, -3);
}
lua_settable(L, -3);
if (curveData.type == CURVE_TYPE_CUSTOM) {
if (CurveHeader.type == CURVE_TYPE_CUSTOM) {
lua_pushstring(L, "x");
lua_newtable(L);
lua_pushinteger(L, 0);
lua_pushinteger(L, -100);
lua_settable(L, -3);
for (int i=0; i < curveData.points + 3; i++) {
for (int i=0; i < CurveHeader.points + 3; i++) {
lua_pushinteger(L, i+1);
lua_pushinteger(L, *point++);
lua_settable(L, -3);
}
lua_pushinteger(L, curveData.points + 4);
lua_pushinteger(L, CurveHeader.points + 4);
lua_pushinteger(L, 100);
lua_settable(L, -3);
lua_settable(L, -3);
@@ -922,9 +922,9 @@ static int luaModelSetCurve(lua_State *L)
memset(yPoints, -127, sizeof(yPoints));
CurveData &destCurveData = g_model.curves[curveIdx];
CurveData newCurveData;
memclear(&newCurveData, sizeof(CurveData));
CurveHeader &destCurveHeader = g_model.curves[curveIdx];
CurveHeader newCurveHeader;
memclear(&newCurveHeader, sizeof(CurveHeader));
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
@@ -932,18 +932,18 @@ static int luaModelSetCurve(lua_State *L)
const char *key = luaL_checkstring(L, -2);
if (!strcmp(key, "name")) {
const char *name = luaL_checkstring(L, -1);
str2zchar(newCurveData.name, name, sizeof(newCurveData.name));
str2zchar(newCurveHeader.name, name, sizeof(newCurveHeader.name));
}
else if (!strcmp(key, "type")) {
newCurveData.type = luaL_checkinteger(L, -1);
newCurveHeader.type = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "smooth")) {
// Earlier version of this api expected a 0/1 integer instead of a boolean
// Still accept a 0/1 here
if (lua_isboolean(L,-1))
newCurveData.smooth = lua_toboolean(L, -1);
newCurveHeader.smooth = lua_toboolean(L, -1);
else
newCurveData.smooth = luaL_checkinteger(L, -1);
newCurveHeader.smooth = luaL_checkinteger(L, -1);
}
else if (!strcmp(key, "x") || !strcmp(key, "y")) {
luaL_checktype(L, -1, LUA_TTABLE);
@@ -972,14 +972,14 @@ static int luaModelSetCurve(lua_State *L)
do {
numPoints++;
} while (yPoints[numPoints]!=-127 && numPoints < MAX_POINTS_PER_CURVE);
newCurveData.points = numPoints - 5;
newCurveHeader.points = numPoints - 5;
if (numPoints < MIN_POINTS_PER_CURVE || numPoints > MAX_POINTS_PER_CURVE) {
lua_pushinteger(L, 1);
return 1;
}
if (newCurveData.type == CURVE_TYPE_CUSTOM) {
if (newCurveHeader.type == CURVE_TYPE_CUSTOM) {
// The rest of the points are checked by the monotonic condition
for (unsigned int i=numPoints; i < sizeof(xPoints);i++)
@@ -992,7 +992,7 @@ static int luaModelSetCurve(lua_State *L)
}
// Check first and last point
if (xPoints[0] != -100 || xPoints[newCurveData.points + 4] != 100) {
if (xPoints[0] != -100 || xPoints[newCurveHeader.points + 4] != 100) {
lua_pushinteger(L, 5);
return 1;
}
@@ -1007,7 +1007,7 @@ static int luaModelSetCurve(lua_State *L)
}
// Check that ypoints have the right number of points set
for (int i=0; i < 5 + newCurveData.points;i++)
for (int i=0; i < 5 + newCurveHeader.points;i++)
{
if (yPoints[i] == -127)
{
@@ -1018,19 +1018,19 @@ static int luaModelSetCurve(lua_State *L)
// Calculate size of curve we replace
int oldCurveMemSize;
if (destCurveData.type == CURVE_TYPE_STANDARD) {
oldCurveMemSize = 5 + destCurveData.points;
if (destCurveHeader.type == CURVE_TYPE_STANDARD) {
oldCurveMemSize = 5 + destCurveHeader.points;
}
else {
oldCurveMemSize = 8 + 2 * destCurveData.points;
oldCurveMemSize = 8 + 2 * destCurveHeader.points;
}
// Calculate own size
int newCurveMemSize;
if (newCurveData.type == CURVE_TYPE_STANDARD)
newCurveMemSize = 5 + newCurveData.points;
if (newCurveHeader.type == CURVE_TYPE_STANDARD)
newCurveMemSize = 5 + newCurveHeader.points;
else
newCurveMemSize = 8 + 2 * newCurveData.points;
newCurveMemSize = 8 + 2 * newCurveHeader.points;
int shift = newCurveMemSize - oldCurveMemSize;
@@ -1042,15 +1042,15 @@ static int luaModelSetCurve(lua_State *L)
}
// Curve fits into mem, fill new curve
destCurveData = newCurveData;
destCurveHeader = newCurveHeader;
int8_t *point = curveAddress(curveIdx);
for (int i = 0; i < destCurveData.points + 5; i++) {
for (int i = 0; i < destCurveHeader.points + 5; i++) {
*point++ = yPoints[i];
}
if (destCurveData.type == CURVE_TYPE_CUSTOM) {
for (int i = 1; i < destCurveData.points + 4; i++) {
if (destCurveHeader.type == CURVE_TYPE_CUSTOM) {
for (int i = 1; i < destCurveHeader.points + 4; i++) {
*point++ = xPoints[i];
}
}
+2 -24
View File
@@ -256,6 +256,7 @@
#endif
#include "myeeprom.h"
#include "curves.h"
inline void memclear(void * p, size_t size)
{
@@ -802,31 +803,8 @@ inline void getGVarIncDecRange(int16_t & valMin, int16_t & valMax)
}
#endif
// Curves
enum BaseCurves {
CURVE_NONE,
CURVE_X_GT0,
CURVE_X_LT0,
CURVE_ABS_X,
CURVE_F_GT0,
CURVE_F_LT0,
CURVE_ABS_F,
CURVE_BASE
};
int8_t * curveAddress(uint8_t idx);
point_t getPoint(uint8_t i);
point_t getPoint(uint8_t curveIndex, uint8_t index);
typedef CurveData CurveInfo;
void loadCurves();
#define LOAD_MODEL_CURVES() loadCurves()
int intpol(int x, uint8_t idx);
int applyCurve(int x, CurveRef & curve);
int applyCustomCurve(int x, uint8_t idx);
int applyCurrentCurve(int x);
int8_t getCurveX(int noPoints, int point);
void resetCustomCurveX(int8_t * points, int noPoints);
bool moveCurve(uint8_t index, int8_t shift); // TODO bool?
void clearInputs();
void defaultInputs();
@@ -200,7 +200,7 @@ PACK(typedef struct {
uint8_t smooth:1;
uint8_t spare:4;
int8_t points;
}) CurveData_v216;
}) CurveHeader_v216;
#if defined(PCBTARANIS)
PACK(typedef struct {
@@ -586,7 +586,7 @@ PACK(typedef struct {
LimitData_v216 limitData[MAX_OUTPUT_CHANNELS_218];
ExpoData_v216 expoData[MAX_EXPOS_218];
CurveData_v216 curves[MAX_CURVES_218];
CurveHeader_v216 curves[MAX_CURVES_218];
int8_t points[MAX_CURVE_POINTS_218];
LogicalSwitchData_v216 logicalSw[32];
@@ -632,7 +632,7 @@ PACK(typedef struct {
LimitData limitData[MAX_OUTPUT_CHANNELS_218];
ExpoData_v217 expoData[MAX_EXPOS_218];
CurveData_v216 curves[MAX_CURVES_218];
CurveHeader_v216 curves[MAX_CURVES_218];
int8_t points[MAX_CURVE_POINTS_218];
LogicalSwitchData_v217 logicalSw[MAX_LOGICAL_SWITCHES_218];
@@ -164,7 +164,7 @@ void convertModelData_218_to_219(ModelData &model)
}
for (uint8_t i=0; i<MAX_CURVES_218; i++) {
memmove(&newModel.curves[i], &oldModel.curves[i], sizeof(CurveData_v218));
memmove(&newModel.curves[i], &oldModel.curves[i], sizeof(CurveHeader_v218));
}
for (uint32_t i=0; i<MAX_CURVE_POINTS_218; i++) {
@@ -249,7 +249,7 @@ PACK(typedef struct {
uint8_t smooth:1;
int8_t points:6; // describes number of points - 5
char name[LEN_CURVE_NAME_218];
}) CurveData_v218;
}) CurveHeader_v218;
PACK(typedef struct {
int16_t calib[4];
@@ -447,7 +447,7 @@ PACK(struct ModelData_v218 {
LimitData limitData[MAX_OUTPUT_CHANNELS_218];
ExpoData_v218 expoData[MAX_EXPOS_218];
CurveData_v218 curves[MAX_CURVES_218];
CurveHeader_v218 curves[MAX_CURVES_218];
int8_t points[MAX_CURVE_POINTS_218];
LogicalSwitchData_v218 logicalSw[MAX_LOGICAL_SWITCHES_218];
+2 -2
View File
@@ -102,7 +102,7 @@ void copyFlightModeData(A * dest, B * src)
}
template <class A, class B>
void copyCurveData(A * dest, B * src)
void copyCurveHeader(A * dest, B * src)
{
dest->type = src->type;
dest->smooth = src->smooth;
@@ -259,7 +259,7 @@ void copyModelData(A * dest, B * src)
copyExpoData(&dest->expoData[i], &src->expoData[i]);
}
for (int i=0; i<32; i++) {
copyCurveData(&dest->curves[i], &src->curves[i]);
copyCurveHeader(&dest->curves[i], &src->curves[i]);
}
memcpy(dest->points, src->points, sizeof(dest->points));
for (int i=0; i<64; i++) {
+1 -1
View File
@@ -157,7 +157,7 @@ void postModelLoad(bool alarms)
}
}
LOAD_MODEL_CURVES();
loadCurves();
resumeMixerCalculations();
if (pulsesStarted()) {
@@ -88,6 +88,9 @@ constexpr uint32_t ALERT_MESSAGE_TOP = ALERT_TITLE_TOP + 90;
constexpr uint32_t ALERT_MESSAGE_LEFT = ALERT_TITLE_LEFT;
constexpr uint32_t ALERT_ACTION_TOP = 240;
constexpr uint32_t PAGE_TITLE_TOP = 2;
constexpr uint32_t PAGE_TITLE_LEFT = 50;
// TODO common code, not in target
enum LcdColorIndex
{
@@ -87,6 +87,9 @@ constexpr uint32_t ALERT_MESSAGE_LEFT = ALERT_TITLE_LEFT;
constexpr uint32_t ALERT_ACTION_TOP = 240;
constexpr uint32_t ALERT_BUTTON_TOP = 300;
constexpr uint32_t PAGE_TITLE_TOP = 4;
constexpr uint32_t PAGE_TITLE_LEFT = 70;
enum LcdColorIndex
{
DEFAULT_COLOR_INDEX,