File indexing completed on 2024-05-12 15:28:06
0001 /*************************************************************************** 0002 File : XYEquationCurveDock.cpp 0003 Project : LabPlot 0004 -------------------------------------------------------------------- 0005 Copyright : (C) 2014-2021 Alexander Semke (alexander.semke@web.de) 0006 Description : widget for editing properties of equation curves 0007 0008 ***************************************************************************/ 0009 0010 /*************************************************************************** 0011 * * 0012 * This program is free software; you can redistribute it and/or modify * 0013 * it under the terms of the GNU General Public License as published by * 0014 * the Free Software Foundation; either version 2 of the License, or * 0015 * (at your option) any later version. * 0016 * * 0017 * This program is distributed in the hope that it will be useful, * 0018 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0020 * GNU General Public License for more details. * 0021 * * 0022 * You should have received a copy of the GNU General Public License * 0023 * along with this program; if not, write to the Free Software * 0024 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0025 * Boston, MA 02110-1301 USA * 0026 * * 0027 ***************************************************************************/ 0028 0029 #include "XYEquationCurveDock.h" 0030 #include "backend/core/AspectTreeModel.h" 0031 #include "backend/core/Project.h" 0032 #include "backend/worksheet/plots/cartesian/XYEquationCurve.h" 0033 #include "backend/gsl/ExpressionParser.h" 0034 #include "kdefrontend/widgets/ConstantsWidget.h" 0035 #include "kdefrontend/widgets/FunctionsWidget.h" 0036 0037 #include <QCompleter> 0038 #include <QKeyEvent> 0039 #include <QMenu> 0040 #include <QWidgetAction> 0041 0042 #include <KLocalizedString> 0043 0044 /*! 0045 \class XYEquationCurveDock 0046 \brief Provides a widget for editing the properties of the XYEquationCurves 0047 (2D-curves defined by a mathematical equation) currently selected in 0048 the project explorer. 0049 0050 If more then one curves are set, the properties of the first column are shown. 0051 The changes of the properties are applied to all curves. 0052 The exclusions are the name, the comment and the datasets (columns) of 0053 the curves - these properties can only be changed if there is only one single curve. 0054 0055 \ingroup kdefrontend 0056 */ 0057 0058 XYEquationCurveDock::XYEquationCurveDock(QWidget *parent): XYCurveDock(parent) { 0059 //remove the tab "Error bars" 0060 ui.tabWidget->removeTab(5); 0061 } 0062 0063 /*! 0064 * // Tab "General" 0065 */ 0066 void XYEquationCurveDock::setupGeneral() { 0067 QWidget* generalTab = new QWidget(ui.tabGeneral); 0068 uiGeneralTab.setupUi(generalTab); 0069 m_leName = uiGeneralTab.leName; 0070 m_leComment = uiGeneralTab.leComment; 0071 0072 auto* gridLayout = dynamic_cast<QGridLayout*>(generalTab->layout()); 0073 if (gridLayout) { 0074 gridLayout->setContentsMargins(2, 2, 2, 2); 0075 gridLayout->setHorizontalSpacing(2); 0076 gridLayout->setVerticalSpacing(2); 0077 } 0078 0079 auto* layout = new QHBoxLayout(ui.tabGeneral); 0080 layout->setMargin(0); 0081 layout->addWidget(generalTab); 0082 0083 uiGeneralTab.tbConstants1->setIcon( QIcon::fromTheme("labplot-format-text-symbol") ); 0084 uiGeneralTab.tbFunctions1->setIcon( QIcon::fromTheme("preferences-desktop-font") ); 0085 0086 uiGeneralTab.tbConstants2->setIcon( QIcon::fromTheme("labplot-format-text-symbol") ); 0087 uiGeneralTab.tbFunctions2->setIcon( QIcon::fromTheme("preferences-desktop-font") ); 0088 0089 uiGeneralTab.cbType->addItem(i18n("Cartesian")); 0090 uiGeneralTab.cbType->addItem(i18n("Polar")); 0091 uiGeneralTab.cbType->addItem(i18n("Parametric")); 0092 // uiGeneralTab.cbType->addItem(i18n("Implicit")); 0093 0094 uiGeneralTab.pbRecalculate->setIcon(QIcon::fromTheme("run-build")); 0095 0096 uiGeneralTab.teEquation2->setExpressionType(XYEquationCurve::EquationType::Parametric); 0097 0098 // uiGeneralTab.teEquation1->setMaximumHeight(uiGeneralTab.leName->sizeHint().height()*2); 0099 // uiGeneralTab.teEquation2->setMaximumHeight(uiGeneralTab.leName->sizeHint().height()*2); 0100 uiGeneralTab.teMin->setMaximumHeight(uiGeneralTab.leName->sizeHint().height()); 0101 uiGeneralTab.teMax->setMaximumHeight(uiGeneralTab.leName->sizeHint().height()); 0102 0103 //Slots 0104 connect(uiGeneralTab.leName, &QLineEdit::textChanged, this, &XYEquationCurveDock::nameChanged); 0105 connect(uiGeneralTab.leComment, &QLineEdit::textChanged, this, &XYEquationCurveDock::commentChanged); 0106 connect(uiGeneralTab.chkVisible, &QCheckBox::clicked, this, &XYEquationCurveDock::visibilityChanged); 0107 0108 connect(uiGeneralTab.cbType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYEquationCurveDock::typeChanged); 0109 connect(uiGeneralTab.teEquation1, &ExpressionTextEdit::expressionChanged, this, &XYEquationCurveDock::enableRecalculate); 0110 connect(uiGeneralTab.teEquation2, &ExpressionTextEdit::expressionChanged, this, &XYEquationCurveDock::enableRecalculate); 0111 connect(uiGeneralTab.tbConstants1, &QToolButton::clicked, this, &XYEquationCurveDock::showConstants); 0112 connect(uiGeneralTab.tbFunctions1, &QToolButton::clicked, this, &XYEquationCurveDock::showFunctions); 0113 connect(uiGeneralTab.tbConstants2, &QToolButton::clicked, this, &XYEquationCurveDock::showConstants); 0114 connect(uiGeneralTab.tbFunctions2, &QToolButton::clicked, this, &XYEquationCurveDock::showFunctions); 0115 connect(uiGeneralTab.teMin, &ExpressionTextEdit::expressionChanged, this, &XYEquationCurveDock::enableRecalculate); 0116 connect(uiGeneralTab.teMax, &ExpressionTextEdit::expressionChanged, this, &XYEquationCurveDock::enableRecalculate); 0117 connect(uiGeneralTab.sbCount, QOverload<int>::of(&QSpinBox::valueChanged), this, &XYEquationCurveDock::enableRecalculate); 0118 connect(uiGeneralTab.pbRecalculate, &QPushButton::clicked, this, &XYEquationCurveDock::recalculateClicked); 0119 } 0120 0121 /*! 0122 sets the curves. The properties of the curves in the list \c list can be edited in this widget. 0123 */ 0124 void XYEquationCurveDock::setCurves(QList<XYCurve*> list) { 0125 m_initializing = true; 0126 m_curvesList = list; 0127 m_curve = list.first(); 0128 m_aspect = list.first(); 0129 m_equationCurve = dynamic_cast<XYEquationCurve*>(m_curve); 0130 Q_ASSERT(m_equationCurve); 0131 m_aspectTreeModel = new AspectTreeModel(m_curve->project()); 0132 XYCurveDock::setModel(); 0133 initGeneralTab(); 0134 initTabs(); 0135 uiGeneralTab.pbRecalculate->setEnabled(false); 0136 m_initializing = false; 0137 } 0138 0139 void XYEquationCurveDock::initGeneralTab() { 0140 //if there are more then one curve in the list, disable the tab "general" 0141 if (m_curvesList.size() == 1) { 0142 uiGeneralTab.lName->setEnabled(true); 0143 uiGeneralTab.leName->setEnabled(true); 0144 uiGeneralTab.lComment->setEnabled(true); 0145 uiGeneralTab.leComment->setEnabled(true); 0146 0147 uiGeneralTab.leName->setText(m_curve->name()); 0148 uiGeneralTab.leComment->setText(m_curve->comment()); 0149 } else { 0150 uiGeneralTab.lName->setEnabled(false); 0151 uiGeneralTab.leName->setEnabled(false); 0152 uiGeneralTab.lComment->setEnabled(false); 0153 uiGeneralTab.leComment->setEnabled(false); 0154 0155 uiGeneralTab.leName->setText(QString()); 0156 uiGeneralTab.leComment->setText(QString()); 0157 } 0158 0159 //show the properties of the first curve 0160 const auto* equationCurve = dynamic_cast<const XYEquationCurve*>(m_curve); 0161 Q_ASSERT(equationCurve); 0162 const XYEquationCurve::EquationData& data = equationCurve->equationData(); 0163 uiGeneralTab.cbType->setCurrentIndex(static_cast<int>(data.type)); 0164 this->typeChanged(static_cast<int>(data.type)); 0165 uiGeneralTab.teEquation1->setText(data.expression1); 0166 uiGeneralTab.teEquation2->setText(data.expression2); 0167 uiGeneralTab.teMin->setText(data.min); 0168 uiGeneralTab.teMax->setText(data.max); 0169 uiGeneralTab.sbCount->setValue(data.count); 0170 0171 uiGeneralTab.chkVisible->setChecked( m_curve->isVisible() ); 0172 0173 //Slots 0174 connect(m_equationCurve, &XYEquationCurve::aspectDescriptionChanged, 0175 this, &XYEquationCurveDock::curveDescriptionChanged); 0176 connect(m_equationCurve, &XYEquationCurve::equationDataChanged, 0177 this, &XYEquationCurveDock::curveEquationDataChanged); 0178 } 0179 0180 //************************************************************* 0181 //**** SLOTs for changes triggered in XYEquationCurveDock ***** 0182 //************************************************************* 0183 void XYEquationCurveDock::typeChanged(int index) { 0184 const auto type{XYEquationCurve::EquationType(index)}; 0185 if (type == XYEquationCurve::EquationType::Cartesian) { 0186 uiGeneralTab.lEquation1->setText("y=f(x)"); 0187 uiGeneralTab.lEquation2->hide(); 0188 uiGeneralTab.teEquation2->hide(); 0189 uiGeneralTab.tbFunctions2->hide(); 0190 uiGeneralTab.tbConstants2->hide(); 0191 uiGeneralTab.lMin->show(); 0192 uiGeneralTab.lMax->show(); 0193 uiGeneralTab.teMin->show(); 0194 uiGeneralTab.teMax->show(); 0195 uiGeneralTab.lMin->setText(i18n("x, min")); 0196 uiGeneralTab.lMax->setText(i18n("x, max")); 0197 } else if (type == XYEquationCurve::EquationType::Polar) { 0198 uiGeneralTab.lEquation1->setText(QString::fromUtf8("r(φ)")); 0199 uiGeneralTab.lEquation2->hide(); 0200 uiGeneralTab.teEquation2->hide(); 0201 uiGeneralTab.tbFunctions2->hide(); 0202 uiGeneralTab.tbConstants2->hide(); 0203 uiGeneralTab.lMin->show(); 0204 uiGeneralTab.lMax->show(); 0205 uiGeneralTab.teMin->show(); 0206 uiGeneralTab.teMax->show(); 0207 uiGeneralTab.lMin->setText(i18n("φ, min")); 0208 uiGeneralTab.lMax->setText(i18n("φ, max")); 0209 } else if (type == XYEquationCurve::EquationType::Parametric) { 0210 uiGeneralTab.lEquation1->setText("x=f(t)"); 0211 uiGeneralTab.lEquation2->setText("y=f(t)"); 0212 uiGeneralTab.lEquation2->show(); 0213 uiGeneralTab.teEquation2->show(); 0214 uiGeneralTab.tbFunctions2->show(); 0215 uiGeneralTab.tbConstants2->show(); 0216 uiGeneralTab.lMin->show(); 0217 uiGeneralTab.lMax->show(); 0218 uiGeneralTab.teMin->show(); 0219 uiGeneralTab.teMax->show(); 0220 uiGeneralTab.lMin->setText(i18n("t, min")); 0221 uiGeneralTab.lMax->setText(i18n("t, max")); 0222 } else if (type == XYEquationCurve::EquationType::Implicit) { 0223 uiGeneralTab.lEquation1->setText("f(x,y)"); 0224 uiGeneralTab.lEquation2->hide(); 0225 uiGeneralTab.teEquation2->hide(); 0226 uiGeneralTab.tbFunctions2->hide(); 0227 uiGeneralTab.tbConstants2->hide(); 0228 uiGeneralTab.lMin->hide(); 0229 uiGeneralTab.lMax->hide(); 0230 uiGeneralTab.teMin->hide(); 0231 uiGeneralTab.teMax->hide(); 0232 } 0233 0234 uiGeneralTab.teEquation1->setExpressionType(type); 0235 this->enableRecalculate(); 0236 } 0237 0238 void XYEquationCurveDock::recalculateClicked() { 0239 XYEquationCurve::EquationData data; 0240 data.type = (XYEquationCurve::EquationType)uiGeneralTab.cbType->currentIndex(); 0241 data.expression1 = uiGeneralTab.teEquation1->document()->toPlainText(); 0242 data.expression2 = uiGeneralTab.teEquation2->document()->toPlainText(); 0243 data.min = uiGeneralTab.teMin->document()->toPlainText(); 0244 data.max = uiGeneralTab.teMax->document()->toPlainText(); 0245 data.count = uiGeneralTab.sbCount->value(); 0246 0247 for (auto* curve : m_curvesList) 0248 static_cast<XYEquationCurve*>(curve)->setEquationData(data); 0249 0250 uiGeneralTab.pbRecalculate->setEnabled(false); 0251 } 0252 0253 void XYEquationCurveDock::showConstants() { 0254 QMenu menu; 0255 ConstantsWidget constants(&menu); 0256 0257 if (QObject::sender() == uiGeneralTab.tbConstants1) 0258 connect(&constants, &ConstantsWidget::constantSelected, this, &XYEquationCurveDock::insertConstant1); 0259 else 0260 connect(&constants, &ConstantsWidget::constantSelected, this, &XYEquationCurveDock::insertConstant2); 0261 0262 connect(&constants, &ConstantsWidget::constantSelected, &menu, &QMenu::close); 0263 connect(&constants, &ConstantsWidget::canceled, &menu, &QMenu::close); 0264 0265 auto* widgetAction = new QWidgetAction(this); 0266 widgetAction->setDefaultWidget(&constants); 0267 menu.addAction(widgetAction); 0268 0269 if (QObject::sender() == uiGeneralTab.tbConstants1) { 0270 QPoint pos(-menu.sizeHint().width()+uiGeneralTab.tbConstants1->width(),-menu.sizeHint().height()); 0271 menu.exec(uiGeneralTab.tbConstants1->mapToGlobal(pos)); 0272 } else { 0273 QPoint pos(-menu.sizeHint().width()+uiGeneralTab.tbConstants2->width(),-menu.sizeHint().height()); 0274 menu.exec(uiGeneralTab.tbConstants2->mapToGlobal(pos)); 0275 } 0276 } 0277 0278 void XYEquationCurveDock::showFunctions() { 0279 QMenu menu; 0280 FunctionsWidget functions(&menu); 0281 if (QObject::sender() == uiGeneralTab.tbFunctions1) 0282 connect(&functions, &FunctionsWidget::functionSelected, this, &XYEquationCurveDock::insertFunction1); 0283 else 0284 connect(&functions, &FunctionsWidget::functionSelected, this, &XYEquationCurveDock::insertFunction2); 0285 0286 connect(&functions, &FunctionsWidget::functionSelected, &menu, &QMenu::close); 0287 connect(&functions, &FunctionsWidget::canceled, &menu, &QMenu::close); 0288 0289 auto* widgetAction = new QWidgetAction(this); 0290 widgetAction->setDefaultWidget(&functions); 0291 menu.addAction(widgetAction); 0292 0293 if (QObject::sender() == uiGeneralTab.tbFunctions1) { 0294 QPoint pos(-menu.sizeHint().width()+uiGeneralTab.tbFunctions1->width(),-menu.sizeHint().height()); 0295 menu.exec(uiGeneralTab.tbFunctions1->mapToGlobal(pos)); 0296 } else { 0297 QPoint pos(-menu.sizeHint().width()+uiGeneralTab.tbFunctions2->width(),-menu.sizeHint().height()); 0298 menu.exec(uiGeneralTab.tbFunctions2->mapToGlobal(pos)); 0299 } 0300 } 0301 0302 void XYEquationCurveDock::insertFunction1(const QString& functionName) { 0303 const auto type{XYEquationCurve::EquationType(uiGeneralTab.cbType->currentIndex())}; 0304 0305 uiGeneralTab.teEquation1->insertPlainText(functionName + ExpressionParser::functionArgumentString(functionName, type)); 0306 } 0307 0308 void XYEquationCurveDock::insertConstant1(const QString& constantsName) { 0309 uiGeneralTab.teEquation1->insertPlainText(constantsName); 0310 } 0311 0312 void XYEquationCurveDock::insertFunction2(const QString& functionName) { 0313 uiGeneralTab.teEquation1->insertPlainText(functionName + ExpressionParser::functionArgumentString(functionName, XYEquationCurve::EquationType::Parametric)); 0314 } 0315 0316 void XYEquationCurveDock::insertConstant2(const QString& constantsName) { 0317 uiGeneralTab.teEquation2->insertPlainText(constantsName); 0318 } 0319 0320 void XYEquationCurveDock::enableRecalculate() const { 0321 if (m_initializing) 0322 return; 0323 0324 //check whether the formular expressions are correct 0325 bool valid = false; 0326 const auto type = XYEquationCurve::EquationType(uiGeneralTab.cbType->currentIndex()); 0327 if (type != XYEquationCurve::EquationType::Parametric) 0328 valid = uiGeneralTab.teEquation1->isValid(); 0329 else 0330 valid = (uiGeneralTab.teEquation1->isValid() && uiGeneralTab.teEquation2->isValid()); 0331 0332 valid = (valid && uiGeneralTab.teMin->isValid() && uiGeneralTab.teMax->isValid()); 0333 uiGeneralTab.pbRecalculate->setEnabled(valid); 0334 } 0335 0336 //************************************************************* 0337 //*********** SLOTs for changes triggered in XYCurve ********** 0338 //************************************************************* 0339 //General-Tab 0340 void XYEquationCurveDock::curveDescriptionChanged(const AbstractAspect* aspect) { 0341 if (m_curve != aspect) 0342 return; 0343 0344 const Lock lock(m_initializing); 0345 if (aspect->name() != uiGeneralTab.leName->text()) 0346 uiGeneralTab.leName->setText(aspect->name()); 0347 else if (aspect->comment() != uiGeneralTab.leComment->text()) 0348 uiGeneralTab.leComment->setText(aspect->comment()); 0349 } 0350 0351 void XYEquationCurveDock::curveEquationDataChanged(const XYEquationCurve::EquationData& data) { 0352 const Lock lock(m_initializing); 0353 uiGeneralTab.cbType->setCurrentIndex(static_cast<int>(data.type)); 0354 uiGeneralTab.teEquation1->setText(data.expression1); 0355 uiGeneralTab.teEquation2->setText(data.expression2); 0356 uiGeneralTab.teMin->setText(data.min); 0357 uiGeneralTab.teMax->setText(data.max); 0358 uiGeneralTab.sbCount->setValue(data.count); 0359 }