diff options
Diffstat (limited to 'kscreensaver/kdesavers/blob.cpp')
-rw-r--r-- | kscreensaver/kdesavers/blob.cpp | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/kscreensaver/kdesavers/blob.cpp b/kscreensaver/kdesavers/blob.cpp new file mode 100644 index 00000000..e717c7ee --- /dev/null +++ b/kscreensaver/kdesavers/blob.cpp @@ -0,0 +1,527 @@ +//----------------------------------------------------------------------------- +// +// kblob - Basic screen saver for KDE +// +// Copyright (c) Tiaan Wessels, 1997 +// +// To add new alg : +// - add blob_alg enum in blob.h before ALG_LAST +// - choose 2 letter prefix for alg and add vars needed to private vars +// in KBlobSaver in blob.h +// - add xxSetup and xxNextFrame method definitions in blob.h +// - implement methods in this file. xxSetup to init vars mentioned +// in step 2. xxNextFrame to advance blob painter ( calc tx,ty and +// use box() method to position painter +// - add descriptive string in alg_str array in this file before "Random" +// - add to Algs array in KBlobSaver constructor in this file +// - test by setup saver and choosing alg from list + +#include <config.h> +#include <stdlib.h> +#include <time.h> +#include <limits.h> +#include <math.h> + +#include <qcolor.h> +#include <qlabel.h> +#include <qlistbox.h> +#include <qlayout.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qimage.h> + +#include <kapplication.h> +#include <kconfig.h> +#include <kmessagebox.h> +#include <knuminput.h> +#include <klocale.h> +#include <kglobal.h> +#include <krandomsequence.h> + +#include "blob.moc" +#include "blob.h" + +#define SMALLRAND(a) (int)(rnd->getLong(a)+1) + + +// libkscreensaver interface +extern "C" +{ + KDE_EXPORT const char *kss_applicationName = "kblob.kss"; + KDE_EXPORT const char *kss_description = I18N_NOOP( "KBlob" ); + KDE_EXPORT const char *kss_version = "2.2.0"; + + KDE_EXPORT KScreenSaver *kss_create( WId id ) + { + return new KBlobSaver( id ); + } + + KDE_EXPORT QDialog *kss_setup() + { + return new KBlobSetup(); + } +} + +static KRandomSequence *rnd = 0; + +QString alg_str[5]; +void initAlg() +{ + alg_str[0] = i18n("Random Linear"); + alg_str[1] = i18n("Horizontal Sine"); + alg_str[2] = i18n("Circular Bounce"); + alg_str[3] = i18n("Polar Coordinates"); + alg_str[4] = i18n("Random"); +} + +//----------------------------------------------------------------------------- +// the blob screensaver's code + +KBlobSaver::KBlobSaver ( WId id) + : KScreenSaver( id ) +{ + rnd = new KRandomSequence(); + initAlg(); + QColor color; + float ramp = (256.0-64.0)/(float)RAMP; + QString msg = + i18n("This screen saver requires a color display."); + + blank(); + + // needs colors to work this one + if (QPixmap::defaultDepth() < 8) + { + QPainter p(this); + p.setPen( white ); + p.drawText( width()/2, height()/2, msg ); + return; + } + + colorContext = QColor::enterAllocContext(); + + // if 8-bit, create lookup table for color ramping further down + if (QPixmap::defaultDepth() == 8) + { + memset(lookup, 0, 256*sizeof(uint)); + int i; + for (i = 0; i < RAMP; i++) + { + color.setRgb(64+(int)(ramp*(float)i), 0, 0); + colors[i] = color.alloc(); + } + memset(lookup, black.pixel(), sizeof(uint)*256); + for (i = 0; i < RAMP-1; i++) + lookup[colors[i]] = colors[i+1]; + lookup[black.pixel()] = lookup[colors[RAMP-1]] = colors[0]; + } + else + { + // make special provision for preview mode + if (height() < 400) + { + if (QPixmap::defaultDepth() > 8 ) + setColorInc(7); + else + setColorInc(4); + } + else + { + if (QPixmap::defaultDepth() > 8 ) + setColorInc(3); + else + setColorInc(2); + } + } + + // the dimensions of the blob painter + dim = height()/70+1; + + // record starting time to know when to change frames + start = time(NULL); + + // init some parameters used by all algorithms + xhalf = width()/2; + yhalf = height()/2; + + // means a new algorithm should be set at entrance of timer + newalg = newalgp = 1; + + // init algorithm space + Algs[0].Name = alg_str[0]; + Algs[0].Init = &KBlobSaver::lnSetup; + Algs[0].NextFrame = &KBlobSaver::lnNextFrame; + + Algs[1].Name = alg_str[1]; + Algs[1].Init = &KBlobSaver::hsSetup; + Algs[1].NextFrame = &KBlobSaver::hsNextFrame; + + Algs[2].Name = alg_str[2]; + Algs[2].Init = &KBlobSaver::cbSetup; + Algs[2].NextFrame = &KBlobSaver::cbNextFrame; + + Algs[3].Name = alg_str[3]; + Algs[3].Init = &KBlobSaver::pcSetup; + Algs[3].NextFrame = &KBlobSaver::pcNextFrame; + + // get setup from kde registry + readSettings(); + + // start timer which will update blob painter + timer.start(SPEED); + connect(&timer, SIGNAL(timeout()), SLOT(slotTimeout())); +} + +KBlobSaver::~KBlobSaver() +{ + timer.stop(); + + QColor::leaveAllocContext(); + QColor::destroyAllocContext(colorContext); + delete rnd; rnd = 0; +} + +void KBlobSaver::setAlgorithm(int a) +{ + newalg = newalgp = ((a == ALG_RANDOM) ? 1 : 2); + alg = a; +} + +void KBlobSaver::lnSetup() +{ + // initialize the blob movement dictators with random vals + // incrementals on axis + ln_xinc = SMALLRAND(3); + ln_yinc = SMALLRAND(2); + + // start position + tx = SMALLRAND(width()-dim-ln_xinc*2); + ty = SMALLRAND(height()-dim-ln_yinc*2); +} + +void KBlobSaver::hsSetup() +{ + hs_per = SMALLRAND(7); + hs_radians = 0.0; + hs_rinc = (hs_per*M_PI)/(hs_per*90*4); + hs_flip = 1.0; +} + +void KBlobSaver::cbSetup() +{ + cb_radians = 0.0; + cb_rinc = (2.0*M_PI)/360.0; + cb_sradians = 0.0; + cb_deviate = SMALLRAND(height()/20)+(height()/15); + cb_radius = height()/2-cb_deviate*2-2*dim; + cb_devradinc = (rnd->getDouble()*10.0*2.0*M_PI)/360.0; +} + +void KBlobSaver::pcSetup() +{ + pc_angle = 0.0; + pc_radius = 0.0; + pc_inc = (2.0*M_PI)/720.0; + pc_crot = 0.0; + pc_div = SMALLRAND(4)-1; +} + +// render next frame ( or change algorithms ) +void KBlobSaver::slotTimeout() +{ + time_t now = time(NULL); + + // should algorithm be changed + if (now-start > showlen) + newalg = newalgp; + + // set new algorithm + if (newalg) + { + blank(); + if (newalg == 1) + alg = SMALLRAND(ALG_LAST)-1; + (this->*Algs[alg].Init)(); + newalg = 0; + start = time(NULL); + } + + // gen next fram for current algorithm + (this->*Algs[alg].NextFrame)(); +} + +void KBlobSaver::lnNextFrame() +{ + int dir; + + // depending on the algorithm to use, move the blob painter to + // a new location + // check for wall hit to change direction + if (tx+dim+ln_xinc > (int)width()-1 || tx+ln_xinc < 0) + { + if (ln_xinc > 0) + dir = -1; + else + dir = 1; + ln_xinc = SMALLRAND(3)*dir; + } + if (ty+dim+ln_yinc > (int)height()-1 || ty+ln_yinc < 0) + { + if (ln_yinc > 0) + dir = -1; + else + dir = 1; + ln_yinc = SMALLRAND(2)*dir; + } + + // move box to new position + tx += ln_xinc; + ty += ln_yinc; + + // draw new box + box(tx, ty); +} + +void KBlobSaver::hsNextFrame() +{ + static int xlen = width()-(4*dim); + static int ylen = height()-(4*dim); + + // calc x as offset on angle line and y as vertical offset + // on interval -1..1 sine of angle + tx = (int)((hs_radians/(hs_per*M_PI))*(float)xlen); + ty = (int)((float)(ylen/4)*(hs_flip*sin(hs_radians)))+yhalf; + + // draw new box + box(tx, ty); + + // set new radians + hs_radians += hs_rinc; + if (hs_radians > hs_per*M_PI) + { + hs_rinc *= -1.0; + hs_radians += hs_rinc; + hs_flip *= -1.0; + } + else if (hs_radians < 0.0) + hsSetup(); +} + +void KBlobSaver::cbNextFrame() +{ + int deviate; + + // calculate deviation of circle main radius + deviate = (int)(sin(cb_sradians)*cb_deviate); + + // calculate topleft of box as a circle with a sine perturbed radius + tx = (int)(cos(cb_radians)*(cb_radius+deviate))+xhalf; + ty = (int)(sin(cb_radians)*(cb_radius+deviate))+yhalf; + + // draw the box + box(tx, ty); + + // increase greater circle render angle + cb_radians += cb_rinc; + if (cb_radians > 2.0*M_PI) + cb_radians -= 2.0*M_PI; + + // increase radius deviation offset on sine wave + cb_sradians += cb_devradinc; +} + +void KBlobSaver::pcNextFrame() +{ + static float scale = (float)height()/3.0 - 4.0*dim; + + // simple polar coordinate equation + if (pc_div < 1.0) + pc_radius = cos(2.0*pc_angle); + else + pc_radius = 1.0/pc_div + cos(2.0*pc_angle); + + tx = (int)(scale*pc_radius*cos(pc_angle+pc_crot))+xhalf; + ty = (int)(scale*pc_radius*sin(pc_angle+pc_crot))+yhalf; + + // advance blob painter + box(tx, ty); + + // new movement parameters + pc_angle += pc_inc; + if (pc_angle > 2.0*M_PI) + { + pc_angle -= 2.0*M_PI; + pc_crot += M_PI/45.0; + } +} + +void KBlobSaver::box ( int x, int y ) +{ + // for bad behaving algorithms that wants to cause an X trap + // confine to the valid region before using potentially fatal XGetImage + if ((x+dim) >= width()) + x = width()-dim-1; + else if (x < 0) + x = 0; + if ((y+dim) > height()) + y = height()-dim-1; + else if (y < 0) + y = 0; + + // get the box region from the display to upgrade + QImage img = QPixmap::grabWindow(winId(), x, y, dim, dim).convertToImage(); + + // depending on the depth of the display, use either lookup table for + // next rgb val ( 8-bit ) or ramp the color directly for other displays + if ( img.depth() == 8) + { + // manipulate image by upgrading each pixel with 1 using a lookup + // table as the color allocation could have resulted in a spread out + // configuration of the color ramp + for (int j = 0; j < img.height(); j++) + { + for (int i = 0; i < img.width(); i++) + { + img.scanLine(j)[i] = lookup[img.scanLine(j)[i]]; + } + } + } + else + { + for (int j = 0; j < img.height(); j++) + { + for (int i = 0; i < img.width(); i++) + { + QRgb p = img.pixel( i, j ); + p += (colorInc<<18); + img.setPixel( i, j, p ); + } + } + } + + // put the image back onto the screen + QPainter p(this); + p.drawImage( x, y, img ); +} + +void KBlobSaver::blank() +{ + setBackgroundColor( black ); + erase(); +} + +void KBlobSaver::readSettings() +{ + KConfig *config = KGlobal::config(); + config->setGroup("Settings"); + + // number of seconds to spend on a frame + showlen = config->readNumEntry("Showtime", 3*60); + + // algorithm to use. if not set then use random + alg = config->readNumEntry("Algorithm", ALG_RANDOM); + if (alg == ALG_RANDOM) + newalg = 1; + else + newalg = 2; + newalgp = newalg; +} + +//----------------------------------------------------------------------------- +// dialog to setup screen saver parameters +// +KBlobSetup::KBlobSetup +( + QWidget *parent, + const char *name +) +: KDialogBase( parent, name, true, i18n( "Setup Blob Screen Saver" ), + Ok|Cancel|Help, Ok, true ) +{ + + initAlg(); + + // get saver configuration from kde registry + readSettings(); + + setButtonText( Help, i18n( "A&bout" ) ); + QWidget *main = makeMainWidget(); + + QHBoxLayout *tl = new QHBoxLayout( main, 0, spacingHint() ); + + QVBoxLayout *vbox = new QVBoxLayout; + tl->addLayout(vbox); + + // seconds to generate on a frame + QLabel *label = new QLabel(i18n("Frame duration:"), main); + stime = new KIntNumInput( showtime, main ); + stime->setSuffix( i18n( " sec" ) ); + vbox->addWidget(label); + vbox->addWidget(stime); + + // available algorithms + label = new QLabel(i18n("Algorithm:"), main); + algs = new QListBox(main); + algs->setMinimumSize(150, 105); + for (int i = 0; i <= ALG_RANDOM; i++) + algs->insertItem(alg_str[i]); + algs->setCurrentItem(alg); + vbox->addWidget(label); + vbox->addWidget(algs); + + // preview window + QWidget *preview = new QWidget( main ); + preview->setFixedSize(220, 170); + preview->setBackgroundColor(black); + preview->show(); + tl->addWidget(preview); + saver = new KBlobSaver(preview->winId()); + saver->setDimension(3); + if (QPixmap::defaultDepth() > 8) + saver->setColorInc(7); + else + saver->setColorInc(4); + + tl->addStretch(); + + // so selecting an algorithm will start previewing that alg + connect(algs, SIGNAL(highlighted(int)), saver, + SLOT(setAlgorithm(int))); +} + +void KBlobSetup::readSettings() +{ + KConfig *config = KGlobal::config(); + config->setGroup("Settings"); + + // number of seconds to spend on a frame + showtime = config->readNumEntry("Showtime", 3*60); + + // algorithm to use. if not set then use random + alg = config->readNumEntry("Algorithm", ALG_LAST); +} + +// Ok pressed - save settings and exit +void KBlobSetup::slotOk() +{ + KConfig *config = KGlobal::config(); + + config->setGroup("Settings"); + + config->writeEntry("Showtime", stime->value()); + config->writeEntry("Algorithm", algs->currentItem()); + + config->sync(); + + accept(); +} + +void KBlobSetup::slotHelp() +{ + KMessageBox::about(this, + i18n("Blobsaver Version 0.1\n\nWritten by Tiaan Wessels 1997\[email protected]")); + if (saver) + saver->setAlgorithm(algs->currentItem()); +} + + |