File indexing completed on 2024-04-28 07:29:30

0001 /*
0002     KmPlot - a math. function plotter for the KDE-Desktop
0003 
0004     SPDX-FileCopyrightText: 2006 David Saxton <david@bluehaze.org>
0005 
0006     This file is part of the KDE Project.
0007     KmPlot is part of the KDE-EDU Project.
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 
0011 */
0012 
0013 #include "parameteranimator.h"
0014 #include "ui_parameteranimator.h"
0015 #include "view.h"
0016 
0017 #include <KConfigGroup>
0018 
0019 #include <QDialogButtonBox>
0020 #include <QIcon>
0021 #include <QTimer>
0022 
0023 #include <assert.h>
0024 #include <cmath>
0025 
0026 using namespace std;
0027 
0028 #ifndef KDEWIN_MATH_H
0029 double inline log(int n)
0030 {
0031     return log(double(n));
0032 }
0033 #endif
0034 
0035 class ParameterAnimatorWidget : public QWidget, public Ui::ParameterAnimator
0036 {
0037 public:
0038     ParameterAnimatorWidget(QWidget *parent = nullptr)
0039         : QWidget(parent)
0040     {
0041         setupUi(this);
0042     }
0043 };
0044 
0045 // BEGIN class ParameterAnimator
0046 ParameterAnimator::ParameterAnimator(QWidget *parent, Function *function)
0047     : QDialog(parent)
0048     , m_function(function)
0049 {
0050     m_widget = new ParameterAnimatorWidget(this);
0051 
0052     setWindowTitle(i18nc("@title:window", "Parameter Animator"));
0053     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
0054     connect(buttonBox, &QDialogButtonBox::rejected, this, &ParameterAnimator::reject);
0055 
0056     QVBoxLayout *dialogLayout = new QVBoxLayout(this);
0057     dialogLayout->addWidget(m_widget);
0058     dialogLayout->addWidget(buttonBox);
0059 
0060     m_mode = Paused;
0061     m_currentValue = 0;
0062     m_function->m_parameters.animating = true;
0063     m_function->k = m_currentValue;
0064 
0065     if (function->eq[0]->usesParameter())
0066         m_widget->warningLabel->hide();
0067 
0068     m_timer = new QTimer(this);
0069     connect(m_timer, &QTimer::timeout, this, &ParameterAnimator::step);
0070 
0071     m_widget->gotoInitial->setIcon(QIcon::fromTheme("go-first"));
0072     m_widget->gotoFinal->setIcon(QIcon::fromTheme("go-last"));
0073     m_widget->stepBackwards->setIcon(QIcon::fromTheme("go-previous"));
0074     m_widget->stepForwards->setIcon(QIcon::fromTheme("go-next"));
0075     m_widget->pause->setIcon(QIcon::fromTheme("media-playback-pause"));
0076 
0077     connect(m_widget->gotoInitial, &QToolButton::clicked, this, &ParameterAnimator::gotoInitial);
0078     connect(m_widget->gotoFinal, &QToolButton::clicked, this, &ParameterAnimator::gotoFinal);
0079     connect(m_widget->stepBackwards, &QToolButton::toggled, this, &ParameterAnimator::stepBackwards);
0080     connect(m_widget->stepForwards, &QToolButton::toggled, this, &ParameterAnimator::stepForwards);
0081     connect(m_widget->pause, &QToolButton::clicked, this, &ParameterAnimator::pause);
0082     connect(m_widget->speed, &QSlider::valueChanged, this, &ParameterAnimator::updateSpeed);
0083 
0084     updateUI();
0085     updateFunctionParameter();
0086 
0087     connect(this, &ParameterAnimator::finished, this, &ParameterAnimator::deleteLater);
0088 }
0089 
0090 ParameterAnimator::~ParameterAnimator()
0091 {
0092     qDebug();
0093     m_function->m_parameters.animating = false;
0094     View::self()->drawPlot();
0095 }
0096 
0097 void ParameterAnimator::step()
0098 {
0099     // This function shouldn't get called when we aren't actually stepping
0100     assert(m_mode != Paused);
0101 
0102     double dx = m_widget->step->value();
0103 
0104     bool increasing = ((m_mode == StepBackwards && (dx < 0)) || (m_mode == StepForwards && (dx > 0)));
0105     bool decreasing = ((m_mode == StepBackwards && (dx > 0)) || (m_mode == StepForwards && (dx < 0)));
0106 
0107     double upper = m_widget->final->value();
0108     double lower = m_widget->initial->value();
0109 
0110     if (lower > upper)
0111         qSwap(lower, upper);
0112 
0113     if ((increasing && (m_currentValue >= upper)) || (decreasing && (m_currentValue <= lower))) {
0114         stopStepping();
0115         return;
0116     }
0117 
0118     if (m_mode == StepForwards)
0119         m_currentValue += dx;
0120     else
0121         m_currentValue -= dx;
0122 
0123     updateUI();
0124     updateFunctionParameter();
0125 }
0126 
0127 void ParameterAnimator::updateFunctionParameter()
0128 {
0129     m_function->k = m_currentValue;
0130     View::self()->drawPlot();
0131 }
0132 
0133 void ParameterAnimator::gotoInitial()
0134 {
0135     m_currentValue = m_widget->initial->value();
0136     updateUI();
0137     updateFunctionParameter();
0138 }
0139 
0140 void ParameterAnimator::gotoFinal()
0141 {
0142     m_currentValue = m_widget->final->value();
0143     updateUI();
0144     updateFunctionParameter();
0145 }
0146 
0147 void ParameterAnimator::stepBackwards(bool step)
0148 {
0149     if (!step) {
0150         pause();
0151         return;
0152     }
0153 
0154     m_mode = StepBackwards;
0155     startStepping();
0156     updateUI();
0157 }
0158 
0159 void ParameterAnimator::stepForwards(bool step)
0160 {
0161     if (!step) {
0162         pause();
0163         return;
0164     }
0165 
0166     m_mode = StepForwards;
0167     startStepping();
0168     updateUI();
0169 }
0170 
0171 void ParameterAnimator::pause()
0172 {
0173     m_mode = Paused;
0174     m_timer->stop();
0175     updateUI();
0176 }
0177 
0178 void ParameterAnimator::updateUI()
0179 {
0180     switch (m_mode) {
0181     case StepBackwards:
0182         m_widget->stepBackwards->setChecked(true);
0183         m_widget->stepForwards->setChecked(false);
0184         break;
0185 
0186     case StepForwards:
0187         m_widget->stepBackwards->setChecked(false);
0188         m_widget->stepForwards->setChecked(true);
0189         break;
0190 
0191     case Paused:
0192         m_widget->stepBackwards->setChecked(false);
0193         m_widget->stepForwards->setChecked(false);
0194         break;
0195     }
0196 
0197     m_widget->currentValue->setText(View::self()->posToString(m_currentValue, m_widget->step->value() * 1e-2, View::DecimalFormat));
0198 }
0199 
0200 void ParameterAnimator::updateSpeed()
0201 {
0202     if (m_mode != Paused)
0203         startStepping();
0204 }
0205 
0206 void ParameterAnimator::startStepping() const
0207 {
0208     double prop = (log(m_widget->speed->value()) - log(m_widget->speed->minimum())) / (log(m_widget->speed->maximum()) - log(m_widget->speed->minimum()));
0209 
0210     // prop = 0  ~ slowest
0211     // prop = 1  ~ fastest
0212 
0213     int min_ms = 40;
0214     int max_ms = 1000;
0215 
0216     int ms = int(prop * min_ms + (1 - prop) * max_ms);
0217     m_timer->start(ms);
0218 }
0219 
0220 void ParameterAnimator::stopStepping()
0221 {
0222     m_timer->stop();
0223     m_mode = Paused;
0224     updateUI();
0225 }
0226 // END class ParameterAnimator
0227 
0228 #include "moc_parameteranimator.cpp"