diff --git a/src/kdefrontend/ui/dockwidgets/xycurvedock.ui b/src/kdefrontend/ui/dockwidgets/xycurvedock.ui index 1dd9f24eb..3c6d12229 100644 --- a/src/kdefrontend/ui/dockwidgets/xycurvedock.ui +++ b/src/kdefrontend/ui/dockwidgets/xycurvedock.ui @@ -1,1453 +1,1453 @@ XYCurveDock 0 0 436 873 0 0 General Line 75 true Connection Type: - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 10 - 23 - - - - 0 0 Interm. points: 0 0 intermediate points to evaluate between each two points 1 Ignore gaps: Style: 0 0 Color: Width: pt 0.500000000000000 Opacity: 0 0 The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. % 0 100 10 100 Qt::Vertical QSizePolicy::Fixed 32 18 0 0 75 true Drop lines Type: Style: 0 0 Color: Width: pt 0.500000000000000 Opacity: 0 0 The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. % 0 100 10 100 Qt::Vertical 18 264 Monoton incr. X: + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 23 + + + + Symbol 0 0 ° -360 360 10 0 Opacity: 0 0 The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. % 0 100 10 100 75 true Filling Style: Color: Style: 0 0 Color: 75 true Border Width: 0 0 pt 0.500000000000000 pt 0.500000000000000 Rotation: Qt::Vertical QSizePolicy::Fixed 72 18 Qt::Vertical QSizePolicy::Fixed 72 18 Qt::Vertical QSizePolicy::Expanding 72 0 75 true General Style: 0 0 Size: Qt::Horizontal QSizePolicy::Fixed 10 23 Values Column: Precision: 0 0 0 16 0 0 0 75 true Text Suffix: Opacity: Font: 75 true General 0 0 0 0 The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. % 0 100 10 100 Qt::Horizontal QSizePolicy::Fixed 10 23 Distance: true 0 0 Color: 0 0 Rotation: pt 0.500000000000000 Prefix: Qt::Vertical 28 47 Qt::Vertical QSizePolicy::Fixed 86 18 75 true Format 0 0 ° -360 360 10 Position: Numeric: Qt::Vertical QSizePolicy::Fixed 86 18 DateTime: Type: Filling Direction: Qt::Horizontal QSizePolicy::Fixed 13 23 0 0 Type: 0 0 File name: Specify the name of the image file. true 0 0 Select the file to import Style: Style: Style: First color: Second color: Opacity: 0 0 The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. % 0 100 10 100 Qt::Vertical 24 271 Error bars 75 true x-error Error type: Qt::Horizontal QSizePolicy::Fixed 13 18 0 0 Data, +: Data, -: Qt::Vertical QSizePolicy::Fixed 20 18 75 true y-error Error type: Data, +: Data, -: Qt::Vertical QSizePolicy::Fixed 20 18 75 true Format Type: Style: Cap size: pt 0.500000000000000 Color: 0 0 Width: pt 0.500000000000000 Opacity: 0 0 The opacity ranges from 0 to 100, where 0 is fully transparent and 100 is fully opaque. % 0 100 10 100 Qt::Vertical QSizePolicy::Expanding 20 104 KComboBox QComboBox
kcombobox.h
KColorButton QPushButton
kcolorbutton.h
KFontRequester QWidget
kfontrequester.h
diff --git a/src/kdefrontend/widgets/FitParametersWidget.cpp b/src/kdefrontend/widgets/FitParametersWidget.cpp index 0c95dcbd6..aebcada3d 100644 --- a/src/kdefrontend/widgets/FitParametersWidget.cpp +++ b/src/kdefrontend/widgets/FitParametersWidget.cpp @@ -1,427 +1,437 @@ /*************************************************************************** File : FitParametersWidget.cc Project : LabPlot Description : widget for editing fit parameters -------------------------------------------------------------------- Copyright : (C) 2014-2016 Alexander Semke (alexander.semke@web.de) Copyright : (C) 2016-2018 Stefan Gerlach (stefan.gerlach@uni.kn) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * 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. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "FitParametersWidget.h" #include #include #include #include #include /*! \class FitParametersWidget \brief Widget for editing fit parameters. For predefined models the number of parameters, their names and default values are given - the user can change the start values. For custom models the user has to define here the parameter names and their start values. \ingroup kdefrontend */ FitParametersWidget::FitParametersWidget(QWidget* parent) : QWidget(parent) { ui.setupUi(this); ui.tableWidget->setColumnCount(5); auto* headerItem = new QTableWidgetItem(); headerItem->setText(i18n("Name")); ui.tableWidget->setHorizontalHeaderItem(0, headerItem); headerItem = new QTableWidgetItem(); headerItem->setText(i18n("Start value")); ui.tableWidget->setHorizontalHeaderItem(1, headerItem); headerItem = new QTableWidgetItem(); headerItem->setText(i18n("Fixed")); ui.tableWidget->setHorizontalHeaderItem(2, headerItem); headerItem = new QTableWidgetItem(); headerItem->setText(i18n("Lower limit")); ui.tableWidget->setHorizontalHeaderItem(3, headerItem); headerItem = new QTableWidgetItem(); headerItem->setText(i18n("Upper limit")); ui.tableWidget->setHorizontalHeaderItem(4, headerItem); ui.tableWidget->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); ui.tableWidget->horizontalHeader()->setStretchLastSection(true); ui.tableWidget->installEventFilter(this); connect( ui.tableWidget, SIGNAL(cellChanged(int,int)), this, SLOT(changed()) ); + updateTableSize(); } void FitParametersWidget::setFitData(XYFitCurve::FitData* data) { DEBUG("FitParametersWidget::setFitData()"); m_initializing = true; m_fitData = data; int np = m_fitData->paramNames.size(); DEBUG("# params = " << np); DEBUG("# start values = " << m_fitData->paramStartValues.size()); if (m_fitData->modelCategory != nsl_fit_model_custom) { // pre-defined models ui.tableWidget->setRowCount(np); for (int i = 0; i < np; ++i) { // name auto* item = new QTableWidgetItem(m_fitData->paramNamesUtf8.at(i)); item->setFlags(item->flags() ^ Qt::ItemIsEditable); item->setBackground(QApplication::palette().color(QPalette::Window)); ui.tableWidget->setItem(i, 0, item); // start value auto* le = new QLineEdit(ui.tableWidget); le->setValidator(new QDoubleValidator(le)); le->setFrame(false); le->insert(QString::number(m_fitData->paramStartValues.at(i), 'g')); ui.tableWidget->setCellWidget(i, 1, le); connect(le, SIGNAL(textChanged(QString)), this, SLOT(startValueChanged()) ); // fixed QWidget* widget = new QWidget(); auto* cb = new QCheckBox(); cb->setChecked(m_fitData->paramFixed.at(i)); auto* cbl = new QHBoxLayout(widget); cbl->addWidget(cb); cbl->setAlignment(Qt::AlignCenter); cbl->setContentsMargins(0, 0, 0, 0); widget->setLayout(cbl); ui.tableWidget->setCellWidget(i, 2, widget); connect(cb, SIGNAL(stateChanged(int)), this, SLOT(changed()) ); // limits le = new QLineEdit(ui.tableWidget); le->setValidator(new QDoubleValidator(le)); le->setFrame(false); if (m_fitData->paramLowerLimits.at(i) > -std::numeric_limits::max()) le->insert(QString::number(m_fitData->paramLowerLimits.at(i), 'g')); ui.tableWidget->setCellWidget(i, 3, le); connect(le, SIGNAL(textChanged(QString)), this, SLOT(lowerLimitChanged()) ); le = new QLineEdit(ui.tableWidget); le->setValidator(new QDoubleValidator(le)); le->setFrame(false); if (m_fitData->paramUpperLimits.at(i) < std::numeric_limits::max()) le->insert(QString::number(m_fitData->paramUpperLimits.at(i), 'g')); ui.tableWidget->setCellWidget(i, 4, le); connect(le, SIGNAL(textChanged(QString)), this, SLOT(upperLimitChanged()) ); } ui.tableWidget->setCurrentCell(0, 1); } else { // custom model if (!m_fitData->paramNames.isEmpty()) { // parameters for the custom model are already available -> show them ui.tableWidget->setRowCount(np); for (int i = 0; i < np; ++i) { // name auto* item = new QTableWidgetItem(m_fitData->paramNames.at(i)); item->setBackground(QApplication::palette().color(QPalette::Window)); ui.tableWidget->setItem(i, 0, item); // start value auto* le = new QLineEdit(ui.tableWidget); le->setValidator(new QDoubleValidator(le)); le->setFrame(false); le->insert(QString::number(m_fitData->paramStartValues.at(i), 'g')); ui.tableWidget->setCellWidget(i, 1, le); connect(le, SIGNAL(textChanged(QString)), this, SLOT(startValueChanged()) ); // fixed QWidget* widget = new QWidget(); auto* cb = new QCheckBox(); cb->setChecked(m_fitData->paramFixed.at(i)); auto* cbl = new QHBoxLayout(widget); cbl->addWidget(cb); cbl->setAlignment(Qt::AlignCenter); cbl->setContentsMargins(0, 0, 0, 0); widget->setLayout(cbl); ui.tableWidget->setCellWidget(i, 2, widget); connect(cb, SIGNAL(stateChanged(int)), this, SLOT(changed()) ); // limits le = new QLineEdit(ui.tableWidget); le->setValidator(new QDoubleValidator(le)); le->setFrame(false); if (m_fitData->paramLowerLimits.at(i) > -std::numeric_limits::max()) le->insert(QString::number(m_fitData->paramLowerLimits.at(i), 'g')); ui.tableWidget->setCellWidget(i, 3, le); connect(le, SIGNAL(textChanged(QString)), this, SLOT(lowerLimitChanged()) ); le = new QLineEdit(ui.tableWidget); le->setValidator(new QDoubleValidator(le)); le->setFrame(false); if (m_fitData->paramUpperLimits.at(i) < std::numeric_limits::max()) le->insert(QString::number(m_fitData->paramUpperLimits.at(i), 'g')); ui.tableWidget->setCellWidget(i, 4, le); connect(le, SIGNAL(textChanged(QString)), this, SLOT(upperLimitChanged()) ); } } else { // no parameters available yet -> create the first row in the table for the first parameter ui.tableWidget->setRowCount(1); // name auto* item = new QTableWidgetItem(); item->setBackground(QApplication::palette().color(QPalette::Window)); ui.tableWidget->setItem(0, 0, item); // start value auto* le = new QLineEdit(ui.tableWidget); le->setValidator(new QDoubleValidator(le)); le->setFrame(false); ui.tableWidget->setCellWidget(0, 1, le); connect(le, SIGNAL(textChanged(QString)), this, SLOT(startValueChanged()) ); // fixed QWidget* widget = new QWidget(); auto* cb = new QCheckBox(); auto* cbl = new QHBoxLayout(widget); cbl->addWidget(cb); cbl->setAlignment(Qt::AlignCenter); cbl->setContentsMargins(0, 0, 0, 0); widget->setLayout(cbl); ui.tableWidget->setCellWidget(0, 2, widget); connect(cb, SIGNAL(stateChanged(int)), this, SLOT(changed()) ); // limits le = new QLineEdit(ui.tableWidget); le->setValidator(new QDoubleValidator(le)); le->setFrame(false); ui.tableWidget->setCellWidget(0, 3, le); connect(le, SIGNAL(textChanged(QString)), this, SLOT(lowerLimitChanged()) ); le = new QLineEdit(ui.tableWidget); le->setValidator(new QDoubleValidator(le)); le->setFrame(false); ui.tableWidget->setCellWidget(0, 4, le); connect(le, SIGNAL(textChanged(QString)), this, SLOT(upperLimitChanged()) ); } ui.tableWidget->setCurrentCell(0, 0); } m_initializing = false; - //set the size of the table to the minimum possible - int h = ui.tableWidget->horizontalHeader()->height(); - h += ui.tableWidget->verticalHeader()->sectionSize(0) * ui.tableWidget->verticalHeader()->count(); - if (ui.tableWidget->horizontalScrollBar()->isVisible()) - h += ui.tableWidget->horizontalScrollBar()->height(); - setMaximumSize(16777215, h); + updateTableSize(); } bool FitParametersWidget::eventFilter(QObject* watched, QEvent* event) { if (watched == ui.tableWidget) { if (event->type() == QEvent::KeyPress) { auto* keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { //on the second column with the values is editable. //navigate to the next cell in the second column if (ui.tableWidget->currentRow() == ui.tableWidget->rowCount() - 1) ui.tableWidget->clearSelection(); else ui.tableWidget->setCurrentCell(ui.tableWidget->currentRow() + 1, 1); return true; } } } return QWidget::eventFilter(watched, event); } +void FitParametersWidget::resizeEvent(QResizeEvent*) { + updateTableSize(); +} + +void FitParametersWidget::updateTableSize() { + //set the size of the table to the minimum possible + int h = ui.tableWidget->horizontalHeader()->height(); + h += ui.tableWidget->verticalHeader()->sectionSize(0) * ui.tableWidget->verticalHeader()->count(); + if (ui.tableWidget->horizontalScrollBar()->isVisible()) + h += ui.tableWidget->horizontalScrollBar()->height(); + setMaximumSize(16777215, h); +} + + void FitParametersWidget::changed() { DEBUG("FitParametersWidget::changed()"); if (!m_initializing) { apply(); emit parametersChanged(false); } } /* * Apply parameter settings by setting m_fitData */ void FitParametersWidget::apply() { DEBUG("FitParametersWidget::apply()"); if (m_fitData->modelCategory != nsl_fit_model_custom) { // pre-defined models for (int i = 0; i < ui.tableWidget->rowCount(); ++i) { m_fitData->paramStartValues[i] = ((QLineEdit *)ui.tableWidget->cellWidget(i, 1))->text().toDouble(); QWidget *widget = ui.tableWidget->cellWidget(i, 2)->layout()->itemAt(0)->widget(); m_fitData->paramFixed[i] = (qobject_cast(widget))->isChecked(); if ( !((QLineEdit *)ui.tableWidget->cellWidget(i, 3))->text().isEmpty() ) m_fitData->paramLowerLimits[i] = ((QLineEdit *)ui.tableWidget->cellWidget(i, 3))->text().toDouble(); else m_fitData->paramLowerLimits[i] = -std::numeric_limits::max(); if ( !((QLineEdit *)ui.tableWidget->cellWidget(i, 4))->text().isEmpty() ) m_fitData->paramUpperLimits[i] = ((QLineEdit *)ui.tableWidget->cellWidget(i, 4))->text().toDouble(); else m_fitData->paramUpperLimits[i] = std::numeric_limits::max(); } } else { // custom model m_fitData->paramNames.clear(); m_fitData->paramNamesUtf8.clear(); m_fitData->paramStartValues.clear(); m_fitData->paramFixed.clear(); m_fitData->paramLowerLimits.clear(); m_fitData->paramUpperLimits.clear(); for (int i = 0; i < ui.tableWidget->rowCount(); ++i) { // skip those rows where either the name or the value is empty if ( !ui.tableWidget->item(i, 0)->text().simplified().isEmpty() && !((QLineEdit *)ui.tableWidget->cellWidget(i, 1))->text().simplified().isEmpty() ) { m_fitData->paramNames.append( ui.tableWidget->item(i, 0)->text() ); m_fitData->paramNamesUtf8.append( ui.tableWidget->item(i, 0)->text() ); m_fitData->paramStartValues.append( ((QLineEdit *)ui.tableWidget->cellWidget(i, 1))->text().toDouble() ); QWidget *widget = ui.tableWidget->cellWidget(i, 2)->layout()->itemAt(0)->widget(); m_fitData->paramFixed.append( (qobject_cast(widget))->isChecked() ); if ( !((QLineEdit *)ui.tableWidget->cellWidget(i, 3))->text().isEmpty() ) m_fitData->paramLowerLimits.append( ((QLineEdit *)ui.tableWidget->cellWidget(i, 3))->text().toDouble() ); else m_fitData->paramLowerLimits.append(-std::numeric_limits::max()); if ( !((QLineEdit *)ui.tableWidget->cellWidget(i, 4))->text().isEmpty() ) m_fitData->paramUpperLimits.append( ((QLineEdit *)ui.tableWidget->cellWidget(i, 4))->text().toDouble() ); else m_fitData->paramUpperLimits.append(std::numeric_limits::max()); } } } } /* * called when a start value is changed */ void FitParametersWidget::startValueChanged() { DEBUG("FitParametersWidget::startValueChanged()"); const int row = ui.tableWidget->currentRow(); const double value = ((QLineEdit *)ui.tableWidget->cellWidget(row, 1))->text().toDouble(); double lowerLimit, upperLimit; if ( !((QLineEdit *)ui.tableWidget->cellWidget(row, 3))->text().isEmpty() ) lowerLimit = ((QLineEdit *)ui.tableWidget->cellWidget(row, 3))->text().toDouble(); else lowerLimit = -std::numeric_limits::max(); if ( !((QLineEdit *)ui.tableWidget->cellWidget(row, 4))->text().isEmpty() ) upperLimit = ((QLineEdit *)ui.tableWidget->cellWidget(row, 4))->text().toDouble(); else upperLimit = std::numeric_limits::max(); const bool invalid = (value < lowerLimit || value > upperLimit); highlightInvalid(row, 1, invalid); if (invalid) m_invalidRanges = true; if (m_rehighlighting) return; //start value was changed -> check whether the lower and upper limits are valid and highlight them if not m_invalidRanges = invalid; m_rehighlighting = true; lowerLimitChanged(); upperLimitChanged(); m_rehighlighting = false; changed(); } // check if lower limit fits to start value and upper limit void FitParametersWidget::lowerLimitChanged() { DEBUG("FitParametersWidget::lowerLimitChanged()"); const int row = ui.tableWidget->currentRow(); const double value = ((QLineEdit *)ui.tableWidget->cellWidget(row, 1))->text().toDouble(); double lowerLimit, upperLimit; if ( !((QLineEdit *)ui.tableWidget->cellWidget(row, 3))->text().isEmpty() ) lowerLimit = ((QLineEdit *)ui.tableWidget->cellWidget(row, 3))->text().toDouble(); else lowerLimit = -std::numeric_limits::max(); if ( !((QLineEdit *)ui.tableWidget->cellWidget(row, 4))->text().isEmpty() ) upperLimit = ((QLineEdit *)ui.tableWidget->cellWidget(row, 4))->text().toDouble(); else upperLimit = std::numeric_limits::max(); const bool invalid = (lowerLimit > value || lowerLimit > upperLimit); highlightInvalid(row, 3, invalid); if (invalid) m_invalidRanges = true; if (m_rehighlighting) return; //lower limit was changed -> check whether the start value and the upper limit are valid and highlight them if not m_invalidRanges = invalid; m_rehighlighting = true; startValueChanged(); upperLimitChanged(); m_rehighlighting = false; changed(); } // check if upper limit fits to start value and lower limit void FitParametersWidget::upperLimitChanged() { DEBUG("FitParametersWidget::upperLimitChanged()"); const int row = ui.tableWidget->currentRow(); const double value = ((QLineEdit *)ui.tableWidget->cellWidget(row, 1))->text().toDouble(); double lowerLimit, upperLimit; if ( !((QLineEdit *)ui.tableWidget->cellWidget(row, 3))->text().isEmpty() ) lowerLimit = ((QLineEdit *)ui.tableWidget->cellWidget(row, 3))->text().toDouble(); else lowerLimit = -std::numeric_limits::max(); if ( !((QLineEdit *)ui.tableWidget->cellWidget(row, 4))->text().isEmpty() ) upperLimit = ((QLineEdit *)ui.tableWidget->cellWidget(row, 4))->text().toDouble(); else upperLimit = std::numeric_limits::max(); const bool invalid = (upperLimit < value || upperLimit < lowerLimit); highlightInvalid(row, 4, invalid); if (invalid) m_invalidRanges = true; if (m_rehighlighting) return; //upper limit was changed -> check whether the start value and the lower limit are valid and highlight them if not m_invalidRanges = invalid; m_rehighlighting = true; startValueChanged(); lowerLimitChanged(); m_rehighlighting = false; changed(); } void FitParametersWidget::highlightInvalid(int row, int col, bool invalid) { QLineEdit* le = ((QLineEdit*)ui.tableWidget->cellWidget(row, col)); if (invalid) le->setStyleSheet("QLineEdit{background: red;}"); else le->setStyleSheet(QString()); if (m_invalidRanges) emit parametersValid(false); else emit parametersValid(true); } diff --git a/src/kdefrontend/widgets/FitParametersWidget.h b/src/kdefrontend/widgets/FitParametersWidget.h index bdcdd2abe..eec6b0422 100644 --- a/src/kdefrontend/widgets/FitParametersWidget.h +++ b/src/kdefrontend/widgets/FitParametersWidget.h @@ -1,66 +1,69 @@ /*************************************************************************** File : FitParametersWidget.h Project : LabPlot Description : widget for editing the fit parameters -------------------------------------------------------------------- Copyright : (C) 2014-2016 by Alexander Semke (alexander.semke@web.de) Copyright : (C) 2016-2018 by Stefan Gerlach (stefan.gerlach@uni-konstanz.de) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * 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. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #ifndef FITPARAMETERSWIDGET_H #define FITPARAMETERSWIDGET_H #include #include "backend/worksheet/plots/cartesian/XYFitCurve.h" #include "ui_fitparameterswidget.h" class FitParametersWidget : public QWidget { Q_OBJECT public: explicit FitParametersWidget(QWidget*); void setFitData(XYFitCurve::FitData*); private: Ui::FitParametersWidget ui; XYFitCurve::FitData* m_fitData{nullptr}; bool m_initializing{false}; bool m_rehighlighting{false}; bool m_invalidRanges{false}; bool eventFilter(QObject*, QEvent*) override; + void resizeEvent(QResizeEvent*) override; + void highlightInvalid(int row, int col, bool invalid); + void updateTableSize(); signals: void parametersChanged(bool); void parametersValid(bool); private slots: void changed(); void apply(); void startValueChanged(); void lowerLimitChanged(); void upperLimitChanged(); }; #endif //FITPARAMETERSWIDGET_H