1 /*
2     KmPlot - a math. function plotter for the KDE-Desktop
3 
4     SPDX-FileCopyrightText: 2006 David Saxton <david@bluehaze.org>
5 
6     This file is part of the KDE Project.
7     KmPlot is part of the KDE-EDU Project.
8 
9     SPDX-License-Identifier: GPL-2.0-or-later
10 
11 */
12 
13 #include "parameteranimator.h"
14 #include "ui_parameteranimator.h"
15 #include "view.h"
16 
17 #include <KConfigGroup>
18 
19 #include <QDialogButtonBox>
20 #include <QIcon>
21 #include <QTimer>
22 
23 #include <assert.h>
24 #include <cmath>
25 
26 using namespace std;
27 
28 #ifndef KDEWIN_MATH_H
log(int n)29 double inline log(int n)
30 {
31 	return log(double(n));
32 }
33 #endif
34 
35 class ParameterAnimatorWidget : public QWidget, public Ui::ParameterAnimator
36 {
37 	public:
ParameterAnimatorWidget(QWidget * parent=0)38 		ParameterAnimatorWidget( QWidget * parent = 0 )
39 	: QWidget( parent )
40 		{ setupUi(this); }
41 };
42 
43 
44 
45 //BEGIN class ParameterAnimator
ParameterAnimator(QWidget * parent,Function * function)46 ParameterAnimator::ParameterAnimator( QWidget * parent, Function * function )
47 	: QDialog( parent ),
48 	m_function( function )
49 {
50 	m_widget = new ParameterAnimatorWidget( this );
51 
52 	setWindowTitle( i18nc("@title:window", "Parameter Animator") );
53 	QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
54 	connect(buttonBox, &QDialogButtonBox::rejected, this, &ParameterAnimator::reject);
55 
56 	QVBoxLayout *dialogLayout = new QVBoxLayout( this );
57 	dialogLayout->addWidget(m_widget);
58 	dialogLayout->addWidget(buttonBox);
59 
60 	m_mode = Paused;
61 	m_currentValue = 0;
62 	m_function->m_parameters.animating = true;
63 	m_function->k = m_currentValue;
64 
65 	if ( function->eq[0]->usesParameter() )
66 		m_widget->warningLabel->hide();
67 
68 	m_timer = new QTimer( this );
69 	connect(m_timer, &QTimer::timeout, this, &ParameterAnimator::step);
70 
71 	m_widget->gotoInitial->setIcon( QIcon::fromTheme( "go-first" ) );
72 	m_widget->gotoFinal->setIcon( QIcon::fromTheme( "go-last" ) );
73 	m_widget->stepBackwards->setIcon( QIcon::fromTheme( "go-previous" ) );
74 	m_widget->stepForwards->setIcon( QIcon::fromTheme( "go-next" ) );
75 	m_widget->pause->setIcon( QIcon::fromTheme( "media-playback-pause" ) );
76 
77 	connect(m_widget->gotoInitial, &QToolButton::clicked, this, &ParameterAnimator::gotoInitial);
78 	connect(m_widget->gotoFinal, &QToolButton::clicked, this, &ParameterAnimator::gotoFinal);
79 	connect(m_widget->stepBackwards, &QToolButton::toggled, this, &ParameterAnimator::stepBackwards);
80 	connect(m_widget->stepForwards, &QToolButton::toggled, this, &ParameterAnimator::stepForwards);
81 	connect(m_widget->pause, &QToolButton::clicked, this, &ParameterAnimator::pause);
82 	connect(m_widget->speed, &QSlider::valueChanged, this, &ParameterAnimator::updateSpeed);
83 
84 	updateUI();
85 	updateFunctionParameter();
86 
87 	connect(this, &ParameterAnimator::finished, this, &ParameterAnimator::deleteLater);
88 }
89 
90 
~ParameterAnimator()91 ParameterAnimator::~ ParameterAnimator()
92 {
93 	qDebug() ;
94 	m_function->m_parameters.animating = false;
95 	View::self()->drawPlot();
96 }
97 
98 
step()99 void ParameterAnimator::step()
100 {
101 	// This function shouldn't get called when we aren't actually stepping
102 	assert( m_mode != Paused );
103 
104 	double dx = m_widget->step->value();
105 
106 	bool increasing = ( (m_mode == StepBackwards && (dx < 0)) || (m_mode == StepForwards && (dx > 0)) );
107 	bool decreasing = ( (m_mode == StepBackwards && (dx > 0)) || (m_mode == StepForwards && (dx < 0)) );
108 
109 	double upper = m_widget->final->value();
110 	double lower = m_widget->initial->value();
111 
112 	if ( lower > upper )
113 		qSwap( lower, upper );
114 
115 	if ( (increasing && (m_currentValue >= upper)) ||
116 			 (decreasing && (m_currentValue <= lower)) )
117 	{
118 		stopStepping();
119 		return;
120 	}
121 
122 	if ( m_mode == StepForwards )
123 		m_currentValue += dx;
124 	else
125 		m_currentValue -= dx;
126 
127 	updateUI();
128 	updateFunctionParameter();
129 }
130 
131 
updateFunctionParameter()132 void ParameterAnimator::updateFunctionParameter()
133 {
134 	m_function->k = m_currentValue;
135 	View::self()->drawPlot();
136 }
137 
138 
gotoInitial()139 void ParameterAnimator::gotoInitial()
140 {
141 	m_currentValue = m_widget->initial->value();
142 	updateUI();
143 	updateFunctionParameter();
144 }
145 
146 
gotoFinal()147 void ParameterAnimator::gotoFinal()
148 {
149 	m_currentValue = m_widget->final->value();
150 	updateUI();
151 	updateFunctionParameter();
152 }
153 
154 
stepBackwards(bool step)155 void ParameterAnimator::stepBackwards( bool step )
156 {
157 	if ( !step )
158 	{
159 		pause();
160 		return;
161 	}
162 
163 	m_mode = StepBackwards;
164 	startStepping();
165 	updateUI();
166 }
167 
168 
stepForwards(bool step)169 void ParameterAnimator::stepForwards( bool step )
170 {
171 	if ( !step )
172 	{
173 		pause();
174 		return;
175 	}
176 
177 	m_mode = StepForwards;
178 	startStepping();
179 	updateUI();
180 }
181 
182 
pause()183 void ParameterAnimator::pause()
184 {
185 	m_mode = Paused;
186 	m_timer->stop();
187 	updateUI();
188 }
189 
190 
updateUI()191 void ParameterAnimator::updateUI()
192 {
193 	switch ( m_mode )
194 	{
195 		case StepBackwards:
196 			m_widget->stepBackwards->setChecked( true );
197 			m_widget->stepForwards->setChecked( false );
198 			break;
199 
200 		case StepForwards:
201 			m_widget->stepBackwards->setChecked( false );
202 			m_widget->stepForwards->setChecked( true );
203 			break;
204 
205 		case Paused:
206 			m_widget->stepBackwards->setChecked( false );
207 			m_widget->stepForwards->setChecked( false );
208 			break;
209 	}
210 
211 	m_widget->currentValue->setText( View::self()->posToString( m_currentValue, m_widget->step->value() * 1e-2, View::DecimalFormat ) );
212 }
213 
214 
updateSpeed()215 void ParameterAnimator::updateSpeed()
216 {
217 	if ( m_mode != Paused )
218 		startStepping();
219 }
220 
221 
startStepping() const222 void ParameterAnimator::startStepping() const
223 {
224 	double prop = (log( m_widget->speed->value() ) - log( m_widget->speed->minimum() )) / (log( m_widget->speed->maximum()) - log( m_widget->speed->minimum()));
225 
226 	// prop = 0  ~ slowest
227 	// prop = 1  ~ fastest
228 
229 	int min_ms = 40;
230 	int max_ms = 1000;
231 
232 	int ms = int( prop*min_ms + (1-prop)*max_ms );
233 	m_timer->start( ms );
234 }
235 
236 
stopStepping()237 void ParameterAnimator::stopStepping()
238 {
239 	m_timer->stop();
240 	m_mode = Paused;
241 	updateUI();
242 }
243 //END class ParameterAnimator
244