File indexing completed on 2024-05-12 07:58:52

0001 /*
0002     SPDX-FileCopyrightText: 2003 Marco Krüger <grisuji@gmx.de>
0003     SPDX-FileCopyrightText: 2003, 2009 Ian Wadham <iandw.au@gmail.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "kgrglobals.h"
0009 
0010 #include "kgrselector.h"
0011 
0012 #include "kgrgameio.h"
0013 
0014 #include <QGridLayout>
0015 #include <QHeaderView>
0016 #include <QScreen>
0017 #include <QLabel>
0018 #include <QPainter>
0019 #include <QPushButton>
0020 #include <QScrollBar>
0021 #include <QSpacerItem>
0022 #include <QSpinBox>
0023 #include <QTextEdit>
0024 #include <QVBoxLayout>
0025 #include <QDialogButtonBox>
0026 #include <KGuiItem>
0027 #include <KConfigGroup>
0028 #include <KSharedConfig>
0029 #include <KLocalizedString>
0030 /******************************************************************************/
0031 /*****************    DIALOG BOX TO SELECT A GAME AND LEVEL   *****************/
0032 /******************************************************************************/
0033 
0034 KGrSLDialog::KGrSLDialog (int action, int requestedLevel, int gameIndex,
0035                         QList<KGrGameData *> & gameList,
0036                         const QString & pSystemDir, const QString & pUserDir,
0037                         QWidget * parent)
0038     :
0039     QDialog       (parent),
0040     slAction      (action),
0041     myGameList    (gameList),
0042     defaultGame   (gameIndex),
0043     defaultLevel  (requestedLevel),
0044     systemDir     (pSystemDir),
0045     userDir       (pUserDir),
0046     slParent      (parent)
0047 {
0048     setupWidgets();
0049 }
0050 
0051 KGrSLDialog::~KGrSLDialog()
0052 {
0053 }
0054 
0055 bool KGrSLDialog::selectLevel (int & selectedGame, int & selectedLevel)
0056 {
0057     selectedGame  = defaultGame;
0058     selectedLevel = 0;      // 0 = no selection (Cancel) or invalid.
0059 
0060     // Create and run a modal dialog box to select a game and level.
0061     while (exec() == QDialog::Accepted) {
0062         selectedGame = slGameIndex;
0063         selectedLevel = 0;  // In case the selection is invalid.
0064         if (myGameList.at (selectedGame)->owner == SYSTEM) {
0065             switch (slAction) {
0066             case SL_CREATE: // Can save only in a USER collection.
0067             case SL_SAVE:
0068             case SL_MOVE:
0069                 KGrMessage::information (slParent, i18n ("Select Level"),
0070                         i18n ("Sorry, you can only save or move "
0071                         "into one of your own games."));
0072                 continue;           // Re-run the dialog box.
0073                 break;
0074             case SL_DELETE: // Can delete only in a USER collection.
0075                 KGrMessage::information (slParent, i18n ("Select Level"),
0076                         i18n ("Sorry, you can only delete a level "
0077                         "from one of your own games."));
0078                 continue;           // Re-run the dialog box.
0079                 break;
0080             case SL_UPD_GAME:   // Can edit info only in a USER collection.
0081                 KGrMessage::information (slParent, i18n ("Edit Game Info"),
0082                         i18n ("Sorry, you can only edit the game "
0083                         "information on your own games."));
0084                 continue;           // Re-run the dialog box.
0085                 break;
0086             default:
0087                 break;
0088             }
0089         }
0090 
0091         selectedLevel = number->value();
0092         if ((selectedLevel > myGameList.at (selectedGame)->nLevels) &&
0093             (slAction != SL_CREATE) && (slAction != SL_SAVE) &&
0094             (slAction != SL_MOVE) && (slAction != SL_UPD_GAME)) {
0095             KGrMessage::information (slParent, i18n ("Select Level"),
0096                 i18n ("There is no level %1 in \"%2\", "
0097                 "so you cannot play or edit it.",
0098                  selectedLevel,
0099                  myGameList.at (selectedGame)->name));
0100             selectedLevel = 0;          // Set an invalid selection.
0101             continue;               // Re-run the dialog box.
0102         }
0103         break;                  // Accepted and valid.
0104     }
0105     return (selectedLevel > 0);         // 0 = cancelled or invalid.
0106 }
0107 
0108 void KGrSLDialog::setupWidgets()
0109 {
0110     int margin    = 0;
0111     int spacing    = 0;
0112     QWidget * dad   = new QWidget (this);
0113 
0114     QVBoxLayout *layout = new QVBoxLayout;
0115     setLayout(layout);
0116     layout->addWidget(dad);
0117 
0118     setWindowTitle (i18nc("@title:window", "Select Game"));
0119     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help);
0120     QVBoxLayout *buttonLayout = new QVBoxLayout;
0121     connect(buttonBox, &QDialogButtonBox::accepted, this, &KGrSLDialog::accept);
0122     connect(buttonBox, &QDialogButtonBox::rejected, this, &KGrSLDialog::reject);
0123     buttonLayout->addWidget(buttonBox);
0124     buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
0125     layout->addWidget(buttonBox);
0126 
0127     QVBoxLayout * mainLayout = new QVBoxLayout (dad);
0128     mainLayout->setSpacing (spacing);
0129     mainLayout->setContentsMargins(margin, margin, margin, margin);
0130 
0131     gameL    = new QLabel
0132                 (i18n ("<html><b>Please select a game:</b></html>"), dad);
0133     mainLayout->addWidget (gameL, 5);
0134 
0135     games    = new QTreeWidget (dad);
0136     mainLayout->addWidget(games);
0137     mainLayout->addWidget (games, 50);
0138     games->setColumnCount (4);
0139     games->setHeaderLabels (QStringList() <<
0140                             i18n ("Name of Game") <<
0141                             i18n ("Rules") <<
0142                             i18n ("Levels") <<
0143                             i18n ("Skill"));
0144     games->setRootIsDecorated (false);
0145 
0146     QHBoxLayout * hboxLayout1 = new QHBoxLayout();
0147     hboxLayout1->setSpacing (6);
0148     hboxLayout1->setContentsMargins(0, 0, 0, 0);
0149 
0150     gameN    = new QLabel (dad);    // Name of selected game.
0151     QFont f = gameN->font();
0152     f.setBold (true);
0153     gameN->setFont (f);
0154     hboxLayout1->addWidget (gameN);
0155 
0156     QSpacerItem * spacerItem1 = new QSpacerItem
0157                         (21, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
0158     hboxLayout1->addItem (spacerItem1);
0159 
0160     gameD    = new QLabel (dad);        // Description of game.
0161     hboxLayout1->addWidget (gameD);
0162     mainLayout->addLayout (hboxLayout1, 5);
0163 
0164     gameAbout = new QTextEdit (dad);
0165     gameAbout->setReadOnly (true);
0166     mainLayout->addWidget (gameAbout, 25);
0167 
0168     QFrame * separator = new QFrame (dad);
0169     separator->setFrameShape (QFrame::HLine);
0170     mainLayout->addWidget (separator);
0171 
0172     if ((slAction == SL_START) || (slAction == SL_UPD_GAME)) {
0173         dad->   setWindowTitle (i18nc("@title:window", "Select Game"));
0174         QLabel * startMsg = new QLabel
0175             (QStringLiteral("<b>") + i18n ("Level 1 of the selected game is:") + QStringLiteral("</b>"), dad);
0176         mainLayout->addWidget (startMsg, 5);
0177     }
0178     else {
0179         dad->   setWindowTitle (i18nc("@title:window", "Select Game/Level"));
0180         QLabel * selectLev = new QLabel
0181             (QStringLiteral("<b>") + i18n ("Please select a level:") + QStringLiteral("</b>"), dad);
0182         mainLayout->addWidget (selectLev, 5);
0183     }
0184 
0185     QGridLayout * grid = new QGridLayout;
0186     mainLayout->addLayout (grid);
0187 
0188     number    = new QScrollBar (Qt::Vertical, dad);
0189     number->setRange (1, 150);
0190     number->setSingleStep (1);
0191     number->setPageStep (10);
0192     number->setValue (1);
0193     grid->addWidget (number, 1, 5, 4, 1);
0194 
0195     QWidget * numberPair = new QWidget (dad);
0196     QHBoxLayout *hboxLayout2 = new QHBoxLayout (numberPair);
0197     hboxLayout2->setContentsMargins(0, 0, 0, 0);
0198     numberPair->setLayout (hboxLayout2);
0199     grid->addWidget (numberPair, 1, 1, 1, 3);
0200     numberL   = new QLabel (i18n ("Level number:"), numberPair);
0201     display = new QSpinBox (numberPair);
0202     display->setRange (1, 150);
0203     hboxLayout2->addWidget (numberL);
0204     hboxLayout2->addWidget (display);
0205 
0206     levelNH   = new QPushButton (i18n ("Edit Level Name o&r Hint"), dad);
0207     mainLayout->addWidget (levelNH);
0208 
0209     slName    = new QLabel (dad);
0210     grid->addWidget (slName, 2, 1, 1, 4);
0211     thumbNail = new KGrThumbNail (dad);
0212     grid->addWidget (thumbNail, 1, 6, 4, 5);
0213 
0214     // Set thumbnail cell size to about 1/5 of game cell size.
0215     int cellSize = slParent->width() / (5 * (FIELDWIDTH + 4));
0216     cellSize =  (cellSize < 4) ? 4 : cellSize;
0217     thumbNail-> setFixedWidth  ((FIELDWIDTH  * cellSize) + 2);
0218     thumbNail-> setFixedHeight ((FIELDHEIGHT * cellSize) + 2);
0219 
0220     // Base the geometry of the dialog box on the playing area.
0221     int cell =  slParent->width() / (FIELDWIDTH + 4);
0222     dad->   setMinimumSize ((FIELDWIDTH*cell/2), (FIELDHEIGHT-3)*cell);
0223 
0224     // Avoid spilling into the Taskbar or Apple Dock area if they get too close.
0225     // Otherwise allow the dialog to choose its size and then be resizeable.
0226     const QSize maxSize = screen()->availableGeometry().size();
0227     if ((maxSize.height() - slParent->height()) <= 120) {
0228         dad->setFixedHeight (slParent->height() - 120); // Keep 120 for buttons.
0229     }
0230 
0231     // Set the default for the level-number in the scrollbar.
0232     number->    setTracking (true);
0233     number->setValue (defaultLevel);
0234 
0235     slSetGames (defaultGame);
0236 
0237     // Vary the dialog according to the action.
0238     QString OKText;
0239     switch (slAction) {
0240     case SL_START:  // Must start at level 1, but can choose a game.
0241                         OKText = i18n ("Start Game");
0242                         number->setValue (1);
0243                         number->setEnabled (false);
0244                         display->setEnabled (false);
0245                         number->hide();
0246                         numberL->hide();
0247                         display->hide();
0248                         break;
0249     case SL_ANY:    // Can start playing at any level in any game.
0250                         OKText = i18n ("Play Level");
0251                         break;
0252     case SL_REPLAY: // Can ask to see a replay of any level in any game.
0253                         OKText = i18n ("Replay Level");
0254                         break;
0255     case SL_SOLVE:  // Can ask to see a solution of any level in any game.
0256                         OKText = i18n ("Show Solution");
0257                         break;
0258     case SL_SAVE_SOLUTION: // Can ask to save a recording on a solution-file.
0259                         OKText = i18n ("Save A Solution");
0260                         break;
0261     case SL_UPDATE: // Can use any level in any game as edit input.
0262                         OKText = i18n ("Edit Level");
0263                         break;
0264     case SL_CREATE: // Can save a new level only in a USER game.
0265                         OKText = i18n ("Save New");
0266                         break;
0267     case SL_SAVE:   // Can save an edited level only in a USER game.
0268                         OKText = i18n ("Save Change");
0269                         break;
0270     case SL_DELETE: // Can delete a level only in a USER game.
0271                         OKText = i18n ("Delete Level");
0272                         break;
0273     case SL_MOVE:   // Can move a level only into a USER game.
0274                         OKText = i18n ("Move To...");
0275                         break;
0276     case SL_UPD_GAME:   // Can only edit USER game details.
0277                         OKText = i18n ("Edit Game Info");
0278                         number->setValue (1);
0279                         number->setEnabled (false);
0280                         display->setEnabled (false);
0281                         number->hide();
0282                         numberL->hide();
0283                         display->hide();
0284                         break;
0285 
0286     default:        break;          // Keep the default settings.
0287     }
0288     if (!OKText.isEmpty()) {
0289         KGuiItem::assign(levelNH, KGuiItem (OKText));
0290     }
0291 
0292     // Set value in the line-edit box.
0293     slShowLevel (number->value());
0294 
0295     if (display->isEnabled()) {
0296         display->setFocus();            // Set the keyboard input on.
0297         display->selectAll();
0298     }
0299 
0300     // Paint a thumbnail sketch of the level.
0301     thumbNail->setFrameStyle (QFrame::Box | QFrame::Plain);
0302     thumbNail->setLineWidth (1);
0303     slPaintLevel();
0304     thumbNail->show();
0305 
0306     connect(games, &QTreeWidget::itemSelectionChanged, this, &KGrSLDialog::slGame);
0307 
0308     connect(display, &QSpinBox::textChanged, this, &KGrSLDialog::slUpdate);
0309     connect(number, &QScrollBar::valueChanged, this, &KGrSLDialog::slShowLevel);
0310 
0311     // Only enable name and hint dialog here if saving a new or edited level.
0312     // At other times the name and hint have not been loaded or initialised yet.
0313     if ((slAction == SL_CREATE) || (slAction == SL_SAVE)) {
0314         // Signal editNameAndHint() relays the click to a KGrEditor connection.
0315         connect(levelNH, &QPushButton::clicked, this, &KGrSLDialog::editNameAndHint);
0316     }
0317     else {
0318         levelNH->setEnabled (false);
0319         levelNH->hide();
0320     }
0321 
0322     connect(games, &QTreeWidget::itemSelectionChanged, this, &KGrSLDialog::slPaintLevel);
0323     connect(number, &QScrollBar::sliderReleased, this, &KGrSLDialog::slPaintLevel);
0324 
0325     connect(buttonBox->button(QDialogButtonBox::Help), &QPushButton::clicked, this, &KGrSLDialog::slotHelp);
0326 }
0327 
0328 /******************************************************************************/
0329 /*****************    LOAD THE LIST OF GAMES (COLLECTIONS)    *****************/
0330 /******************************************************************************/
0331 
0332 void KGrSLDialog::slSetGames (int cIndex)
0333 {
0334     int i;
0335     int imax = myGameList.count();
0336 
0337     // Set values in the table that holds details of available games.
0338     // The table is displayed in order of skill then the kind of rules.
0339     games->clear();
0340     slGameIndex = -1;
0341 
0342     QList<char> sortOrder1, sortOrder2;     // Crude, but effective.
0343     sortOrder1 << 'N' << 'C' << 'T';
0344     sortOrder2 << 'T' << 'K';
0345 
0346     for (char sortItem1 : std::as_const(sortOrder1)) {
0347         for (char sortItem2 : std::as_const(sortOrder2)) {
0348             for (i = 0; i < imax; ++i) {
0349                 if ((myGameList.at (i)->skill == sortItem1) &&
0350                     (myGameList.at (i)->rules == sortItem2)) {
0351                     QStringList data;
0352                     data
0353                         << myGameList.at (i)->name
0354                         << ((myGameList.at (i)->rules == 'K') ? 
0355                             i18nc ("Rules", "KGoldrunner") :
0356                             i18nc ("Rules", "Traditional"))
0357                         << QString().setNum (myGameList.at (i)->nLevels)
0358                         << ((myGameList.at (i)->skill == 'T') ? 
0359                             i18nc ("Skill Level", "Tutorial") :
0360                             ((myGameList.at (i)->skill == 'N') ? 
0361                             i18nc ("Skill Level", "Normal") :
0362                             i18nc ("Skill Level", "Championship")));
0363                     KGrGameListItem * thisGame = new KGrGameListItem (data, i);
0364                     games->addTopLevelItem (thisGame);
0365 
0366                     if (slGameIndex < 0) {
0367                         slGameIndex = i; // There is at least one game.
0368                     }
0369                     if (i == cIndex) {
0370                         // Mark the currently selected game (default 0).
0371                         games->setCurrentItem (thisGame);
0372                     }
0373                 }
0374             } // End "for" loop.
0375         }
0376     }
0377 
0378     if (slGameIndex < 0) {
0379         return;             // The game-list is empty (unlikely).
0380     }
0381 
0382     // Fetch and display information on the selected game.
0383     slGame();
0384 
0385     // Make the column for the game's name a bit wider.
0386     games->header()->setSectionResizeMode (0, QHeaderView::ResizeToContents);
0387     games->header()->setSectionResizeMode (1, QHeaderView::ResizeToContents);
0388     games->header()->setSectionResizeMode (2, QHeaderView::ResizeToContents);
0389 }
0390 
0391 /******************************************************************************/
0392 /*****************    SLOTS USED BY LEVEL SELECTION DIALOG    *****************/
0393 /******************************************************************************/
0394 
0395 void KGrSLDialog::slGame()
0396 {
0397 
0398     if (slGameIndex < 0) {
0399         // Ignore the "highlighted" signal caused by inserting in an empty box.
0400         return;
0401     }
0402 
0403     if (games->selectedItems().size() <= 0) {
0404         return;
0405     }
0406 
0407     slGameIndex = (dynamic_cast<KGrGameListItem *>
0408                         (games->selectedItems().first()))->id();
0409     int n = slGameIndex;                // Game selected.
0410     int N = defaultGame;                // Current game.
0411     if (myGameList.at (n)->nLevels > 0) {
0412         number->setMaximum (myGameList.at (n)->nLevels);
0413         display->setMaximum (myGameList.at (n)->nLevels);
0414     }
0415     else {
0416         number->setMaximum (1);         // Avoid range errors.
0417         display->setMaximum (1);
0418     }
0419 
0420     KConfigGroup gameGroup (KSharedConfig::openConfig(), QStringLiteral("KDEGame"));
0421     int lev = 1;
0422 
0423     // Set a default level number for the selected game.
0424     switch (slAction) {
0425     case SL_ANY:
0426     case SL_REPLAY:
0427     case SL_SOLVE:
0428     case SL_SAVE_SOLUTION:
0429     case SL_UPDATE:
0430     case SL_DELETE:
0431     case SL_UPD_GAME:
0432         // If selecting the current game, use the current level number.
0433         if (n == N) {
0434             number->setValue (defaultLevel);
0435         }
0436         // Else use the last level played in the selected game (from KConfig).
0437         else {
0438             lev = gameGroup.readEntry (QLatin1String("Level_") + myGameList.at (n)->prefix, 1);
0439             number->setValue (lev);         // Else use level 1.
0440         }
0441         break;
0442     case SL_CREATE:
0443     case SL_SAVE:
0444     case SL_MOVE:
0445         if ((n == N) && (slAction != SL_CREATE)) {
0446             // Saving/moving level in current game: use current number.
0447             number->setValue (defaultLevel);
0448         }
0449         else {
0450             // Saving new/edited level or relocating a level: use "nLevels + 1".
0451             number->setMaximum (myGameList.at (n)->nLevels + 1);
0452             display->setMaximum (myGameList.at (n)->nLevels + 1);
0453             number->setValue (number->maximum());
0454         }
0455         break;
0456     default:
0457         number->setValue (1);               // Default is level 1.
0458         break;
0459     }
0460 
0461     slShowLevel (number->value());
0462 
0463     int levCnt = myGameList.at (n)->nLevels;
0464     if (myGameList.at (n)->rules == 'K')
0465         gameD->setText (i18np ("1 level, uses KGoldrunner rules.",
0466                                 "%1 levels, uses KGoldrunner rules.", levCnt));
0467     else
0468         gameD->setText (i18np ("1 level, uses Traditional rules.",
0469                                 "%1 levels, uses Traditional rules.", levCnt));
0470     gameN->setText (myGameList.at (n)->name);
0471     QString s;
0472     if (myGameList.at (n)->about.isEmpty()) {
0473         s = i18n ("Sorry, there is no further information about this game.");
0474     }
0475     else {
0476         s = (i18n (myGameList.at (n)->about.constData()));
0477     } 
0478     gameAbout->setText (s);
0479 }
0480 
0481 void KGrSLDialog::slShowLevel (int i)
0482 {
0483     // Display the level number as the slider is moved.
0484     display->setValue (i);
0485 }
0486 
0487 void KGrSLDialog::slUpdate (const QString & text)
0488 {
0489     // Move the slider when a valid level number is entered.
0490     QString s = text;
0491     bool ok = false;
0492     int n = s.toInt (&ok);
0493     if (ok) {
0494         number->setValue (n);
0495         slPaintLevel();
0496     }
0497     else
0498         KGrMessage::information (this, i18n ("Select Level"),
0499                 i18n ("This level number is not valid. It can not be used."));
0500 }
0501 
0502 void KGrSLDialog::slPaintLevel()
0503 {
0504     // Repaint the thumbnail sketch of the level whenever the level changes.
0505     if (slGameIndex < 0) {
0506         return;                 // Owner has no games.
0507     }
0508     // Fetch level-data and save layout, name and label in the thumbnail.
0509     QString dir = (myGameList.at (slGameIndex)->owner == USER) ?
0510                                   userDir : systemDir;
0511     thumbNail->setLevelData (dir, myGameList.at (slGameIndex)->prefix,
0512                                   number->value(), slName);
0513     thumbNail->repaint();           // Will call "paintEvent (e)".
0514 }
0515 
0516 void KGrSLDialog::slotHelp()
0517 {
0518     // Help for "Select Game and Level" dialog box.
0519     QString s =
0520         i18n ("The main button at the bottom echoes the "
0521         "menu action you selected. Click it after choosing "
0522         "a game and level - or use \"Cancel\".");
0523 
0524     if (slAction == SL_START) {
0525         s += i18n ("\n\nIf this is your first time in KGoldrunner, select the "
0526             "tutorial game, which gives you hints as you go.\n\n"
0527             "Otherwise, just click on the name of a game in the table, "
0528             "then, to start at level 001, click on the main button at the "
0529             "bottom. Play begins when you move the mouse or press a key.");
0530    }
0531    else {
0532         switch (slAction) {
0533         case SL_UPDATE:
0534             s += i18n ("\n\nYou can select System levels for editing (or "
0535                 "copying), but you must save the result in a game you have "
0536                 "created.  Use the left mouse-button as a paintbrush and the "
0537                 "editor toolbar buttons as a palette.  Use the 'Erase' button "
0538                 "or the right mouse-button to erase.  You can drag the mouse "
0539                 "with a button held down and paint or erase multiple squares.");
0540             break;
0541         case SL_CREATE:
0542             s += i18n("\n\nYou can add a name and hint to your new level here, "
0543                 "but you must save the level you have created into one of "
0544                 "your own games. By default your new level will go at the "
0545                 "end of your game, but you can also select a level number and "
0546                 "save into the middle of your game.");
0547             break;
0548         case SL_SAVE:
0549             s += i18n("\n\nYou can create or edit a name and hint here, before "
0550                 "saving. If you change the game or level, you can do a copy "
0551                 "or \"Save As\", but you must always save into one of your "
0552                 "own games. If you save a level into the middle of a series, "
0553                 "the other levels are automatically re-numbered.");
0554             break;
0555         case SL_DELETE:
0556             s += i18n ("\n\nYou can only delete levels from one of your own "
0557                 "games. If you delete a level from the middle of a series, "
0558                 "the other levels are automatically re-numbered.");
0559             break;
0560         case SL_MOVE:
0561             s += i18n ("\n\nTo move (re-number) a level, you must first select "
0562                 "it by using \"Edit Any Level...\", then you can use "
0563                 "\"Move Level...\" to move it to a new number or even a "
0564                 "different game. Other levels are automatically re-numbered as "
0565                 "required. You can only move levels within your own games.");
0566             break;
0567         case SL_UPD_GAME:
0568             s += i18n ("\n\nWhen editing game info you only need to choose a "
0569                 "game, then you can go to a dialog where you edit the "
0570                 "details of the game.");
0571             break;
0572         default:
0573             break;
0574         }
0575         s += i18n ("\n\nClick on the table to choose a game.  "
0576             "In the table and below it you can see more information about the "
0577             "selected game, including how many levels there are, how difficult "
0578             "the game is and what "
0579             "rules the enemies follow (see the KGoldrunner Handbook).\n\n"
0580             "You select "
0581             "a level number by typing it or using the spin box or scroll bar.  "
0582             "As you vary the game or level, the thumbnail area shows a "
0583             "preview of your choice.");
0584    }
0585 
0586    KGrMessage::information (slParent, i18n ("Help: Select Game & Level"), s);
0587 }
0588 
0589 /*******************************************************************************
0590 *************************  ITEM FOR THE LIST OF GAMES  *************************
0591 *******************************************************************************/
0592 
0593 KGrGameListItem::KGrGameListItem (const QStringList & data,
0594                                   const int internalId)
0595         : QTreeWidgetItem (data)
0596 {
0597     mInternalId = internalId;
0598 }
0599 
0600 int KGrGameListItem::id() const
0601 {
0602     return mInternalId;
0603 }
0604 
0605 void KGrGameListItem::setId (const int internalId)
0606 {
0607     mInternalId = internalId;
0608 }
0609 
0610 /******************************************************************************/
0611 /**********************    CLASS TO DISPLAY THUMBNAIL   ***********************/
0612 /******************************************************************************/
0613 
0614 KGrThumbNail::KGrThumbNail (QWidget * parent)
0615     :
0616     QFrame (parent),
0617     io     (new KGrGameIO (parent))
0618 {
0619     // Let the parent do all the work.  We need a class here so that
0620     // QFrame::paintEvent (QPaintEvent *) can be re-implemented and
0621     // the thumbnail can be automatically re-painted when required.
0622 }
0623 
0624 KGrThumbNail::~KGrThumbNail()
0625 {
0626     delete io;
0627 }
0628 
0629 void KGrThumbNail::setLevelData (const QString & dir, const QString& prefix,
0630                                  int level, QLabel * sln)
0631 {
0632     KGrLevelData d;
0633     QString filePath;
0634 
0635     IOStatus stat = io->fetchLevelData (dir, prefix, level, d, filePath);
0636     if (stat == OK) {
0637         // Keep a safe copy of the layout.  Translate and display the name.
0638         levelLayout = d.layout;
0639         sln->setText ((d.name.size() > 0) ? i18n (d.name.constData()) : QString());
0640     }
0641     else {
0642         // Level-data inaccessible or not found.
0643         levelLayout = "";
0644         sln->setText (QString());
0645     }
0646 }
0647 
0648 void KGrThumbNail::paintEvent (QPaintEvent * /* event (unused) */)
0649 {
0650     QPainter    p (this);
0651     QFile   openFile;
0652     QPen    pen = p.pen();
0653     char    obj = FREE;
0654     int     fw = 1;             // Set frame width.
0655     int     n = width() / FIELDWIDTH;   // Set thumbnail cell-size.
0656 
0657     QColor backgroundColor = QColor ("#000038"); // Midnight blue.
0658     QColor brickColor =      QColor ("#9c0f0f"); // Oxygen's brick-red.
0659     QColor concreteColor =   QColor ("#585858"); // Dark grey.
0660     QColor ladderColor =     QColor ("#a0a0a0"); // Steely grey.
0661     QColor poleColor =       QColor ("#a0a0a0"); // Steely grey.
0662     QColor heroColor =       QColor ("#00ff00"); // Green.
0663     QColor enemyColor =      QColor ("#0080ff"); // Bright blue.
0664     QColor gold =            QColor::fromString(QStringLiteral("gold")); // Gold.
0665 
0666     pen.setColor (backgroundColor);
0667     p.setPen (pen);
0668 
0669     if (levelLayout.isEmpty()) {
0670         // There is no file, so fill the thumbnail with "FREE" cells.
0671         p.drawRect (QRect (fw, fw, FIELDWIDTH*n, FIELDHEIGHT*n));
0672         return;
0673     }
0674 
0675     for (int j = 0; j < FIELDHEIGHT; j++)
0676     for (int i = 0; i < FIELDWIDTH; i++) {
0677 
0678         obj = levelLayout.at (j*FIELDWIDTH + i);
0679 
0680         // Set the colour of each object.
0681         switch (obj) {
0682         case BRICK:
0683         case FBRICK:
0684             pen.setColor (brickColor); p.setPen (pen); break;
0685         case CONCRETE:
0686             pen.setColor (concreteColor); p.setPen (pen); break;
0687         case LADDER:
0688             pen.setColor (ladderColor); p.setPen (pen); break;
0689         case BAR:
0690             pen.setColor (poleColor); p.setPen (pen); break;
0691         case HERO:
0692             pen.setColor (heroColor); p.setPen (pen); break;
0693         case ENEMY:
0694             pen.setColor (enemyColor); p.setPen (pen); break;
0695         default:
0696             // Set the background colour for FREE, HLADDER and NUGGET.
0697             pen.setColor (backgroundColor); p.setPen (pen); break;
0698         }
0699 
0700         // Draw n x n pixels as n lines of length n.
0701         p.drawLine (i*n+fw, j*n+fw, i*n+(n-1)+fw, j*n+fw);
0702         if (obj == BAR) {
0703             // For a pole, only the top line is drawn in white.
0704             pen.setColor (backgroundColor);
0705             p.setPen (pen);
0706         }
0707         for (int k = 1; k < n; k++) {
0708             p.drawLine (i*n+fw, j*n+k+fw, i*n+(n-1)+fw, j*n+k+fw);
0709         }
0710 
0711         // For a nugget, add just a vertical touch  of yellow (2-3 pixels).
0712         if (obj == NUGGET) {
0713             int k = (n/2)+fw;
0714             pen.setColor (gold);    // Gold.
0715             p.setPen (pen);
0716             p.drawLine (i*n+k, j*n+k, i*n+k, j*n+(n-1)+fw);
0717             p.drawLine (i*n+k+1, j*n+k, i*n+k+1, j*n+(n-1)+fw);
0718         }
0719     }
0720 
0721     // Finally, draw a small black border around the outside of the thumbnail.
0722     pen.setColor (Qt::black); 
0723     p.setPen (pen);
0724     p.drawRect (rect().left(), rect().top(), rect().right(), rect().bottom());
0725 }
0726 
0727 #include "moc_kgrselector.cpp"