• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kgoldrunner

kgrcanvas.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           kgrcanvas.cpp  -  description
00003                              -------------------
00004     begin                : Wed Jan 23 2002
00005     Copyright 2002 Marco Krüger <grisuji@gmx.de>
00006     Copyright 2002 Ian Wadham <ianw2@optusnet.com.au>
00007 ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "kgrcanvas.h"
00019 #include "klocale.h"
00020 
00021 #include <QPixmap>
00022 #include <QList>
00023 #include <QLabel>
00024 #include <QMouseEvent>
00025 
00026 #include <KDebug>
00027 
00028 #include <KConfig>
00029 
00030 #include <cmath>
00031 
00032 
00033 // Helper function: find how many tiles are needed to cover at least w pixels
00034 static int numSections(int w, int sectionWidth)
00035 {
00036     return 1 + w / sectionWidth; 
00037 }
00038 
00039 static QString scoreText(int score) 
00040 {
00041     return ki18n ("Score: ").toString() + QString::number(score).rightJustified(7, '0');
00042 }
00043 
00044 static QString livesText(int lives) 
00045 {
00046     return ki18n ("Lives: ").toString() + QString::number(lives).rightJustified(3, '0');
00047 }
00048 
00049 KGrCanvas::KGrCanvas (QWidget * parent, const double scale,
00050                         const QString & systemDataDir)
00051                         : KGameCanvasWidget (parent),
00052                           firstSceneDrawn (false),
00053                           topLeft (0, 0), bgw (4 * STEP), bgh (4 * STEP),
00054                           m_scoreText(0),
00055                           m_livesText(0),
00056                           m_scoreDisplay(0),
00057                           m_livesDisplay(0),
00058                           m_fadingTimeLine (1000, this),
00059                           theme (systemDataDir)
00060 
00061 {
00062     resizeCount = 0;        // IDW
00063 
00064     kDebug() << "Called KGrCanvas::KGrCanvas ..." << this->size();
00065     m = new QCursor();      // For handling the mouse.
00066 
00067     // The default background is black.  It appears during partial repaints.
00068     setPalette (QPalette (Qt::black));
00069     setAutoFillBackground (true);
00070 
00071     scaleStep = STEP;       // Initial scale is 1:1.
00072     baseScale = scaleStep;
00073     baseFontSize = fontInfo().pointSize() + 2;
00074     scaleStep = (int) ((scale * STEP) + 0.05);
00075     kDebug() << "Scale" << scale << "Scaled Step" << scaleStep;
00076 
00077     nCellsW = FIELDWIDTH;
00078     nCellsH = FIELDHEIGHT;
00079     border = 4;         // Make border at least tiles wide all around.
00080     lineDivider = 8;        // Make lines of inner border 1/8 tile wide.
00081 
00082     heroSprite = 0;
00083 
00084     // Create an empty list of enemy sprites.
00085     enemySprites = new QList<KGrSprite *>();
00086 
00087     kDebug() << "Calling initView() ...";
00088     initView();         // Set up the graphics, etc.
00089 
00090     // Initialise the KGoldrunner grid.
00091     unsigned int seed = 42;
00092     for (int x = 0; x < FIELDWIDTH; x++) {
00093     for (int y = 0; y < FIELDHEIGHT; y++) {
00094         tileNo[x][y] = KGrTheme::EmptyTile;
00095         randomOffsets[x][y] = rand_r (&seed);
00096     }
00097     }
00098 
00099     title = 0;
00100     level = 0;
00101 
00102     // Set minimum size to 12x12 pixels per tile.
00103     setMinimumSize ((FIELDWIDTH + 4) * 12, (FIELDHEIGHT + 4) * 12);
00104 
00105     m_scoreText = new KGameCanvasText ("", Qt::white, QFont(), 
00106             KGameCanvasText::HLeft, KGameCanvasText::VTop, this);
00107     m_livesText = new KGameCanvasText ("", Qt::white, QFont(), 
00108             KGameCanvasText::HRight, KGameCanvasText::VTop, this);
00109 
00110     m_spotLight = new KGameCanvasPicture (this);
00111     m_fadingTimeLine.setCurveShape (QTimeLine::LinearCurve);
00112     m_fadingTimeLine.setUpdateInterval (60);
00113     connect (&m_fadingTimeLine, SIGNAL (valueChanged (qreal)),
00114                 this, SLOT (drawSpotLight (qreal)));
00115     connect (&m_fadingTimeLine, SIGNAL (finished()),
00116                 this, SIGNAL (fadeFinished()));
00117 }
00118 
00119 KGrCanvas::~KGrCanvas()
00120 {
00121     tileset->clear();
00122     heroFrames->clear();
00123     enemyFrames->clear();
00124     delete tileset;
00125     delete heroFrames;
00126     delete enemyFrames;
00127     delete m_spotLight;
00128     delete m;
00129 }
00130 
00131 
00132 void KGrCanvas::goToBlack()
00133 {
00134         drawSpotLight (0);
00135 }
00136 
00137 void KGrCanvas::fadeIn()
00138 {
00139         m_fadingTimeLine.setDirection (QTimeLine::Forward);
00140         m_fadingTimeLine.start();
00141 }
00142 
00143 void KGrCanvas::fadeOut()
00144 {
00145         m_fadingTimeLine.setDirection (QTimeLine::Backward);
00146         m_fadingTimeLine.start();
00147 }
00148 
00149 void KGrCanvas::drawTheScene (bool changePixmaps)
00150 {
00151     t.restart();
00152     kDebug() << 0 << "msec.  Start drawTheScene";
00153 
00154     // The pixmaps for tiles and sprites have to be re-loaded
00155     // if and only if the theme or the cell size has changed.
00156 
00157     // The background has to be re-loaded if the theme has
00158     // changed, the cell size has changed or the canvas size
00159     // has changed and the bg must fill it (! themeDrawBorder).
00160 
00161     double scale = (double) imgW / (double) bgw;
00162     kDebug() << "Images:" << imgW<<"x"<<imgH;
00163     if (imgW == 0) {
00164         return;
00165     }
00166 
00167     // Draw the tiles and background in the playfield.
00168     if (playfield) {
00169     loadBackground();
00170 
00171     if (changePixmaps) {
00172         tileset->clear();
00173 
00174         *tileset << theme.tiles (imgH);
00175     }
00176 
00177     // Now set our tileset in the scene.
00178     playfield->setTiles (tileset, topLeft, nCellsW, nCellsH, imgW, imgH);
00179 
00180     // Set each cell to same type of tile (i.e. tile-number) as before.
00181     for (int x = 0; x < FIELDWIDTH; x++) {
00182         for (int y = 0; y < FIELDHEIGHT; y++) {
00183         playfield->setTile (x, y, tileNumber(tileNo[x][y], x, y));
00184         }
00185     }
00186     }
00187     kDebug() << t.restart() << "msec.  Tiles + background done.";
00188 
00189     /* ******************************************************************** */
00190     /* The pixmaps for hero and enemies are arranged in strips of 36: walk  */
00191     /* right (8), walk left (8), climb right along bar (8), climb left (8), */
00192     /* climb up ladder (2) and fall (2) --- total 36.  The appendFrames()   */
00193     /* method extracts the frames from the strip, scales                    */
00194     /* them and adds them to a list of frames (QPixmaps).                   */
00195     /* ******************************************************************** */
00196 
00197     if (changePixmaps) {
00198         heroFrames->clear();
00199         enemyFrames->clear();
00200 
00201         *heroFrames << theme.hero (imgH);
00202         *enemyFrames << theme.enemy (imgH);
00203     }
00204     kDebug() << t.restart() << "msec.  Hero + enemies done.";
00205 
00206     int spriteframe;
00207     QPoint spriteloc;
00208 
00209     // Draw the hero.
00210     if (heroSprite) {
00211         spriteframe = heroSprite->currentFrame();
00212         spriteloc = heroSprite->currentLoc();
00213         heroSprite->addFrames (heroFrames, topLeft, scale);
00214 
00215         // Force a re-draw of both pixmap and position.
00216         heroSprite->move (0, 0, (spriteframe > 0) ? 0 : 1);
00217         heroSprite->move (spriteloc.x(), spriteloc.y(), spriteframe);
00218     }
00219 
00220     if (enemySprites) {
00221         for (int i = 0; i < enemySprites->size(); ++i) {
00222             // kDebug() << "accessing enemySprite" << i;
00223             KGrSprite * thisenemy = enemySprites->at (i);
00224             if (thisenemy) {
00225                 spriteframe = thisenemy->currentFrame();
00226                 spriteloc = thisenemy->currentLoc();
00227                 thisenemy->addFrames (enemyFrames, topLeft, scale);
00228 
00229                 // Force re-draw of both pixmap and position.
00230                 thisenemy->move (0, 0, (spriteframe > 0) ? 0 : 1);
00231                 thisenemy->move (spriteloc.x(), spriteloc.y(), spriteframe);
00232             }
00233         }
00234     }
00235     kDebug() << t.restart() << "msec.  Finished drawTheScene.";
00236 
00237     // Recreate the border.
00238     makeBorder();
00239 
00240     // Force the title size and position to be re-calculated.
00241     QString t = title->text();
00242     makeTitle();
00243     setTitle (t);
00244 
00245     // Create and position the score and lives text areas
00246     QFont f;
00247     f.setPixelSize (imgH - 2);
00248     f.setWeight (QFont::Bold);
00249     f.setStretch (QFont::Expanded);
00250     m_scoreText->setFont (f);
00251     m_scoreText->setColor (theme.textColor());
00252     int vTextPos = (1 + imgH) * nCellsH + 1;
00253     QPoint scorePos = topLeft + QPoint (imgW, vTextPos);
00254 
00255     m_livesText->setFont (f);
00256     m_livesText->setColor (theme.textColor());
00257     QPoint livesPos = topLeft + QPoint (imgW * (nCellsW - 1), vTextPos);
00258     QList< QPixmap > display = theme.displayTiles (imgW);
00259     delete m_scoreDisplay; m_scoreDisplay = 0;
00260     delete m_livesDisplay; m_livesDisplay = 0;
00261     // If the theme has display decoration support
00262     if (!display.isEmpty()) {
00263         QFontMetrics fm (f);
00264         int w = fm.width (scoreText (0));
00265         m_scoreDisplay = makeDisplay (display, w);
00266         m_scoreDisplay->moveTo (scorePos + QPoint (-imgW, 0));
00267         int sections = numSections (w, imgW);
00268         // Adjust score position to center them in the display
00269         int deltaW = (sections * imgW - w) / 2;
00270         scorePos.rx() += deltaW;
00271         w = fm.width(livesText(0));
00272         m_livesDisplay = makeDisplay (display, w);
00273         sections = numSections (w, imgW);
00274         m_livesDisplay->moveTo (livesPos + QPoint (-(sections + 1) * imgW, 0));
00275         // Adjust lives position to center them in the display
00276         deltaW = (sections * imgW - w) / 2;
00277         livesPos.rx() -= deltaW;
00278     }
00279     m_scoreText->moveTo (scorePos);
00280     m_livesText->moveTo (livesPos);
00281     m_scoreText->show();
00282     m_scoreText->raise();
00283     m_livesText->show();
00284     m_livesText->raise();
00285 
00286     // When the initial resizing, rendering and painting has been done,
00287     // future resizes and re-rendering will be caused by end-user activity.
00288     firstSceneDrawn = true;
00289 }
00290 
00291 bool KGrCanvas::changeTheme (const QString & themeFilepath)
00292 {
00293     t.restart();
00294     kDebug() << 0 << "msec.  New Theme -" << themeFilepath;
00295     bool success = theme.load (themeFilepath);
00296     kDebug() << t.restart() << "msec.  Finish loading new theme.";
00297     if (success) {
00298         // Use the border color to fill empty rectangles during partial
00299         // repaints and soften their contrast with the rest of the picture.
00300         setPalette (QPalette (theme.borderColor()));
00301         setAutoFillBackground (true);
00302 
00303         const bool changePixmaps = true;
00304         drawTheScene (changePixmaps);
00305     }
00306     return success;
00307 }
00308 
00309 void KGrCanvas::resizeEvent (QResizeEvent * event)
00310 {
00311     resizeCount++;
00312     kDebug()<< "RESIZE:" << resizeCount << event->size() <<
00313         "Resize pending?" << QWidget::testAttribute (Qt::WA_PendingResizeEvent)
00314         << "Spontaneous?" << event->spontaneous();
00315     
00316     double w = (double) event->size().width()  / (nCellsW + border);
00317     double h = (double) event->size().height() / (nCellsH + border);
00318     int cellSize = (w < h) ? (int) (w + 0.05) : (int) (h + 0.05);
00319 
00320     imgW = cellSize;
00321     imgH = cellSize;
00322     topLeft.setX ((event->size().width()  - (nCellsW * imgW)) / 2);
00323     topLeft.setY ((event->size().height() - (nCellsH * imgH)) / 2);
00324 
00325     bool changePixmaps = ((imgW != oldImgW) || (imgH != oldImgH));
00326     oldImgW = imgW;
00327     oldImgH = imgH;
00328 
00329     // The first 1, 2 or 3 resize events are caused by KMainWindow and friends,
00330     // so do not re-scale, render-SVG or re-draw until they are over.  After
00331     // that, any resize events are caused by the end-user and we must re-scale,
00332     // render-SVG and re-draw each time.
00333     if (firstSceneDrawn) {
00334         drawTheScene (changePixmaps);
00335         QWidget::resizeEvent (event);
00336     }
00337 }
00338 
00339 KGrTheme::TileType KGrCanvas::tileForType(char type)
00340 {
00341     switch (type) {
00342     case NUGGET:
00343     return KGrTheme::GoldTile;
00344     case POLE:
00345     return KGrTheme::BarTile;
00346     case LADDER:
00347     return KGrTheme::LadderTile;
00348     case HLADDER:
00349     return KGrTheme::HiddenLadderTile;
00350     case HERO:
00351     return KGrTheme::HeroTile;
00352     case ENEMY:
00353     return KGrTheme::EnemyTile;
00354     case BETON:
00355     return KGrTheme::ConcreteTile;
00356     case BRICK:
00357     return KGrTheme::BrickTile;
00358     case FBRICK:
00359     return KGrTheme::FalseBrickTile;
00360     case FREE:
00361     default:
00362     return KGrTheme::EmptyTile;
00363     }
00364 }
00365 
00366 int KGrCanvas::tileNumber (KGrTheme::TileType type, int x, int y)
00367 {
00368     // For Multiple block variant theming, the actual tile is chosen between
00369     // the available tiles provided, by using x and y coordinates to produce a
00370     // pseudorandom pattern.
00371     // However, we cannot do that for the brick digging sequence, so this is a
00372     // special case.
00373     const int offset = type - KGrTheme::BrickAnimation1Tile;
00374     const int count = theme.tileCount (KGrTheme::BrickAnimation1Tile);
00375 
00376     if (offset >= 0 && offset < count) {
00377     // Offsets 1-9 are for digging sequence.
00378     return theme.firstTile (KGrTheme::BrickAnimation1Tile) + offset;
00379     } 
00380     else {
00381     int number = theme.firstTile (type);
00382     int c = theme.tileCount (type);
00383     if (c > 1) {
00384         return number + (randomOffsets[x][y] % c);
00385     } 
00386     else {
00387         return theme.firstTile (type);
00388     }
00389     }
00390 }
00391 
00392 void KGrCanvas::paintCell (int x, int y, char type, int offset)
00393 {
00394     KGrTheme::TileType tileType = tileForType (type);
00395     // In KGrGame, the top-left visible cell is [1,1]: in KGrPlayfield [0,0].
00396     x--; y--;
00397     switch (offset) {
00398     case 1: tileType = KGrTheme::BrickAnimation1Tile; break;
00399     case 2: tileType = KGrTheme::BrickAnimation2Tile; break;
00400     case 3: tileType = KGrTheme::BrickAnimation3Tile; break;
00401     case 4: tileType = KGrTheme::BrickAnimation4Tile; break;
00402     case 5: tileType = KGrTheme::BrickAnimation5Tile; break;
00403     case 6: tileType = KGrTheme::BrickAnimation6Tile; break;
00404     case 7: tileType = KGrTheme::BrickAnimation7Tile; break;
00405     case 8: tileType = KGrTheme::BrickAnimation8Tile; break;
00406     case 9: tileType = KGrTheme::BrickAnimation9Tile; break;
00407     case 0:
00408     default:
00409     break;
00410     }
00411 
00412     tileNo [x][y] = tileType;           // Save the tile-number for repaint.
00413 
00414     playfield->setTile (x, y, tileNumber (tileType, x, y)); // Paint with required pixmap.
00415 }
00416 
00417 void KGrCanvas::setBaseScale()
00418 {
00419     // Synchronize the desktop font size with the initial canvas scale.
00420     baseScale = scaleStep;
00421     QString t = "";
00422     if (title) {
00423         t = title->text();
00424     }
00425     makeTitle();
00426     setTitle (t);
00427 }
00428 
00429 void KGrCanvas::setTitle (const QString &newTitle)
00430 {
00431     title->setText (newTitle);
00432 }
00433 
00434 void KGrCanvas::makeTitle()
00435 {
00436     if (title != 0)
00437         title->close();         // Close and delete previous title.
00438 
00439     title = new QLabel ("", this);
00440     int lw = imgW / lineDivider;    // Line width (as used in makeBorder()).
00441     title->resize (width(), topLeft.y() - lw);
00442     title->move (0, 0);
00443     QPalette palette;
00444     palette.setColor (title->backgroundRole(), theme.borderColor());
00445     palette.setColor (title->foregroundRole(), theme.textColor());
00446     title->setPalette (palette);
00447     title->setFont (QFont (fontInfo().family(),
00448                  (baseFontSize * scaleStep) / baseScale, QFont::Bold));
00449     title->setAlignment (Qt::AlignCenter);
00450     title->setAttribute (Qt::WA_QuitOnClose, false); //Otherwise the close above might exit app
00451     title->raise();
00452     title->show();
00453 }
00454 
00455 void KGrCanvas::updateScore (int score)
00456 {
00457     if (m_scoreText) 
00458         m_scoreText->setText (scoreText(score));
00459 }
00460 
00461 void KGrCanvas::updateLives (int lives)
00462 {
00463     // TODO use hero frames to show the lives?
00464     if (m_livesText) 
00465         m_livesText->setText (livesText(lives));
00466 }
00467 
00468 void KGrCanvas::mousePressEvent (QMouseEvent * mouseEvent)
00469 {
00470     emit mouseClick (mouseEvent->button());
00471 }
00472 
00473 void KGrCanvas::mouseReleaseEvent (QMouseEvent * mouseEvent)
00474 {
00475     emit mouseLetGo (mouseEvent->button());
00476 }
00477 
00478 QPoint KGrCanvas::getMousePos()
00479 {
00480     int i, j;
00481     QPoint p = mapFromGlobal (m->pos());
00482 
00483     // In KGoldrunner, the top-left visible cell is [1,1]: in KGrSprite [0,0].
00484     i = ((p.x() - topLeft.x()) / imgW) + 1;
00485     j = ((p.y() - topLeft.y()) / imgH) + 1;
00486 
00487     return (QPoint (i, j));
00488 }
00489 
00490 void KGrCanvas::setMousePos (int i, int j)
00491 {
00492     // In KGoldrunner, the top-left visible cell is [1,1]: in KGrSprite [0,0].
00493     i--; j--;
00494     m->setPos (mapToGlobal (QPoint (
00495                                 topLeft.x() + i * imgW + imgW / 2,
00496                                 topLeft.y() + j * imgH + imgH / 2)));
00497 }
00498 
00499 void KGrCanvas::makeHeroSprite (int i, int j, int startFrame)
00500 {
00501     heroSprite = new KGrSprite (this);
00502 
00503     double scale = (double) imgW / (double) bgw;
00504     heroSprite->addFrames (heroFrames, topLeft, scale);
00505 
00506     // In KGoldrunner, the top-left visible cell is [1,1]: in KGrSprite [0,0].
00507     i--; j--;
00508     heroSprite->move (i * bgw, j * bgh, startFrame);
00509     heroSprite->setZ (1);
00510     heroSprite->setVisible (true);
00511 }
00512 
00513 void KGrCanvas::setHeroVisible (bool newState)
00514 {
00515     heroSprite->setVisible (newState);      // Show or hide the hero.
00516 }
00517 
00518 void KGrCanvas::makeEnemySprite (int i, int j, int startFrame)
00519 {
00520     KGrSprite * enemySprite = new KGrSprite (this);
00521 
00522     double scale = (double) imgW / (double) bgw;
00523     enemySprite->addFrames (enemyFrames, topLeft, scale);
00524     enemySprites->append (enemySprite);
00525 
00526     // In KGoldrunner, the top-left visible cell is [1,1]: in KGrSprite [0,0].
00527     i--; j--;
00528     enemySprite->move (i * bgw, j * bgh, startFrame);
00529     enemySprite->setZ (2);
00530     enemySprite->show();
00531 }
00532 
00533 void KGrCanvas::moveHero (int x, int y, int frame)
00534 {
00535     // In KGoldrunner, the top-left visible cell is [1,1]: in KGrSprite [0,0].
00536     heroSprite->move (x - bgw, y - bgh, frame);
00537 }
00538 
00539 void KGrCanvas::moveEnemy (int id, int x, int y, int frame, int nuggets)
00540 {
00541     if (nuggets != 0) {             // If enemy is carrying gold,
00542         frame = frame + goldEnemy;      // show him with gold outline.
00543     }
00544 
00545     // In KGoldrunner, the top-left visible cell is [1,1]: in KGrSprite [0,0].
00546     // kDebug() << "accessing enemySprite" << id;
00547     enemySprites->at (id)->move (x - bgw, y - bgh, frame);
00548 }
00549 
00550 void KGrCanvas::deleteEnemySprites()
00551 {
00552     while (!enemySprites->isEmpty())
00553         delete enemySprites->takeFirst();
00554 }
00555 
00556 QPixmap KGrCanvas::getPixmap (char type)
00557 {
00558     return tileset->at (theme.firstTile(tileForType(type)));
00559 }
00560 
00561 void KGrCanvas::initView()
00562 {
00563     // Set default tile-size (if not played before or no KMainWindow settings).
00564     imgW = (bgw * scaleStep) / STEP;
00565     imgH = (bgh * scaleStep) / STEP;
00566     oldImgW = 0;
00567     oldImgH = 0;
00568 
00569     // Define the canvas as an array of tiles.  Default tile is 0 (free space).
00570     playfield = new KGrPlayField (this); // The drawing-area for the playfield.
00571     tileset     = new QList<QPixmap>(); // The tiles that can be set in there.
00572     heroFrames  = new QList<QPixmap>(); // Animation frames for the hero.
00573     enemyFrames = new QList<QPixmap>(); // Animation frames for enemies.
00574     goldEnemy = 36;         // Offset of gold-carrying frames.
00575 }
00576 
00577 void KGrCanvas::setLevel (unsigned int l)
00578 {
00579     if (l != level) {
00580         level= l;
00581         if (theme.backgroundCount() > 1) {
00582             loadBackground();
00583         }
00584     }
00585 }
00586 
00587 void KGrCanvas::loadBackground()
00588 {
00589     kDebug() << "loadBackground called";
00590     bool fillCanvas = !theme.isBorderRequired(); // Background must fill canvas?
00591     int w = fillCanvas ? (this->width())  : (nCellsW * imgW);
00592     int h = fillCanvas ? (this->height()) : (nCellsH * imgH);
00593     if (theme.backgroundCount() > 0) {
00594         QPixmap background = theme.background (w, h, level);
00595         playfield->setBackground (true, background, 
00596                 theme.isBorderRequired() ? topLeft : QPoint (0, 0));
00597     }
00598     else {
00599         playfield->setBackground (true, QPixmap(), 
00600                 theme.isBorderRequired() ? topLeft : QPoint (0, 0));
00601     }
00602 }
00603 
00604 void KGrCanvas::makeBorder ()
00605 {
00606     // Draw main part of border, in the order: top, bottom, left, right.
00607     // Allow some overlap to prevent slits appearing when resizing.
00608 
00609     colour = theme.borderColor();
00610     int cw = width();               // Size of canvas.
00611     int ch = width();
00612     int pw = nCellsW * imgW;            // Size of playfield.
00613     int ph = nCellsH * imgW;
00614     int tlX = topLeft.x();          // Top left of playfield.
00615     int tlY = topLeft.y();
00616     int lw = imgW / lineDivider;        // Line width.
00617 
00618     while (!borderRectangles.isEmpty())
00619     delete borderRectangles.takeFirst();
00620     while (!borderElements.isEmpty())
00621     delete borderElements.takeFirst();
00622 
00623     // a fancy border can be specified in the SVG file; if that is unavailable,
00624     // a simple border can be specified in the theme properties file.
00625     QList< QPixmap > l = theme.frameTiles (imgW);
00626     if (!l.isEmpty()) {
00627     kDebug() << "drawing the border tiles...";
00628     // Draw fancy border
00629     
00630     borderElements.append(makeBorderElement(l, tlX - imgW, tlY - imgW, 0));
00631     borderElements.append(makeBorderElement(l, tlX + pw, tlY - imgW, 2));
00632     borderElements.append(makeBorderElement(l, tlX - imgW, tlY + ph, 6));
00633     borderElements.append(makeBorderElement(l, tlX + pw, tlY + ph, 8));
00634     
00635     for (int i = 0; i < nCellsW * imgW; i += imgW) {
00636         borderElements.append(makeBorderElement(l, tlX + i, tlY - imgW, 1));
00637         borderElements.append(makeBorderElement(l, tlX + i, tlY + ph, 7));
00638     }
00639     for (int i = 0; i < nCellsH * imgH; i += imgH) {
00640         borderElements.append(makeBorderElement(l, tlX - imgW, tlY + i, 3));
00641         borderElements.append(makeBorderElement(l, tlX + pw, tlY + i, 5));
00642     }
00643     }
00644     else {
00645     kDebug() << "drawing the border rects...";
00646     KGameCanvasRectangle * nextRectangle;
00647 
00648     if (theme.isBorderRequired()) {
00649         nextRectangle = drawRectangle (0, 0, cw, tlY - lw);
00650         borderRectangles.append (nextRectangle);
00651         nextRectangle = drawRectangle (0, tlY + ph + lw,
00652                             cw, ch - tlY - ph - lw);
00653         borderRectangles.append (nextRectangle);
00654         nextRectangle = drawRectangle (0, tlY - lw, tlX - lw, ph + 2*lw);
00655         borderRectangles.append (nextRectangle);
00656         nextRectangle = drawRectangle (tlX + pw + lw, tlY - lw,
00657                             cw - tlX -pw - lw, ph + 2*lw);
00658         borderRectangles.append (nextRectangle);
00659     }
00660 
00661     // Draw the inside edges of the border, in the same way.
00662     colour = QColor (Qt::black);
00663 
00664     nextRectangle = drawRectangle (tlX - lw, tlY - lw, pw + 2*lw, lw);
00665     borderRectangles.append (nextRectangle);
00666     nextRectangle = drawRectangle (tlX - lw, ph + tlY, pw + 2*lw, lw);
00667     borderRectangles.append (nextRectangle);
00668     nextRectangle = drawRectangle (tlX - lw, tlY, lw, ph);
00669     borderRectangles.append (nextRectangle);
00670     nextRectangle = drawRectangle (tlX + pw, tlY, lw, ph);
00671     borderRectangles.append (nextRectangle);
00672     }
00673 }
00674 
00675 void KGrCanvas::drawSpotLight (qreal value)
00676 {
00677     static int count = 0;
00678     if (value > 0.99) {
00679         count = 0;
00680         // Hide the spotlight animation -- all scene visible
00681         m_spotLight->hide();
00682         m_spotLight->lower();
00683         return;
00684     }
00685     count++;
00686     m_spotLight->raise();
00687     m_spotLight->show();
00688     QPicture picture;
00689     qreal w = qreal (nCellsW * imgW);
00690     qreal h = qreal (nCellsH * imgW);
00691     qreal x = qreal (topLeft.x());
00692     qreal y = qreal (topLeft.y());
00693     qreal dh = 0.5 * std::sqrt (w * w + h * h);
00694 
00695     QPainter p;
00696     p.begin (&picture);
00697     if (value < 0.01) {
00698         // Draw a solid black background if the circle would be too small/
00699         p.fillRect (QRectF (x, y, w, h), QColor (0, 0, 0, 255));
00700     }
00701     else {
00702         static const qreal outerRatio = 1.00;
00703         static const qreal innerRatio = 0.85;
00704         static const qreal sqrt1_2 = 0.5 * std::sqrt ((double)2.0);
00705         qreal wh = w * 0.5;
00706         qreal hh = h * 0.5;
00707         qreal radius = dh * value;
00708         qreal innerRadius = radius * innerRatio;
00709         qreal innerDistance = sqrt1_2 * innerRadius;
00710         qreal side = 2.0 * innerDistance;
00711 
00712         QPointF center (width() * 0.5, height() * 0.5);
00713         QRadialGradient gradient (center, radius, center);
00714         gradient.setColorAt (outerRatio, QColor (0, 0, 0, 255));
00715         gradient.setColorAt (innerRatio, QColor (0, 0, 0, 0));
00716 
00717         QBrush brush (gradient);
00718         QBrush blackbrush (QColor (0, 0, 0, 255));
00719         // Draw a transparent circle over the scene.
00720         p.setCompositionMode (QPainter::CompositionMode_SourceOver);
00721         if (radius < wh) {
00722             // If the spotlight radius is smaller than half the scene width,
00723             // draw black rectangles to its sides, which is faster.
00724             qreal diameter = radius * 2.0;
00725             p.fillRect (QRectF (x, y, 1.0 + wh - radius, h), blackbrush);
00726             p.fillRect (QRectF (x + wh + radius, y,
00727                             wh - radius, h), blackbrush);
00728             if (radius < hh) {
00729                 // If the spotlight radius is smaller than half the scene
00730                 // height, draw black rectangles to its top and bottom sides,
00731                 // which is faster.
00732                 p.fillRect (QRectF (x + wh - radius, y,
00733                             diameter, hh - radius + 1.0), blackbrush);
00734                 p.fillRect (QRectF (x + wh - radius, y + hh + radius,
00735                             diameter, hh - radius), blackbrush);
00736             
00737                 // Draw the spotlight circle, but skip the transparent center.
00738                 p.fillRect (QRectF (x + wh - radius, y + hh - radius,
00739                             radius - innerDistance, diameter), brush);
00740                 p.fillRect (QRectF (x + wh + innerDistance, y + hh - radius,
00741                             radius - innerDistance, diameter), brush);
00742                 p.fillRect (QRectF (x + wh - innerDistance, y + hh - radius,
00743                             side, radius - innerDistance), brush);
00744                 p.fillRect (QRectF (x + wh - innerDistance,
00745                             y + hh + innerDistance,
00746                             side, radius - innerDistance), brush);
00747             }
00748             else {
00749                 // Else draw the radial gradient
00750                 p.fillRect (QRectF (x + wh - radius, y, diameter, h), brush);
00751             }
00752         }
00753         else {
00754             // If the spotlight is bigger than the scene, draw only the
00755             // sections where the gradient is not transparent.
00756             p.fillRect (QRectF (x, y, wh - innerDistance, h), brush);
00757             p.fillRect (QRectF (x + wh + innerDistance, y,
00758                             wh - innerDistance, h), brush);
00759             if (innerDistance < hh) {
00760                 p.fillRect (QRectF (x + wh - innerDistance, y,
00761                             side, hh - innerDistance), brush);
00762                 p.fillRect (QRectF (x + wh - innerDistance,
00763                             y + hh + innerDistance,
00764                             side, hh - innerDistance), brush);
00765             }
00766         }
00767     }
00768 
00769     p.end();
00770     m_spotLight->setPicture (picture);
00771 }
00772 
00773 KGameCanvasRectangle * KGrCanvas::drawRectangle (int x, int y, int w, int h)
00774 {
00775     KGameCanvasRectangle * r =
00776                 new KGameCanvasRectangle (colour, QSize (w, h), this);
00777     r->moveTo (x, y);
00778     r->show();
00779     return (r);
00780 }
00781 
00782 KGameCanvasPixmap * KGrCanvas::makeBorderElement(QList< QPixmap >frameTiles, 
00783                                                  int x, int y, int which)
00784 {
00785     KGameCanvasPixmap *borderElement = new KGameCanvasPixmap (this);
00786     borderElement->setPixmap (frameTiles.at (which));
00787     borderElement->moveTo (x, y);
00788     borderElement->show();
00789     return borderElement;
00790 }
00791 
00792 KGameCanvasPixmap * KGrCanvas::makeDisplay (QList< QPixmap > tiles, int w)
00793 {
00794     int sections = 1 + numSections(w, imgW); 
00795     int width = (sections + 2) * imgW;
00796     QPixmap pix (width, imgH);
00797     pix.fill(QColor(0, 0, 0, 0));
00798     QPainter p;
00799     p.begin (&pix);
00800     p.drawPixmap (0, 0, tiles.at(0));
00801     for (int x = imgW; x < sections * imgW; x += imgW) {
00802         p.drawPixmap (x, 0, tiles.at(1));
00803     }
00804     p.drawPixmap (sections * imgW, 0, tiles.at(2));
00805     
00806     p.end();
00807     KGameCanvasPixmap *element = new KGameCanvasPixmap (this);
00808     element->setPixmap (pix);
00809     element->show();
00810     return element;
00811 }
00812 
00813 QSize KGrCanvas::sizeHint() const
00814 {
00815     return QSize ((nCellsW  + border) * imgW, (nCellsH + border) * imgH);
00816 }
00817 
00818 #include "kgrcanvas.moc"
00819 // vi: set sw=4 et:

kgoldrunner

Skip menu "kgoldrunner"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

API Reference

Skip menu "API Reference"
  • kblackbox
  • kgoldrunner
  • kmahjongg
  • ksquares
  • libkdegames
  •   highscore
  •   kgame
  •   kggzgames
  •   kggzmod
  •   kggznet
  • libkmahjongg
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal