diff --git a/Project/QtCreator/qctools-gui/qctools-gui.pro b/Project/QtCreator/qctools-gui/qctools-gui.pro index 2c7112ec7..320ab5611 100644 --- a/Project/QtCreator/qctools-gui/qctools-gui.pro +++ b/Project/QtCreator/qctools-gui/qctools-gui.pro @@ -75,7 +75,8 @@ HEADERS += \ $$SOURCES_PATH/GUI/filterselector.h \ $$SOURCES_PATH/GUI/playercontrol.h \ $$SOURCES_PATH/GUI/panelsview.h \ - $$SOURCES_PATH/GUI/plotschooser.h + $$SOURCES_PATH/GUI/plotschooser.h \ + $$SOURCES_PATH/GUI/yminmaxselector.h SOURCES += \ $$SOURCES_PATH/GUI/FilesList.cpp \ @@ -108,7 +109,8 @@ SOURCES += \ $$SOURCES_PATH/GUI/filterselector.cpp \ $$SOURCES_PATH/GUI/playercontrol.cpp \ $$SOURCES_PATH/GUI/panelsview.cpp \ - $$SOURCES_PATH/GUI/plotschooser.cpp + $$SOURCES_PATH/GUI/plotschooser.cpp \ + $$SOURCES_PATH/GUI/yminmaxselector.cpp include(../zlib.pri) @@ -121,7 +123,8 @@ FORMS += \ $$SOURCES_PATH/GUI/barchartconditioninput.ui \ $$SOURCES_PATH/GUI/managebarchartconditions.ui \ $$SOURCES_PATH/GUI/playercontrol.ui \ - $$SOURCES_PATH/GUI/plotschooser.ui + $$SOURCES_PATH/GUI/plotschooser.ui \ + $$SOURCES_PATH/GUI/yminmaxselector.ui \ RESOURCES += \ $$SOURCES_PATH/Resource/Resources.qrc diff --git a/Source/GUI/Plot.cpp b/Source/GUI/Plot.cpp index d7fad43f8..e8a23bd86 100644 --- a/Source/GUI/Plot.cpp +++ b/Source/GUI/Plot.cpp @@ -26,6 +26,8 @@ #include #include "Core/FileInformation.h" +#include +#include #include static double stepSize( double distance, int numSteps ) @@ -346,31 +348,35 @@ void Plot::initYAxis() } else { + auto yMin = 0.0; + auto yMax = 0.0; const size_t plotType = type(); const size_t plotGroup = group(); CommonStats* stat = stats( streamPos() ); const struct per_group& group = PerStreamType[plotType].PerGroup[plotGroup]; - auto yMin = 0.0; - if(m_minValue.isNull() || m_minValue.isError() || m_minValue.isUndefined()) { - yMin = stat->y_Min[plotGroup]; // auto-select min - } else { + if(m_yminMaxMode == Formula) + { if(m_minValue.isNumber()) yMin = m_minValue.toNumber(); else if(m_minValue.isCallable()) yMin = m_minValue.call().toNumber(); - } - auto yMax = 0.0; - if(m_maxValue.isNull() || m_maxValue.isError() || m_maxValue.isUndefined()) { - yMax = stat->y_Max[plotGroup]; // auto-select min - } else { if(m_maxValue.isNumber()) yMax = m_maxValue.toNumber(); else if(m_maxValue.isCallable()) yMax = m_maxValue.call().toNumber(); } + else if(m_yminMaxMode == MinMaxOfThePlot) + { + yMin = stat->y_Min[plotGroup]; // auto-select min + yMax = stat->y_Max[plotGroup]; // auto-select max + } else if(m_yminMaxMode == Custom) + { + yMin = m_customYMin; + yMax = m_customYMax; + } setYAxis( yMin, yMax, group.StepsCount ); } @@ -428,6 +434,47 @@ bool Plot::isBarchart() const return m_barchart; } +void Plot::setYAxisMinMaxMode(YMinMaxMode mode) +{ + m_yminMaxMode = mode; + initYAxis(); +} + +Plot::YMinMaxMode Plot::yAxisMinMaxMode() const +{ + return m_yminMaxMode; +} + +void Plot::setYAxisCustomMinMax(double min, double max) +{ + m_customYMin = min; + m_customYMax = max; +} + +void Plot::getYAxisCustomMinMax(double &min, double &max) +{ + min = m_customYMin; + max = m_customYMax; +} + +bool Plot::hasMinMaxFormula() const +{ + if(m_minValue.isNull() || m_minValue.isError() || m_minValue.isUndefined()) { + return false; + } + + if(m_maxValue.isNull() || m_maxValue.isError() || m_maxValue.isUndefined()) { + return false; + } + + return true; +} + +const CommonStats *Plot::getStats() const +{ + return stats( streamPos() ); +} + void Plot::setBarchart(bool value) { if(m_barchart != value) @@ -623,6 +670,28 @@ Plot::Plot( size_t streamPos, size_t Type, size_t Group, const FileInformation* #else panner->setMouseButton( Qt::MiddleButton ); #endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + + QSettings settings; + settings.beginGroup("yminmax"); + + QMetaEnum metaEnum = QMetaEnum::fromType(); + QString value = settings.value(QString::number(m_group)).toString(); + if(!value.isEmpty()) { + auto splitted = value.split(";"); + auto yMinMaxMode = (Plot::YMinMaxMode) metaEnum.keyToValue(splitted[0].toLatin1().constData()); + + if(yMinMaxMode == Plot::Custom) { + auto min = splitted[1].toDouble(); + auto max = splitted[2].toDouble(); + + setYAxisCustomMinMax(min, max); + } + + setYAxisMinMaxMode(yMinMaxMode); + } + + settings.endGroup(); + } //--------------------------------------------------------------------------- diff --git a/Source/GUI/Plot.h b/Source/GUI/Plot.h index 12138aa3a..3afcbc9ea 100644 --- a/Source/GUI/Plot.h +++ b/Source/GUI/Plot.h @@ -437,6 +437,13 @@ class Plot : public QwtPlot Q_OBJECT public: + enum YMinMaxMode { + MinMaxOfThePlot, + Formula, + Custom + }; + Q_ENUM(YMinMaxMode); + explicit Plot( size_t streamPos, size_t Type, size_t Group, const FileInformation* fileInformation, QWidget *parent ); virtual ~Plot(); @@ -472,6 +479,15 @@ class Plot : public QwtPlot void updateSymbols(); bool isBarchart() const; + void setYAxisMinMaxMode(YMinMaxMode mode); + YMinMaxMode yAxisMinMaxMode() const; + + void setYAxisCustomMinMax(double min, double max); + void getYAxisCustomMinMax(double& min, double& max); + + bool hasMinMaxFormula() const; + + const CommonStats* getStats() const; Q_SIGNALS: void cursorMoved(const QPointF& point, int index); void visibilityChanged(bool visible); @@ -488,6 +504,9 @@ private Q_SLOTS: const QwtPlotCurve* curve( int index ) const; QColor curveColor( int index ) const; + YMinMaxMode m_yminMaxMode { MinMaxOfThePlot }; + double m_customYMin { 0.0 }; + double m_customYMax { 0.0 }; QJSValue m_maxValue; QJSValue m_minValue; QJSEngine m_engine; diff --git a/Source/GUI/Plots.cpp b/Source/GUI/Plots.cpp index 8473e1e48..f3e42d650 100755 --- a/Source/GUI/Plots.cpp +++ b/Source/GUI/Plots.cpp @@ -17,6 +17,7 @@ #include "Core/Core.h" #include #include "playercontrol.h" +#include "yminmaxselector.h" #include #include #include @@ -123,6 +124,18 @@ void Plots::showEditBarchartProfileDialog(const size_t plotGroup, Plot* plot, co } } +void Plots::showYMinMaxConfigDialog(const size_t plotGroup, Plot *plot, const stream_info &streamInfo, QToolButton* button) +{ + auto globalButtonPos = button->mapToGlobal(QPoint(0, 0)); + auto geometry = m_yMinMaxSelector->geometry(); + + m_yMinMaxSelector->setPlot(plot); + m_yMinMaxSelector->enableFormulaMinMax(plot->hasMinMaxFormula()); + m_yMinMaxSelector->move(QPoint(globalButtonPos.x() - geometry.width(), globalButtonPos.y())); + if(!m_yMinMaxSelector->isVisible()) + m_yMinMaxSelector->show(); +} + Plots::Plots( QWidget *parent, FileInformation* fileInformation ) : QWidget( parent ), m_zoomFactor ( 0 ), @@ -282,11 +295,18 @@ Plots::Plots( QWidget *parent, FileInformation* fileInformation ) : barchartPlotSwitch->setIcon(switchToBarcharts ? QIcon(":/icon/chart_chart.png") : QIcon(":/icon/bar_chart.png")); }); + QToolButton* yMinMaxConfigButton = new QToolButton(); + connect(plot, SIGNAL(visibilityChanged(bool)), yMinMaxConfigButton, SLOT(setVisible(bool))); + connect(yMinMaxConfigButton, &QToolButton::clicked, [=]() { + showYMinMaxConfigDialog(plotGroup, plot, streamInfo, yMinMaxConfigButton); + }); + QHBoxLayout* barchartAndConfigurationLayout = new QHBoxLayout(); barchartAndConfigurationLayout->setAlignment(Qt::AlignLeft); barchartAndConfigurationLayout->setSpacing(5); barchartAndConfigurationLayout->addWidget(barchartPlotSwitch); barchartAndConfigurationLayout->addWidget(barchartConfigButton); + barchartAndConfigurationLayout->addWidget(yMinMaxConfigButton); legendLayout->addItem(barchartAndConfigurationLayout); legendLayout->addWidget(plot->plotLegend()); @@ -496,6 +516,9 @@ Plots::Plots( QWidget *parent, FileInformation* fileInformation ) : m_scaleWidget->setScale( m_timeInterval.from, m_timeInterval.to); setCursorPos( framePos() ); + + m_yMinMaxSelector = new YMinMaxSelector(this); + m_yMinMaxSelector->setWindowFlag(Qt::Popup); } //--------------------------------------------------------------------------- diff --git a/Source/GUI/Plots.h b/Source/GUI/Plots.h index 65f9a303c..c0586e4c8 100755 --- a/Source/GUI/Plots.h +++ b/Source/GUI/Plots.h @@ -22,6 +22,8 @@ class QwtPlot; class Plot; class PlotScaleWidget; class PlayerControl; +class YMinMaxSelector; +class QToolButton; void showEditFrameCommentsDialog(QWidget* parentWidget, FileInformation* info, CommonStats* stats, size_t frameIndex); @@ -116,6 +118,7 @@ class Plots : public QWidget void loadBarchartsProfile(const QJsonObject& profile); void showEditBarchartProfileDialog(const size_t plotGroup, Plot* plot, const stream_info& streamInfo); + void showYMinMaxConfigDialog(const size_t plotGroup, Plot* plot, const stream_info& streamInfo, QToolButton* button); Q_SIGNALS: void visibleFramesChanged(int from, int to); @@ -146,6 +149,7 @@ private Q_SLOTS: void setFramePos( size_t framePos, size_t statsPos = (size_t)-1 ) const { m_fileInfoData->Frames_Pos_Set(framePos, statsPos); } private: + YMinMaxSelector* m_yMinMaxSelector; PlotScaleWidget* m_scaleWidget; CommentsPlot* m_commentsPlot; std::vector m_PanelsViews; diff --git a/Source/GUI/yminmaxselector.cpp b/Source/GUI/yminmaxselector.cpp new file mode 100644 index 000000000..1dd4cc7a7 --- /dev/null +++ b/Source/GUI/yminmaxselector.cpp @@ -0,0 +1,118 @@ +#include "yminmaxselector.h" +#include "ui_yminmaxselector.h" +#include "Plot.h" + +#include +#include + +YMinMaxSelector::YMinMaxSelector(QWidget *parent) + : QWidget(parent) + , ui(new Ui::YMinMaxSelector) +{ + ui->setupUi(this); + + connect(ui->customMinMax_radioButton, &QRadioButton::toggled, this, &YMinMaxSelector::enableCustomMinMax); +} + +YMinMaxSelector::~YMinMaxSelector() +{ + delete ui; +} + +bool YMinMaxSelector::isMinMaxFromThePlot() const +{ + return ui->minMaxOfThePlot_radioButton->isChecked(); +} + +bool YMinMaxSelector::isFormula() const +{ + return ui->minMaxSystemProvided_radioButton->isChecked(); +} + +bool YMinMaxSelector::isCustom() const +{ + return ui->customMinMax_radioButton->isChecked(); +} + +void YMinMaxSelector::enableCustomMinMax(bool value) +{ + ui->min_label->setEnabled(value); + ui->min_doubleSpinBox->setEnabled(value); + ui->max_label->setEnabled(value); + ui->max_doubleSpinBox->setEnabled(value); +} + +void YMinMaxSelector::enableFormulaMinMax(bool value) +{ + ui->minMaxSystemProvided_radioButton->setEnabled(value); +} + +void YMinMaxSelector::setPlot(Plot *plot) +{ + m_plot = plot; + + if(plot->yAxisMinMaxMode() == Plot::MinMaxOfThePlot) { + ui->minMaxOfThePlot_radioButton->setChecked(true); + } else if(plot->yAxisMinMaxMode() == Plot::Formula) { + ui->minMaxSystemProvided_radioButton->setChecked(true); + } else if(plot->yAxisMinMaxMode() == Plot::Custom) { + ui->customMinMax_radioButton->setChecked(true); + } + + double min, max; + m_plot->getYAxisCustomMinMax(min, max); + + ui->min_doubleSpinBox->setValue(min); + ui->max_doubleSpinBox->setValue(max); + + if(qFuzzyCompare(ui->min_doubleSpinBox->value(), 0) && qFuzzyCompare(ui->max_doubleSpinBox->value(), 0)) { + auto stat = m_plot->getStats(); + auto plotGroup = m_plot->group(); + + auto yMin = stat->y_Min[plotGroup]; // auto-select min + auto yMax = stat->y_Max[plotGroup]; // auto-select max + + ui->min_doubleSpinBox->setValue(yMin); + ui->max_doubleSpinBox->setValue(yMax); + } +} + +Plot *YMinMaxSelector::getPlot() const +{ + return m_plot; +} + +void YMinMaxSelector::on_apply_pushButton_clicked() +{ + if(isFormula()) + { + m_plot->setYAxisMinMaxMode(Plot::Formula); + } + else if(isMinMaxFromThePlot()) + { + m_plot->setYAxisMinMaxMode(Plot::MinMaxOfThePlot); + } + else if(isCustom()) + { + m_plot->setYAxisCustomMinMax(ui->min_doubleSpinBox->value(), ui->max_doubleSpinBox->value()); + m_plot->setYAxisMinMaxMode(Plot::Custom); + } + + QSettings settings; + settings.beginGroup("yminmax"); + + QMetaEnum metaEnum = QMetaEnum::fromType(); + QString stringValue = metaEnum.valueToKey(m_plot->yAxisMinMaxMode()); + if(m_plot->yAxisMinMaxMode() == Plot::Custom) { + stringValue.append(";"); + stringValue.append(QString::number(ui->min_doubleSpinBox->value())); + stringValue.append(";"); + stringValue.append(QString::number(ui->max_doubleSpinBox->value())); + } + + settings.setValue(QString::number(m_plot->group()), stringValue); + settings.endGroup(); + + m_plot->replot(); +} + diff --git a/Source/GUI/yminmaxselector.h b/Source/GUI/yminmaxselector.h new file mode 100644 index 000000000..2ede67eec --- /dev/null +++ b/Source/GUI/yminmaxselector.h @@ -0,0 +1,36 @@ +#ifndef YMINMAXSELECTOR_H +#define YMINMAXSELECTOR_H + +#include + +namespace Ui { +class YMinMaxSelector; +} + +class Plot; +class YMinMaxSelector : public QWidget +{ + Q_OBJECT + +public: + explicit YMinMaxSelector(QWidget *parent = nullptr); + ~YMinMaxSelector(); + + bool isMinMaxFromThePlot() const; + bool isFormula() const; + bool isCustom() const; + + void enableFormulaMinMax(bool value); + void setPlot(Plot* plot); + Plot* getPlot() const; + +private Q_SLOTS: + void enableCustomMinMax(bool value); + void on_apply_pushButton_clicked(); + +private: + Plot* m_plot { nullptr }; + Ui::YMinMaxSelector *ui; +}; + +#endif // YMINMAXSELECTOR_H diff --git a/Source/GUI/yminmaxselector.ui b/Source/GUI/yminmaxselector.ui new file mode 100644 index 000000000..0fcd65009 --- /dev/null +++ b/Source/GUI/yminmaxselector.ui @@ -0,0 +1,155 @@ + + + YMinMaxSelector + + + + 0 + 0 + 400 + 192 + + + + Form + + + true + + + + + + Select y-axis min/max + + + + + + min/max value of the plot + + + true + + + + + + + system provided min/max + + + false + + + + + + + + + custom + + + + + + + false + + + min: + + + + + + + false + + + + 0 + 0 + + + + -100000000000000004384584304507619735463404765184.000000000000000 + + + 100000000000000004384584304507619735463404765184.000000000000000 + + + + + + + false + + + max: + + + + + + + false + + + + 0 + 0 + + + + -100000000000000004384584304507619735463404765184.000000000000000 + + + 100000000000000004384584304507619735463404765184.000000000000000 + + + + + + + + + + + + Qt::Horizontal + + + + 133 + 20 + + + + + + + + Apply + + + + + + + Qt::Horizontal + + + + 132 + 20 + + + + + + + + +