Qt3to4
[kdeartwork.git] / kscreensaver / kdesavers / blob.cpp
blobaf61e1ceea9fb5c97dbd2c5923fe39a20c01d507
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 extern "C"
53 KDE_EXPORT const char *kss_applicationName = "kblob.kss";
54 KDE_EXPORT const char *kss_description = I18N_NOOP( "KBlob" );
55 KDE_EXPORT const char *kss_version = "2.2.0";
57 KDE_EXPORT KScreenSaver *kss_create( WId id )
59 return new KBlobSaver( id );
62 KDE_EXPORT QDialog *kss_setup()
64 return new KBlobSetup();
68 static KRandomSequence *rnd = 0;
70 QString alg_str[5];
71 void initAlg()
73 alg_str[0] = i18n("Random Linear");
74 alg_str[1] = i18n("Horizontal Sine");
75 alg_str[2] = i18n("Circular Bounce");
76 alg_str[3] = i18n("Polar Coordinates");
77 alg_str[4] = i18n("Random");
80 //-----------------------------------------------------------------------------
81 // the blob screensaver's code
83 KBlobSaver::KBlobSaver ( WId id)
84 : KScreenSaver( id )
86 rnd = new KRandomSequence();
87 initAlg();
88 QColor color;
89 float ramp = (256.0-64.0)/(float)RAMP;
90 QString msg =
91 i18n("This screen saver requires a color display.");
93 blank();
95 // needs colors to work this one
96 if (QPixmap::defaultDepth() < 8)
98 QPainter p(this);
99 p.setPen( white );
100 p.drawText( width()/2, height()/2, msg );
101 return;
104 colorContext = QColor::enterAllocContext();
106 // if 8-bit, create lookup table for color ramping further down
107 if (QPixmap::defaultDepth() == 8)
109 memset(lookup, 0, 256*sizeof(uint));
110 int i;
111 for (i = 0; i < RAMP; i++)
113 color.setRgb(64+(int)(ramp*(float)i), 0, 0);
114 colors[i] = color.alloc();
116 memset(lookup, black.pixel(), sizeof(uint)*256);
117 for (i = 0; i < RAMP-1; i++)
118 lookup[colors[i]] = colors[i+1];
119 lookup[black.pixel()] = lookup[colors[RAMP-1]] = colors[0];
121 else
123 // make special provision for preview mode
124 if (height() < 400)
126 if (QPixmap::defaultDepth() > 8 )
127 setColorInc(7);
128 else
129 setColorInc(4);
131 else
133 if (QPixmap::defaultDepth() > 8 )
134 setColorInc(3);
135 else
136 setColorInc(2);
140 // the dimensions of the blob painter
141 dim = height()/70+1;
143 // record starting time to know when to change frames
144 start = time(NULL);
146 // init some parameters used by all algorithms
147 xhalf = width()/2;
148 yhalf = height()/2;
150 // means a new algorithm should be set at entrance of timer
151 newalg = newalgp = 1;
153 // init algorithm space
154 Algs[0].Name = alg_str[0];
155 Algs[0].Init = &KBlobSaver::lnSetup;
156 Algs[0].NextFrame = &KBlobSaver::lnNextFrame;
158 Algs[1].Name = alg_str[1];
159 Algs[1].Init = &KBlobSaver::hsSetup;
160 Algs[1].NextFrame = &KBlobSaver::hsNextFrame;
162 Algs[2].Name = alg_str[2];
163 Algs[2].Init = &KBlobSaver::cbSetup;
164 Algs[2].NextFrame = &KBlobSaver::cbNextFrame;
166 Algs[3].Name = alg_str[3];
167 Algs[3].Init = &KBlobSaver::pcSetup;
168 Algs[3].NextFrame = &KBlobSaver::pcNextFrame;
170 // get setup from kde registry
171 readSettings();
173 // start timer which will update blob painter
174 timer.start(SPEED);
175 connect(&timer, SIGNAL(timeout()), SLOT(slotTimeout()));
178 KBlobSaver::~KBlobSaver()
180 timer.stop();
182 QColor::leaveAllocContext();
183 QColor::destroyAllocContext(colorContext);
184 delete rnd; rnd = 0;
187 void KBlobSaver::setAlgorithm(int a)
189 newalg = newalgp = ((a == ALG_RANDOM) ? 1 : 2);
190 alg = a;
193 void KBlobSaver::lnSetup()
195 // initialize the blob movement dictators with random vals
196 // incrementals on axis
197 ln_xinc = SMALLRAND(3);
198 ln_yinc = SMALLRAND(2);
200 // start position
201 tx = SMALLRAND(width()-dim-ln_xinc*2);
202 ty = SMALLRAND(height()-dim-ln_yinc*2);
205 void KBlobSaver::hsSetup()
207 hs_per = SMALLRAND(7);
208 hs_radians = 0.0;
209 hs_rinc = (hs_per*M_PI)/(hs_per*90*4);
210 hs_flip = 1.0;
213 void KBlobSaver::cbSetup()
215 cb_radians = 0.0;
216 cb_rinc = (2.0*M_PI)/360.0;
217 cb_sradians = 0.0;
218 cb_deviate = SMALLRAND(height()/20)+(height()/15);
219 cb_radius = height()/2-cb_deviate*2-2*dim;
220 cb_devradinc = (rnd->getDouble()*10.0*2.0*M_PI)/360.0;
223 void KBlobSaver::pcSetup()
225 pc_angle = 0.0;
226 pc_radius = 0.0;
227 pc_inc = (2.0*M_PI)/720.0;
228 pc_crot = 0.0;
229 pc_div = SMALLRAND(4)-1;
232 // render next frame ( or change algorithms )
233 void KBlobSaver::slotTimeout()
235 time_t now = time(NULL);
237 // should algorithm be changed
238 if (now-start > showlen)
239 newalg = newalgp;
241 // set new algorithm
242 if (newalg)
244 blank();
245 if (newalg == 1)
246 alg = SMALLRAND(ALG_LAST)-1;
247 (this->*Algs[alg].Init)();
248 newalg = 0;
249 start = time(NULL);
252 // gen next fram for current algorithm
253 (this->*Algs[alg].NextFrame)();
256 void KBlobSaver::lnNextFrame()
258 int dir;
260 // depending on the algorithm to use, move the blob painter to
261 // a new location
262 // check for wall hit to change direction
263 if (tx+dim+ln_xinc > (int)width()-1 || tx+ln_xinc < 0)
265 if (ln_xinc > 0)
266 dir = -1;
267 else
268 dir = 1;
269 ln_xinc = SMALLRAND(3)*dir;
271 if (ty+dim+ln_yinc > (int)height()-1 || ty+ln_yinc < 0)
273 if (ln_yinc > 0)
274 dir = -1;
275 else
276 dir = 1;
277 ln_yinc = SMALLRAND(2)*dir;
280 // move box to new position
281 tx += ln_xinc;
282 ty += ln_yinc;
284 // draw new box
285 box(tx, ty);
288 void KBlobSaver::hsNextFrame()
290 static int xlen = width()-(4*dim);
291 static int ylen = height()-(4*dim);
293 // calc x as offset on angle line and y as vertical offset
294 // on interval -1..1 sine of angle
295 tx = (int)((hs_radians/(hs_per*M_PI))*(float)xlen);
296 ty = (int)((float)(ylen/4)*(hs_flip*sin(hs_radians)))+yhalf;
298 // draw new box
299 box(tx, ty);
301 // set new radians
302 hs_radians += hs_rinc;
303 if (hs_radians > hs_per*M_PI)
305 hs_rinc *= -1.0;
306 hs_radians += hs_rinc;
307 hs_flip *= -1.0;
309 else if (hs_radians < 0.0)
310 hsSetup();
313 void KBlobSaver::cbNextFrame()
315 int deviate;
317 // calculate deviation of circle main radius
318 deviate = (int)(sin(cb_sradians)*cb_deviate);
320 // calculate topleft of box as a circle with a sine perturbed radius
321 tx = (int)(cos(cb_radians)*(cb_radius+deviate))+xhalf;
322 ty = (int)(sin(cb_radians)*(cb_radius+deviate))+yhalf;
324 // draw the box
325 box(tx, ty);
327 // increase greater circle render angle
328 cb_radians += cb_rinc;
329 if (cb_radians > 2.0*M_PI)
330 cb_radians -= 2.0*M_PI;
332 // increase radius deviation offset on sine wave
333 cb_sradians += cb_devradinc;
336 void KBlobSaver::pcNextFrame()
338 static float scale = (float)height()/3.0 - 4.0*dim;
340 // simple polar coordinate equation
341 if (pc_div < 1.0)
342 pc_radius = cos(2.0*pc_angle);
343 else
344 pc_radius = 1.0/pc_div + cos(2.0*pc_angle);
346 tx = (int)(scale*pc_radius*cos(pc_angle+pc_crot))+xhalf;
347 ty = (int)(scale*pc_radius*sin(pc_angle+pc_crot))+yhalf;
349 // advance blob painter
350 box(tx, ty);
352 // new movement parameters
353 pc_angle += pc_inc;
354 if (pc_angle > 2.0*M_PI)
356 pc_angle -= 2.0*M_PI;
357 pc_crot += M_PI/45.0;
361 void KBlobSaver::box ( int x, int y )
363 // for bad behaving algorithms that wants to cause an X trap
364 // confine to the valid region before using potentially fatal XGetImage
365 if ((x+dim) >= width())
366 x = width()-dim-1;
367 else if (x < 0)
368 x = 0;
369 if ((y+dim) > height())
370 y = height()-dim-1;
371 else if (y < 0)
372 y = 0;
374 // get the box region from the display to upgrade
375 QImage img = QPixmap::grabWindow(winId(), x, y, dim, dim).convertToImage();
377 // depending on the depth of the display, use either lookup table for
378 // next rgb val ( 8-bit ) or ramp the color directly for other displays
379 if ( img.depth() == 8)
381 // manipulate image by upgrading each pixel with 1 using a lookup
382 // table as the color allocation could have resulted in a spread out
383 // configuration of the color ramp
384 for (int j = 0; j < img.height(); j++)
386 for (int i = 0; i < img.width(); i++)
388 img.scanLine(j)[i] = lookup[img.scanLine(j)[i]];
392 else
394 for (int j = 0; j < img.height(); j++)
396 for (int i = 0; i < img.width(); i++)
398 QRgb p = img.pixel( i, j );
399 p += (colorInc<<18);
400 img.setPixel( i, j, p );
405 // put the image back onto the screen
406 QPainter p(this);
407 p.drawImage( x, y, img );
410 void KBlobSaver::blank()
412 setBackgroundColor( black );
413 erase();
416 void KBlobSaver::readSettings()
418 KConfig *config = KGlobal::config();
419 config->setGroup("Settings");
421 // number of seconds to spend on a frame
422 showlen = config->readNumEntry("Showtime", 3*60);
424 // algorithm to use. if not set then use random
425 alg = config->readNumEntry("Algorithm", ALG_RANDOM);
426 if (alg == ALG_RANDOM)
427 newalg = 1;
428 else
429 newalg = 2;
430 newalgp = newalg;
433 //-----------------------------------------------------------------------------
434 // dialog to setup screen saver parameters
436 KBlobSetup::KBlobSetup
438 QWidget *parent,
439 const char *name
441 : KDialogBase( parent, name, true, i18n( "Setup Blob Screen Saver" ),
442 Ok|Cancel|Help, Ok, true )
445 initAlg();
447 // get saver configuration from kde registry
448 readSettings();
450 setButtonText( Help, i18n( "A&bout" ) );
451 QWidget *main = makeMainWidget();
453 QHBoxLayout *tl = new QHBoxLayout( main, 0, spacingHint() );
455 QVBoxLayout *vbox = new QVBoxLayout;
456 tl->addLayout(vbox);
458 // seconds to generate on a frame
459 QLabel *label = new QLabel(i18n("Frame duration:"), main);
460 stime = new KIntNumInput( showtime, main );
461 stime->setSuffix( i18n( " sec" ) );
462 vbox->addWidget(label);
463 vbox->addWidget(stime);
465 // available algorithms
466 label = new QLabel(i18n("Algorithm:"), main);
467 algs = new Q3ListBox(main);
468 algs->setMinimumSize(150, 105);
469 for (int i = 0; i <= ALG_RANDOM; i++)
470 algs->insertItem(alg_str[i]);
471 algs->setCurrentItem(alg);
472 vbox->addWidget(label);
473 vbox->addWidget(algs);
475 // preview window
476 QWidget *preview = new QWidget( main );
477 preview->setFixedSize(220, 170);
478 preview->setBackgroundColor(black);
479 preview->show();
480 tl->addWidget(preview);
481 saver = new KBlobSaver(preview->winId());
482 saver->setDimension(3);
483 if (QPixmap::defaultDepth() > 8)
484 saver->setColorInc(7);
485 else
486 saver->setColorInc(4);
488 tl->addStretch();
490 // so selecting an algorithm will start previewing that alg
491 connect(algs, SIGNAL(highlighted(int)), saver,
492 SLOT(setAlgorithm(int)));
495 void KBlobSetup::readSettings()
497 KConfig *config = KGlobal::config();
498 config->setGroup("Settings");
500 // number of seconds to spend on a frame
501 showtime = config->readNumEntry("Showtime", 3*60);
503 // algorithm to use. if not set then use random
504 alg = config->readNumEntry("Algorithm", ALG_LAST);
507 // Ok pressed - save settings and exit
508 void KBlobSetup::slotOk()
510 KConfig *config = KGlobal::config();
512 config->setGroup("Settings");
514 config->writeEntry("Showtime", stime->value());
515 config->writeEntry("Algorithm", algs->currentItem());
517 config->sync();
519 accept();
522 void KBlobSetup::slotHelp()
524 KMessageBox::about(this,
525 i18n("Blobsaver Version 0.1\n\nWritten by Tiaan Wessels 1997\ntiaan@netsys.co.za"));
526 if (saver)
527 saver->setAlgorithm(algs->currentItem());