Necessary to change KDE4_AUTOMOC macro to support
[kdeartwork.git] / kscreensaver / kdesavers / blob.cpp
blobcdcb846178ea48b9431e1a0ed2fade3d14f98493
1 //-----------------------------------------------------------------------------
2 //
3 // kblob - Basic screen saver for KDE
4 //
5 // Copyright (c) Tiaan Wessels, 1997
6 //
7 // To add new alg :
8 // - add blob_alg enum in blob.h before ALG_LAST
9 // - choose 2 letter prefix for alg and add vars needed to private vars
10 // in KBlobSaver in blob.h
11 // - add xxSetup and xxNextFrame method definitions in blob.h
12 // - implement methods in this file. xxSetup to init vars mentioned
13 // in step 2. xxNextFrame to advance blob painter ( calc tx,ty and
14 // use box() method to position painter
15 // - add descriptive string in alg_str array in this file before "Random"
16 // - add to Algs array in KBlobSaver constructor in this file
17 // - test by setup saver and choosing alg from list
19 #include <config.h>
20 #include <stdlib.h>
21 #include <time.h>
22 #include <limits.h>
23 #include <math.h>
25 #include <qcolor.h>
26 #include <qlabel.h>
27 #include <q3listbox.h>
28 #include <qlayout.h>
29 #include <qpainter.h>
30 #include <qpixmap.h>
31 #include <qimage.h>
32 //Added by qt3to4:
33 #include <QVBoxLayout>
34 #include <QHBoxLayout>
36 #include <kapplication.h>
37 #include <kconfig.h>
38 #include <kmessagebox.h>
39 #include <knuminput.h>
40 #include <klocale.h>
41 #include <kglobal.h>
42 #include <krandomsequence.h>
44 #include "blob.moc"
45 #include "blob.h"
47 #define SMALLRAND(a) (int)(rnd->getLong(a)+1)
50 // libkscreensaver interface
51 class KBlobSaverInterface : public KScreenSaverInterface
55 public:
56 virtual KAboutData* aboutData() {
57 return new KAboutData( "kblob.kss", I18N_NOOP( "KBlob" ), "2.2.0", I18N_NOOP( "KBlob" ) );
61 virtual KScreenSaver* create( WId id )
63 return new KBlobSaver( id );
66 virtual QDialog* setup()
68 return new KBlobSetup();
72 int main( int argc, char *argv[] )
74 KBlobSaverInterface kss;
75 return kScreenSaverMain( argc, argv, kss );
78 static KRandomSequence *rnd = 0;
80 QString alg_str[5];
81 void initAlg()
83 alg_str[0] = i18n("Random Linear");
84 alg_str[1] = i18n("Horizontal Sine");
85 alg_str[2] = i18n("Circular Bounce");
86 alg_str[3] = i18n("Polar Coordinates");
87 alg_str[4] = i18n("Random");
90 //-----------------------------------------------------------------------------
91 // the blob screensaver's code
93 KBlobSaver::KBlobSaver ( WId id)
94 : KScreenSaver( id )
96 rnd = new KRandomSequence();
97 initAlg();
98 QColor color;
99 float ramp = (256.0-64.0)/(float)RAMP;
100 QString msg =
101 i18n("This screen saver requires a color display.");
103 blank();
105 // needs colors to work this one
106 if (QPixmap::defaultDepth() < 8)
108 QPainter p(this);
109 p.setPen( Qt::white );
110 p.drawText( width()/2, height()/2, msg );
111 return;
115 // if 8-bit, create lookup table for color ramping further down
116 if (QPixmap::defaultDepth() == 8)
118 memset(lookup, 0, 256*sizeof(uint));
119 int i;
120 for (i = 0; i < RAMP; i++)
122 color.setRgb(64+(int)(ramp*(float)i), 0, 0);
123 colors[i] = color.pixel();
125 memset(lookup, QColor(Qt::black).pixel(), sizeof(uint)*256);
126 for (i = 0; i < RAMP-1; i++)
127 lookup[colors[i]] = colors[i+1];
128 lookup[QColor(Qt::black).pixel()] = lookup[colors[RAMP-1]] = colors[0];
130 else
132 // make special provision for preview mode
133 if (height() < 400)
135 if (QPixmap::defaultDepth() > 8 )
136 setColorInc(7);
137 else
138 setColorInc(4);
140 else
142 if (QPixmap::defaultDepth() > 8 )
143 setColorInc(3);
144 else
145 setColorInc(2);
149 // the dimensions of the blob painter
150 dim = height()/70+1;
152 // record starting time to know when to change frames
153 start = time(NULL);
155 // init some parameters used by all algorithms
156 xhalf = width()/2;
157 yhalf = height()/2;
159 // means a new algorithm should be set at entrance of timer
160 newalg = newalgp = 1;
162 // init algorithm space
163 Algs[0].Name = alg_str[0];
164 Algs[0].Init = &KBlobSaver::lnSetup;
165 Algs[0].NextFrame = &KBlobSaver::lnNextFrame;
167 Algs[1].Name = alg_str[1];
168 Algs[1].Init = &KBlobSaver::hsSetup;
169 Algs[1].NextFrame = &KBlobSaver::hsNextFrame;
171 Algs[2].Name = alg_str[2];
172 Algs[2].Init = &KBlobSaver::cbSetup;
173 Algs[2].NextFrame = &KBlobSaver::cbNextFrame;
175 Algs[3].Name = alg_str[3];
176 Algs[3].Init = &KBlobSaver::pcSetup;
177 Algs[3].NextFrame = &KBlobSaver::pcNextFrame;
179 // get setup from kde registry
180 readSettings();
182 // start timer which will update blob painter
183 timer.start(SPEED);
184 connect(&timer, SIGNAL(timeout()), SLOT(slotTimeout()));
187 KBlobSaver::~KBlobSaver()
189 timer.stop();
191 delete rnd; rnd = 0;
194 void KBlobSaver::setAlgorithm(int a)
196 newalg = newalgp = ((a == ALG_RANDOM) ? 1 : 2);
197 alg = a;
200 void KBlobSaver::lnSetup()
202 // initialize the blob movement dictators with random vals
203 // incrementals on axis
204 ln_xinc = SMALLRAND(3);
205 ln_yinc = SMALLRAND(2);
207 // start position
208 tx = SMALLRAND(width()-dim-ln_xinc*2);
209 ty = SMALLRAND(height()-dim-ln_yinc*2);
212 void KBlobSaver::hsSetup()
214 hs_per = SMALLRAND(7);
215 hs_radians = 0.0;
216 hs_rinc = (hs_per*M_PI)/(hs_per*90*4);
217 hs_flip = 1.0;
220 void KBlobSaver::cbSetup()
222 cb_radians = 0.0;
223 cb_rinc = (2.0*M_PI)/360.0;
224 cb_sradians = 0.0;
225 cb_deviate = SMALLRAND(height()/20)+(height()/15);
226 cb_radius = height()/2-cb_deviate*2-2*dim;
227 cb_devradinc = (rnd->getDouble()*10.0*2.0*M_PI)/360.0;
230 void KBlobSaver::pcSetup()
232 pc_angle = 0.0;
233 pc_radius = 0.0;
234 pc_inc = (2.0*M_PI)/720.0;
235 pc_crot = 0.0;
236 pc_div = SMALLRAND(4)-1;
239 // render next frame ( or change algorithms )
240 void KBlobSaver::slotTimeout()
242 time_t now = time(NULL);
244 // should algorithm be changed
245 if (now-start > showlen)
246 newalg = newalgp;
248 // set new algorithm
249 if (newalg)
251 blank();
252 if (newalg == 1)
253 alg = SMALLRAND(ALG_LAST)-1;
254 (this->*Algs[alg].Init)();
255 newalg = 0;
256 start = time(NULL);
259 // gen next fram for current algorithm
260 (this->*Algs[alg].NextFrame)();
263 void KBlobSaver::lnNextFrame()
265 int dir;
267 // depending on the algorithm to use, move the blob painter to
268 // a new location
269 // check for wall hit to change direction
270 if (tx+dim+ln_xinc > (int)width()-1 || tx+ln_xinc < 0)
272 if (ln_xinc > 0)
273 dir = -1;
274 else
275 dir = 1;
276 ln_xinc = SMALLRAND(3)*dir;
278 if (ty+dim+ln_yinc > (int)height()-1 || ty+ln_yinc < 0)
280 if (ln_yinc > 0)
281 dir = -1;
282 else
283 dir = 1;
284 ln_yinc = SMALLRAND(2)*dir;
287 // move box to new position
288 tx += ln_xinc;
289 ty += ln_yinc;
291 // draw new box
292 box(tx, ty);
295 void KBlobSaver::hsNextFrame()
297 static int xlen = width()-(4*dim);
298 static int ylen = height()-(4*dim);
300 // calc x as offset on angle line and y as vertical offset
301 // on interval -1..1 sine of angle
302 tx = (int)((hs_radians/(hs_per*M_PI))*(float)xlen);
303 ty = (int)((float)(ylen/4)*(hs_flip*sin(hs_radians)))+yhalf;
305 // draw new box
306 box(tx, ty);
308 // set new radians
309 hs_radians += hs_rinc;
310 if (hs_radians > hs_per*M_PI)
312 hs_rinc *= -1.0;
313 hs_radians += hs_rinc;
314 hs_flip *= -1.0;
316 else if (hs_radians < 0.0)
317 hsSetup();
320 void KBlobSaver::cbNextFrame()
322 int deviate;
324 // calculate deviation of circle main radius
325 deviate = (int)(sin(cb_sradians)*cb_deviate);
327 // calculate topleft of box as a circle with a sine perturbed radius
328 tx = (int)(cos(cb_radians)*(cb_radius+deviate))+xhalf;
329 ty = (int)(sin(cb_radians)*(cb_radius+deviate))+yhalf;
331 // draw the box
332 box(tx, ty);
334 // increase greater circle render angle
335 cb_radians += cb_rinc;
336 if (cb_radians > 2.0*M_PI)
337 cb_radians -= 2.0*M_PI;
339 // increase radius deviation offset on sine wave
340 cb_sradians += cb_devradinc;
343 void KBlobSaver::pcNextFrame()
345 static float scale = (float)height()/3.0 - 4.0*dim;
347 // simple polar coordinate equation
348 if (pc_div < 1.0)
349 pc_radius = cos(2.0*pc_angle);
350 else
351 pc_radius = 1.0/pc_div + cos(2.0*pc_angle);
353 tx = (int)(scale*pc_radius*cos(pc_angle+pc_crot))+xhalf;
354 ty = (int)(scale*pc_radius*sin(pc_angle+pc_crot))+yhalf;
356 // advance blob painter
357 box(tx, ty);
359 // new movement parameters
360 pc_angle += pc_inc;
361 if (pc_angle > 2.0*M_PI)
363 pc_angle -= 2.0*M_PI;
364 pc_crot += M_PI/45.0;
368 void KBlobSaver::box ( int x, int y )
370 // for bad behaving algorithms that wants to cause an X trap
371 // confine to the valid region before using potentially fatal XGetImage
372 if ((x+dim) >= width())
373 x = width()-dim-1;
374 else if (x < 0)
375 x = 0;
376 if ((y+dim) > height())
377 y = height()-dim-1;
378 else if (y < 0)
379 y = 0;
381 // get the box region from the display to upgrade
382 QImage img = QPixmap::grabWindow(winId(), x, y, dim, dim).convertToImage();
384 // depending on the depth of the display, use either lookup table for
385 // next rgb val ( 8-bit ) or ramp the color directly for other displays
386 if ( img.depth() == 8)
388 // manipulate image by upgrading each pixel with 1 using a lookup
389 // table as the color allocation could have resulted in a spread out
390 // configuration of the color ramp
391 for (int j = 0; j < img.height(); j++)
393 for (int i = 0; i < img.width(); i++)
395 img.scanLine(j)[i] = lookup[img.scanLine(j)[i]];
399 else
401 for (int j = 0; j < img.height(); j++)
403 for (int i = 0; i < img.width(); i++)
405 QRgb p = img.pixel( i, j );
406 p += (colorInc<<18);
407 img.setPixel( i, j, p );
412 // put the image back onto the screen
413 QPainter p(this);
414 p.drawImage( x, y, img );
417 void KBlobSaver::blank()
419 setBackgroundColor( Qt::black );
420 erase();
423 void KBlobSaver::readSettings()
425 KConfig *config = KGlobal::config();
426 config->setGroup("Settings");
428 // number of seconds to spend on a frame
429 showlen = config->readEntry("Showtime", 3*60);
431 // algorithm to use. if not set then use random
432 alg = config->readEntry("Algorithm", int(ALG_RANDOM));
433 if (alg == ALG_RANDOM)
434 newalg = 1;
435 else
436 newalg = 2;
437 newalgp = newalg;
440 //-----------------------------------------------------------------------------
441 // dialog to setup screen saver parameters
443 KBlobSetup::KBlobSetup
445 QWidget *parent,
446 const char *name
448 : KDialog( parent)
450 setCaption(i18n( "Setup Blob Screen Saver" ));
451 setButtons(Ok|Cancel|Help);
452 setDefaultButton(Ok);
453 setModal(true);
454 initAlg();
456 // get saver configuration from kde registry
457 readSettings();
459 setButtonText( Help, i18n( "A&bout" ) );
460 QWidget *main = new QWidget(this);
461 setMainWidget(main);
463 QHBoxLayout *tl = new QHBoxLayout( main, 0, spacingHint() );
465 QVBoxLayout *vbox = new QVBoxLayout;
466 tl->addLayout(vbox);
468 // seconds to generate on a frame
469 QLabel *label = new QLabel(i18n("Frame duration:"), main);
470 stime = new KIntNumInput( showtime, main );
471 stime->setSuffix( i18n( " sec" ) );
472 vbox->addWidget(label);
473 vbox->addWidget(stime);
475 // available algorithms
476 label = new QLabel(i18n("Algorithm:"), main);
477 algs = new Q3ListBox(main);
478 algs->setMinimumSize(150, 105);
479 for (int i = 0; i <= ALG_RANDOM; i++)
480 algs->insertItem(alg_str[i]);
481 algs->setCurrentItem(alg);
482 vbox->addWidget(label);
483 vbox->addWidget(algs);
485 // preview window
486 QWidget *preview = new QWidget( main );
487 preview->setFixedSize(220, 170);
488 preview->setBackgroundColor(Qt::black);
489 preview->show();
490 tl->addWidget(preview);
491 saver = new KBlobSaver(preview->winId());
492 saver->setDimension(3);
493 if (QPixmap::defaultDepth() > 8)
494 saver->setColorInc(7);
495 else
496 saver->setColorInc(4);
498 tl->addStretch();
500 // so selecting an algorithm will start previewing that alg
501 connect(algs, SIGNAL(highlighted(int)), saver,
502 SLOT(setAlgorithm(int)));
505 void KBlobSetup::readSettings()
507 KConfig *config = KGlobal::config();
508 config->setGroup("Settings");
510 // number of seconds to spend on a frame
511 showtime = config->readEntry("Showtime", 3*60);
513 // algorithm to use. if not set then use random
514 alg = config->readEntry("Algorithm", (int)ALG_LAST);
517 // Ok pressed - save settings and exit
518 void KBlobSetup::slotOk()
520 KConfig *config = KGlobal::config();
522 config->setGroup("Settings");
524 config->writeEntry("Showtime", stime->value());
525 config->writeEntry("Algorithm", algs->currentItem());
527 config->sync();
529 accept();
532 void KBlobSetup::slotHelp()
534 KMessageBox::about(this,
535 i18n("Blobsaver Version 0.1\n\nWritten by Tiaan Wessels 1997\ntiaan@netsys.co.za"));
536 if (saver)
537 saver->setAlgorithm(algs->currentItem());