File indexing completed on 2024-04-28 04:02:15

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