Qt3to4
[kdeartwork.git] / kscreensaver / kdesavers / pendulum.cpp
blob502c7597daee2788c9435ff9275a4214cbca9788
1 //============================================================================
2 //
3 // KPendulum screen saver for KDE
4 //
5 // The screen saver displays a physically realistic simulation of a two-part
6 // pendulum.
7 //
8 // Developed by Georg Drenkhahn, georg-d@users.sourceforge.net
9 //
10 // $Id$
13 * Copyright (C) 2004 Georg Drenkhahn
15 * KRotation is free software; you can redistribute it and/or modify it under
16 * the terms of the GNU General Public License version 2 as published by the
17 * Free Software Foundation.
19 * KRotation is distributed in the hope that it will be useful, but WITHOUT ANY
20 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
21 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License along with
24 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
25 * Place, Suite 330, Boston, MA 02110-1301 USA
27 //============================================================================
29 #define QT_NO_COMPAT
31 // std. C++ headers
32 #include <cstdlib>
34 // Qt headers
35 #include <qlineedit.h>
36 #include <qspinbox.h>
37 #include <qvalidator.h>
38 #include <qcolordialog.h>
39 #include <qpushbutton.h>
40 #include <qtooltip.h>
41 //Added by qt3to4:
42 #include <QResizeEvent>
43 // KDE headers
44 #include <klocale.h>
45 #include <kconfig.h>
46 #include <kdebug.h>
47 #include <kmessagebox.h>
49 #include "sspreviewarea.h"
51 // pendulum.moc includes pendulum.h
52 #include "pendulum.moc"
54 #define KPENDULUM_VERSION "1.1"
56 // libkscreensaver interface
57 extern "C"
59 /// application name for libkscreensaver interface
60 KDE_EXPORT const char *kss_applicationName = "kpendulum.kss";
61 /// application description for libkscreensaver interface
62 KDE_EXPORT const char *kss_description = I18N_NOOP("Simulation of\
63 a two-part pendulum");
64 /// application version for libkscreensaver interface
65 KDE_EXPORT const char *kss_version = KPENDULUM_VERSION;
67 /// function to create screen saver object
68 KDE_EXPORT KScreenSaver* kss_create(WId id)
70 return new KPendulumSaver(id);
73 /// function to create setup dialog for screen saver
74 KDE_EXPORT QDialog* kss_setup()
76 return new KPendulumSetup();
80 //-----------------------------------------------------------------------------
81 // PendulumOdeSolver
82 //-----------------------------------------------------------------------------
84 PendulumOdeSolver::PendulumOdeSolver(
85 const double &_t,
86 const double &_dt,
87 std::valarray<double> &_y,
88 const double &_eps,
89 const double &_m1,
90 const double &_m2,
91 const double &_l1,
92 const double &_l2,
93 const double &_g)
94 : RkOdeSolver<double>(_t,_y,_dt,_eps),
95 A(1.0/(_m2*_l1*_l1)),
96 B1(_m2*_l1*_l2), // constants for faster numeric calculation
97 B(1.0/B1), // derived from m1,m2,l1,l2,g
98 C((_m1+_m2)/(_m2*_m2*_l2*_l2)),
99 D(_g*(_m1+_m2)*_l1),
100 E(_g*_m2*_l2),
101 M((_m1+_m2)/_m2)
105 std::valarray<double> PendulumOdeSolver::f(
106 const double &x,
107 const std::valarray<double> &y) const
109 (void)x; // unused
111 const double& q1 = y[0];
112 const double& q2 = y[1];
113 const double& p1 = y[2];
114 const double& p2 = y[3];
116 const double cosDq = std::cos(q1-q2);
117 const double iden = 1.0/(M - cosDq*cosDq); // invers denominator
118 const double dq1dt = (A*p1 - B*cosDq*p2)*iden;
119 const double dq2dt = (C*p2 - B*cosDq*p1)*iden;
121 std::valarray<double> ypr(y.size());
122 ypr[0] = dq1dt;
123 ypr[1] = dq2dt;
125 const double K = B1 * dq1dt*dq2dt * std::sin(q1-q2);
126 ypr[2] = -K - D * std::sin(q1);
127 ypr[3] = K - E * std::sin(q2);
129 return ypr;
132 //-----------------------------------------------------------------------------
133 // Rotation: screen saver widget
134 //-----------------------------------------------------------------------------
136 PendulumGLWidget::PendulumGLWidget(QWidget* parent, const char* name)
137 : QGLWidget(parent, name),
138 eyeR(30), // eye coordinates (polar)
139 eyeTheta(M_PI*0.45),
140 eyePhi(0),
141 lightR(eyeR), // light coordinates (polar)
142 lightTheta(M_PI*0.25),
143 lightPhi(M_PI*0.25),
144 quadM1(gluNewQuadric()),
145 m_barColor(KPendulumSaver::barColorDefault),
146 m_m1Color(KPendulumSaver::m1ColorDefault),
147 m_m2Color(KPendulumSaver::m2ColorDefault)
151 PendulumGLWidget::~PendulumGLWidget(void)
153 gluDeleteQuadric(quadM1);
156 void PendulumGLWidget::setEyePhi(double phi)
158 eyePhi = phi;
159 while (eyePhi < 0) eyePhi += 2.*M_PI;
160 while (eyePhi > 2*M_PI) eyePhi -= 2.*M_PI;
162 // get the view port
163 static GLint vp[4];
164 glGetIntegerv(GL_VIEWPORT, vp);
165 // calc new perspective, a resize event is simulated here
166 resizeGL(static_cast<int>(vp[2]), static_cast<int>(vp[3]));
169 void PendulumGLWidget::setAngles(const double& q1, const double& q2)
171 ang1 = static_cast<GLfloat>(q1*180./M_PI);
172 ang2 = static_cast<GLfloat>(q2*180./M_PI);
175 void PendulumGLWidget::setMasses(const double& m1, const double& m2)
177 sqrtm1 = static_cast<GLfloat>(sqrt(m1));
178 sqrtm2 = static_cast<GLfloat>(sqrt(m2));
181 void PendulumGLWidget::setLengths(const double& _l1, const double& _l2)
183 l1 = static_cast<GLfloat>(_l1);
184 l2 = static_cast<GLfloat>(_l2);
187 void PendulumGLWidget::setBarColor(const QColor& c)
189 if (c.isValid())
191 m_barColor = c;
195 void PendulumGLWidget::setM1Color(const QColor& c)
197 if (c.isValid())
199 m_m1Color = c;
202 void PendulumGLWidget::setM2Color(const QColor& c)
204 if (c.isValid())
206 m_m2Color = c;
210 /* --------- protected methods ----------- */
212 void PendulumGLWidget::initializeGL(void)
214 qglClearColor(QColor(Qt::black)); // set color to clear the background
216 glClearDepth(1); // depth buffer setup
217 glEnable(GL_DEPTH_TEST); // depth testing
218 glDepthFunc(GL_LEQUAL); // type of depth test
220 glShadeModel(GL_SMOOTH); // smooth color shading in poygons
222 // nice perspective calculation
223 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
225 // set up the light
226 glEnable(GL_LIGHTING);
227 glEnable(GL_LIGHT0);
228 glEnable(GL_LIGHT1);
230 glMatrixMode(GL_MODELVIEW); // select modelview matrix
231 glLoadIdentity();
232 // set positon of light0
233 GLfloat lightPos[4]=
234 {lightR * sin(lightTheta) * sin(lightPhi),
235 lightR * sin(lightTheta) * cos(lightPhi),
236 lightR * cos(lightTheta),
238 glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
239 // set positon of light1
240 lightPos[0] = lightR * sin(lightTheta) * sin(lightPhi+M_PI);
241 lightPos[1] = lightR * sin(lightTheta) * cos(lightPhi+M_PI);
242 glLightfv(GL_LIGHT1, GL_POSITION, lightPos);
244 // only for lights #>0
245 GLfloat spec[]={1,1,1,1};
246 glLightfv(GL_LIGHT1, GL_SPECULAR, spec);
247 glLightfv(GL_LIGHT1, GL_DIFFUSE, spec);
249 // enable setting the material colour by glColor()
250 glEnable(GL_COLOR_MATERIAL);
252 GLfloat emi[4] = {.13, .13, .13, 1};
253 glMaterialfv(GL_FRONT, GL_EMISSION, emi);
256 void PendulumGLWidget::paintGL(void)
258 // clear color and depth buffer
259 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
261 glMatrixMode(GL_MODELVIEW); // select modelview matrix
263 glLoadIdentity();
265 static const GLfloat width = 2.0;
266 static const GLfloat masswidth = 1.0;
267 static const int noOfSlices = 20;
269 // top axis, left (x>0)
270 glTranslatef(0.5*width, 0, 0);
271 glRotatef(90, 0, 1, 0);
272 qglColor(m_barColor);
273 gluCylinder(quadM1, 0.2, 0.2, 5, 10, 1);
274 gluSphere(quadM1, 0.2, 10, 10);
275 // top axis, right
276 glLoadIdentity();
277 glTranslatef(-0.5*width, 0, 0);
278 glRotatef(-90, 0, 1, 0);
279 gluCylinder(quadM1, 0.2, 0.2, 5, 10, 1);
280 gluSphere(quadM1, 0.2, 10, 10);
281 // 1. part, left
282 glLoadIdentity();
283 glRotatef(ang1, 1, 0, 0);
284 glPushMatrix();
285 glTranslatef(0.5*width, 0, -l1);
286 gluCylinder(quadM1, 0.2, 0.2, l1, 10, 1);
287 glPopMatrix();
289 // 1. part, right
290 glPushMatrix();
291 glTranslatef(-0.5*width, 0, -l1);
292 gluCylinder(quadM1, 0.2, 0.2, l1, 10, 1);
293 // 1. part, bottom
294 glRotatef(90, 0, 1, 0);
295 gluSphere(quadM1, 0.2, 10, 10); // bottom corner 1
296 gluCylinder(quadM1, 0.2, 0.2, width, 10, 1); // connection
297 glTranslatef(0, 0, 0.5*(width-masswidth));
298 qglColor(m_m1Color);
299 gluCylinder(quadM1, sqrtm1, sqrtm1, masswidth, noOfSlices, 1); // mass 1
300 gluQuadricOrientation(quadM1, GLU_INSIDE);
301 gluDisk(quadM1, 0, sqrtm1, noOfSlices,1); // bottom of mass
302 gluQuadricOrientation(quadM1, GLU_OUTSIDE);
303 glTranslatef(0, 0, masswidth);
304 gluDisk(quadM1, 0, sqrtm1, noOfSlices,1); // top of mass
306 glTranslatef(0, 0, 0.5*(width-masswidth));
307 qglColor(m_barColor);
308 gluSphere(quadM1, 0.2, 10, 10); // bottom corner 2
309 glPopMatrix();
311 // 2. pendulum bar
312 glLoadIdentity();
313 glTranslatef(0, l1*std::sin(ang1*M_PI/180.), -l1*std::cos(ang1*M_PI/180.));
314 glRotatef(ang2, 1, 0, 0);
315 glTranslatef(0, 0, -l2);
316 qglColor(m_barColor);
317 gluCylinder(quadM1, 0.2, 0.2, l2, 10, 1);
319 // mass 2
320 glRotatef(90, 0, 1, 0);
321 glTranslatef(0, 0, -0.5*masswidth);
322 qglColor(m_m2Color);
323 gluCylinder(quadM1, sqrtm2, sqrtm2, masswidth, noOfSlices, 1);
324 gluQuadricOrientation(quadM1, GLU_INSIDE);
325 gluDisk(quadM1, 0, sqrtm2, noOfSlices,1); // bottom of mass
326 gluQuadricOrientation(quadM1, GLU_OUTSIDE);
327 glTranslatef(0, 0, masswidth);
328 gluDisk(quadM1, 0, sqrtm2, noOfSlices,1); // top of mass
330 glFlush();
333 void PendulumGLWidget::resizeGL(int w, int h)
335 // Prevent a divide by zero
336 if (h == 0) h = 1;
338 // set the new view port
339 glViewport(0, 0, static_cast<GLint>(w), static_cast<GLint>(h));
341 // set up projection matrix
342 glMatrixMode(GL_PROJECTION);
343 glLoadIdentity();
344 // Perspective view
345 gluPerspective(40.0f,
346 static_cast<GLdouble>(w)/static_cast<GLdouble>(h),
347 1.0, 100.0f);
349 // Viewing transformation, position for better view
350 // Theta is polar angle 0<Theta<Pi
351 gluLookAt(
352 eyeR * sin(eyeTheta) * sin(eyePhi),
353 eyeR * sin(eyeTheta) * cos(eyePhi),
354 eyeR * cos(eyeTheta),
355 0,0,0,
356 0,0,1);
359 //-----------------------------------------------------------------------------
360 // KPendulumSaver: screen saver class
361 //-----------------------------------------------------------------------------
363 KPendulumSaver::KPendulumSaver(WId id) :
364 KScreenSaver(id),
365 solver(0),
366 m_massRatio(massRatioDefault),
367 m_lengthRatio(lengthRatioDefault),
368 m_g(gDefault),
369 m_E(EDefault),
370 m_persChangeInterval(persChangeIntervalDefault)
372 setEraseColor(Qt::black);
373 erase(); // erase area
374 glArea = new PendulumGLWidget(this); // create gl widget
375 glArea->setEyePhi(eyePhiDefault);
377 readSettings(); // read global settings into pars
378 initData(); // init solver and glArea with read settings
380 embed(glArea); // embed gl widget and resize it
381 glArea->show(); // show gl widget
383 // set up and start cyclic timer
384 timer = new QTimer(this);
385 timer->start(deltaT, TRUE);
386 connect(timer, SIGNAL(timeout()), this, SLOT(doTimeStep()));
389 KPendulumSaver::~KPendulumSaver()
391 // time, rotation are automatically deleted with parent KPendulumSaver
392 delete solver;
396 void KPendulumSaver::readSettings()
398 // read configuration settings from config file
399 KConfig *config = KGlobal::config();
400 config->setGroup("Settings");
402 // internal saver parameters are set to stored values or left at their
403 // default values if stored values are out of range
404 setMassRatio(
405 config->readDoubleNumEntry(
406 "mass ratio",
407 KPendulumSaver::massRatioDefault));
408 setLengthRatio(
409 config->readDoubleNumEntry(
410 "length ratio",
411 KPendulumSaver::lengthRatioDefault));
412 setG(
413 config->readDoubleNumEntry(
414 "g",
415 KPendulumSaver::gDefault));
416 setE(
417 config->readDoubleNumEntry(
418 "E",
419 KPendulumSaver::EDefault));
420 setPersChangeInterval(
421 config->readUnsignedNumEntry(
422 "perspective change interval",
423 KPendulumSaver::persChangeIntervalDefault));
425 // set the colours
426 setBarColor(config->readColorEntry("bar color", &barColorDefault));
427 setM1Color( config->readColorEntry("m1 color", &m1ColorDefault));
428 setM2Color( config->readColorEntry("m2 color", &m2ColorDefault));
431 void KPendulumSaver::initData()
433 const double m1plusm2 = 2; // m1+m2
434 const double m2 = m_massRatio * m1plusm2;
435 const double m1 = m1plusm2 - m2;
436 glArea->setMasses(m1, m2);
437 glArea->setAngles(0, 0);
439 const double l1plusl2 = 9; // l1+l2
440 const double l2 = m_lengthRatio * l1plusl2;
441 const double l1 = l1plusl2 - l2;
442 glArea->setLengths(l1, l2);
444 // kinetic energy of m2 and m1
445 const double kin_energy = m_E * m_g * (l1*m1 + (m1+m2)*(l1+l2));
446 // angular velocity for 1. and 2. pendulum
447 const double qp = sqrt(2.*kin_energy/((m1+m2)*l1*l1 + m2*l2*l2 + m2*l1*l2));
449 // assemble initial y for solver
450 std::valarray<double> y(4);
451 y[0] = 0; // q1
452 y[1] = 0; // q2
453 y[2] = (m1+m2)*l1*l1*qp + 0.5*m2*l1*l2*qp; // p1
454 y[3] = m2*l2*l2*qp + 0.5*m2*l1*l2*qp; // p2
456 // delete old solver
457 if (solver!=0) delete solver;
458 // init new solver
459 solver = new PendulumOdeSolver(
460 0.0, // t
461 0.01, // first dt step size estimation
463 1e-5, // eps
468 m_g);
472 void KPendulumSaver::setBarColor(const QColor& c)
474 glArea->setBarColor(c);
476 QColor KPendulumSaver::barColor(void) const
478 return glArea->barColor();
481 const QColor KPendulumSaver::barColorDefault(255, 255, 127);
483 void KPendulumSaver::setM1Color(const QColor& c)
485 glArea->setM1Color(c);
487 QColor KPendulumSaver::m1Color(void) const
489 return glArea->m1Color();
492 const QColor KPendulumSaver::m1ColorDefault(170, 0, 127);
494 void KPendulumSaver::setM2Color(const QColor& c)
496 glArea->setM2Color(c);
498 QColor KPendulumSaver::m2Color(void) const
500 return glArea->m2Color();
503 const QColor KPendulumSaver::m2ColorDefault( 85, 170, 127);
506 void KPendulumSaver::setMassRatio(const double& massRatio)
508 // range check is not neccessary in normal operation because validators check
509 // the values at input. But the validators do not check for corrupted
510 // settings read from disk.
511 if (massRatio >= massRatioLimitLower
512 && massRatio <= massRatioLimitUpper
513 && m_massRatio != massRatio)
515 m_massRatio = massRatio;
516 if (timer!=0)
518 initData();
523 const double KPendulumSaver::massRatioLimitLower = 0.01;
524 const double KPendulumSaver::massRatioLimitUpper = 0.99;
525 const double KPendulumSaver::massRatioDefault = 0.5;
527 void KPendulumSaver::setLengthRatio(const double& lengthRatio)
529 if (lengthRatio >= lengthRatioLimitLower
530 && lengthRatio <= lengthRatioLimitUpper
531 && m_lengthRatio != lengthRatio)
533 m_lengthRatio = lengthRatio;
534 if (timer!=0)
536 initData();
541 const double KPendulumSaver::lengthRatioLimitLower = 0.01;
542 const double KPendulumSaver::lengthRatioLimitUpper = 0.99;
543 const double KPendulumSaver::lengthRatioDefault = 0.5;
545 void KPendulumSaver::setG(const double& g)
547 if (g >= gLimitLower
548 && g <= gLimitUpper
549 && m_g != g)
551 m_g = g;
552 if (timer!=0)
554 initData();
559 const double KPendulumSaver::gLimitLower = 0.1;
560 const double KPendulumSaver::gLimitUpper = 300.0;
561 const double KPendulumSaver::gDefault = 40.0;
563 void KPendulumSaver::setE(const double& E)
565 if (E >= ELimitLower
566 && E <= ELimitUpper
567 && m_E != E)
569 m_E = E;
570 if (timer!=0)
572 initData();
577 const double KPendulumSaver::ELimitLower = 0.0;
578 const double KPendulumSaver::ELimitUpper = 5.0;
579 const double KPendulumSaver::EDefault = 1.2;
581 void KPendulumSaver::setPersChangeInterval(
582 const unsigned int& persChangeInterval)
584 if (persChangeInterval >= persChangeIntervalLimitLower
585 && persChangeInterval <= persChangeIntervalLimitUpper
586 && m_persChangeInterval != persChangeInterval)
588 m_persChangeInterval = persChangeInterval;
589 // do not restart simulation here
593 const double KPendulumSaver::eyePhiDefault = 0.25*M_PI;
596 void KPendulumSaver::doTimeStep()
598 /* time (in seconds) of perspective change.
599 * - t<0: no change yet
600 * - t=0: change starts
601 * - 0<t<moving time: change takes place
602 * - t=moving time: end of the change */
603 static double persChangeTime = -5;
605 // integrate a step ahead
606 solver->integrate(0.001*deltaT);
608 // read new y from solver
609 const std::valarray<double> y = solver->Y();
611 // tell glArea the new coordinates/angles of the pendulum
612 glArea->setAngles(y[0], y[1]);
614 // handle perspective change
615 persChangeTime += 0.001*deltaT;
616 if (persChangeTime > 0)
618 // phi value at the start of a perspective change
619 static double eyePhi0 = eyePhiDefault;
620 // phi value at the end of a perspective change
621 static double eyePhi1 = 0.75*M_PI;
622 static double deltaEyePhi = eyePhi1-eyePhi0;
624 // movement acceleration/deceleration
625 const double a = 3;
626 // duration of the change period
627 const double movingTime = 2.*sqrt(fabs(deltaEyePhi)/a);
629 // new current phi of eye
630 double eyePhi = persChangeTime < 0.5*movingTime ?
631 // accelerating phase
632 eyePhi0 + (deltaEyePhi>0?1:-1)
633 * 0.5*a*persChangeTime*persChangeTime:
634 // decellerating phase
635 eyePhi1 - (deltaEyePhi>0?1:-1)
636 * 0.5*a*(movingTime-persChangeTime)*(movingTime-persChangeTime);
638 if (persChangeTime>movingTime)
639 { // perspective change has finished
640 // set new time till next change
641 persChangeTime = -double(m_persChangeInterval);
642 eyePhi0 = eyePhi = eyePhi1;
643 // find new phi value with angleLimit < phi < Pi-angleLimit or
644 // Pi+angleLimit < phi < 2*Pi-angleLimit
645 const double angleLimit = M_PI*0.2;
646 for (eyePhi1 = 0;
647 eyePhi1<angleLimit
648 || (eyePhi1<M_PI+angleLimit && eyePhi1>M_PI-angleLimit)
649 || eyePhi1>2*M_PI-angleLimit;
650 eyePhi1 = double(rand())/RAND_MAX * 2*M_PI)
652 // new delta phi for next change
653 deltaEyePhi = eyePhi1 - eyePhi0;
654 // find shortest perspective change
655 if (deltaEyePhi < -M_PI) deltaEyePhi += 2*M_PI;
658 glArea->setEyePhi(eyePhi); // set new perspective
661 glArea->updateGL(); // repaint scenery
662 timer->start(deltaT, TRUE); // restart timer
665 // public slot of KPendulumSaver, forward resize event to public slot of glArea
666 // to allow the resizing of the gl area withing the setup dialog
667 void KPendulumSaver::resizeGlArea(QResizeEvent* e)
669 glArea->resize(e->size());
672 //-----------------------------------------------------------------------------
673 // KPendulumSetup: dialog to setup screen saver parameters
674 //-----------------------------------------------------------------------------
676 KPendulumSetup::KPendulumSetup(QWidget* parent, const char* name)
677 : KPendulumSetupUi(parent, name),
678 // create saver and give it the WinID of the preview area
679 saver(new KPendulumSaver(preview->winId()))
681 // the dialog should block, no other control center input should be possible
682 // until the dialog is closed
683 setModal(TRUE);
685 // create input validators
686 mEdit->setValidator(new QDoubleValidator(
687 KPendulumSaver::massRatioLimitLower,
688 KPendulumSaver::massRatioLimitUpper,
689 5, mEdit));
690 lEdit->setValidator(new QDoubleValidator(
691 KPendulumSaver::lengthRatioLimitLower,
692 KPendulumSaver::lengthRatioLimitUpper,
693 5, lEdit));
694 gEdit->setValidator(new QDoubleValidator(
695 KPendulumSaver::gLimitLower,
696 KPendulumSaver::gLimitUpper,
697 5, gEdit));
698 eEdit->setValidator(new QDoubleValidator(
699 KPendulumSaver::ELimitLower,
700 KPendulumSaver::ELimitUpper,
701 5, eEdit));
703 // set input limits for the perspective change interval time
704 persSpinBox->setMinValue(KPendulumSaver::persChangeIntervalLimitLower);
705 persSpinBox->setMaxValue(KPendulumSaver::persChangeIntervalLimitUpper);
707 // set tool tips of editable fields
708 QToolTip::add(
709 mEdit,
710 i18n("Ratio of 2nd mass to sum of both masses.\nValid values from %1 to %2.")
711 .arg(KPendulumSaver::massRatioLimitLower, 0, 'f', 2)
712 .arg(KPendulumSaver::massRatioLimitUpper, 0, 'f', 2));
713 QToolTip::add(
714 lEdit,
715 i18n("Ratio of 2nd pendulum part length to the sum of both part lengths.\nValid values from %1 to %2.")
716 .arg(KPendulumSaver::lengthRatioLimitLower, 0, 'f', 2)
717 .arg(KPendulumSaver::lengthRatioLimitUpper, 0, 'f', 2));
718 QToolTip::add(
719 gEdit,
720 i18n("Gravitational constant in arbitrary units.\nValid values from %1 to %2.")
721 .arg(KPendulumSaver::gLimitLower, 0, 'f', 2)
722 .arg(KPendulumSaver::gLimitUpper, 0, 'f', 2));
723 QToolTip::add(
724 eEdit,
725 i18n("Energy in units of the maximum potential energy of the given configuration.\nValid values from %1 to %2.")
726 .arg(KPendulumSaver::ELimitLower, 0, 'f', 2)
727 .arg(KPendulumSaver::ELimitUpper, 0, 'f', 2));
728 QToolTip::add(
729 persSpinBox,
730 i18n("Time in seconds after which a random perspective change occurs.\nValid values from %1 to %2.")
731 .arg(KPendulumSaver::persChangeIntervalLimitLower)
732 .arg(KPendulumSaver::persChangeIntervalLimitUpper));
734 // init preview area
735 preview->setBackgroundColor(Qt::black);
736 preview->show(); // otherwise saver does not get correct size
738 // read settings from saver and update GUI elements with these values, saver
739 // has read settings in its constructor
741 // set editable fields with stored values as defaults
742 QString text;
743 text.setNum(saver->massRatio());
744 mEdit->setText(text);
745 text.setNum(saver->lengthRatio());
746 lEdit->setText(text);
747 text.setNum(saver->g());
748 gEdit->setText(text);
749 text.setNum(saver->E());
750 eEdit->setText(text);
752 persSpinBox->setValue(saver->persChangeInterval());
754 barColorButton->setPaletteBackgroundColor(saver->barColor());
755 m1ColorButton->setPaletteBackgroundColor(saver->m1Color());
756 m2ColorButton->setPaletteBackgroundColor(saver->m2Color());
758 // if the preview area is resized it emmits the resized() event which is
759 // caught by the saver. The embedded GlArea is resized to fit into the
760 // preview area.
761 connect(preview, SIGNAL(resized(QResizeEvent*)),
762 saver, SLOT(resizeGlArea(QResizeEvent*)));
765 KPendulumSetup::~KPendulumSetup()
767 delete saver;
770 // Ok pressed - save settings and exit
771 void KPendulumSetup::okButtonClickedSlot()
773 KConfig* config = KGlobal::config();
774 config->setGroup("Settings");
776 config->writeEntry("mass ratio", saver->massRatio());
777 config->writeEntry("length ratio", saver->lengthRatio());
778 config->writeEntry("g", saver->g());
779 config->writeEntry("E", saver->E());
780 config->writeEntry("perspective change interval",
781 saver->persChangeInterval());
782 config->writeEntry("bar color", saver->barColor());
783 config->writeEntry("m1 color", saver->m1Color());
784 config->writeEntry("m2 color", saver->m2Color());
786 config->sync();
787 accept();
790 void KPendulumSetup::aboutButtonClickedSlot()
792 KMessageBox::about(this, i18n("\
793 <h3>KPendulum Screen Saver for KDE</h3>\
794 <p>Simulation of a two-part pendulum</p>\
795 <p>Copyright (c) Georg&nbsp;Drenkhahn 2004</p>\
796 <p><tt>georg-d@users.sourceforge.net</tt></p>"));
799 void KPendulumSetup::mEditLostFocusSlot(void)
801 if (mEdit->hasAcceptableInput())
803 saver->setMassRatio(mEdit->text().toDouble());
805 else
806 { // write current setting back into input field
807 QString text;
808 text.setNum(saver->massRatio());
809 mEdit->setText(text);
812 void KPendulumSetup::lEditLostFocusSlot(void)
814 if (lEdit->hasAcceptableInput())
816 saver->setLengthRatio(lEdit->text().toDouble());
818 else
819 { // write current setting back into input field
820 QString text;
821 text.setNum(saver->lengthRatio());
822 lEdit->setText(text);
825 void KPendulumSetup::gEditLostFocusSlot(void)
827 if (gEdit->hasAcceptableInput())
829 saver->setG(gEdit->text().toDouble());
831 else
832 { // write current setting back into input field
833 QString text;
834 text.setNum(saver->g());
835 gEdit->setText(text);
838 void KPendulumSetup::eEditLostFocusSlot(void)
840 if (eEdit->hasAcceptableInput())
842 saver->setE(eEdit->text().toDouble());
844 else
845 { // write current setting back into input field
846 QString text;
847 text.setNum(saver->E());
848 eEdit->setText(text);
851 void KPendulumSetup::persChangeEnteredSlot(int t)
853 saver->setPersChangeInterval(t);
856 void KPendulumSetup::barColorButtonClickedSlot(void)
858 QColor color = QColorDialog::getColor(
859 saver->barColor(), this, QString("bar color dialog"));
860 if (color.isValid())
862 saver->setBarColor(color);
863 barColorButton->setPaletteBackgroundColor(color);
866 void KPendulumSetup::m1ColorButtonClickedSlot(void)
868 QColor color = QColorDialog::getColor(
869 saver->m1Color(), this, QString("mass 1 color dialog"));
870 if (color.isValid())
872 saver->setM1Color(color);
873 m1ColorButton->setPaletteBackgroundColor(color);
876 void KPendulumSetup::m2ColorButtonClickedSlot(void)
878 QColor color = QColorDialog::getColor(
879 saver->m2Color(), this, QString("mass 2 color dialog"));
880 if (color.isValid())
882 saver->setM2Color(color);
883 m2ColorButton->setPaletteBackgroundColor(color);