feat: Companion - New model curve tab layout, curve edit dialog and mix edit curve view (#1484)

Add curve image and double click to edit to input edit, mix edit and outputs
This commit is contained in:
Neil Horne
2022-03-08 13:10:13 +10:00
committed by GitHub
parent 70a4f6c154
commit e0e196a6e6
30 changed files with 2076 additions and 1472 deletions
+1 -1
View File
@@ -66,7 +66,7 @@ qt5_wrap_cpp(firmwares_SRCS ${firmwares_QT})
add_library(firmwares ${firmwares_SRCS} ${firmwares_HDRS})
target_link_libraries(firmwares ${CPN_COMMON_LIB} datamodels Qt5::Core Qt5::Xml Qt5::Widgets)
target_link_libraries(firmwares ${CPN_COMMON_LIB} datamodels shared Qt5::Core Qt5::Xml Qt5::Widgets)
target_link_libraries(firmwares yaml-cpp)
target_include_directories(firmwares
+87
View File
@@ -20,6 +20,8 @@
#include "curvedata.h"
#include "datahelpers.h"
#include "compounditemmodels.h"
#include "eeprominterface.h"
CurveData::CurveData()
{
@@ -32,6 +34,22 @@ void CurveData::clear(int count)
this->count = count;
}
void CurveData::init()
{
float incr = 200.0 / ((float)count - 1.0);
// points[0].x must be -100
for (int i = 0; i < count; i++) {
if (i < count - 1)
points[i].x = -100 + (int)(incr * i);
else
points[i].x = 100; // points[count - 1].x must be +100 do not risk a rounding issue using incr
points[i].y = points[i].x;
}
}
bool CurveData::isEmpty() const
{
CurveData tmp;
@@ -42,3 +60,72 @@ QString CurveData::nameToString(const int idx) const
{
return DataHelpers::getElementName(tr("CV"), idx + 1, name);
}
QString CurveData::typeToString() const
{
return typeToString(type);
}
// static
QString CurveData::typeToString(int value)
{
switch (value) {
case CURVE_TYPE_STANDARD:
return tr("Standard");
case CURVE_TYPE_CUSTOM:
return tr("Custom");
default:
return CPN_STR_UNKNOWN_ITEM;
}
}
QString CurveData::pointsToString() const
{
QString result = "[";
if (type == CURVE_TYPE_CUSTOM) {
for (int j = 0; j < count; j++) {
if (j != 0)
result.append(", ");
result.append(QString("(%1, %2)").arg(points[j].x).arg(points[j].y));
}
}
else {
for (int j = 0; j < count; j++) {
if (j != 0)
result.append(", ");
result.append(QString("%1").arg(points[j].y));
}
}
result.append("]");
return result;
}
// static
AbstractStaticItemModel * CurveData::typeItemModel()
{
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
mdl->setName("curvedata.type");
for (int i = 0; i <= CURVE_TYPE_LAST; i++) {
mdl->appendToItemList(typeToString(i), i);
}
mdl->loadItemList();
return mdl;
}
// static
AbstractStaticItemModel * CurveData::pointsItemModel()
{
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
mdl->setName("curvedata.points");
for (int i = 2; i <= CPN_MAX_POINTS; i++) {
mdl->appendToItemList(tr("%1 points").arg(i), i);
}
mdl->loadItemList();
return mdl;
}
+8
View File
@@ -24,6 +24,8 @@
#include <QtCore>
class AbstractStaticItemModel;
class CurvePoint {
public:
int8_t x;
@@ -51,6 +53,12 @@ class CurveData {
char name[CURVEDATA_NAME_LEN + 1];
void clear(int count = 5);
void init();
bool isEmpty() const;
QString nameToString(const int idx) const;
QString typeToString() const;
QString pointsToString() const;
static QString typeToString(int value);
static AbstractStaticItemModel * typeItemModel();
static AbstractStaticItemModel * pointsItemModel();
};
+68 -11
View File
@@ -23,6 +23,8 @@
#include "helpers.h"
#include "modeldata.h"
#include "filtereditemmodels.h"
#include "curveimagewidget.h"
#include "curvedialog.h"
const QString CurveReference::toString(const ModelData * model, bool verbose) const
{
@@ -82,7 +84,7 @@ int CurveReference::getDefaultValue(const CurveRefType type, const bool isGVar)
// static
QString CurveReference::typeToString(const CurveRefType type)
{
const QStringList strl = { tr("Diff"), tr("Expo") , tr("Func"), tr("Curve") };
const QStringList strl = { tr("Diff"), tr("Expo") , tr("Func"), tr("Custom") };
int idx = (int)type;
if (idx < 0 || idx >= strl.count())
@@ -145,7 +147,8 @@ int CurveReference::functionCount()
*/
CurveReferenceUIManager::CurveReferenceUIManager(QComboBox * curveTypeCB, QCheckBox * curveGVarCB, QSpinBox * curveValueSB,
QComboBox * curveValueCB, CurveReference & curveRef, const ModelData & model,
QComboBox * curveValueCB, QLabel * curveLabelImage,
CurveReference & curveRef, ModelData & model, CompoundItemModelFactory * sharedItemModels,
CurveRefFilteredFactory * curveRefFilteredFactory, QObject * parent) :
QObject(parent),
curveTypeCB(curveTypeCB),
@@ -154,9 +157,13 @@ CurveReferenceUIManager::CurveReferenceUIManager(QComboBox * curveTypeCB, QCheck
curveValueCB(curveValueCB),
curveRef(curveRef),
model(model),
sharedItemModels(sharedItemModels),
filteredModelFactory(curveRefFilteredFactory),
lock(false),
filteredModelFactory(curveRefFilteredFactory)
curveImageWidget(nullptr)
{
connectItemModelEvents(filteredModelFactory->getItemModel(CurveRefFilteredFactory::CRFIM_CURVE));
hasCapabilityGvars = getCurrentFirmware()->getCapability(Gvars);
if (curveTypeCB) {
@@ -178,6 +185,15 @@ CurveReferenceUIManager::CurveReferenceUIManager(QComboBox * curveTypeCB, QCheck
curveValueCB->setSizeAdjustPolicy(QComboBox::AdjustToContents);
curveValueCB->setMaxVisibleItems(10);
connect(curveValueCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valueCBChanged()));
if (curveLabelImage) {
curveImageWidget = qobject_cast<CurveImageWidget *>(curveLabelImage);
if (curveImageWidget) {
curveImageWidget->set(&model, getCurrentFirmware(), sharedItemModels, abs(curveRef.value) - 1, Qt::black, 3);
curveImageWidget->setGrid(Qt::gray, 2);
connect(curveImageWidget, &CurveImageWidget::doubleClicked, this, &CurveReferenceUIManager::curveImageDoubleClicked);
}
}
}
update();
@@ -185,12 +201,13 @@ CurveReferenceUIManager::CurveReferenceUIManager(QComboBox * curveTypeCB, QCheck
CurveReferenceUIManager::~CurveReferenceUIManager()
{
delete filteredModelFactory;
}
#define CURVE_REF_UI_GVAR_SHOW (1<<0)
#define CURVE_REF_UI_VALUE_SHOW (1<<1)
#define CURVE_REF_UI_REF_SHOW (1<<2)
#define CURVE_REF_UI_GVAR_SHOW (1 << 0)
#define CURVE_REF_UI_VALUE_SHOW (1 << 1)
#define CURVE_REF_UI_REF_SHOW (1 << 2)
#define CURVE_REF_UI_CURVE_SHOW (1 << 3)
void CurveReferenceUIManager::update()
{
@@ -214,20 +231,34 @@ void CurveReferenceUIManager::update()
widgetsMask |= CURVE_REF_UI_REF_SHOW;
}
if(curveTypeCB) {
if (curveRef.type == CurveReference::CURVE_REF_CUSTOM)
widgetsMask |= CURVE_REF_UI_CURVE_SHOW;
if (curveTypeCB) {
curveTypeCB->setCurrentIndex(curveTypeCB->findData(curveRef.type));
curveTypeCB->show();
}
if(curveGVarCB)
if (curveGVarCB)
curveGVarCB->setVisible(widgetsMask & CURVE_REF_UI_GVAR_SHOW);
if(curveValueSB)
if (curveValueSB)
curveValueSB->setVisible(widgetsMask & CURVE_REF_UI_VALUE_SHOW);
if(curveValueCB) {
if (curveValueCB) {
if (curveRef.isValueReference())
populateValueCB(curveValueCB);
curveValueCB->setVisible(widgetsMask & CURVE_REF_UI_REF_SHOW);
}
if (curveValueCB && curveImageWidget) {
curveImageWidget->draw();
curveImageWidget->setVisible(widgetsMask & CURVE_REF_UI_CURVE_SHOW);
}
emit resized();
lock = false;
}
@@ -244,6 +275,8 @@ void CurveReferenceUIManager::typeChanged(int value)
if (!lock) {
CurveReference::CurveRefType type = (CurveReference::CurveRefType)curveTypeCB->itemData(curveTypeCB->currentIndex()).toInt();
curveRef = CurveReference(type, CurveReference::getDefaultValue(type));
if (curveImageWidget && curveRef.type == CurveReference::CURVE_REF_CUSTOM)
curveImageWidget->setIndex(abs(curveRef.value) - 1);
update();
}
}
@@ -260,6 +293,8 @@ void CurveReferenceUIManager::valueCBChanged()
{
if (!lock) {
curveRef.value = curveValueCB->itemData(curveValueCB->currentIndex()).toInt();
if (curveImageWidget && curveRef.type == CurveReference::CURVE_REF_CUSTOM)
curveImageWidget->setIndex(abs(curveRef.value) - 1);
update();
}
}
@@ -285,3 +320,25 @@ void CurveReferenceUIManager::populateValueCB(QComboBox * cb)
cb->setCurrentIndex(cb->findData(curveRef.value));
}
}
void CurveReferenceUIManager::curveImageDoubleClicked()
{
if (curveRef.type == CurveReference::CURVE_REF_CUSTOM && abs(curveRef.value) > 0)
curveImageWidget->edit();
}
void CurveReferenceUIManager::connectItemModelEvents(const FilteredItemModel * itemModel)
{
connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &CurveReferenceUIManager::onItemModelAboutToBeUpdated);
connect(itemModel, &FilteredItemModel::updateComplete, this, &CurveReferenceUIManager::onItemModelUpdateComplete);
}
void CurveReferenceUIManager::onItemModelAboutToBeUpdated()
{
lock = true;
}
void CurveReferenceUIManager::onItemModelUpdateComplete()
{
update();
}
+23 -12
View File
@@ -18,18 +18,20 @@
* GNU General Public License for more details.
*/
#ifndef CURVEREFERENCE_H
#define CURVEREFERENCE_H
#pragma once
#include <QtCore>
#include <QComboBox>
#include <QCheckBox>
#include <QLabel>
#include <QSpinBox>
#include <QStandardItemModel>
class ModelData;
class CurveRefFilteredFactory;
class CompoundItemModelFactory;
class FilteredItemModel;
class CurveImageWidget;
class CurveReference {
@@ -90,21 +92,27 @@ class CurveReferenceUIManager : public QObject {
public:
explicit CurveReferenceUIManager(QComboBox *curveTypeCB, QCheckBox *curveGVarCB, QSpinBox *curveValueSB, QComboBox *curveValueCB,
CurveReference & curve, const ModelData & model, CurveRefFilteredFactory * curveRefFilteredFactory,
QObject * parent = nullptr);
QLabel *curveImage, CurveReference & curve, ModelData & model, CompoundItemModelFactory * sharedItemModels,
CurveRefFilteredFactory * curveRefFilteredFactory, QObject * parent = nullptr);
explicit CurveReferenceUIManager(QComboBox *curveValueCB, CurveReference & curve, const ModelData & model,
explicit CurveReferenceUIManager(QComboBox *curveValueCB, CurveReference & curve, ModelData & model, CompoundItemModelFactory * sharedItemModels,
CurveRefFilteredFactory * curveRefFilteredFactory, QObject * parent = nullptr) :
CurveReferenceUIManager(nullptr, nullptr, nullptr, curveValueCB, curve, model, curveRefFilteredFactory, parent) {}
CurveReferenceUIManager(nullptr, nullptr, nullptr, curveValueCB, nullptr, curve, model, sharedItemModels, curveRefFilteredFactory, parent) {}
virtual ~CurveReferenceUIManager();
signals:
void resized();
protected slots:
void gvarCBChanged(int);
void typeChanged(int);
void valueSBChanged();
void valueCBChanged();
void update();
void curveImageDoubleClicked();
void onItemModelAboutToBeUpdated();
void onItemModelUpdateComplete();
private:
QComboBox *curveTypeCB;
@@ -112,11 +120,14 @@ class CurveReferenceUIManager : public QObject {
QSpinBox *curveValueSB;
QComboBox *curveValueCB;
CurveReference & curveRef;
const ModelData & model;
bool lock;
bool hasCapabilityGvars;
ModelData & model;
CompoundItemModelFactory *sharedItemModels;
CurveRefFilteredFactory *filteredModelFactory;
bool lock;
CurveImageWidget *curveImageWidget = nullptr;
bool hasCapabilityGvars;
void connectItemModelEvents(const FilteredItemModel * itemModel);
void populateValueCB(QComboBox * cb);
};
#endif // CURVEREFERENCE_H
@@ -48,11 +48,6 @@ void YamlReadCurvePoints(const YAML::Node& node, CurveData* curves)
}
}
curve.points[curve.count - 1].x = +100;
} else {
// Standard curve: X points are generated
for (int k = 0; k < curve.count; k++) {
curve.points[k].x = -100 + (200 * k) / (curve.count - 1);
}
}
}
}
+4 -4
View File
@@ -584,18 +584,18 @@ TableLayout::TableLayout(QWidget * parent, int rowCount, const QStringList & hea
#endif
}
void TableLayout::addWidget(int row, int column, QWidget * widget)
void TableLayout::addWidget(int row, int column, QWidget * widget, Qt::Alignment alignment)
{
#if defined(TABLE_LAYOUT)
QHBoxLayout * layout = new QHBoxLayout(tableWidget);
layout->addWidget(widget);
addLayout(row, column, layout);
#else
gridWidget->addWidget(widget, row + 1, column);
gridWidget->addWidget(widget, row + 1, column, alignment);
#endif
}
void TableLayout::addLayout(int row, int column, QLayout * layout)
void TableLayout::addLayout(int row, int column, QLayout * layout, Qt::Alignment alignment)
{
#if defined(TABLE_LAYOUT)
layout->setContentsMargins(1, 3, 1, 3);
@@ -603,7 +603,7 @@ void TableLayout::addLayout(int row, int column, QLayout * layout)
containerWidget->setLayout(layout);
tableWidget->setCellWidget(row, column, containerWidget);
#else
gridWidget->addLayout(layout, row + 1, column);
gridWidget->addLayout(layout, row + 1, column, alignment);
#endif
}
+2 -2
View File
@@ -186,8 +186,8 @@ public:
TableLayout(QWidget * parent, int rowCount, const QStringList & headerLabels);
// ~TableLayout() ;
void addWidget(int row, int column, QWidget * widget);
void addLayout(int row, int column, QLayout * layout);
void addWidget(int row, int column, QWidget * widget, Qt::Alignment alignment = Qt::Alignment());
void addLayout(int row, int column, QLayout * layout, Qt::Alignment alignment = Qt::Alignment());
void resizeColumnsToContents();
void setColumnWidth(int col, int width);
+2 -1
View File
@@ -8,7 +8,6 @@ set(modeledit_NAMES
modeledit
setup
heli
curves
telemetry
expodialog
mixerdialog
@@ -27,6 +26,7 @@ set(modeledit_SRCS
# edge.cpp ## commenting them here avoids a "duplicate target" warning eg. from ninja
colorcustomscreens.cpp
telemetry_customscreens.cpp
curves.cpp
)
set(modeledit_HDRS
@@ -40,6 +40,7 @@ set(modeledit_HDRS
# node.h
colorcustomscreens.h
telemetry_customscreens.h
curves.h
)
set(modeledit_UIS
+41 -4
View File
@@ -21,6 +21,7 @@
#include "channels.h"
#include "helpers.h"
#include "filtereditemmodels.h"
#include "curveimagewidget.h"
LimitsGroup::LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row, int col, int & value, const ModelData & model,
int min, int max, int deflt, FilteredItemModel * gvarModel, ModelPanel * panel):
@@ -107,7 +108,7 @@ ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSetting
}
headerLabels << tr("Subtrim") << tr("Min") << tr("Max") << tr("Direction");
if (IS_HORUS_OR_TARANIS(firmware->getBoard()))
headerLabels << tr("Curve");
headerLabels << tr("Curve") << tr("Plot");
if (firmware->getCapability(PPMCenter))
headerLabels << tr("PPM Center");
if (firmware->getCapability(SYMLimits))
@@ -159,9 +160,20 @@ ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSetting
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
curveCB[i] = new QComboBox(this);
curveCB[i]->setProperty("index", i);
curveCB[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents);
curveCB[i]->setModel(dialogFilteredItemModels->getItemModel(crvid));
connect(curveCB[i], SIGNAL(currentIndexChanged(int)), this, SLOT(curveEdited()));
tableLayout->addWidget(i, col++, curveCB[i]);
curveImage[i] = new CurveImageWidget(this);
int crvidx = model.limitData[i].curve.value - 1;
QColor pencolor = colors[crvidx >= 0 ? crvidx : Qt::black];
curveImage[i]->set(&model, firmware, sharedItemModels, crvidx, pencolor, 3);
curveImage[i]->setGrid(Qt::gray, 2);
curveImage[i]->setProperty("index", i);
curveImage[i]->setFixedSize(QSize(100, 100));
connect(curveImage[i], &CurveImageWidget::doubleClicked, this, &ChannelsPanel::on_curveImageDoubleClicked);
tableLayout->addWidget(i, col++, curveImage[i]);
}
// PPM center
@@ -191,7 +203,9 @@ ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSetting
disableMouseScrolling();
tableLayout->resizeColumnsToContents();
tableLayout->pushRowsUp(chnCapability+1);
tableLayout->pushRowsUp(chnCapability + 1);
adjustSize();
}
ChannelsPanel::~ChannelsPanel()
@@ -260,8 +274,13 @@ void ChannelsPanel::curveEdited()
QComboBox *cb = qobject_cast<QComboBox*>(sender());
int index = cb->property("index").toInt();
// ignore unnecessary updates that could be triggered by updates to the data model
if (model->limitData[index].curve != CurveReference(CurveReference::CURVE_REF_CUSTOM, cb->itemData(cb->currentIndex()).toInt())) {
model->limitData[index].curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, cb->itemData(cb->currentIndex()).toInt());
LimitData &ld = model->limitData[index];
if (ld.curve != CurveReference(CurveReference::CURVE_REF_CUSTOM, cb->itemData(cb->currentIndex()).toInt())) {
ld.curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, cb->itemData(cb->currentIndex()).toInt());
curveImage[index]->setIndex(abs(ld.curve.value) - 1);
if (abs(ld.curve.value) > 0)
curveImage[index]->setPen(colors[abs(ld.curve.value) - 1], 3);
updateLine(index);
emit modified();
}
}
@@ -298,6 +317,13 @@ void ChannelsPanel::updateLine(int i)
invCB[i]->setCurrentIndex((chn.revert) ? 1 : 0);
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
curveCB[i]->setCurrentIndex(curveCB[i]->findData(chn.curve.value));
if (chn.curve.value == 0) {
curveImage[i]->setVisible(false);
}
else {
curveImage[i]->setVisible(true);
curveImage[i]->draw();
}
}
if (firmware->getCapability(PPMCenter)) {
centerSB[i]->setValue(chn.ppmCenter + 1500);
@@ -468,3 +494,14 @@ void ChannelsPanel::updateItemModels()
sharedItemModels->update(AbstractItemModel::IMUE_Channels);
emit modified();
}
void ChannelsPanel::on_curveImageDoubleClicked()
{
bool ok = false;
int index = sender()->property("index").toInt(&ok);
if (ok && curveImage[abs(index)]->edit()) {
updateLine(index);
emit modified();
}
}
+10 -5
View File
@@ -27,6 +27,7 @@
class CompoundItemModelFactory;
class FilteredItemModelFactory;
class CurveImageWidget;
constexpr char MIMETYPE_CHANNEL[] = "application/x-companion-channel";
@@ -85,24 +86,28 @@ class ChannelsPanel : public ModelPanel
void onCustomContextMenuRequested(QPoint pos);
void onItemModelAboutToBeUpdated();
void onItemModelUpdateComplete();
void on_curveImageDoubleClicked();
private:
bool hasClipboardData(QByteArray * data = nullptr) const;
bool insertAllowed() const;
bool moveDownAllowed() const;
bool moveUpAllowed() const;
QLineEdit *name[CPN_MAX_CHNOUT];
LimitsGroup *chnOffset[CPN_MAX_CHNOUT];
LimitsGroup *chnMin[CPN_MAX_CHNOUT];
LimitsGroup *chnMax[CPN_MAX_CHNOUT];
QComboBox *invCB[CPN_MAX_CHNOUT];
QComboBox *curveCB[CPN_MAX_CHNOUT];
CurveImageWidget *curveImage[CPN_MAX_CHNOUT];
QSpinBox *centerSB[CPN_MAX_CHNOUT];
QCheckBox *symlimitsChk[CPN_MAX_CHNOUT];
int selectedIndex;
int chnCapability;
CompoundItemModelFactory *sharedItemModels;
FilteredItemModelFactory *dialogFilteredItemModels;
bool hasClipboardData(QByteArray * data = nullptr) const;
bool insertAllowed() const;
bool moveDownAllowed() const;
bool moveUpAllowed() const;
void updateItemModels();
void connectItemModelEvents(const FilteredItemModel * itemModel);
FilteredItemModelFactory *dialogFilteredItemModels;
};
+121 -634
View File
@@ -19,652 +19,140 @@
*/
#include "curves.h"
#include "ui_curves.h"
#include "node.h"
#include "edge.h"
#include "curveimagewidget.h"
#include "compounditemmodels.h"
#include "datahelpers.h"
#include "helpers.h"
#include "filtereditemmodels.h"
#define GFX_MARGIN 16
#define CURVE_COEFF_ENABLE 1
#define CURVE_YMID_ENABLE 2
#define CURVE_YMIN_ENABLE 4
float curveLinear(float x, float coeff, float yMin, float yMid, float yMax)
{
float a = (yMax - yMin) / 200.0;
return yMin + a * (x + 100.0);
}
float c9xexpou(float point, float coeff)
{
float x = point * 1024.0 / 100.0;
float k = coeff * 256.0 / 100.0;
return ((k * x * x * x / (1024 * 1024) + x * (256 - k) + 128) / 256) / 1024.0 * 100;
}
float curveExpo(float x, float coeff, float yMin, float yMid, float yMax)
{
float a = (yMax - yMin) / 100.0;
x += 100.0;
x /= 2.0;
if (coeff >= 0) {
return round(c9xexpou(x, coeff)*a + yMin);
}
else {
coeff = -coeff;
x = 100 - x;
return round((100.0 - c9xexpou(x, coeff)) * a + yMin);
}
}
float curveSymmetricalY(float x, float coeff, float yMin, float yMid, float yMax)
{
bool invert;
if (x < 0) {
x = -x;
invert = 1;
}
else {
invert = 0;
}
float y;
if (coeff >= 0) {
y = round(c9xexpou(x, coeff) * (yMax / 100.0));
}
else {
coeff = -coeff;
x = 100.0 - x;
y = round((100.0 - c9xexpou(x, coeff)) * (yMax / 100.0));
}
if (invert) {
y = -y;
}
return y;
}
float curveSymmetricalX(float x, float coeff, float yMin, float yMid, float yMax)
{
float a = (yMax - yMid) / 100.0;
if (x < 0)
x = -x;
float y;
if (coeff >= 0) {
y = round(c9xexpou(x, coeff) * a + yMid);
}
else {
coeff = -coeff;
x = 100 - x;
y = round((100.0 - c9xexpou(x, coeff)) * a + yMid);
}
return y;
}
CurvesPanel::CurvesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware,
CompoundItemModelFactory * sharedItemModels):
CurvesPanel::CurvesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels):
ModelPanel(parent, model, generalSettings, firmware),
ui(new Ui::Curves),
currentCurve(0),
sharedItemModels(sharedItemModels)
{
ui->setupUi(this);
lock = true;
maxCurves = firmware->getCapability(NumCurves);
hasNames = firmware->getCapability(HasCvNames);
hasEnhanced = firmware->getCapability(EnhancedCurves);
maxPoints = firmware->getCapability(NumCurvePoints);
if (!hasNames) {
ui->curveName->hide();
ui->curveNameLabel->hide();
}
QStringList headerLabels;
headerLabels << "#";
scene = new CustomScene(ui->curvePreview);
scene->setItemIndexMethod(QGraphicsScene::NoIndex);
connect(scene, SIGNAL(newPoint(int, int)), this, SLOT(onSceneNewPoint(int, int)));
headerLabels << tr("Plot") << tr("Details");
ui->curvePreview->setScene(scene);
TableLayout *tableLayout = new TableLayout(this, maxCurves, headerLabels);
int limit;
if (maxCurves > 16) {
limit = maxCurves / 2;
} else {
limit = maxCurves;
}
for (int i = 0; i < maxCurves; i++) {
visibleCurves[i] = false;
int col = 0;
// The edit curve button
QPushButton * edit = new QPushButton(this);
edit->setProperty("index", i);
QLabel *label = new QLabel(this);
label->setText(tr("CV%1").arg(i+1));
label->setProperty("index", i);
label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
label->setContextMenuPolicy(Qt::CustomContextMenu);
label->setToolTip(tr("Popup menu available"));
label->setMouseTracking(true);
connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequested(QPoint)));
tableLayout->addWidget(i, col++, label);
QString style = QString(
"QPushButton {"
#ifdef __GNUC__
// creates more compact and likely consistent buttons across OS flavors
"background-color: %1; color: white; padding: 2px 3px; border-style: outset; border-width: 1px; border-radius: 2px; border-color: inherit;"
#else
"background-color: %1; color: white;"
#endif
"}"
"QToolTip { background: white; color: black; }");
image[i] = new CurveImageWidget(this);
image[i]->set(&model, firmware, sharedItemModels, i, colors[i], 3);
image[i]->setGrid(Qt::gray, 2);
image[i]->setProperty("index", i);
image[i]->setFixedSize(QSize(100, 100));
connect(image[i], &CurveImageWidget::doubleClicked, this, &CurvesPanel::on_curveImageDoubleClicked);
edit->setStyleSheet(style.arg(colors[i].name()));
edit->setText(tr("Curve %1").arg(i + 1));
edit->setContextMenuPolicy(Qt::CustomContextMenu);
edit->setToolTip(tr("Popup menu available"));
connect(edit, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onCustomContextMenuRequested(const QPoint&)));
connect(edit, SIGNAL(clicked()), this, SLOT(editCurve()));
if (i < limit) {
ui->curvesLayout->addWidget(edit, i, 1, 1, 1);
} else {
ui->curvesLayout2->addWidget(edit, i - limit, 2, 1, 1);
}
tableLayout->addWidget(i, col++, image[i]);
// The curve plot checkbox
QCheckBox * plot = new QCheckBox(this);
plot->setProperty("index", i);
connect(plot, SIGNAL(toggled(bool)), this, SLOT(plotCurve(bool)));
if (i < limit) {
ui->curvesLayout->addWidget(plot, i, 2, 1, 1);
} else {
ui->curvesLayout2->addWidget(plot, i-limit, 1, 1, 1);
}
}
QSpacerItem * item = new QSpacerItem(1,1, QSizePolicy::Fixed, QSizePolicy::Expanding);
grp[i] = new QWidget(); // layouts are not hideable so use widget as parent for grid
ui->curvesLayout->addItem(item,limit + 1, 1, 1, 1, 0);
if (limit != maxCurves) {
QSpacerItem * item2 = new QSpacerItem(1,1, QSizePolicy::Fixed, QSizePolicy::Expanding);
ui->curvesLayout2->addItem(item2,limit + 1, 1, 1, 1, 0);
grid[i] = new QGridLayout(grp[i]);
int row = 0;
grid[i]->addWidget(new QLabel(tr("Name:")), row, 0, Qt::AlignLeft);
name[i] = new QLabel();
grid[i]->addWidget(name[i], row++, 1, Qt::AlignLeft);
grid[i]->addWidget(new QLabel(tr("Type:")), row, 0, Qt::AlignLeft);
type[i] = new QLabel();
grid[i]->addWidget(type[i], row++, 1, Qt::AlignLeft);
grid[i]->addWidget(new QLabel(tr("Points:")), row, 0, Qt::AlignLeft);
numpoints[i] = new QLabel();
grid[i]->addWidget(numpoints[i], row, 1);
points[i] = new QLabel();
grid[i]->addWidget(points[i], row++, 2, Qt::AlignLeft);
grid[i]->addWidget(new QLabel(tr("Smooth:")), row, 0, Qt::AlignLeft);
smooth[i] = new QLabel();
grid[i]->addWidget(smooth[i], row++, 1, Qt::AlignLeft);
tableLayout->addWidget(i, col++, grp[i], Qt::AlignLeft);
}
for (int i = 0; i < CPN_MAX_POINTS; i++) {
spnx[i] = new QSpinBox(this);
spnx[i]->setProperty("index", i);
spnx[i]->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
spnx[i]->setAccelerated(true);
connect(spnx[i], SIGNAL(valueChanged(int)), this, SLOT(onPointEdited()));
ui->pointsLayout->addWidget(spnx[i], i, 0, 1, 1);
tableLayout->resizeColumnsToContents();
tableLayout->pushColumnsLeft(headerLabels.count());
tableLayout->pushRowsUp(maxCurves + 1);
spny[i] = new QSpinBox(this);
spny[i]->setProperty("index", i);
spny[i]->setMinimum(-100);
spny[i]->setMaximum(+100);
spny[i]->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
spny[i]->setAccelerated(true);
connect(spny[i], SIGNAL(valueChanged(int)), this, SLOT(onPointEdited()));
ui->pointsLayout->addWidget(spny[i], i, 1, 1, 1);
bool insert;
if (hasEnhanced) {
insert = (i >= 1);
}
else {
insert = (i == 2 || i == 4 || i ==8 || i == 16);
}
if (insert) {
ui->curvePoints->addItem(tr("%1 points").arg(i + 1), i + 1);
}
for (int i = 0; i < CPN_MAX_CURVES; i++) {
update(i);
}
addTemplate(tr("Linear"), CURVE_YMIN_ENABLE, curveLinear);
addTemplate(tr("Single Expo"), CURVE_COEFF_ENABLE | CURVE_YMIN_ENABLE, curveExpo);
addTemplate(tr("Symmetrical f(x)=-f(-x)"), CURVE_COEFF_ENABLE, curveSymmetricalY);
addTemplate(tr("Symmetrical f(x)=f(-x)"), CURVE_COEFF_ENABLE | CURVE_YMID_ENABLE, curveSymmetricalX);
ui->pointSize->setValue(10);
ui->pointSize->setMinimum(3);
ui->pointSize->setMaximum(20);
connect(ui->pointSize, SIGNAL(valueChanged(int)), this, SLOT(onPointSizeEdited()));
disableMouseScrolling();
lock = false;
}
CurvesPanel::~CurvesPanel()
{
delete ui;
}
void CurvesPanel::editCurve()
{
QPushButton *button = (QPushButton *)sender();
int index = button->property("index").toInt();
setCurrentCurve(index);
update();
}
void CurvesPanel::plotCurve(bool checked)
{
QCheckBox *chk = (QCheckBox *)sender();
int index = chk->property("index").toInt();
visibleCurves[index] = checked;
updateCurve();
// compiler warning if delete[]
for (int i = 0; i < CPN_MAX_CURVES; i++) {
delete image[i];
delete name[i];
delete type[i];
delete numpoints[i];
delete points[i];
delete smooth[i];
delete grid[i];
delete grp[i];
}
}
void CurvesPanel::update()
{
lock = true;
if (hasNames) {
ui->curveName->setText(model->curves[currentCurve].name);
}
updateCurveType();
updateCurve();
updateCurvePoints();
lock = false;
}
void CurvesPanel::setCurrentCurve(int index)
{
currentCurve = index;
}
void CurvesPanel::updateCurveType()
{
lock = true;
int index = 0;
if (hasEnhanced) {
index = model->curves[currentCurve].count - 2;
}
else {
ui->curveSmooth->hide();
if (model->curves[currentCurve].count == 5)
index = 1;
else if (model->curves[currentCurve].count == 9)
index = 2;
else if (model->curves[currentCurve].count == 17)
index = 3;
}
ui->curvePoints->setCurrentIndex(index);
ui->curveCustom->setCurrentIndex(model->curves[currentCurve].type);
ui->curveSmooth->setCurrentIndex(model->curves[currentCurve].smooth);
lock = false;
}
void CurvesPanel::updateCurve()
{
lock = true;
Node * nodel = 0;
Node * nodex = 0;
QColor color;
scene->clear();
qreal width = scene->sceneRect().width();
qreal height = scene->sceneRect().height();
qreal centerX = scene->sceneRect().left() + width / 2;
qreal centerY = scene->sceneRect().top() + height / 2;
QGraphicsSimpleTextItem *ti = scene->addSimpleText(tr("Editing curve %1").arg(currentCurve + 1));
ti->setPos(3, 3);
scene->addLine(centerX, GFX_MARGIN, centerX, height + GFX_MARGIN);
scene->addLine(GFX_MARGIN, centerY, width + GFX_MARGIN, centerY);
QPen pen;
pen.setWidth(1);
pen.setStyle(Qt::SolidLine);
for (int k = 0; k < maxCurves; k++) {
pen.setColor(colors[k]);
if (currentCurve != k && visibleCurves[k]) {
int numpoints = model->curves[k].count;
for (int i = 0; i < numpoints - 1; i++) {
if (model->curves[k].type == CurveData::CURVE_TYPE_CUSTOM)
scene->addLine(centerX + (qreal)model->curves[k].points[i].x * width / 200,
centerY - (qreal)model->curves[k].points[i].y * height / 200,
centerX + (qreal)model->curves[k].points[i + 1].x * width / 200,
centerY - (qreal)model->curves[k].points[i + 1].y * height / 200, pen);
else
scene->addLine(GFX_MARGIN + i * width / (numpoints - 1),
centerY - (qreal)model->curves[k].points[i].y * height / 200,
GFX_MARGIN + (i + 1) * width / (numpoints - 1),
centerY - (qreal)model->curves[k].points[i + 1].y * height / 200, pen);
}
}
}
int numpoints = model->curves[currentCurve].count;
for (int i = 0; i < numpoints; i++) {
nodel = nodex;
nodex = new Node();
nodex->setProperty("index", i);
nodex->setColor(colors[currentCurve]);
nodex->setBallSize(ui->pointSize->value());
nodex->setBallHeight(0);
if (model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM) {
if (i > 0 && i < numpoints - 1) {
nodex->setFixedX(false);
nodex->setMinX(model->curves[currentCurve].points[i - 1].x);
nodex->setMaxX(model->curves[currentCurve].points[i + 1].x);
}
else {
nodex->setFixedX(true);
}
nodex->setPos(centerX + (qreal)model->curves[currentCurve].points[i].x * width / 200,
centerY - (qreal)model->curves[currentCurve].points[i].y * height / 200);
}
else {
nodex->setFixedX(true);
nodex->setPos(GFX_MARGIN + i * width / (numpoints - 1),
centerY - (qreal)model->curves[currentCurve].points[i].y * height / 200);
}
connect(nodex, SIGNAL(moved(int, int)), this, SLOT(onNodeMoved(int, int)));
connect(nodex, SIGNAL(focus()), this, SLOT(onNodeFocus()));
connect(nodex, SIGNAL(unfocus()), this, SLOT(onNodeUnfocus()));
connect(nodex, SIGNAL(deleteMe()), this, SLOT(onNodeDelete()));
scene->addItem(nodex);
if (i > 0)
scene->addItem(new Edge(nodel, nodex));
}
lock = false;
}
void CurvesPanel::updateCurvePoints()
{
lock = true;
int count = model->curves[currentCurve].count;
for (int i = 0; i < count; i++) {
spny[i]->show();
spny[i]->setValue(model->curves[currentCurve].points[i].y);
if (model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM) {
spnx[i]->show();
if (i == 0 || i == model->curves[currentCurve].count - 1) {
spnx[i]->setDisabled(true);
spnx[i]->setMaximum(+100);
spnx[i]->setMinimum(-100);
}
else {
spnx[i]->setDisabled(false);
spnx[i]->setMaximum(model->curves[currentCurve].points[i + 1].x);
spnx[i]->setMinimum(model->curves[currentCurve].points[i - 1].x);
}
spnx[i]->setValue(model->curves[currentCurve].points[i].x);
}
else {
spnx[i]->hide();
}
}
for (int i = count; i < CPN_MAX_POINTS; i++) {
spny[i]->hide();
spnx[i]->hide();
}
lock = false;
}
void CurvesPanel::onPointEdited()
{
if (!lock) {
int index = sender()->property("index").toInt();
model->curves[currentCurve].points[index].x = spnx[index]->value();
model->curves[currentCurve].points[index].y = spny[index]->value();
updateCurve();
updateCurvePoints();
emit modified();
}
}
void CurvesPanel::onNodeMoved(int x, int y)
{
if (!lock) {
lock = true;
int index = sender()->property("index").toInt();
model->curves[currentCurve].points[index].x = x;
model->curves[currentCurve].points[index].y = y;
spnx[index]->setValue(x);
spny[index]->setValue(y);
if (index > 0)
spnx[index - 1]->setMaximum(x);
if (index < model->curves[currentCurve].count - 1)
spnx[index + 1]->setMinimum(x);
emit modified();
lock = false;
}
}
void CurvesPanel::onNodeFocus()
{
int index = sender()->property("index").toInt();
spny[index]->setFocus();
}
void CurvesPanel::onNodeUnfocus()
{
int index = sender()->property("index").toInt();
spny[index]->clearFocus();
updateCurve();
}
bool CurvesPanel::allowCurveType(int points, CurveData::CurveType type)
{
int totalpoints = 0;
for (int i = 0; i < maxCurves; i++) {
int cvPoints = (i == currentCurve ? points : model->curves[i].count);
CurveData::CurveType cvType = (i == currentCurve ? type : model->curves[i].type);
totalpoints += cvPoints + (cvType == CurveData::CURVE_TYPE_CUSTOM ? cvPoints - 2 : 0);
update(i);
}
}
if (totalpoints > maxPoints) {
QMessageBox::warning(this, "companion", tr("Not enough free points in EEPROM to store the curve."));
return false;
void CurvesPanel::update(int index)
{
if (model->curves[index].isEmpty()) {
image[index]->setVisible(false);
grp[index]->setVisible(false);
}
else {
return true;
image[index]->setVisible(true);
grp[index]->setVisible(true);
image[index]->draw();
name[index]->setText(QString(model->curves[index].name));
type[index]->setText(model->curves[index].typeToString());
numpoints[index]->setText(QString::number(model->curves[index].count));
points[index]->setText(model->curves[index].pointsToString());
smooth[index]->setText(DataHelpers::boolToString(model->curves[index].smooth, DataHelpers::BOOL_FMT_YESNO));
}
}
void CurvesPanel::on_curvePoints_currentIndexChanged(int index)
void CurvesPanel::editCurve(int index)
{
if (!lock) {
int numpoints = ((QComboBox *)sender())->itemData(index).toInt();
if (allowCurveType(numpoints, model->curves[currentCurve].type)) {
model->curves[currentCurve].count = numpoints;
// TODO something better + reuse!
for (int i = 0; i < CPN_MAX_POINTS; i++) {
model->curves[currentCurve].points[i].x = (i >= numpoints - 1 ? +100 : -100 + (200 * i) / (numpoints - 1));
model->curves[currentCurve].points[i].y = 0;
}
update();
emit modified();
}
else {
updateCurveType();
}
}
}
void CurvesPanel::on_curveCustom_currentIndexChanged(int index)
{
if (!lock) {
CurveData::CurveType type = (CurveData::CurveType)index;
int numpoints = ui->curvePoints->itemData(ui->curvePoints->currentIndex()).toInt();
if (allowCurveType(model->curves[currentCurve].count, type)) {
model->curves[currentCurve].type = type;
// TODO something better + reuse!
for (int i = 0; i < CPN_MAX_POINTS; i++) {
model->curves[currentCurve].points[i].x = (i >= numpoints - 1 ? +100 : -100 + (200 * i) / (numpoints - 1));
model->curves[currentCurve].points[i].y = 0;
}
update();
emit modified();
}
else {
updateCurveType();
}
}
}
void CurvesPanel::on_curveSmooth_currentIndexChanged(int index)
{
model->curves[currentCurve].smooth = index;
update();
}
void CurvesPanel::on_curveName_editingFinished()
{
if (ui->curveName->text() != model->curves[currentCurve].name) {
memset(model->curves[currentCurve].name, 0, sizeof(model->curves[currentCurve].name));
strcpy(model->curves[currentCurve].name, ui->curveName->text().toLatin1());
updateItemModels();
if (image[index]->edit()) {
update(index);
emit modified();
}
}
void CurvesPanel::resizeEvent(QResizeEvent *event)
void CurvesPanel::on_curveImageDoubleClicked()
{
QRect qr = ui->curvePreview->contentsRect();
ui->curvePreview->scene()->setSceneRect(GFX_MARGIN, GFX_MARGIN, qr.width() - GFX_MARGIN * 2, qr.height() - GFX_MARGIN * 2);
updateCurve();
ModelPanel::resizeEvent(event);
}
bool ok = false;
int index = sender()->property("index").toInt(&ok);
void CurvesPanel::on_curveType_currentIndexChanged(int index)
{
unsigned int flags = templates[index].flags;
ui->curveCoeffLabel->setVisible(flags & CURVE_COEFF_ENABLE);
ui->curveCoeff->setVisible(flags & CURVE_COEFF_ENABLE);
ui->yMax->setValue(100);
ui->yMidLabel->setVisible(flags & CURVE_YMID_ENABLE);
ui->yMid->setVisible(flags & CURVE_YMID_ENABLE);
ui->yMid->setValue(0);
ui->yMinLabel->setVisible(flags & CURVE_YMIN_ENABLE);
ui->yMin->setVisible(flags & CURVE_YMIN_ENABLE);
ui->yMin->setValue(-100);
}
void CurvesPanel::addTemplate(QString name, unsigned int flags, curveFunction function)
{
CurveCreatorTemplate tmpl;
tmpl.name = name;
tmpl.flags = flags;
tmpl.function = function;
templates.append(tmpl);
ui->curveType->addItem(name);
}
void CurvesPanel::on_curveApply_clicked()
{
int index = ui->curveType->currentIndex();
int numpoints = model->curves[currentCurve].count;
for (int i = 0; i < numpoints; i++) {
float x;
if (model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM)
x = model->curves[currentCurve].points[i].x;
else
x = -100.0 + (200.0 / (numpoints - 1)) * i;
bool apply = false;
switch (ui->curveSide->currentIndex()) {
case 0:
apply = true;
break;
case 1:
if (x >= 0)
apply = true;
break;
case 2:
if (x < 0)
apply = true;
break;
}
if (apply) {
model->curves[currentCurve].points[i].y = templates[index].function(x, ui->curveCoeff->value(), ui->yMin->value(), ui->yMid->value(),
ui->yMax->value());
}
}
updateCurve();
updateCurvePoints();
emit modified();
}
void CurvesPanel::onPointSizeEdited()
{
if (!lock) {
update();
}
}
void CurvesPanel::onNodeDelete()
{
int index = sender()->property("index").toInt();
int numpoints = model->curves[currentCurve].count;
if ((model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM) && (index > 0) && (index < numpoints-1)) {
spny[index]->clearFocus();
for (int i=index+1; i<numpoints; i++) {
model->curves[currentCurve].points[i-1] = model->curves[currentCurve].points[i];
}
numpoints--;
model->curves[currentCurve].points[numpoints].x = 0;
model->curves[currentCurve].points[numpoints].y = 0;
model->curves[currentCurve].count = numpoints;
update();
emit modified();
}
}
void CurvesPanel::onSceneNewPoint(int x, int y)
{
if ((model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM) && (model->curves[currentCurve].count < CPN_MAX_POINTS)) {
int newidx = 0;
int numpoints = model->curves[currentCurve].count;
if (x < model->curves[currentCurve].points[0].x) {
newidx = 0;
}
else if (x > model->curves[currentCurve].points[numpoints - 1].x) {
newidx = numpoints;
}
else {
for (int i = 0; i < numpoints; i++) {
if (x < model->curves[currentCurve].points[i].x) {
newidx = i;
break;
}
}
}
numpoints++;
model->curves[currentCurve].count = numpoints;
for (int idx = (numpoints - 1); idx > newidx; idx--) {
model->curves[currentCurve].points[idx] = model->curves[currentCurve].points[idx - 1];
}
model->curves[currentCurve].points[newidx].x = x;
model->curves[currentCurve].points[newidx].y = y;
update();
emit modified();
}
if (ok)
editCurve(index);
}
void CurvesPanel::onCustomContextMenuRequested(QPoint pos)
@@ -674,10 +162,13 @@ void CurvesPanel::onCustomContextMenuRequested(QPoint pos)
QPoint globalPos = button->mapToGlobal(pos);
QMenu contextMenu;
contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"), this, SLOT(cmCopy()));
contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"), this, SLOT(cmCut()));
contextMenu.addAction(CompanionIcon("new.png"), tr("Add"), this, SLOT(cmEdit()))->setEnabled(!curveExists());
contextMenu.addAction(CompanionIcon("edit.png"), tr("Edit"), this, SLOT(cmEdit()))->setEnabled(curveExists());
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"), this, SLOT(cmCopy()))->setEnabled(curveExists());
contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"), this, SLOT(cmCut()))->setEnabled(curveExists());
contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"), this, SLOT(cmPaste()))->setEnabled(hasClipboardData());
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"), this, SLOT(cmClear()));
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"), this, SLOT(cmClear()))->setEnabled(curveExists());
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"), this, SLOT(cmInsert()))->setEnabled(insertAllowed());
contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"), this, SLOT(cmDelete()));
@@ -701,6 +192,11 @@ bool CurvesPanel::hasClipboardData(QByteArray * data) const
return false;
}
bool CurvesPanel::curveExists() const
{
return !model->curves[selectedIndex].isEmpty();
}
bool CurvesPanel::insertAllowed() const
{
return ((selectedIndex < maxCurves - 1) && (model->curves[maxCurves - 1].isEmpty()));
@@ -708,37 +204,38 @@ bool CurvesPanel::insertAllowed() const
bool CurvesPanel::moveDownAllowed() const
{
return selectedIndex < maxCurves - 1;
return selectedIndex < maxCurves - 1 && curveExists();
}
bool CurvesPanel::moveUpAllowed() const
{
return selectedIndex > 0;
return selectedIndex > 0 && curveExists();
}
void CurvesPanel::cmClear(bool prompt)
{
if (prompt) {
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear curve %1:%2. Are you sure?").arg(QString::number(selectedIndex + 1)).arg(model->curves[selectedIndex].name), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
}
model->curves[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_CLEAR, selectedIndex);
update();
update(selectedIndex);
updateItemModels();
emit modified();
}
void CurvesPanel::cmClearAll()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Curves. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all curves. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
for (int i = 0; i < maxCurves; i++) {
model->curves[i].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_CLEAR, i);
}
update();
updateItemModels();
emit modified();
@@ -755,7 +252,7 @@ void CurvesPanel::cmCopy()
void CurvesPanel::cmCut()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut curve %1:%2. Are you sure?").arg(QString::number(selectedIndex + 1)).arg(model->curves[selectedIndex].name), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
cmCopy();
cmClear(false);
@@ -763,23 +260,32 @@ void CurvesPanel::cmCut()
void CurvesPanel::cmDelete()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete curve %1:%2. Are you sure?").arg(QString::number(selectedIndex + 1)).arg(model->curves[selectedIndex].name), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
memmove(&model->curves[selectedIndex], &model->curves[selectedIndex + 1], (CPN_MAX_CURVES - (selectedIndex + 1)) * sizeof(CurveData));
model->curves[maxCurves - 1].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1);
update();
for (int i = selectedIndex; i < CPN_MAX_CURVES; i++) {
update(i);
}
updateItemModels();
emit modified();
}
void CurvesPanel::cmEdit()
{
editCurve(selectedIndex);
}
void CurvesPanel::cmInsert()
{
memmove(&model->curves[selectedIndex + 1], &model->curves[selectedIndex], (CPN_MAX_CURVES - (selectedIndex + 1)) * sizeof(CurveData));
model->curves[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1);
update();
for (int i = selectedIndex; i < CPN_MAX_CURVES; i++) {
update(i);
}
updateItemModels();
emit modified();
}
@@ -800,7 +306,7 @@ void CurvesPanel::cmPaste()
if (hasClipboardData(&data)) {
CurveData *cd = &model->curves[selectedIndex];
memcpy(cd, data.constData(), sizeof(CurveData));
update();
update(selectedIndex);
updateItemModels();
emit modified();
}
@@ -815,7 +321,8 @@ void CurvesPanel::swapData(int idx1, int idx2)
memcpy(cd2, cd1, sizeof(CurveData));
memcpy(cd1, &cdtmp, sizeof(CurveData));
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
update();
update(idx1);
update(idx2);
updateItemModels();
emit modified();
}
@@ -825,23 +332,3 @@ void CurvesPanel::updateItemModels()
{
sharedItemModels->update(AbstractItemModel::IMUE_Curves);
}
CustomScene::CustomScene(QGraphicsView * view) :
QGraphicsScene(view)
{
}
void CustomScene::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
if (event->button() == Qt::LeftButton && event->modifiers() == Qt::ControlModifier) {
QRectF rect = sceneRect();
QPointF pos = event->scenePos();
QPointF p;
p.setX(-100 + ((pos.x() - rect.left()) * 200) / rect.width());
p.setY(100 + (rect.top() - pos.y()) * 200 / rect.height());
QGraphicsScene::mouseReleaseEvent(event);
emit newPoint((int)p.x(), (int)p.y());
}
else
QGraphicsScene::mouseReleaseEvent(event);
}
+34 -76
View File
@@ -18,111 +18,69 @@
* GNU General Public License for more details.
*/
#ifndef _CURVES_H_
#define _CURVES_H_
#pragma once
#include "constants.h"
#include "modeledit.h"
#include "eeprominterface.h"
#include <QGraphicsScene>
#include <QGraphicsView>
class CompoundItemModelFactory;
constexpr char MIMETYPE_CURVE[] = "application/x-companion-curve";
constexpr char MIMETYPE_CURVE[] = { "application/x-companion-curve" };
namespace Ui {
class Curves;
}
typedef float (*curveFunction) (float x, float coeff, float yMin, float yMid, float yMax);
struct CurveCreatorTemplate {
QString name;
unsigned int flags;
curveFunction function;
};
class CustomScene : public QGraphicsScene
{
Q_OBJECT
public:
CustomScene(QGraphicsView * view);
signals:
void newPoint(int, int);
protected:
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * event) override;
};
class CurveImageWidget;
class CurvesPanel : public ModelPanel
{
Q_OBJECT
public:
CurvesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels);
CurvesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware,
CompoundItemModelFactory * sharedItemModels);
virtual ~CurvesPanel();
virtual void update();
private slots:
void editCurve();
void plotCurve(bool checked);
void on_curveName_editingFinished();
void on_curvePoints_currentIndexChanged(int index);
void on_curveCustom_currentIndexChanged(int index);
void on_curveSmooth_currentIndexChanged(int index);
void onPointEdited();
void onNodeMoved(int x, int y);
void onNodeFocus();
void onNodeUnfocus();
void on_curveType_currentIndexChanged(int index);
void on_curveApply_clicked();
void onSceneNewPoint(int x, int y);
void onPointSizeEdited();
void onNodeDelete();
void update();
void update(int index);
void on_curveImageDoubleClicked();
void onCustomContextMenuRequested(QPoint pos);
void cmClear(bool prompt = true);
void cmClearAll();
void cmCopy();
void cmCut();
void cmDelete();
void cmEdit();
void cmInsert();
void cmPaste();
void cmMoveDown();
void cmMoveUp();
protected:
virtual void resizeEvent(QResizeEvent *event);
void addTemplate(QString name, unsigned int flags, curveFunction function);
void cmPaste();
private:
Ui::Curves *ui;
int currentCurve;
bool visibleCurves[CPN_MAX_CURVES];
QSpinBox * spnx[CPN_MAX_POINTS];
QSpinBox * spny[CPN_MAX_POINTS];
QVector<CurveCreatorTemplate> templates;
void setCurrentCurve(int index);
void updateCurve();
void updateCurveType();
void updateCurvePoints();
bool allowCurveType(int points, CurveData::CurveType type);
void setPointY(int i, int x, int y);
CustomScene * scene;
void editCurve(int index);
int maxCurves;
int hasNames;
int hasEnhanced;
int maxPoints;
int selectedIndex;
void swapData(int idx1, int idx2);
void updateItemModels();
// context menu
bool hasClipboardData(QByteArray * data = nullptr) const;
bool curveExists() const;
bool insertAllowed() const;
bool moveDownAllowed() const;
bool moveUpAllowed() const;
void swapData(int idx1, int idx2);
CompoundItemModelFactory * sharedItemModels;
void updateItemModels();
};
int selectedIndex;
#endif // _CURVES_H_
// keep constructor pointer to enable triggering update of item models when curves change
CompoundItemModelFactory *sharedItemModels;
// ui widgets
QWidget *grp[CPN_MAX_CURVES];
QGridLayout *grid[CPN_MAX_CURVES];
CurveImageWidget *image[CPN_MAX_CURVES];
QLabel *name[CPN_MAX_CURVES];
QLabel *type[CPN_MAX_CURVES];
QLabel *numpoints[CPN_MAX_CURVES];
QLabel *points[CPN_MAX_CURVES];
QLabel *smooth[CPN_MAX_CURVES];
};
+13 -8
View File
@@ -53,13 +53,21 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_GVarRef)), "GVarRef");
gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, ed->weight, model, 100, -100, 100, 1.0,
dialogFilteredItemModels->getItemModel(id));
gvOffsetGroup = new GVarGroup(ui->offsetGV, ui->offsetSB, ui->offsetCB, ed->offset, model, 0, -100, 100, 1.0,
dialogFilteredItemModels->getItemModel(id));
curveRefFilteredItemModels = new CurveRefFilteredFactory(sharedItemModels,
firmware->getCapability(HasInputDiff) ? 0 : FilteredItemModel::PositiveFilter);
curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, ed->curve, model,
curveRefFilteredItemModels, this);
curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, ui->curveImage, ed->curve, model,
sharedItemModels, curveRefFilteredItemModels, this);
connect(curveGroup, &CurveReferenceUIManager::resized, this, [=] () {
this->adjustSize();
this->adjustSize(); // second call seems to be required when hidden fields otherwise not all padding removed
});
id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch),
RawSwitch::MixesContext), "RawSwitch");
@@ -143,14 +151,16 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
connect(ui->trimCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
connect(ui->switchesCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
connect(ui->sideCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
connect(cb_fp[i], SIGNAL(toggled(bool)), this, SLOT(valuesChanged()));
}
if (firmware->getCapability(VirtualInputs)) {
connect(ui->inputName, SIGNAL(editingFinished()), this, SLOT(valuesChanged()));
}
QTimer::singleShot(0, this, SLOT(shrink()));
adjustSize();
}
ExpoDialog::~ExpoDialog()
@@ -224,11 +234,6 @@ void ExpoDialog::valuesChanged()
}
}
void ExpoDialog::shrink()
{
resize(0, 0);
}
void ExpoDialog::label_phases_customContextMenuRequested(const QPoint & pos)
{
QLabel *label = (QLabel *)sender();
+1 -5
View File
@@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
#ifndef _EXPODIALOG_H_
#define _EXPODIALOG_H_
#pragma once
#include <QtWidgets>
#include "eeprominterface.h"
@@ -47,7 +46,6 @@ class ExpoDialog : public QDialog {
private slots:
void valuesChanged();
void shrink();
void label_phases_customContextMenuRequested(const QPoint & pos);
void fmClearAll();
void fmSetAll();
@@ -70,5 +68,3 @@ class ExpoDialog : public QDialog {
CurveRefFilteredFactory *curveRefFilteredItemModels;
int carryTrimFilterFlags = 0;
};
#endif // _EXPODIALOG_H_
+259 -246
View File
@@ -6,12 +6,12 @@
<rect>
<x>0</x>
<y>0</y>
<width>394</width>
<height>488</height>
<width>442</width>
<height>411</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -30,6 +30,237 @@
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="13" column="1">
<widget class="QComboBox" name="sideCB">
<item>
<property name="text">
<string>NEG</string>
</property>
</item>
<item>
<property name="text">
<string>POS</string>
</property>
</item>
<item>
<property name="text">
<string>ALL</string>
</property>
</item>
</widget>
</item>
<item row="8" column="1">
<layout class="QHBoxLayout" name="offsetLayout" stretch="0,0,1,0">
<item>
<widget class="QCheckBox" name="offsetGV">
<property name="text">
<string>GV</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="offsetSB"/>
</item>
<item>
<widget class="QComboBox" name="offsetCB">
<property name="whatsThis">
<string>The source for the mixer</string>
</property>
</widget>
</item>
<item>
<spacer name="offsetSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="14" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="trimCB"/>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineName">
<property name="maxLength">
<number>6</number>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_curves">
<property name="text">
<string>Curve</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Switch</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_phases">
<property name="text">
<string>Flight modes</string>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="sideLabel">
<property name="text">
<string>Stick Side</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Weight</string>
</property>
</widget>
</item>
<item row="7" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0,1,0">
<item>
<widget class="QCheckBox" name="weightGV">
<property name="text">
<string>GV</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="weightSB"/>
</item>
<item>
<widget class="QComboBox" name="weightCB">
<property name="whatsThis">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="11" column="1">
<widget class="QComboBox" name="switchesCB">
<property name="whatsThis">
<string>Switch used to enable the line.
If blank then the input is considered to be &quot;ON&quot; all the time.</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="offsetLabel">
<property name="text">
<string>Offset</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="sourceLabel">
<property name="text">
<string>Source</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="inputNameLabel">
<property name="text">
<string>Input name</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="sourceCB">
<property name="whatsThis">
<string>Source for the mixer.</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="inputName">
<property name="maxLength">
<number>6</number>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QDoubleSpinBox" name="dsbScale">
<property name="whatsThis">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblScaleUnit">
<property name="text">
<string>unit</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="10" column="1">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
@@ -187,25 +418,15 @@
</item>
</layout>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="inputName">
<property name="maxLength">
<number>6</number>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="offsetLabel">
<item row="3" column="0">
<widget class="QLabel" name="lblScale">
<property name="text">
<string>Offset</string>
<string>Scale</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="trimCB"/>
</item>
<item row="9" column="1">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,1,0">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,1,0,0">
<item>
<widget class="QComboBox" name="curveTypeCB">
<property name="toolTip">
@@ -233,102 +454,27 @@
<item>
<widget class="QSpinBox" name="curveValueSB"/>
</item>
</layout>
</item>
<item row="13" column="0">
<widget class="QLabel" name="sideLabel">
<property name="text">
<string>Stick Side</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="sourceCB">
<property name="whatsThis">
<string>Source for the mixer.</string>
</property>
</widget>
</item>
<item row="8" column="1">
<layout class="QHBoxLayout" name="offsetLayout" stretch="0,0,1,0">
<item>
<widget class="QCheckBox" name="offsetGV">
<property name="text">
<string>GV</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="offsetSB"/>
</item>
<item>
<widget class="QComboBox" name="offsetCB">
<property name="whatsThis">
<string>The source for the mixer</string>
</property>
</widget>
</item>
<item>
<spacer name="offsetSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<widget class="CurveImageWidget" name="curveImage">
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
<width>100</width>
<height>100</height>
</size>
</property>
</spacer>
<property name="maximumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="text">
<string>image</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="13" column="1">
<widget class="QComboBox" name="sideCB">
<item>
<property name="text">
<string>NEG</string>
</property>
</item>
<item>
<property name="text">
<string>POS</string>
</property>
</item>
<item>
<property name="text">
<string>ALL</string>
</property>
</item>
</widget>
</item>
<item row="14" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>30</height>
</size>
</property>
</spacer>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Switch</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineName">
<property name="maxLength">
<number>6</number>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="trimLabel">
<property name="text">
@@ -336,76 +482,6 @@
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_phases">
<property name="text">
<string>Flight modes</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="inputNameLabel">
<property name="text">
<string>Input name</string>
</property>
</widget>
</item>
<item row="7" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0,1,0">
<item>
<widget class="QCheckBox" name="weightGV">
<property name="text">
<string>GV</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="weightSB"/>
</item>
<item>
<widget class="QComboBox" name="weightCB">
<property name="whatsThis">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="11" column="1">
<widget class="QComboBox" name="switchesCB">
<property name="whatsThis">
<string>Switch used to enable the line.
If blank then the input is considered to be &quot;ON&quot; all the time.</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Weight</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="sourceLabel">
<property name="text">
<string>Source</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lineNameLabel">
<property name="text">
@@ -413,78 +489,15 @@ If blank then the input is considered to be &quot;ON&quot; all the time.</string
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_curves">
<property name="text">
<string>Curve</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblScale">
<property name="text">
<string>Scale</string>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QDoubleSpinBox" name="dsbScale">
<property name="whatsThis">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblScaleUnit">
<property name="text">
<string>unit</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="15" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>CurveImageWidget</class>
<extends>QLabel</extends>
<header>curveimagewidget.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>inputName</tabstop>
<tabstop>lineName</tabstop>
+14 -8
View File
@@ -55,17 +55,25 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
ui->sourceCB->setCurrentIndex(ui->sourceCB->findData(md->srcRaw.toValue()));
int limit = firmware->getCapability(OffsetWeight);
id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_GVarRef)), "GVarRef");
gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, md->weight, model, 100, -limit, limit, 1.0,
dialogFilteredItemModels->getItemModel(id));
gvOffsetGroup = new GVarGroup(ui->offsetGV, ui->offsetSB, ui->offsetCB, md->sOffset, model, 0, -limit, limit, 1.0,
dialogFilteredItemModels->getItemModel(id));
curveRefFilteredItemModels = new CurveRefFilteredFactory(sharedItemModels,
firmware->getCapability(HasMixerExpo) ? 0 : FilteredItemModel::PositiveFilter);
curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, md->curve, model,
curveRefFilteredItemModels, this);
curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, ui->curveImage, md->curve,
model, sharedItemModels, curveRefFilteredItemModels, this);
connect(curveGroup, &CurveReferenceUIManager::resized, this, [=] () {
this->adjustSize();
this->adjustSize(); // second call seems to be required when hidden fields otherwise not all padding removed
});
ui->MixDR_CB->setChecked(md->noExpo == 0);
@@ -141,9 +149,9 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
ui->delayUpSB->setSingleStep(1.0 / scale);
ui->delayUpSB->setDecimals((scale == 1 ? 0 : 1));
ui->delayUpSB->setValue((float)md->delayUp / scale);
QTimer::singleShot(0, this, SLOT(shrink()));
valuesChanged();
connect(ui->mixerName,SIGNAL(editingFinished()),this,SLOT(valuesChanged()));
connect(ui->sourceCB,SIGNAL(currentIndexChanged(int)),this,SLOT(valuesChanged()));
connect(ui->trimCB,SIGNAL(currentIndexChanged(int)),this,SLOT(valuesChanged()));
@@ -155,9 +163,12 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
connect(ui->delayUpSB,SIGNAL(editingFinished()),this,SLOT(valuesChanged()));
connect(ui->slowDownSB,SIGNAL(editingFinished()),this,SLOT(valuesChanged()));
connect(ui->slowUpSB,SIGNAL(editingFinished()),this,SLOT(valuesChanged()));
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) {
connect(cb_fp[i],SIGNAL(toggled(bool)),this,SLOT(valuesChanged()));
}
adjustSize();
}
MixerDialog::~MixerDialog()
@@ -216,11 +227,6 @@ void MixerDialog::valuesChanged()
}
}
void MixerDialog::shrink()
{
resize(0, 0);
}
void MixerDialog::label_phases_customContextMenuRequested(const QPoint & pos)
{
QLabel *label = (QLabel *)sender();
+1 -5
View File
@@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
#ifndef _MIXERDIALOG_H_
#define _MIXERDIALOG_H_
#pragma once
#include <QtWidgets>
#include "eeprominterface.h"
@@ -46,7 +45,6 @@ class MixerDialog : public QDialog {
private slots:
void valuesChanged();
void shrink();
void label_phases_customContextMenuRequested(const QPoint & pos);
void fmClearAll();
void fmSetAll();
@@ -66,5 +64,3 @@ class MixerDialog : public QDialog {
FilteredItemModelFactory *dialogFilteredItemModels;
CurveRefFilteredFactory *curveRefFilteredItemModels;
};
#endif // _MIXERDIALOG_H_
+191 -156
View File
@@ -6,12 +6,12 @@
<rect>
<x>0</x>
<y>0</y>
<width>412</width>
<height>541</height>
<width>527</width>
<height>571</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -24,158 +24,9 @@
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0">
<item row="0" column="1">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Delay</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Slow</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Up</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Down</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QDoubleSpinBox" name="slowUpSB">
<property name="whatsThis">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Delay ans Slow&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;These values control the speed and delay of the output of the mix. &lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Delay is not zero the actuation of the mix will be delayed by the specified amount of seconds.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Slow is not zero then the speed of the mix will be set by the value specified -&amp;gt; the value states the number of seconds it takes to transit from -100 to 100.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>7.500000000000000</double>
</property>
<property name="singleStep">
<double>0.500000000000000</double>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QDoubleSpinBox" name="slowDownSB">
<property name="whatsThis">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Delay ans Slow&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;These values control the speed and delay of the output of the mix. &lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Delay is not zero the actuation of the mix will be delayed by the specified amount of seconds.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Slow is not zero then the speed of the mix will be set by the value specified -&amp;gt; the value states the number of seconds it takes to transit from -100 to 100.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>7.500000000000000</double>
</property>
<property name="singleStep">
<double>0.500000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="delayUpSB">
<property name="whatsThis">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Delay ans Slow&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;These values control the speed and delay of the output of the mix. &lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Delay is not zero the actuation of the mix will be delayed by the specified amount of seconds.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Slow is not zero then the speed of the mix will be set by the value specified -&amp;gt; the value states the number of seconds it takes to transit from -100 to 100.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="delayDownSB">
<property name="whatsThis">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Delay ans Slow&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;These values control the speed and delay of the output of the mix. &lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Delay is not zero the actuation of the mix will be delayed by the specified amount of seconds.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Slow is not zero then the speed of the mix will be set by the value specified -&amp;gt; the value states the number of seconds it takes to transit from -100 to 100.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<property name="verticalSpacing">
<number>6</number>
</property>
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0,0">
<item row="5" column="0">
@@ -587,7 +438,7 @@ If blank then the mix is considered to be &quot;ON&quot; all the time.</string>
</widget>
</item>
<item row="4" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,0,0">
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,0,0,0">
<item>
<widget class="QCheckBox" name="curveGVarCB">
<property name="text">
@@ -605,12 +456,196 @@ If blank then the mix is considered to be &quot;ON&quot; all the time.</string>
<item>
<widget class="QSpinBox" name="curveValueSB"/>
</item>
<item>
<widget class="CurveImageWidget" name="curveImage">
<property name="minimumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="text">
<string>imgage</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0">
<item row="0" column="1">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Delay</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Slow</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Up</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Down</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QDoubleSpinBox" name="slowUpSB">
<property name="whatsThis">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Delay ans Slow&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;These values control the speed and delay of the output of the mix. &lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Delay is not zero the actuation of the mix will be delayed by the specified amount of seconds.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Slow is not zero then the speed of the mix will be set by the value specified -&amp;gt; the value states the number of seconds it takes to transit from -100 to 100.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>7.500000000000000</double>
</property>
<property name="singleStep">
<double>0.500000000000000</double>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QDoubleSpinBox" name="slowDownSB">
<property name="whatsThis">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Delay ans Slow&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;These values control the speed and delay of the output of the mix. &lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Delay is not zero the actuation of the mix will be delayed by the specified amount of seconds.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Slow is not zero then the speed of the mix will be set by the value specified -&amp;gt; the value states the number of seconds it takes to transit from -100 to 100.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>7.500000000000000</double>
</property>
<property name="singleStep">
<double>0.500000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="delayUpSB">
<property name="whatsThis">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Delay ans Slow&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;These values control the speed and delay of the output of the mix. &lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Delay is not zero the actuation of the mix will be delayed by the specified amount of seconds.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Slow is not zero then the speed of the mix will be set by the value specified -&amp;gt; the value states the number of seconds it takes to transit from -100 to 100.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="delayDownSB">
<property name="whatsThis">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Delay ans Slow&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;These values control the speed and delay of the output of the mix. &lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Delay is not zero the actuation of the mix will be delayed by the specified amount of seconds.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If Slow is not zero then the speed of the mix will be set by the value specified -&amp;gt; the value states the number of seconds it takes to transit from -100 to 100.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>CurveImageWidget</class>
<extends>QLabel</extends>
<header>curveimagewidget.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>mixerName</tabstop>
<tabstop>sourceCB</tabstop>
+2 -48
View File
@@ -25,6 +25,7 @@
#include "helpers_html.h"
#include "appdata.h"
#include "adjustmentreference.h"
#include "curveimage.h"
#include <QApplication>
#include <QPainter>
@@ -646,55 +647,8 @@ QString ModelPrinter::printCurveName(int idx)
QString ModelPrinter::printCurve(int idx)
{
QString result;
const CurveData & curve = model.curves[idx];
result += (curve.type == CurveData::CURVE_TYPE_CUSTOM) ? tr("Custom") : tr("Standard");
result += ", [";
if (curve.type == CurveData::CURVE_TYPE_CUSTOM) {
for (int j=0; j<curve.count; j++) {
if (j != 0)
result += ", ";
result += QString("(%1, %2)").arg(curve.points[j].x).arg(curve.points[j].y);
}
}
else {
for (int j=0; j<curve.count; j++) {
if (j != 0)
result += ", ";
result += QString("%1").arg(curve.points[j].y);
}
}
result += "]";
return result;
}
CurveImage::CurveImage():
size(200),
image(size+1, size+1, QImage::Format_RGB32),
painter(&image)
{
painter.setBrush(QBrush("#FFFFFF"));
painter.setPen(QColor(0, 0, 0));
painter.drawRect(0, 0, size, size);
painter.setPen(QColor(0, 0, 0));
painter.drawLine(0, size/2, size, size/2);
painter.drawLine(size/2, 0, size/2, size);
for (int i=0; i<21; i++) {
painter.drawLine(size/2-5, (size*i)/(20), size/2+5, (size*i)/(20));
painter.drawLine((size*i)/(20), size/2-5, (size*i)/(20), size/2+5);
}
}
void CurveImage::drawCurve(const CurveData & curve, QColor color)
{
painter.setPen(QPen(color, 2, Qt::SolidLine));
for (int j=1; j<curve.count; j++) {
if (curve.type == CurveData::CURVE_TYPE_CUSTOM)
painter.drawLine(size/2+(size*curve.points[j-1].x)/200, size/2-(size*curve.points[j-1].y)/200, size/2+(size*curve.points[j].x)/200, size/2-(size*curve.points[j].y)/200);
else
painter.drawLine(size*(j-1)/(curve.count-1), size/2-(size*curve.points[j-1].y)/200, size*(j)/(curve.count-1), size/2-(size*curve.points[j].y)/200);
}
return QString("%1 %2").arg(curve.typeToString()).arg(curve.pointsToString());
}
QString ModelPrinter::createCurveImage(int idx, QTextDocument * document)
-13
View File
@@ -31,19 +31,6 @@ QString addFont(const QString & input, const QString & color = "", const QString
void debugHtml(const QString & html);
QString formatTitle(const QString & name);
class CurveImage
{
public:
CurveImage();
void drawCurve(const CurveData & curve, QColor color);
const QImage & get() const { return image; }
protected:
int size;
QImage image;
QPainter painter;
};
class ModelPrinter: public QObject
{
Q_OBJECT
+10 -1
View File
@@ -14,6 +14,12 @@ set(shared_NAMES
autoslider
autospinbox
autotimeedit
curveimagewidget
curvedialog
)
set(shared_UIS
curvedialog.ui
)
foreach(name ${shared_NAMES})
@@ -21,13 +27,16 @@ foreach(name ${shared_NAMES})
set(shared_HDRS ${shared_HDRS} ${name}.h)
endforeach()
qt5_wrap_ui(shared_SRCS ${shared_UIS})
qt5_wrap_cpp(shared_SRCS ${shared_HDRS})
# add after moc generation to stop warnings
set(shared_SRCS ${shared_SRCS}
autowidget.h
autowidget.cpp
curveimage.h
curveimage.cpp
)
add_library(shared ${shared_SRCS})
target_link_libraries(shared PRIVATE Qt5::Widgets ${CPN_COMMON_LIB})
target_link_libraries(shared PRIVATE datamodels Qt5::Widgets ${CPN_COMMON_LIB})
+599
View File
@@ -0,0 +1,599 @@
/*
* 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.
*/
#include "curvedialog.h"
#include "ui_curvedialog.h"
#include "../modeledit/node.h"
#include "../modeledit/edge.h"
#include "helpers.h"
#include "filtereditemmodels.h"
#include "eeprominterface.h"
float curveLinear(float x, float coeff, float yMin, float yMid, float yMax)
{
float a = (yMax - yMin) / 200.0;
return yMin + a * (x + 100.0);
}
float curveexpou(float point, float coeff)
{
float x = point * 1024.0 / 100.0;
float k = coeff * 256.0 / 100.0;
return ((k * x * x * x / (1024 * 1024) + x * (256 - k) + 128) / 256) / 1024.0 * 100;
}
float curveExpo(float x, float coeff, float yMin, float yMid, float yMax)
{
float a = (yMax - yMin) / 100.0;
x += 100.0;
x /= 2.0;
if (coeff >= 0) {
return round(curveexpou(x, coeff)*a + yMin);
}
else {
coeff = -coeff;
x = 100 - x;
return round((100.0 - curveexpou(x, coeff)) * a + yMin);
}
}
float curveSymmetricalY(float x, float coeff, float yMin, float yMid, float yMax)
{
bool invert;
if (x < 0) {
x = -x;
invert = 1;
}
else {
invert = 0;
}
float y;
if (coeff >= 0) {
y = round(curveexpou(x, coeff) * (yMax / 100.0));
}
else {
coeff = -coeff;
x = 100.0 - x;
y = round((100.0 - curveexpou(x, coeff)) * (yMax / 100.0));
}
if (invert) {
y = -y;
}
return y;
}
float curveSymmetricalX(float x, float coeff, float yMin, float yMid, float yMax)
{
float a = (yMax - yMid) / 100.0;
if (x < 0)
x = -x;
float y;
if (coeff >= 0) {
y = round(curveexpou(x, coeff) * a + yMid);
}
else {
coeff = -coeff;
x = 100 - x;
y = round((100.0 - curveexpou(x, coeff)) * a + yMid);
}
return y;
}
#define GFX_MARGIN 16
#define CURVE_COEFF_ENABLE 1
#define CURVE_YMID_ENABLE 2
#define CURVE_YMIN_ENABLE 4
/*
CurveDialog
*/
CurveDialog::CurveDialog(QWidget * parent, ModelData & model, const int curveIdx, Firmware * firmware,
CompoundItemModelFactory * sharedItemModels) :
QDialog(parent),
ui(new Ui::CurveDialog),
model(model),
curve(model.curves[curveIdx]),
curveIdx(curveIdx),
sharedItemModels(sharedItemModels)
{
ui->setupUi(this);
if (curve.isEmpty())
curve.init();
lock = true;
maxCurves = firmware->getCapability(NumCurves);
maxPoints = firmware->getCapability(NumCurvePoints);
ui->curveName->setField(curve.name, CURVEDATA_NAME_LEN);
connect(ui->curveName, &AutoLineEdit::currentDataChanged, this, &CurveDialog::on_curveNameChanged);
on_curveNameChanged();
dialogFilterFactory = new FilteredItemModelFactory();
int id = dialogFilterFactory->registerItemModel(new FilteredItemModel(CurveData::typeItemModel()),
"Curve Type");
ui->curveType->setModel(dialogFilterFactory->getItemModel(id));
ui->curveType->setField((int &)curve.type);
connect(ui->curveType, &AutoComboBox::currentDataChanged, this, [&] () { on_curveTypeChanged(ui->curveType->currentIndex()) ;});
id = dialogFilterFactory->registerItemModel(new FilteredItemModel(CurveData::pointsItemModel()),
"Curve Points");
ui->curvePoints->setModel(dialogFilterFactory->getItemModel(id));
ui->curvePoints->setField(curve.count);
connect(ui->curvePoints, &AutoComboBox::currentDataChanged, this, [&] () { on_curvePointsChanged(ui->curvePoints->currentIndex()) ;});
ui->curveSmooth->setField(curve.smooth);
connect(ui->curveSmooth, &AutoCheckBox::currentDataChanged, this, [&] () { update() ;});
scene = new CustomScene(ui->curvePreview);
scene->setItemIndexMethod(QGraphicsScene::NoIndex);
connect(scene, &CustomScene::newPoint, this, &CurveDialog::onSceneNewPoint);
ui->curvePreview->setScene(scene);
for (int i = 0; i < CPN_MAX_POINTS; i++) {
spnx[i] = new QSpinBox(this);
spnx[i]->setProperty("index", i);
spnx[i]->setMinimum(-100);
spnx[i]->setMaximum(+100);
spnx[i]->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
spnx[i]->setAccelerated(true);
connect(spnx[i], QOverload<int>::of(&QSpinBox::valueChanged), this, &CurveDialog::onPointEdited);
ui->pointsLayout->addWidget(spnx[i], i, 0, 1, 1);
spny[i] = new QSpinBox(this);
spny[i]->setProperty("index", i);
spny[i]->setMinimum(-100);
spny[i]->setMaximum(+100);
spny[i]->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
spny[i]->setAccelerated(true);
connect(spny[i], QOverload<int>::of(&QSpinBox::valueChanged), this, &CurveDialog::onPointEdited);
ui->pointsLayout->addWidget(spny[i], i, 1, 1, 1);
}
addTemplate(tr("Linear"), CURVE_YMIN_ENABLE, curveLinear);
addTemplate(tr("Single Expo"), CURVE_COEFF_ENABLE | CURVE_YMIN_ENABLE, curveExpo);
addTemplate(tr("Symmetrical f(x)=-f(-x)"), CURVE_COEFF_ENABLE, curveSymmetricalY);
addTemplate(tr("Symmetrical f(x)=f(-x)"), CURVE_COEFF_ENABLE | CURVE_YMID_ENABLE, curveSymmetricalX);
on_curveTemplateChanged(0);
ui->pointSize->setValue(10);
ui->pointSize->setMinimum(3);
ui->pointSize->setMaximum(20);
connect(ui->pointSize, QOverload<int>::of(&QSpinBox::valueChanged), this, [&] () { if (!lock) update(); });
connect(ui->curveTemplate, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CurveDialog::on_curveTemplateChanged);
connect(ui->curveApply, &QPushButton::clicked, this, &CurveDialog::on_curveApplyClicked);
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
connect(this, &QDialog::accepted, this, &CurveDialog::onDialogAccepted);
update();
shrink();
lock = false;
}
CurveDialog::~CurveDialog()
{
delete ui;
delete dialogFilterFactory;
}
void CurveDialog::onDialogAccepted()
{
model.curves[curveIdx] = curve;
if (sharedItemModels)
sharedItemModels->update(AbstractItemModel::IMUE_Curves);
}
void CurveDialog::update()
{
lock = true;
ui->curveName->update();
updateCurveType();
updateCurve();
updateCurvePoints();
shrink();
lock = false;
}
void CurveDialog::updateCurveType()
{
lock = true;
ui->curveType->update();
ui->curvePoints->update();
ui->curveSmooth->update();
lock = false;
}
void CurveDialog::updateCurve()
{
lock = true;
Node * nodel = 0;
Node * nodex = 0;
QColor color;
scene->clear();
qreal width = scene->sceneRect().width();
qreal height = scene->sceneRect().height();
qreal leftX = scene->sceneRect().left() + width / 4 * 1;
qreal centerX = scene->sceneRect().left() + width / 2;
qreal rightX = scene->sceneRect().left() + width / 4 * 3;
qreal topY = scene->sceneRect().top() + height / 4 * 1;
qreal centerY = scene->sceneRect().top() + height / 2;
qreal bottomY = scene->sceneRect().top() + height / 4 * 3;
scene->addLine(leftX, GFX_MARGIN, leftX, height + GFX_MARGIN);
scene->addLine(centerX, GFX_MARGIN, centerX, height + GFX_MARGIN);
scene->addLine(rightX, GFX_MARGIN, rightX, height + GFX_MARGIN);
scene->addLine(GFX_MARGIN, topY, width + GFX_MARGIN, topY);
scene->addLine(GFX_MARGIN, centerY, width + GFX_MARGIN, centerY);
scene->addLine(GFX_MARGIN, bottomY, width + GFX_MARGIN, bottomY);
QPen pen;
pen.setWidth(1);
pen.setStyle(Qt::SolidLine);
pen.setColor(colors[0]); // needed????
int numpoints = curve.count;
for (int i = 0; i < numpoints - 1; i++) {
if (curve.type == CurveData::CURVE_TYPE_CUSTOM)
scene->addLine(centerX + (qreal)curve.points[i].x * width / 200,
centerY - (qreal)curve.points[i].y * height / 200,
centerX + (qreal)curve.points[i + 1].x * width / 200,
centerY - (qreal)curve.points[i + 1].y * height / 200, pen);
else
scene->addLine(GFX_MARGIN + i * width / (numpoints - 1),
centerY - (qreal)curve.points[i].y * height / 200,
GFX_MARGIN + (i + 1) * width / (numpoints - 1),
centerY - (qreal)curve.points[i + 1].y * height / 200, pen);
}
for (int i = 0; i < numpoints; i++) {
nodel = nodex;
nodex = new Node();
nodex->setProperty("index", i);
nodex->setColor(colors[0]);
nodex->setBallSize(ui->pointSize->value());
nodex->setBallHeight(0);
if (curve.type == CurveData::CURVE_TYPE_CUSTOM) {
if (i > 0 && i < numpoints - 1) {
nodex->setFixedX(false);
nodex->setMinX(curve.points[i - 1].x);
nodex->setMaxX(curve.points[i + 1].x);
}
else {
nodex->setFixedX(true);
}
nodex->setPos(centerX + (qreal)curve.points[i].x * width / 200,
centerY - (qreal)curve.points[i].y * height / 200);
}
else {
nodex->setFixedX(true);
nodex->setPos(GFX_MARGIN + i * width / (numpoints - 1),
centerY - (qreal)curve.points[i].y * height / 200);
}
connect(nodex, SIGNAL(moved(int, int)), this, SLOT(onNodeMoved(int, int)));
connect(nodex, SIGNAL(focus()), this, SLOT(onNodeFocus()));
connect(nodex, SIGNAL(unfocus()), this, SLOT(onNodeUnfocus()));
connect(nodex, SIGNAL(deleteMe()), this, SLOT(onNodeDelete()));
scene->addItem(nodex);
if (i > 0)
scene->addItem(new Edge(nodel, nodex));
}
lock = false;
}
void CurveDialog::updateCurvePoints()
{
lock = true;
int count = curve.count;
for (int i = 0; i < count; i++) {
spny[i]->show();
spny[i]->setValue(curve.points[i].y);
if (curve.type == CurveData::CURVE_TYPE_CUSTOM) {
spnx[i]->show();
if (i == 0 || i == count - 1) {
spnx[i]->setDisabled(true);
spnx[i]->setMaximum(+100);
spnx[i]->setMinimum(-100);
}
else {
spnx[i]->setDisabled(false);
spnx[i]->setMaximum(curve.points[i + 1].x);
spnx[i]->setMinimum(curve.points[i - 1].x);
}
spnx[i]->setValue(curve.points[i].x);
}
else {
spnx[i]->hide();
}
}
for (int i = count; i < CPN_MAX_POINTS; i++) {
spny[i]->hide();
spnx[i]->hide();
}
lock = false;
}
void CurveDialog::onPointEdited(int i)
{
if (!lock) {
int index = sender()->property("index").toInt();
curve.points[index].x = spnx[index]->value();
curve.points[index].y = spny[index]->value();
updateCurve();
updateCurvePoints();
}
}
void CurveDialog::onNodeMoved(int x, int y)
{
if (!lock) {
lock = true;
int index = sender()->property("index").toInt();
curve.points[index].x = x;
curve.points[index].y = y;
spnx[index]->setValue(x);
spny[index]->setValue(y);
if (index > 0)
spnx[index - 1]->setMaximum(x);
if (index < curve.count - 1)
spnx[index + 1]->setMinimum(x);
lock = false;
}
}
void CurveDialog::onNodeFocus()
{
int index = sender()->property("index").toInt();
spny[index]->setFocus();
}
void CurveDialog::onNodeUnfocus()
{
int index = sender()->property("index").toInt();
spny[index]->clearFocus();
updateCurve();
}
bool CurveDialog::allowCurveType(int points, CurveData::CurveType type)
{
int totalpoints = 0;
for (int i = 0; i < maxCurves; i++) {
int cvPoints = (i == curveIdx ? points : model.curves[i].count);
CurveData::CurveType cvType = (i == curveIdx ? type : model.curves[i].type);
totalpoints += cvPoints + (cvType == CurveData::CURVE_TYPE_CUSTOM ? cvPoints - 2 : 0);
}
if (totalpoints > maxPoints) {
QMessageBox::warning(this, CPN_STR_APP_NAME, tr("Not enough free points in global points array to store the curve."));
return false;
}
else {
return true;
}
}
void CurveDialog::on_curveNameChanged()
{
setWindowTitle(tr("Editing curve %1: %2").arg(curveIdx + 1).arg(QString(curve.name)));
}
void CurveDialog::on_curvePointsChanged(int index)
{
if (!lock) {
int numpoints = ((QComboBox *)sender())->itemData(index).toInt();
if (allowCurveType(numpoints, curve.type)) {
curve.count = numpoints;
curve.init();
update();
}
else {
updateCurveType();
}
}
}
void CurveDialog::on_curveTypeChanged(int index)
{
if (!lock) {
CurveData::CurveType type = (CurveData::CurveType)index;
int numpoints = ui->curvePoints->itemData(ui->curvePoints->currentIndex()).toInt();
if (allowCurveType(numpoints, type)) {
//curve.clear(numpoints);
curve.type = type;
//curve.init();
update();
}
else {
updateCurveType();
}
}
}
void CurveDialog::resizeEvent(QResizeEvent *event)
{
QRect qr = ui->curvePreview->contentsRect();
ui->curvePreview->scene()->setSceneRect(GFX_MARGIN, GFX_MARGIN, qr.width() - GFX_MARGIN * 2, qr.height() - GFX_MARGIN * 2);
updateCurve();
}
void CurveDialog::on_curveTemplateChanged(int index)
{
unsigned int flags = templates[index].flags;
ui->curveCoeffLabel->setVisible(flags & CURVE_COEFF_ENABLE);
ui->curveCoeff->setVisible(flags & CURVE_COEFF_ENABLE);
ui->yMax->setValue(100);
ui->yMidLabel->setVisible(flags & CURVE_YMID_ENABLE);
ui->yMid->setVisible(flags & CURVE_YMID_ENABLE);
ui->yMid->setValue(0);
ui->yMinLabel->setVisible(flags & CURVE_YMIN_ENABLE);
ui->yMin->setVisible(flags & CURVE_YMIN_ENABLE);
ui->yMin->setValue(-100);
}
void CurveDialog::addTemplate(QString name, unsigned int flags, curveFunction function)
{
CurveCreatorTemplate tmpl;
tmpl.name = name;
tmpl.flags = flags;
tmpl.function = function;
templates.append(tmpl);
ui->curveTemplate->addItem(name);
}
void CurveDialog::on_curveApplyClicked()
{
int index = ui->curveTemplate->currentIndex();
int numpoints = curve.count;
for (int i = 0; i < numpoints; i++) {
float x;
if (curve.type == CurveData::CURVE_TYPE_CUSTOM)
x = curve.points[i].x;
else
x = -100.0 + (200.0 / (numpoints - 1)) * i;
bool apply = false;
switch (ui->curveSide->currentIndex()) {
case 0:
apply = true;
break;
case 1:
if (x >= 0)
apply = true;
break;
case 2:
if (x < 0)
apply = true;
break;
}
if (apply) {
curve.points[i].y = templates[index].function(x, ui->curveCoeff->value(), ui->yMin->value(), ui->yMid->value(),
ui->yMax->value());
}
}
updateCurve();
updateCurvePoints();
}
void CurveDialog::onNodeDelete()
{
int index = sender()->property("index").toInt();
int numpoints = curve.count;
if ((curve.type == CurveData::CURVE_TYPE_CUSTOM) && (index > 0) && (index < numpoints - 1)) {
spny[index]->clearFocus();
for (int i = index + 1; i < numpoints; i++) {
curve.points[i - 1] = curve.points[i];
}
numpoints--;
curve.points[numpoints].x = 0;
curve.points[numpoints].y = 0;
curve.count = numpoints;
update();
}
}
void CurveDialog::onSceneNewPoint(int x, int y)
{
if ((curve.type == CurveData::CURVE_TYPE_CUSTOM) && (curve.count < CPN_MAX_POINTS)) {
int newidx = 0;
int numpoints = curve.count;
if (x < curve.points[0].x) {
newidx = 0;
}
else if (x > curve.points[numpoints - 1].x) {
newidx = numpoints;
}
else {
for (int i = 0; i < numpoints; i++) {
if (x < curve.points[i].x) {
newidx = i;
break;
}
}
}
numpoints++;
curve.count = numpoints;
for (int idx = (numpoints - 1); idx > newidx; idx--) {
curve.points[idx] = curve.points[idx - 1];
}
curve.points[newidx].x = x;
curve.points[newidx].y = y;
update();
}
}
void CurveDialog::shrink()
{
resize(0, 0);
}
CustomScene::CustomScene(QGraphicsView * view) :
QGraphicsScene(view)
{
}
void CustomScene::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
if (event->button() == Qt::LeftButton && event->modifiers() == Qt::ControlModifier) {
QRectF rect = sceneRect();
QPointF pos = event->scenePos();
QPointF p;
p.setX(-100 + ((pos.x() - rect.left()) * 200) / rect.width());
p.setY(100 + (rect.top() - pos.y()) * 200 / rect.height());
QGraphicsScene::mouseReleaseEvent(event);
emit newPoint((int)p.x(), (int)p.y());
}
else
QGraphicsScene::mouseReleaseEvent(event);
}
+109
View File
@@ -0,0 +1,109 @@
/*
* 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.
*/
#pragma once
#include "constants.h"
#include "modeldata.h"
#include <QtWidgets>
#include <QGraphicsScene>
#include <QGraphicsView>
class Firmware;
class FilteredItemModelFactory;
class CompoundItemModelFactory;
namespace Ui {
class CurveDialog;
}
typedef float (*curveFunction) (float x, float coeff, float yMin, float yMid, float yMax);
struct CurveCreatorTemplate {
QString name;
unsigned int flags;
curveFunction function;
};
class CustomScene : public QGraphicsScene
{
Q_OBJECT
public:
CustomScene(QGraphicsView * view);
signals:
void newPoint(int, int);
protected:
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * event) override;
};
class CurveDialog : public QDialog
{
Q_OBJECT
public:
CurveDialog(QWidget *parent, ModelData & model, const int curveIdx, Firmware * firmware, CompoundItemModelFactory * sharedItemModels);
virtual ~CurveDialog();
private slots:
void shrink();
void on_curveNameChanged();
void on_curvePointsChanged(int index);
void on_curveTypeChanged(int index);
void onPointEdited(int i);
void onNodeMoved(int x, int y);
void onNodeFocus();
void onNodeUnfocus();
void on_curveTemplateChanged(int index);
void on_curveApplyClicked();
void onSceneNewPoint(int x, int y);
void onNodeDelete();
void onDialogAccepted();
protected:
virtual void resizeEvent(QResizeEvent *event);
void addTemplate(QString name, unsigned int flags, curveFunction function);
private:
Ui::CurveDialog *ui;
ModelData &model;
CurveData curve; // copy initialised in constructor and copied back to model if dialog is accepted
const int curveIdx;
CompoundItemModelFactory *sharedItemModels;
QSpinBox *spnx[CPN_MAX_POINTS];
QSpinBox *spny[CPN_MAX_POINTS];
QVector<CurveCreatorTemplate> templates;
CustomScene *scene;
int maxCurves;
int maxPoints;
bool lock;
FilteredItemModelFactory * dialogFilterFactory;
void update();
void updateCurve();
void updateCurveType();
void updateCurvePoints();
bool allowCurveType(int points, CurveData::CurveType type);
void setPointY(int i, int x, int y);
};
@@ -1,153 +1,119 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Curves</class>
<widget class="QWidget" name="Curves">
<class>CurveDialog</class>
<widget class="QDialog" name="CurveDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>672</width>
<height>539</height>
<width>658</width>
<height>523</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string/>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QGridLayout" name="curvesLayout"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_1">
<property name="rightMargin">
<number>0</number>
</property>
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item row="0" column="0" rowspan="2">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGraphicsView" name="curvePreview">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>400</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="curveNameLabel">
<property name="text">
<string>Curve name</string>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGraphicsView" name="curvePreview">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>400</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0,0">
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="curvePoints"/>
</item>
<item>
<widget class="QComboBox" name="curveCustom">
<item>
<property name="text">
<string>Fixed X</string>
</property>
</item>
<item>
<property name="text">
<string>Custom X</string>
</property>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="curveNameLabel">
<property name="text">
<string>Name</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="curveSmooth">
<item>
<property name="text">
<string>Lines</string>
</property>
</item>
<item>
<property name="text">
<string>Smooth</string>
</property>
</item>
<item row="0" column="1">
<widget class="AutoLineEdit" name="curveName">
<property name="maxLength">
<number>3</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="curveTypeLabel">
<property name="text">
<string>Type</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="AutoComboBox" name="curveType"/>
</item>
<item row="1" column="2">
<widget class="AutoComboBox" name="curvePoints"/>
</item>
<item row="1" column="3">
<widget class="AutoCheckBox" name="curveSmooth">
<property name="text">
<string>Smooth</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="curveName">
<property name="maxLength">
<number>3</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="curveTypeLabel">
<property name="text">
<string>Curve type</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="curvesLayout2"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QGridLayout" name="pointsLayout">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="horizontalSpacing">
<number>0</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
</layout>
<layout class="QGridLayout" name="pointsLayout"/>
</item>
<item>
<spacer name="verticalSpacer_2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@@ -161,7 +127,7 @@
</item>
</layout>
</item>
<item>
<item row="0" column="2" rowspan="2">
<widget class="QGroupBox" name="curveCreator">
<property name="font">
<font>
@@ -175,7 +141,17 @@
<property name="title">
<string>Curve Creator</string>
</property>
<layout class="QGridLayout" name="gridLayout_76" rowstretch="0,0,0,0,0,0,0,0,0,0">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="curveTemplateLabel">
<property name="text">
<string>Template</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="curveTemplate"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="curveCoeffLabel">
<property name="text">
@@ -183,51 +159,8 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="curveTypeLabel_2">
<property name="text">
<string>Curve type</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="curveSideLabel">
<property name="text">
<string>Side</string>
</property>
</widget>
</item>
<item row="9" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="1" colspan="3">
<widget class="QSpinBox" name="yMax">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="3" column="1" colspan="3">
<widget class="QSpinBox" name="yMid">
<item row="1" column="1">
<widget class="QSpinBox" name="curveCoeff">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -249,7 +182,76 @@
</property>
</widget>
</item>
<item row="5" column="1" colspan="3">
<item row="2" column="1">
<widget class="QSpinBox" name="yMin">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="yMidLabel">
<property name="text">
<string>Y at X=0</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="yMid">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="yMaxLabel">
<property name="text">
<string>Y at X=100</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="yMax">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="curveSideLabel">
<property name="text">
<string>Side</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="curveSide">
<item>
<property name="text">
@@ -268,43 +270,17 @@
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="yMaxLabel">
<property name="text">
<string>Y at X=100</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QSpinBox" name="curveCoeff">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="6" column="0" colspan="4">
<item row="6" column="0">
<widget class="QPushButton" name="curveApply">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QComboBox" name="curveType"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="yMidLabel">
<property name="text">
<string>Y at X=0</string>
<item row="7" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
@@ -315,57 +291,74 @@
</property>
</widget>
</item>
<item row="2" column="1" colspan="3">
<widget class="QSpinBox" name="yMin">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="8" column="1" colspan="3">
<item row="8" column="1">
<widget class="QSpinBox" name="pointSize"/>
</item>
<item row="7" column="0" colspan="4">
<widget class="Line" name="line">
<item row="9" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Vertical</enum>
</property>
</widget>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<item row="1" column="3">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<width>1</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>AutoLineEdit</class>
<extends>QLineEdit</extends>
<header>autolineedit.h</header>
</customwidget>
<customwidget>
<class>AutoComboBox</class>
<extends>QComboBox</extends>
<header>autocombobox.h</header>
</customwidget>
<customwidget>
<class>AutoCheckBox</class>
<extends>QCheckBox</extends>
<header>autocheckbox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>curvePreview</tabstop>
<tabstop>curvePoints</tabstop>
<tabstop>curveCustom</tabstop>
<tabstop>curveSmooth</tabstop>
<tabstop>curveName</tabstop>
<tabstop>curveType</tabstop>
<tabstop>curveTemplate</tabstop>
<tabstop>curveCoeff</tabstop>
<tabstop>yMin</tabstop>
<tabstop>yMid</tabstop>
+61
View File
@@ -0,0 +1,61 @@
/*
* 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.
*/
#include "curveimage.h"
#include "curvedata.h"
constexpr int IMAGE_SIZE = { 200 };
CurveImage::CurveImage(QColor gridColor, qreal gridWidth):
size(IMAGE_SIZE),
image(size + 1, size + 1, QImage::Format_RGB32),
painter(&image)
{
painter.setBrush(QBrush(Qt::white));
painter.setPen(Qt::black);
painter.drawRect(0, 0, size, size);
painter.setPen(QPen(gridColor, gridWidth));
const int step = size / 4;
painter.drawLine(0, step * 1, size, step * 1);
painter.drawLine(0, step * 2, size, step * 2);
painter.drawLine(0, step * 3, size, step * 3);
painter.drawLine(step * 1, 0, step * 1, size);
painter.drawLine(step * 2, 0, step * 2, size);
painter.drawLine(step * 3, 0, step * 3, size);
}
void CurveImage::drawCurve(const CurveData & curve, QColor color, qreal width)
{
painter.setPen(QPen(color, width, Qt::SolidLine));
for (int j = 1; j < curve.count; j++) {
if (curve.type == CurveData::CURVE_TYPE_CUSTOM)
painter.drawLine(size / 2 + (size * curve.points[j - 1].x) / IMAGE_SIZE,
size / 2 - (size * curve.points[j - 1].y) / IMAGE_SIZE,
size / 2 + (size * curve.points[j].x) / IMAGE_SIZE,
size / 2 - (size * curve.points[j].y) / IMAGE_SIZE);
else
painter.drawLine(size * (j-1) / (curve.count - 1),
size / 2 - (size * curve.points[j - 1].y) / IMAGE_SIZE,
size * (j) / (curve.count - 1),
size / 2 - (size * curve.points[j].y) / IMAGE_SIZE);
}
}
+39
View File
@@ -0,0 +1,39 @@
/*
* 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.
*/
#pragma once
#include <QPainter>
class CurveData;
class CurveImage
{
public:
CurveImage(QColor gridColor = Qt::darkGray, qreal gridWidth = 1);
void drawCurve(const CurveData & curve, QColor color = Qt::black, qreal width = 2);
const QImage & get() const { return image; }
protected:
int size;
QImage image;
QPainter painter;
};
+97
View File
@@ -0,0 +1,97 @@
/*
* 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.
*/
#include "curveimagewidget.h"
#include "curveimage.h"
#include "curvedialog.h"
#include "compounditemmodels.h"
#include "modeldata.h"
#include "eeprominterface.h"
CurveImageWidget::CurveImageWidget(QWidget * parent) :
QLabel(parent)
{
setToolTip(tr("Double click to edit"));
}
void CurveImageWidget::set(ModelData * model, Firmware * firmware, CompoundItemModelFactory * sharedItemModels, int index, QColor penColor, qreal penWidth)
{
this->model = model;
this->firmware = firmware;
this->sharedItemModels = sharedItemModels;
this->penWidth = penWidth;
this->penColor = penColor;
setIndex(index);
setGrid();
}
void CurveImageWidget::setIndex(int index)
{
this->index = (index >= 0 && index < CPN_MAX_CURVES) ? index : -1;
}
void CurveImageWidget::setGrid(QColor color, qreal width)
{
gridColor = color;
gridWidth = width;
}
void CurveImageWidget::setPen(QColor color, qreal width)
{
penColor = color;
penWidth = width;
}
int CurveImageWidget::edit()
{
int ret = 0;
if (index >= 0 && index < CPN_MAX_CURVES) {
CurveDialog *dlg = new CurveDialog(this, *model, index, firmware, sharedItemModels);
ret = dlg->exec();
delete dlg;
}
return ret;
}
void CurveImageWidget::draw()
{
if (index >= 0 && index < CPN_MAX_CURVES) {
CurveImage *curveImage = new CurveImage(gridColor, gridWidth);
curveImage->drawCurve(model->curves[index], penColor, penWidth);
QImage image = curveImage->get();
setPixmap(QPixmap::fromImage(image.scaled(height(), width())));
delete curveImage;
}
else {
CurveImage *curveImage = new CurveImage(gridColor, gridWidth);
QImage image = curveImage->get();
setPixmap(QPixmap::fromImage(image.scaled(height(), width())));
}
}
void CurveImageWidget::mouseDoubleClickEvent(QMouseEvent * event)
{
QLabel::mouseDoubleClickEvent(event);
emit doubleClicked();
}
+59
View File
@@ -0,0 +1,59 @@
/*
* 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.
*/
#pragma once
#include <QLabel>
class ModelData;
class Firmware;
class CompoundItemModelFactory;
class CurveImageWidget : public QLabel
{
Q_OBJECT
public:
CurveImageWidget(QWidget * parent);
virtual ~CurveImageWidget() {}
void set(ModelData * model, Firmware * firmware, CompoundItemModelFactory * sharedItemModels, int index, QColor penColor = Qt::black, qreal penWidth = 2);
void setIndex(int index);
void setGrid(QColor color = Qt::darkGray, qreal width = 1);
void setPen(QColor color = Qt::black, qreal width = 2);
int edit();
void draw();
signals:
void doubleClicked();
protected:
virtual void mouseDoubleClickEvent(QMouseEvent * event);
private:
ModelData *model = nullptr;
Firmware *firmware = nullptr;
CompoundItemModelFactory *sharedItemModels;
int index;
qreal penWidth;
QColor penColor;
qreal gridWidth;
QColor gridColor;
};
+1 -1
View File
@@ -119,4 +119,4 @@ qt5_wrap_ui(simulation_SRCS ${simulation_UIS})
qt5_wrap_cpp(simulation_SRCS ${simulation_HDRS})
add_library(simulation ${simulation_SRCS} ${simulation_HDRS})
target_link_libraries(simulation PRIVATE ${CPN_COMMON_LIB} Qt5::Core Qt5::Widgets Qt5::Svg)
target_link_libraries(simulation PRIVATE ${CPN_COMMON_LIB} shared Qt5::Core Qt5::Widgets Qt5::Svg)