Deprecated--
[kdeartwork.git] / kscreensaver / kdesavers / Flux.cpp
blobac6a19b1f9e493532fc290553220559d61e4ac07
1 //============================================================================
2 //
3 // Terence Welsh Screensaver - Flux
4 // http://www.reallyslick.com/
5 //
6 // Ported to KDE by Karl Robillard
7 //
8 /*
9 * Copyright (C) 2002 Terence M. Welsh
11 * Flux is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * Flux is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //============================================================================
28 TODO
30 [ ] Regular and others are messed up after Sparkler.
31 Insane seems to reset them.
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <math.h>
38 #include <time.h>
39 #include <qtimer.h>
40 //Added by qt3to4:
41 #include <QVBoxLayout>
42 #include <QHBoxLayout>
43 #include <QKeyEvent>
44 #include "Flux.h"
45 #include "Flux.moc"
48 #define NUMCONSTS 8
49 #define PIx2 6.28318530718f
50 #define DEG2RAD 0.0174532925f
53 void hsl2rgb(float h, float s, float l, float &r, float &g, float &b)
55 // hue influence
56 if(h < 0.166667){ // full red, some green
57 r = 1.0;
58 g = h * 6.0f;
59 b = 0.0;
61 else {
62 if(h < 0.5){ // full green
63 g = 1.0;
64 if(h < 0.333333){ // some red
65 r = 1.0f - ((h - 0.166667f) * 6.0f);
66 b = 0.0;
68 else{ // some blue
69 b = (h - 0.333333f) * 6.0f;
70 r = 0.0;
73 else{
74 if(h < 0.833333){ // full blue
75 b = 1.0;
76 if(h < 0.666667){ // some green
77 g = 1.0f - ((h - 0.5f) * 6.0f);
78 r = 0.0;
80 else{ // some red
81 r = (h - 0.666667f) * 6.0f;
82 g = 0.0;
85 else{ // full red, some blue
86 r = 1.0;
87 b = 1.0f - ((h - 0.833333f) * 6.0f);
88 g = 0.0;
93 // saturation influence
94 r = 1.0f - (s * (1.0f - r));
95 g = 1.0f - (s * (1.0f - g));
96 b = 1.0f - (s * (1.0f - b));
98 // luminosity influence
99 r *= l;
100 g *= l;
101 b *= l;
105 // Useful random number macros
106 // Don't forget to initialize with srand()
107 inline int myRandi(int x){
108 return((rand() * x) / RAND_MAX);
110 inline float myRandf(float x){
111 return(float(rand() * x) / float(RAND_MAX));
115 //----------------------------------------------------------------------------
118 // Flux context to allow many instances.
119 static FluxWidget* _fc = 0;
121 static int whichparticle;
124 // This class is poorly named. It's actually a whole trail of particles.
125 class particle
127 public:
129 particle();
130 ~particle();
131 float update(float *c);
133 private:
135 float** vertices;
136 short trails;
137 short counter;
138 float offset[3];
142 particle::particle()
144 // Offsets are somewhat like default positions for the head of each
145 // particle trail. Offsets spread out the particle trails and keep
146 // them from all overlapping.
147 offset[0] = cos(PIx2 * float(whichparticle) / float(_fc->dParticles));
148 offset[1] = float(whichparticle) / float(_fc->dParticles) - 0.5f;
149 offset[2] = sin(PIx2 * float(whichparticle) / float(_fc->dParticles));
150 whichparticle++;
152 // Initialize memory and set initial positions out of view of the camera
153 trails = _fc->dTrail;
154 vertices = new float*[ trails ];
156 int i;
157 for(i=0; i<trails; i++)
159 vertices[i] = new float[5]; // 0,1,2 = position, 3 = hue, 4 = saturation
160 vertices[i][0] = 0.0f;
161 vertices[i][1] = 3.0f;
162 vertices[i][2] = 0.0f;
163 vertices[i][3] = 0.0f;
164 vertices[i][4] = 0.0f;
167 counter = 0;
171 particle::~particle()
173 for(int i=0; i<trails; i++)
174 delete[] vertices[i];
175 delete[] vertices;
179 float particle::update(float *c)
181 int i, p, growth;
182 float rgb[3];
183 float cx, cy, cz; // Containment variables
184 float luminosity;
185 static float expander = 1.0f + 0.0005f * float(_fc->dExpansion);
186 static float blower = 0.001f * float(_fc->dWind);
187 //static float otherxyz[3];
188 float depth = 0;
190 // Record old position
191 int oldc = counter;
192 float oldpos[3];
193 oldpos[0] = vertices[oldc][0];
194 oldpos[1] = vertices[oldc][1];
195 oldpos[2] = vertices[oldc][2];
197 counter ++;
198 if(counter >= _fc->dTrail)
199 counter = 0;
201 // Here's the iterative math for calculating new vertex positions
202 // first calculate limiting terms which keep vertices from constantly
203 // flying off to infinity
204 cx = vertices[oldc][0] * (1.0f - 1.0f / (vertices[oldc][0] * vertices[oldc][0] + 1.0f));
205 cy = vertices[oldc][1] * (1.0f - 1.0f / (vertices[oldc][1] * vertices[oldc][1] + 1.0f));
206 cz = vertices[oldc][2] * (1.0f - 1.0f / (vertices[oldc][2] * vertices[oldc][2] + 1.0f));
207 // then calculate new positions
208 vertices[counter][0] = vertices[oldc][0] + c[6] * offset[0] - cx
209 + c[2] * vertices[oldc][1]
210 + c[5] * vertices[oldc][2];
211 vertices[counter][1] = vertices[oldc][1] + c[6] * offset[1] - cy
212 + c[1] * vertices[oldc][2]
213 + c[4] * vertices[oldc][0];
214 vertices[counter][2] = vertices[oldc][2] + c[6] * offset[2] - cz
215 + c[0] * vertices[oldc][0]
216 + c[3] * vertices[oldc][1];
218 // Pick a hue
219 vertices[counter][3] = cx * cx + cy * cy + cz * cz;
220 if(vertices[counter][3] > 1.0f)
221 vertices[counter][3] = 1.0f;
222 vertices[counter][3] += c[7];
223 // Limit the hue (0 - 1)
224 if(vertices[counter][3] > 1.0f)
225 vertices[counter][3] -= 1.0f;
226 if(vertices[counter][3] < 0.0f)
227 vertices[counter][3] += 1.0f;
228 // Pick a saturation
229 vertices[counter][4] = c[0] + vertices[counter][3];
230 // Limit the saturation (0 - 1)
231 if(vertices[counter][4] < 0.0f)
232 vertices[counter][4] = -vertices[counter][4];
233 vertices[counter][4] -= float(int(vertices[counter][4]));
234 vertices[counter][4] = 1.0f - (vertices[counter][4] * vertices[counter][4]);
236 // Bring particles back if they escape
237 if(!counter){
238 if((vertices[0][0] > 1000000000.0f) || (vertices[0][0] < -1000000000.0f)
239 || (vertices[0][1] > 1000000000.0f) || (vertices[0][1] < -1000000000.0f)
240 || (vertices[2][2] > 1000000000.0f) || (vertices[0][2] < -1000000000.0f)){
241 vertices[0][0] = myRandf(2.0f) - 1.0f;
242 vertices[0][1] = myRandf(2.0f) - 1.0f;
243 vertices[0][2] = myRandf(2.0f) - 1.0f;
247 // Draw every vertex in particle trail
248 p = counter;
249 growth = 0;
250 luminosity = _fc->lumdiff;
251 for(i=0; i<_fc->dTrail; i++){
252 p ++;
253 if(p >= _fc->dTrail)
254 p = 0;
255 growth++;
257 // assign color to particle
258 hsl2rgb(vertices[p][3], vertices[p][4], luminosity, rgb[0], rgb[1], rgb[2]);
259 glColor3fv(rgb);
261 glPushMatrix();
262 if(_fc->dGeometry == 1) // Spheres
263 glTranslatef(vertices[p][0], vertices[p][1], vertices[p][2]);
264 else{ // Points or lights
265 depth = _fc->cosCameraAngle * vertices[p][2] - _fc->sinCameraAngle * vertices[p][0];
266 glTranslatef(_fc->cosCameraAngle * vertices[p][0] + _fc->sinCameraAngle
267 * vertices[p][2], vertices[p][1], depth);
269 if(_fc->dGeometry){ // Spheres or lights
270 switch(_fc->dTrail - growth){
271 case 0:
272 glScalef(0.259f, 0.259f, 0.259f);
273 break;
274 case 1:
275 glScalef(0.5f, 0.5f, 0.5f);
276 break;
277 case 2:
278 glScalef(0.707f, 0.707f, 0.707f);
279 break;
280 case 3:
281 glScalef(0.866f, 0.866f, 0.866f);
282 break;
283 case 4:
284 glScalef(0.966f, 0.966f, 0.966f);
287 switch(_fc->dGeometry){
288 case 0: // Points
289 switch(_fc->dTrail - growth){
290 case 0:
291 glPointSize(float(_fc->dSize * (depth + 200.0f) * 0.001036f));
292 break;
293 case 1:
294 glPointSize(float(_fc->dSize * (depth + 200.0f) * 0.002f));
295 break;
296 case 2:
297 glPointSize(float(_fc->dSize * (depth + 200.0f) * 0.002828f));
298 break;
299 case 3:
300 glPointSize(float(_fc->dSize * (depth + 200.0f) * 0.003464f));
301 break;
302 case 4:
303 glPointSize(float(_fc->dSize * (depth + 200.0f) * 0.003864f));
304 break;
305 default:
306 glPointSize(float(_fc->dSize * (depth + 200.0f) * 0.004f));
308 glBegin(GL_POINTS);
309 glVertex3f(0.0f,0.0f,0.0f);
310 glEnd();
311 break;
312 case 1: // Spheres
313 case 2: // Lights
314 glCallList(1);
316 glPopMatrix();
317 vertices[p][0] *= expander;
318 vertices[p][1] *= expander;
319 vertices[p][2] *= expander;
320 vertices[p][2] += blower;
321 luminosity += _fc->lumdiff;
324 // Find distance between new position and old position and return it
325 oldpos[0] -= vertices[counter][0];
326 oldpos[1] -= vertices[counter][1];
327 oldpos[2] -= vertices[counter][2];
328 return(float(sqrt(oldpos[0] * oldpos[0] + oldpos[1] * oldpos[1] + oldpos[2] * oldpos[2])));
332 // This class is a set of particle trails and constants that enter
333 // into their equations of motion.
334 class flux
336 public:
338 flux();
339 ~flux();
340 void update();
342 particle *particles;
343 int randomize;
344 float c[NUMCONSTS]; // constants
345 float cv[NUMCONSTS]; // constants' change velocities
346 int currentSmartConstant;
347 float oldDistance;
351 flux::flux()
353 whichparticle = 0;
355 particles = new particle[_fc->dParticles];
356 randomize = 1;
358 float instability = _fc->dInstability;
359 int i;
360 for(i=0; i<NUMCONSTS; i++)
362 c[i] = myRandf(2.0f) - 1.0f;
363 cv[i] = myRandf(0.000005f * instability * instability)
364 + 0.000001f * instability * instability;
367 currentSmartConstant = 0;
368 oldDistance = 0.0f;
372 flux::~flux()
374 delete[] particles;
378 void flux::update()
380 int i;
382 // randomize constants
383 if(_fc->dRandomize){
384 randomize --;
385 if(randomize <= 0){
386 for(i=0; i<NUMCONSTS; i++)
387 c[i] = myRandf(2.0f) - 1.0f;
388 int temp = 101 - _fc->dRandomize;
389 temp = temp * temp;
390 randomize = temp + myRandi(temp);
394 // update constants
395 for(i=0; i<NUMCONSTS; i++){
396 c[i] += cv[i];
397 if(c[i] >= 1.0f){
398 c[i] = 1.0f;
399 cv[i] = -cv[i];
401 if(c[i] <= -1.0f){
402 c[i] = -1.0f;
403 cv[i] = -cv[i];
407 // update all particles in this flux field
408 float dist;
409 for(i=0; i<_fc->dParticles; i++)
410 dist = particles[i].update(c);
412 // use dist from last particle to activate smart constants
413 _fc->dSmart = 0;
414 if(_fc->dSmart){
415 const float upper = 0.4f;
416 const float lower = 0.2f;
417 int beSmart = 0;
418 if(dist > upper && dist > oldDistance)
419 beSmart = 1;
420 if(dist < lower && dist < oldDistance)
421 beSmart = 1;
422 if(beSmart){
423 cv[currentSmartConstant] = -cv[currentSmartConstant];
424 currentSmartConstant ++;
425 if(currentSmartConstant >= _fc->dSmart)
426 currentSmartConstant = 0;
428 oldDistance = dist;
433 //----------------------------------------------------------------------------
436 FluxWidget::FluxWidget( QWidget* parent, const char* name )
437 : QGLWidget(parent, name), _fluxes(0)
439 setDefaults( Regular );
441 _frameTime = 1000 / 60;
442 _timer = new QTimer( this );
443 connect( _timer, SIGNAL(timeout()), this, SLOT(nextFrame()) );
447 FluxWidget::~FluxWidget()
449 // Free memory
450 delete[] _fluxes;
454 void FluxWidget::paintGL()
456 // clear the screen
457 glLoadIdentity();
459 if(dBlur) // partially
461 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
462 glEnable(GL_BLEND);
463 glDisable(GL_DEPTH_TEST);
464 glColor4f(0.0f, 0.0f, 0.0f, 0.5f - (float(sqrt(sqrt(double(dBlur)))) * 0.15495f));
465 glBegin(GL_TRIANGLE_STRIP);
466 glVertex3f(-5.0f, -4.0f, 0.0f);
467 glVertex3f(5.0f, -4.0f, 0.0f);
468 glVertex3f(-5.0f, 4.0f, 0.0f);
469 glVertex3f(5.0f, 4.0f, 0.0f);
470 glEnd();
472 else // completely
474 glClear(GL_COLOR_BUFFER_BIT);
477 cameraAngle += 0.01f * float(dRotation);
478 if(cameraAngle >= 360.0f)
479 cameraAngle -= 360.0f;
480 if(dGeometry == 1) // Only rotate for spheres
481 glRotatef(cameraAngle, 0.0f, 1.0f, 0.0f);
482 else
484 cosCameraAngle = cos(cameraAngle * DEG2RAD);
485 sinCameraAngle = sin(cameraAngle * DEG2RAD);
488 // set up blend modes for rendering particles
489 switch(dGeometry)
491 case 0: // Blending for points
492 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
493 glEnable(GL_BLEND);
494 glEnable(GL_POINT_SMOOTH);
495 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
496 break;
498 case 1: // No blending for spheres, but we need z-buffering
499 glDisable(GL_BLEND);
500 glEnable(GL_DEPTH_TEST);
501 glClear(GL_DEPTH_BUFFER_BIT);
502 break;
504 case 2: // Blending for lights
505 glBlendFunc(GL_ONE, GL_ONE);
506 glEnable(GL_BLEND);
509 // Update particles
510 if( _fluxes )
512 _fc = this;
513 int i;
514 for(i=0; i<dFluxes; i++)
515 _fluxes[i].update();
518 glFlush();
522 void FluxWidget::resizeGL( int w, int h )
524 glViewport(0, 0, w, h );
526 glMatrixMode(GL_PROJECTION);
527 glLoadIdentity();
528 gluPerspective(100.0, (float) w / (float) h, 0.01, 200);
529 glTranslatef(0.0, 0.0, -2.5);
530 glMatrixMode(GL_MODELVIEW);
531 glLoadIdentity();
535 // Window initialization
536 void FluxWidget::initializeGL()
538 //resizeGL( width(), height() );
540 updateParameters();
541 _timer->setSingleShot(true);
542 _timer->start( _frameTime );
546 #ifdef UNIT_TEST
547 void FluxWidget::keyPressEvent( QKeyEvent* e )
549 if( e->key() == Qt::Key_0 ) { setDefaults( 0 ); updateParameters(); }
550 if( e->key() == Qt::Key_1 ) { setDefaults( 1 ); updateParameters(); }
551 if( e->key() == Qt::Key_2 ) { setDefaults( 2 ); updateParameters(); }
552 if( e->key() == Qt::Key_3 ) { setDefaults( 3 ); updateParameters(); }
553 if( e->key() == Qt::Key_4 ) { setDefaults( 4 ); updateParameters(); }
554 if( e->key() == Qt::Key_5 ) { setDefaults( 5 ); updateParameters(); }
556 #endif
559 void FluxWidget::nextFrame()
561 updateGL();
562 _timer->setSingleShot(true);
563 _timer->start( _frameTime );
568 May be called at any time - makes no OpenGL calls.
570 void FluxWidget::setDefaults( int which )
572 switch(which)
574 case Hypnotic:
575 dFluxes = 2;
576 dParticles = 10;
577 dTrail = 40;
578 dGeometry = 2;
579 dSize = 15;
580 dRandomize = 80;
581 dExpansion = 20;
582 dRotation = 0;
583 dWind = 40;
584 dInstability = 10;
585 dBlur = 30;
586 break;
588 case Insane:
589 dFluxes = 4;
590 dParticles = 30;
591 dTrail = 8;
592 dGeometry = 2;
593 dSize = 25;
594 dRandomize = 0;
595 dExpansion = 80;
596 dRotation = 60;
597 dWind = 40;
598 dInstability = 100;
599 dBlur = 10;
600 break;
602 case Sparklers:
603 dFluxes = 3;
604 dParticles = 20;
605 dTrail = 6;
606 dGeometry = 1;
607 dSize = 20;
608 dComplexity = 3;
609 dRandomize = 85;
610 dExpansion = 60;
611 dRotation = 30;
612 dWind = 20;
613 dInstability = 30;
614 dBlur = 0;
615 break;
617 case Paradigm:
618 dFluxes = 1;
619 dParticles = 40;
620 dTrail = 40;
621 dGeometry = 2;
622 dSize = 5;
623 dRandomize = 90;
624 dExpansion = 30;
625 dRotation = 20;
626 dWind = 10;
627 dInstability = 5;
628 dBlur = 10;
629 break;
631 case Galactic:
632 dFluxes = 1;
633 dParticles = 2;
634 dTrail = 1500;
635 dGeometry = 2;
636 dSize = 10;
637 dRandomize = 0;
638 dExpansion = 5;
639 dRotation = 25;
640 dWind = 0;
641 dInstability = 5;
642 dBlur = 0;
643 break;
645 case Regular:
646 default:
647 dFluxes = 1;
648 dParticles = 20;
649 dTrail = 40;
650 dGeometry = 2;
651 dSize = 15;
652 dRandomize = 0;
653 dExpansion = 40;
654 dRotation = 30;
655 dWind = 20;
656 dInstability = 20;
657 dBlur = 0;
658 break;
664 Called after dGeometry, dTrail, or dFluxes is changed
665 (such as with setDefaults).
667 void FluxWidget::updateParameters()
669 int i, j;
670 float x, y, temp;
672 srand((unsigned)time(NULL));
673 rand(); rand(); rand(); rand(); rand();
675 cameraAngle = 0.0f;
677 glFrontFace(GL_CCW);
678 glEnable(GL_CULL_FACE);
679 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
680 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
682 if(dGeometry == 0)
684 glDisable(GL_LIGHTING);
685 glDisable(GL_COLOR_MATERIAL);
686 glDisable(GL_TEXTURE_2D);
688 glEnable(GL_POINT_SMOOTH);
689 //glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
691 else if(dGeometry == 1) // Spheres and their lighting
693 glNewList(1, GL_COMPILE);
694 GLUquadricObj* qobj = gluNewQuadric();
695 gluSphere(qobj, 0.005f * dSize, dComplexity + 2, dComplexity + 1);
696 gluDeleteQuadric(qobj);
697 glEndList();
699 glDisable(GL_TEXTURE_2D);
700 glEnable(GL_LIGHTING);
701 glEnable(GL_LIGHT0);
703 float ambient[4] = {0.0f, 0.0f, 0.0f, 0.0f};
704 float diffuse[4] = {1.0f, 1.0f, 1.0f, 0.0f};
705 float specular[4] = {1.0f, 1.0f, 1.0f, 0.0f};
706 float position[4] = {500.0f, 500.0f, 500.0f, 0.0f};
708 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
709 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
710 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
711 glLightfv(GL_LIGHT0, GL_POSITION, position);
712 glEnable(GL_COLOR_MATERIAL);
713 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
715 else if(dGeometry == 2) // Init lights
717 for(i=0; i<LIGHTSIZE; i++)
719 for(j=0; j<LIGHTSIZE; j++)
721 x = float(i - LIGHTSIZE / 2) / float(LIGHTSIZE / 2);
722 y = float(j - LIGHTSIZE / 2) / float(LIGHTSIZE / 2);
723 temp = 1.0f - float(sqrt((x * x) + (y * y)));
724 if(temp > 1.0f)
725 temp = 1.0f;
726 if(temp < 0.0f)
727 temp = 0.0f;
728 lightTexture[i][j] = (unsigned char) (255.0f * temp * temp);
732 glDisable(GL_LIGHTING);
733 glDisable(GL_COLOR_MATERIAL);
735 glEnable(GL_TEXTURE_2D);
736 glBindTexture(GL_TEXTURE_2D, 1);
737 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
738 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
739 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
740 glTexImage2D(GL_TEXTURE_2D, 0, 1, LIGHTSIZE, LIGHTSIZE, 0,
741 GL_LUMINANCE, GL_UNSIGNED_BYTE, lightTexture);
743 temp = float(dSize) * 0.005f;
744 glNewList(1, GL_COMPILE);
745 glBindTexture(GL_TEXTURE_2D, 1);
746 glBegin(GL_TRIANGLES);
747 glTexCoord2f(0.0f, 0.0f);
748 glVertex3f(-temp, -temp, 0.0f);
749 glTexCoord2f(1.0f, 0.0f);
750 glVertex3f(temp, -temp, 0.0f);
751 glTexCoord2f(1.0f, 1.0f);
752 glVertex3f(temp, temp, 0.0f);
753 glTexCoord2f(0.0f, 0.0f);
754 glVertex3f(-temp, -temp, 0.0f);
755 glTexCoord2f(1.0f, 1.0f);
756 glVertex3f(temp, temp, 0.0f);
757 glTexCoord2f(0.0f, 1.0f);
758 glVertex3f(-temp, temp, 0.0f);
759 glEnd();
760 glEndList();
763 // Initialize luminosity difference
764 lumdiff = 1.0f / float(dTrail);
766 _fc = this;
767 delete[] _fluxes;
768 _fluxes = new flux[dFluxes];
772 //----------------------------------------------------------------------------
775 #ifndef UNIT_TEST
776 #include <klocale.h>
777 #include <kglobal.h>
778 #include <kconfig.h>
781 // libkscreensaver interface
782 class KFluxSaverInterface : public KScreenSaverInterface
786 public:
787 virtual KAboutData* aboutData() {
788 return new KAboutData( "kflux.kss", I18N_NOOP( "Flux" ), "1.0", I18N_NOOP( "Flux" ) );
792 virtual KScreenSaver* create( WId id )
794 return new KFluxScreenSaver( id );
797 virtual QDialog* setup()
799 return new KFluxSetup;
803 int main( int argc, char *argv[] )
805 KFluxSaverInterface kss;
806 return kScreenSaverMain( argc, argv, kss );
810 //----------------------------------------------------------------------------
813 KFluxScreenSaver::KFluxScreenSaver( WId id ) : KScreenSaver( id )
815 _flux = new FluxWidget;
817 readSettings();
819 embed( _flux );
820 _flux->show();
824 KFluxScreenSaver::~KFluxScreenSaver()
829 static int filterRandom( int n )
831 if( (n < 0) || (n >= FluxWidget::DefaultModes) )
833 srand((unsigned)time(NULL));
834 n = rand() % FluxWidget::DefaultModes;
836 return n;
840 void KFluxScreenSaver::readSettings()
842 KConfig* config = KGlobal::config();
843 config->setGroup("Settings");
845 _mode = config->readEntry( "Mode", (int)FluxWidget::Regular );
846 _flux->setDefaults( filterRandom(_mode) );
851 Any invalid mode will select one at random.
853 void KFluxScreenSaver::setMode( int id )
855 _mode = id;
856 _flux->setDefaults( filterRandom(id) );
857 _flux->updateParameters();
861 //----------------------------------------------------------------------------
864 #include <qlayout.h>
865 #include <qpushbutton.h>
866 #include <qlabel.h>
867 #include <qcombobox.h>
868 #include <kbuttonbox.h>
869 #include <kmessagebox.h>
872 static const char* defaultText[] =
874 I18N_NOOP( "Regular" ),
875 I18N_NOOP( "Hypnotic" ),
876 I18N_NOOP( "Insane" ),
877 I18N_NOOP( "Sparklers" ),
878 I18N_NOOP( "Paradigm" ),
879 I18N_NOOP( "Galactic" ),
880 I18N_NOOP( "(Random)" ),
885 KFluxSetup::KFluxSetup( QWidget* parent, const char* name )
886 : KDialog( parent)
888 setButtonText( Help, i18n( "A&bout" ) );
889 setButtons(Ok|Cancel|Help);
890 setDefaultButton(Ok);
891 setModal(true);
892 showButtonSeparator(true);
893 QWidget *main = new QWidget(this);
894 setMainWidget(main);
896 QHBoxLayout* top = new QHBoxLayout( main, 0, spacingHint() );
897 QVBoxLayout* leftCol = new QVBoxLayout;
898 top->addLayout( leftCol );
900 // Parameters
901 QLabel* label = new QLabel( i18n("Mode:"), main );
902 leftCol->addWidget( label );
904 modeW = new QComboBox( main );
905 int i = 0;
906 while (defaultText[i])
907 modeW->insertItem( i18n(defaultText[i++]) );
908 leftCol->addWidget( modeW );
910 leftCol->addStretch();
912 // Preview
913 QWidget* preview;
914 preview = new QWidget( main );
915 preview->setFixedSize( 220, 165 );
916 preview->setBackgroundColor( Qt::black );
917 preview->show(); // otherwise saver does not get correct size
918 _saver = new KFluxScreenSaver( preview->winId() );
919 top->addWidget(preview);
921 // Now that we have _saver...
922 modeW->setCurrentIndex( _saver->mode() ); // set before we connect
923 connect( modeW, SIGNAL(activated(int)), _saver, SLOT(setMode(int)) );
924 connect( this, SIGNAL(okClicked()), SLOT(slotOk()));
928 KFluxSetup::~KFluxSetup()
930 delete _saver;
934 void KFluxSetup::slotHelp()
936 KMessageBox::about(this,
937 i18n("<h3>Flux 1.0</h3>\n<p>Copyright (c) 2002 Terence M. Welsh<br>\n<a href=\"http://www.reallyslick.com/\">http://www.reallyslick.com/</a></p>\n\n<p>Ported to KDE by Karl Robillard</p>"),
938 QString::null, KMessageBox::AllowLink);
943 Ok pressed - save settings and exit
945 void KFluxSetup::slotOk()
947 KConfig* config = KGlobal::config();
948 config->setGroup("Settings");
950 QString val;
951 val.setNum( modeW->currentIndex() );
952 config->writeEntry("Mode", val );
954 config->sync();
955 accept();
957 #endif
960 //----------------------------------------------------------------------------
963 #ifdef UNIT_TEST
964 // moc Flux.h -o Flux.moc
965 // g++ -g -DUNIT_TEST Flux.cpp -I/usr/lib/qt3/include -lqt -L/usr/lib/qt3/lib -lGLU -lGL
967 #include <qapplication.h>
969 int main( int argc, char** argv )
971 QApplication app( argc, argv );
973 FluxWidget w;
974 w.setDefaults( FluxWidget::Sparklers );
975 app.setMainWidget( &w );
976 w.show();
978 return app.exec();
980 #endif
983 //EOF