kgoldrunner.cpp 42.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/****************************************************************************
 *    Copyright 2002  Marco Krüger <grisuji@gmx.de>                         *
 *    Copyright 2002  Ian Wadham <iandw.au@gmail.com>                       *
 *    Copyright 2009  Ian Wadham <iandw.au@gmail.com>                       *
 *                                                                          *
 *    This program is free software; you can redistribute it and/or         *
 *    modify it under the terms of the GNU General Public License as        *
 *    published by the Free Software Foundation; either version 2 of        *
 *    the License, or (at your option) any later version.                   *
 *                                                                          *
 *    This program is distributed in the hope that it will be useful,       *
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *    GNU General Public License for more details.                          *
 *                                                                          *
 *    You should have received a copy of the GNU General Public License     *
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 ****************************************************************************/
Ian Wadham's avatar
Ian Wadham committed
19

20 21
#include "kgoldrunner.h"

22
#include <QApplication>
Laurent Montel's avatar
Laurent Montel committed
23 24
#include <QDesktopWidget>
#include <QSignalMapper>
25 26
#include <QShortcut>
#include <QKeySequence>
27
#include <QKeyEvent>
Ian Wadham's avatar
Ian Wadham committed
28

Laurent Montel's avatar
Laurent Montel committed
29
#include <KShortcut>
30
#include <kglobal.h>
31
#include <kshortcutsdialog.h>
32
#include <KStandardDirs>
Laurent Montel's avatar
Laurent Montel committed
33

34
#include <kconfig.h>
35
#include <kconfiggroup.h>
36

Laurent Montel's avatar
Laurent Montel committed
37 38
#include "kgoldrunner_debug.h"
#include "kgoldrunner_debug.h"
39

40
#include <ktoolbar.h>
41
#include <kmenubar.h>
42

Laurent Montel's avatar
Laurent Montel committed
43
#include <QAction>
44
#include <kactioncollection.h>
45
#include <ktoggleaction.h>
Luciano Montanaro's avatar
Luciano Montanaro committed
46
#include <ktogglefullscreenaction.h>
Aaron J. Seigo's avatar
Aaron J. Seigo committed
47
#include <kstandardaction.h>
48
#include <kstandardgameaction.h>
Laurent Montel's avatar
Laurent Montel committed
49
#include <QIcon>
50 51 52
#include <KMenu>
#include <KCmdLineArgs>
#include <KAboutData>
53

54
#include <libkdegames_capabilities.h> //defines KGAUDIO_BACKEND_OPENAL (or not)
55

56
#include "kgrgame.h"
57 58 59
#include "kgrview.h"
#include "kgrscene.h"
#include "kgrrenderer.h"
Ian Wadham's avatar
Ian Wadham committed
60

61 62 63
// Shorthand for references to actions.
#define ACTION(x)   (actionCollection()->action(x))

64
KGoldrunner::KGoldrunner()
65 66
    :
    KXmlGuiWindow (0)
67 68 69 70
{
/******************************************************************************/
/*************  FIND WHERE THE GAMES DATA AND HANDBOOK SHOULD BE  *************/
/******************************************************************************/
Ian Wadham's avatar
Ian Wadham committed
71

72
    setObjectName ( QLatin1String("KGoldrunner" ));
73

74
    // Avoid "saveOK()" check if an error-exit occurs during the file checks.
Jaison Lee's avatar
Jaison Lee committed
75
    startupOK = true;
Ian Wadham's avatar
Ian Wadham committed
76

77 78
    // Get directory paths for the system levels, user levels and manual.
    if (! getDirectories()) {
79 80 81
        fprintf (stderr, "getDirectories() FAILED\n");
        startupOK = false;
        return;				// If games directory not found, abort.
Ian Wadham's avatar
Ian Wadham committed
82 83
    }

84
    // This message is to help diagnose distribution or installation problems.
85 86 87
    fprintf (stderr,
        "The games data and handbook should be in the following locations:\n");
    fprintf (stderr, "System games: %s\nUser data:    %s\nHandbook:     %s\n",
88
        qPrintable(systemDataDir), qPrintable(userDataDir), qPrintable(systemHTMLDir));
Ian Wadham's avatar
Ian Wadham committed
89 90

/******************************************************************************/
91
/************************  SET PLAYFIELD AND GAME DATA  ***********************/
Ian Wadham's avatar
Ian Wadham committed
92 93
/******************************************************************************/

Ian Wadham's avatar
Ian Wadham committed
94
    // Base the size of playing-area and widgets on the monitor resolution.
95
    int dw = QApplication::desktop()->width();
Ian Wadham's avatar
Ian Wadham committed
96 97

    // Need to consider the height, for widescreen displays (eg. 1280x768).
98
    int dh = QApplication::desktop()->height();
Ian Wadham's avatar
Ian Wadham committed
99

100 101
    dw = qMin ((4 * dh + 1) / 3, dw);	// KGoldrunner aspect ratio is 4:3.
    dh = (3 * dw + 2) / 4;
102 103

    view = new KGrView (this);
104 105
    view->setMinimumSize ((dw + 1) / 2, (dh + 1) / 2);

106
    game = new KGrGame (view, systemDataDir, userDataDir);
Ian Wadham's avatar
Ian Wadham committed
107

108 109
    // Initialise the lists of games (i.e. collections of levels).
    if (! game->initGameLists()) {
110 111
        startupOK = false;
        return;				// If no game files, abort.
Ian Wadham's avatar
Ian Wadham committed
112 113
    }

114 115 116
/******************************************************************************/
/*************************  SET UP THE USER INTERFACE  ************************/
/******************************************************************************/
Ian Wadham's avatar
Ian Wadham committed
117

118
    // Tell the KMainWindow that the KGrCanvas object is the main widget.
119
    setCentralWidget (view);
120

121 122
    scene       = view->gameScene ();
    renderer    = scene->renderer ();
123

124 125
    // Set up our actions (menu, toolbar and keystrokes) ...
    setupActions();
126

Ian Wadham's avatar
Ian Wadham committed
127 128
    // Do NOT put show/hide actions for the statusbar and toolbar in the GUI.
    // We do not have a statusbar any more and the toolbar is relevant only
129
    // when using the game editor and then it appears automatically.  Maybe 1%
130
    // of players would use the game editor for 5% of their time.  Also we have
131
    // our own action to configure shortcut keys, so disable the KXmlGui one.
132
    setupGUI (static_cast<StandardWindowOption> (Default &
133
                        (~StatusBar) & (~ToolBar) & (~Keys)));
134

135 136 137
    // Initialize text-item lengths in the scene, before the first resize.
    scene->showLives (0);
    scene->showScore (0);
Ian Wadham's avatar
Ian Wadham committed
138 139
    adjustHintAction (false);
    gameFreeze (false);
140

141
    // Connect the game actions to the menu and toolbar displays.
142
    connect (game, SIGNAL (quitGame()),	         SLOT (close()));
143
    connect (game, SIGNAL (setEditMenu(bool)),	 SLOT (setEditMenu(bool)));
Ian Wadham's avatar
Ian Wadham committed
144 145
    connect (game, SIGNAL (showLives(long)), scene, SLOT (showLives(long)));
    connect (game, SIGNAL (showScore(long)), scene, SLOT (showScore(long)));
146
    connect (game, SIGNAL (hintAvailable(bool)), SLOT (adjustHintAction(bool)));
Ian Wadham's avatar
Ian Wadham committed
147
    connect (game, SIGNAL (gameFreeze(bool)), SLOT (gameFreeze(bool)));
148

Laurent Montel's avatar
Laurent Montel committed
149 150 151 152
    connect (game, SIGNAL (setAvail(const char*,bool)),
                   SLOT   (setAvail(const char*,bool)));
    connect (game, SIGNAL (setToggle(const char*,bool)),
                   SLOT   (setToggle(const char*,bool)));
153

154 155
    connect (scene, SIGNAL (redrawEditToolbar()), SLOT (redrawEditToolbar()));

156 157 158 159
    // Apply the saved mainwindow settings, if any, and ask the mainwindow
    // to automatically save settings if changed: window size, toolbar
    // position, icon size, etc.
    setAutoSaveSettings();
160

161
    // Explicitly hide the edit toolbar - we need it in edit mode only and we
162
    // always start in play mode, even if the last session ended in edit mode.
163 164
    // Besides, we cannot render it until after the initial resize event (s).
    toolBar ("editToolbar")->hide();
165

Ian Wadham's avatar
Ian Wadham committed
166
    // Do NOT paint main widget yet (title bar, menu, blank playfield).
167
    // Instead, queue a call to the "KGoldrunner_2" constructor extension.
168
    QMetaObject::invokeMethod (this, "KGoldrunner_2", Qt::QueuedConnection);
Laurent Montel's avatar
Laurent Montel committed
169 170
    //qCDebug(KGOLDRUNNER_LOG) << "QMetaObject::invokeMethod (this, \"KGoldrunner_2\") done ... ";
    //qCDebug(KGOLDRUNNER_LOG) << "1st scan of event-queue ...";
171 172 173 174
}

void KGoldrunner::KGoldrunner_2()
{
Laurent Montel's avatar
Laurent Montel committed
175
    //qCDebug(KGOLDRUNNER_LOG) << "Entered constructor extension ...";
176 177 178 179

    // Queue a call to the "initGame" method. This renders and paints the
    // initial graphics, but only AFTER the initial main-window resize events
    // have been seen and the final SVG scale is known.
180
    QMetaObject::invokeMethod (game, "initGame", Qt::QueuedConnection);
Laurent Montel's avatar
Laurent Montel committed
181 182
    //qCDebug(KGOLDRUNNER_LOG) << "QMetaObject::invokeMethod (game, \"initGame\") done ... ";
    //qCDebug(KGOLDRUNNER_LOG) << "2nd scan of event-queue ...";
Ian Wadham's avatar
Ian Wadham committed
183 184
}

185
KGoldrunner::~KGoldrunner()
Ian Wadham's avatar
Ian Wadham committed
186
{
187 188 189 190 191 192 193 194
}

void KGoldrunner::setupActions()
{
    /**************************************************************************/
    /******************************   GAME MENU  ******************************/
    /**************************************************************************/

195
    QSignalMapper * gameMapper = new QSignalMapper (this);
Laurent Montel's avatar
Laurent Montel committed
196
    connect (gameMapper, SIGNAL (mapped(int)), game, SLOT (gameActions(int)));
197 198
    tempMapper = gameMapper;

199 200 201 202
    // New Game...
    // Load Saved Game...
    // --------------------------

Laurent Montel's avatar
Laurent Montel committed
203
    QAction * a = KStandardGameAction::gameNew (gameMapper, SLOT(map()), this);
204 205 206 207
    actionCollection()->addAction (a->objectName(), a);
    gameMapper->setMapping (a, NEW);
    a->setText (i18n ("&New Game..."));

208 209 210 211 212 213 214
    a        = gameAction ("next_level", NEXT_LEVEL,
                           i18n ("Pla&y Next Level"),
                           i18n ("Play next level."),
                           i18n ("Try the next level in the game "
                                 "you are playing."),
                           Qt::Key_Y);

215 216 217 218
    a =	KStandardGameAction::load (gameMapper, SLOT(map()), this);
    actionCollection()->addAction (a->objectName(), a);
    gameMapper->setMapping (a, LOAD);
    a->setText (i18n ("&Load Saved Game..."));
219

220 221 222 223
    // Save Game...
    // Save Edits... (extra copy)
    // --------------------------

224
    saveGame = KStandardGameAction::save (gameMapper, SLOT(map()), this);
225
    actionCollection()->addAction (saveGame->objectName(), saveGame);
226 227
    gameMapper->setMapping (saveGame, SAVE_GAME);
    saveGame->setText (i18n ("&Save Game..."));
Laurent Montel's avatar
Laurent Montel committed
228
    actionCollection()->setDefaultShortcut(saveGame, Qt::Key_S); // Alternate key.
229 230 231 232 233 234 235

    // Pause
    // Show High Scores
    // Get a Hint
    // Kill the Hero
    // --------------------------

236
    myPause = KStandardGameAction::pause (gameMapper, SLOT(map()), this);
237
    actionCollection()->addAction (myPause->objectName(), myPause);
238
    gameMapper->setMapping (myPause, PAUSE);
Laurent Montel's avatar
Laurent Montel committed
239 240
#if 0 //QT5
    // QAction * myPause gets QAction::shortcut(), returning 1 OR 2 shortcuts.
241 242 243
    KShortcut pauseShortcut = myPause->shortcut();
    pauseShortcut.setAlternate (Qt::Key_Escape);	// Add "Esc" shortcut.
    myPause->setShortcut (pauseShortcut);
Laurent Montel's avatar
Laurent Montel committed
244
#endif
245
    highScore = KStandardGameAction::highscores (gameMapper, SLOT(map()), this);
246
    actionCollection()->addAction (highScore->objectName(), highScore);
247
    gameMapper->setMapping (highScore, HIGH_SCORE);
248

249
    hintAction = KStandardGameAction::hint (gameMapper, SLOT (map()), this);
250
    actionCollection()->addAction (hintAction->objectName(), hintAction);
251 252
    gameMapper->setMapping (hintAction, HINT);

253 254 255 256 257 258 259
    a = KStandardGameAction::demo (gameMapper, SLOT (map()), this);
    actionCollection()->addAction (a->objectName(), a);
    gameMapper->setMapping (a, DEMO);

    a = KStandardGameAction::solve (gameMapper, SLOT (map()), this);
    actionCollection()->addAction (a->objectName(), a);
    gameMapper->setMapping (a, SOLVE);
260 261
    a->setText      (i18n ("&Show A Solution"));
    a->setToolTip   (i18n ("Show how to win this level."));
262
    a->setWhatsThis (i18n ("Play a recording of how to win this level, if "
263
                           "there is one available."));
264 265 266

    a        = gameAction ("instant_replay", INSTANT_REPLAY,
                           i18n ("&Instant Replay"),
267 268 269 270 271 272 273 274 275 276 277 278
                           i18n ("Instant replay."),
                           i18n ("Show a recording of the level "
                                 "you are currently playing."),
                           Qt::Key_R);

    a        = gameAction ("replay_last", REPLAY_LAST,
                           i18n ("Replay &Last Level"),
                           i18n ("Replay last level."),
                           i18n ("Show a recording of the last level you "
                                 "played and finished, regardless of whether "
                                 "you won or lost."),
                           Qt::Key_A);
279 280 281

    a        = gameAction ("replay_any", REPLAY_ANY,
                           i18n ("&Replay Any Level"),
282 283 284
                           i18n ("Replay any level."),
                           i18n ("Show a recording of any level you have "
                                 "played so far."),
285 286
                           QKeySequence());	// No key assigned.

287 288
    killHero = gameAction ("kill_hero", KILL_HERO,
                           i18n ("&Kill Hero"),
289
                           i18n ("Kill Hero."),
290
                           i18n ("Kill the hero, in case he finds himself in "
291
                                 "a situation from which he cannot escape."),
292
                           Qt::Key_Q);
293 294 295 296

    // Quit
    // --------------------------

297
    KStandardGameAction::quit (this, SLOT (close()), actionCollection());
298 299 300 301 302

    /**************************************************************************/
    /***************************   GAME EDITOR MENU  **************************/
    /**************************************************************************/

303
    QSignalMapper * editMapper = new QSignalMapper (this);
304
    connect (editMapper, SIGNAL (mapped(int)), game, SLOT (editActions(int)));
305 306
    tempMapper = editMapper;

307
    // Create a Level
308
    // Edit a Level...
309 310
    // --------------------------

Laurent Montel's avatar
Laurent Montel committed
311
    QAction * ed = editAction ("create_level", CREATE_LEVEL,
312
                               i18n ("&Create Level"),
313 314
                               i18n ("Create level."),
                               i18n ("Create a completely new level."));
Laurent Montel's avatar
Laurent Montel committed
315
    ed->setIcon (QIcon::fromTheme( QLatin1String( "document-new" )));
316
    ed->setIconText (i18n ("Create"));
317

318 319 320 321
    ed           = editAction ("edit_any", EDIT_ANY,
                               i18n ("&Edit Level..."),
                               i18n ("Edit level..."),
                               i18n ("Edit any level..."));
Laurent Montel's avatar
Laurent Montel committed
322
    ed->setIcon (QIcon::fromTheme( QLatin1String( "document-open" )));
323
    ed->setIconText (i18n ("Edit"));
324

325 326 327 328 329
    // Save Edits...
    // Move Level...
    // Delete Level...
    // --------------------------

330 331 332 333
    saveEdits    = editAction ("save_edits", SAVE_EDITS,
                               i18n ("&Save Edits..."),
                               i18n ("Save edits..."),
                               i18n ("Save your level after editing..."));
Laurent Montel's avatar
Laurent Montel committed
334
    saveEdits->setIcon (QIcon::fromTheme( QLatin1String( "document-save" )));
335
    saveEdits->setIconText (i18n ("Save"));
336 337 338 339 340 341 342 343 344 345 346 347
    saveEdits->setEnabled (false);		// Nothing to save, yet.

    ed           = editAction ("move_level", MOVE_LEVEL,
                               i18n ("&Move Level..."),
                               i18n ("Move level..."),
                               i18n ("Change a level's number or move "
                                     "it to another game..."));

    ed           = editAction ("delete_level", DELETE_LEVEL,
                               i18n ("&Delete Level..."),
                               i18n ("Delete level..."),
                               i18n ("Delete a level..."));
348 349 350 351 352

    // Create a Game
    // Edit Game Info...
    // --------------------------

353 354 355 356
    ed           = editAction ("create_game", CREATE_GAME,
                               i18n ("Create &Game..."),
                               i18n ("Create game..."),
                               i18n ("Create a completely new game..."));
357

358 359 360 361 362
    ed           = editAction ("edit_game", EDIT_GAME,
                               i18n ("Edit Game &Info..."),
                               i18n ("Edit game info..."),
                               i18n ("Change the name, rules or description "
                                     "of a game..."));
363

364
    /**************************************************************************/
365
    /****************************   SETTINGS MENU  ****************************/
366 367
    /**************************************************************************/

368
    // Theme settings are handled by this class and KGrRenderer.
369 370 371 372 373
    QAction * themes = actionCollection()->addAction ("select_theme");
    themes->setText      (i18n ("Change &Theme..."));
    themes->setToolTip   (i18n ("Change the graphics theme..."));
    themes->setWhatsThis (i18n ("Alter the visual appearance of the runners "
                                "and background scene..."));
Laurent Montel's avatar
Laurent Montel committed
374
    connect (themes, SIGNAL (triggered(bool)), this, SLOT (changeTheme()));
375

376 377 378 379
    // Show/Exit Full Screen Mode
    KToggleFullScreenAction * fullScreen = KStandardAction::fullScreen
                        (this, SLOT (viewFullScreen(bool)), this, this);
    actionCollection()->addAction (fullScreen->objectName(), fullScreen);
380

381
    // Other settings are handled by KGrGame.
382
    QSignalMapper * settingMapper = new QSignalMapper (this);
Laurent Montel's avatar
Laurent Montel committed
383
    connect (settingMapper, SIGNAL (mapped(int)), game, SLOT (settings(int)));
384 385
    tempMapper = settingMapper;

386
#ifdef KGAUDIO_BACKEND_OPENAL
387
    // Sound effects on/off
388
                                  settingAction ("options_sounds", PLAY_SOUNDS,
389
                                  i18n ("&Play Sounds"),
390 391
                                  i18n ("Play sound effects."),
                                  i18n ("Play sound effects during the game."));
392 393 394 395 396

                                  settingAction ("options_steps", PLAY_STEPS,
                                  i18n ("Play &Footstep Sounds"),
                                  i18n ("Make sounds of player's footsteps."),
                                  i18n ("Make sounds of player's footsteps."));
397
#endif
398

399
    // Demo at start on/off.
400
                                  settingAction ("options_demo", STARTUP_DEMO,
401
                                  i18n ("&Demo At Start"),
402 403
                                  i18n ("Run a demo when the game starts."),
                                  i18n ("Run a demo when the game starts."));
404

405 406
    // Mouse Controls Hero
    // Keyboard Controls Hero
Ian Wadham's avatar
Ian Wadham committed
407
    // Laptop Hybrid
408 409
    // --------------------------

410 411
    KToggleAction * setMouse    = settingAction ("mouse_mode", MOUSE,
                                  i18n ("&Mouse Controls Hero"),
412
                                  i18n ("Mouse controls hero."),
413
                                  i18n ("Use the mouse to control "
414
                                        "the hero's moves."));
415 416 417

    KToggleAction * setKeyboard = settingAction ("keyboard_mode", KEYBOARD,
                                  i18n ("&Keyboard Controls Hero"),
418
                                  i18n ("Keyboard controls hero."),
419
                                  i18n ("Use the keyboard to control "
420
                                        "the hero's moves."));
421 422

    KToggleAction * setLaptop   = settingAction ("laptop_mode", LAPTOP,
423
                                  i18n ("Hybrid Control (&Laptop)"),
Andrew Coles's avatar
Andrew Coles committed
424 425
                                  i18n ("Pointer controls hero; dig "
                                        "using keyboard."),
Burkhard Lück's avatar
Burkhard Lück committed
426
                                  i18n ("Use the laptop's pointer device "
427 428
                                        "to control the hero's moves, and use "
                                        "the keyboard to dig left and right."));
Ian Wadham's avatar
Ian Wadham committed
429

430 431 432
    QActionGroup* controlGrp = new QActionGroup (this);
    controlGrp->addAction (setMouse);
    controlGrp->addAction (setKeyboard);
Ian Wadham's avatar
Ian Wadham committed
433
    controlGrp->addAction (setLaptop);
434
    controlGrp->setExclusive (true);
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458

    // Options within keyboard mode.
    // Click key to begin moving and continue moving indefinitely.
    // Click and hold key to begin moving: release key to stop.

    KToggleAction * clickKey    = settingAction ("click_key", CLICK_KEY,
                                  i18n ("&Click Key To Move"),
                                  i18n ("Click Key To Move."),
                                  i18n ("In keyboard mode, click a "
                                        "direction-key to start moving "
                                        "and keep on going until you "
                                        "click another key."));

    KToggleAction * holdKey     = settingAction ("hold_key", HOLD_KEY,
                                  i18n ("&Hold Key To Move"),
                                  i18n ("Hold Key To Move."),
                                  i18n ("In keyboard mode, hold down a "
                                        "direction-key to move "
                                        "and release it to stop."));

    QActionGroup * keyGrp = new QActionGroup (this);
    keyGrp->addAction (clickKey);
    keyGrp->addAction (holdKey);
    keyGrp->setExclusive (true);
459 460 461 462 463 464 465 466

    // Normal Speed
    // Beginner Speed
    // Champion Speed
    // Increase Speed
    // Decrease Speed
    // --------------------------

467 468
    KToggleAction * nSpeed      = settingAction ("normal_speed", NORMAL_SPEED,
                                  i18n ("Normal Speed"),
469
                                  i18n ("Set normal speed."),
470
                                  i18n ("Set normal game speed."));
471 472 473 474

    KToggleAction * bSpeed      = settingAction ("beginner_speed",
                                  BEGINNER_SPEED,
                                  i18n ("Beginner Speed"),
475
                                  i18n ("Set beginners' speed."),
476 477
                                  i18n ("Set beginners' game speed "
                                        "(0.5 times normal)."));
478 479 480 481

    KToggleAction * cSpeed      = settingAction ("champion_speed",
                                  CHAMPION_SPEED,
                                  i18n ("Champion Speed"),
482
                                  i18n ("Set champions' speed."),
483 484
                                  i18n ("Set champions' game speed "
                                        "(1.5 times normal)."));
485

486
    a                           = gameAction ("increase_speed", INC_SPEED,
487
                                  i18n ("Increase Speed"),
488
                                  i18n ("Increase speed."),
489 490
                                  i18n ("Increase the game speed by 0.1 "
                                        "(maximum is 2.0 times normal)."),
491 492
                                  Qt::Key_Plus);

493
    a                           = gameAction ("decrease_speed", DEC_SPEED,
494
                                  i18n ("Decrease Speed"),
495
                                  i18n ("Decrease speed."),
496 497
                                  i18n ("Decrease the game speed by 0.1 "
                                        "(minimum is 0.2 times normal)."),
498
                                  Qt::Key_Minus);
499 500 501 502 503

    QActionGroup* speedGrp = new QActionGroup (this);
    speedGrp->addAction (nSpeed);
    speedGrp->addAction (bSpeed);
    speedGrp->addAction (cSpeed);
504
    speedGrp->setExclusive (true);
505 506 507 508

    // Configure Shortcuts...
    // --------------------------

Aaron J. Seigo's avatar
Aaron J. Seigo committed
509
    KStandardAction::keyBindings (
510 511
                                this, SLOT (optionsConfigureKeys()),
                                actionCollection());
512 513 514 515 516 517 518

    /**************************************************************************/
    /**************************   KEYSTROKE ACTIONS  **************************/
    /**************************************************************************/

    // Two-handed KB controls and alternate one-handed controls for the hero.

519
    QSignalMapper * kbMapper = new QSignalMapper (this);
Laurent Montel's avatar
Laurent Montel committed
520
    connect (kbMapper, SIGNAL (mapped(int)), game, SLOT(kbControl(int)));
521
    tempMapper = kbMapper;
522

523 524 525 526 527 528 529
    // The actions for the movement keys are created but disabled.  This lets
    // keyPressEvent() come through, instead of a signal, while still allowing
    // Settings->Configure Keys to change the key mappings.  The keyPressEvent()
    // call is needed so that the key can be identified and matched to the
    // corresponding keyReleaseEvent() call and make the hold-key option
    // work correctly when two keys are held down simultaneously.

530
    keyControl ("stop",       i18n ("Stop"),       Qt::Key_Space, STAND);
531 532 533 534
    keyControl ("move_right", i18n ("Move Right"), Qt::Key_Right, RIGHT, true);
    keyControl ("move_left",  i18n ("Move Left"),  Qt::Key_Left,  LEFT,  true);
    keyControl ("move_up",    i18n ("Move Up"),    Qt::Key_Up,    UP,    true);
    keyControl ("move_down",  i18n ("Move Down"),  Qt::Key_Down,  DOWN,  true);
535 536
    keyControl ("dig_right",  i18n ("Dig Right"),  Qt::Key_C,     DIG_RIGHT);
    keyControl ("dig_left",   i18n ("Dig Left"),   Qt::Key_Z,     DIG_LEFT);
537

538 539 540 541 542 543 544 545 546 547
    // Alternate one-handed controls.  Set up in "kgoldrunnerui.rc".

    // Key_I, "move_up"
    // Key_L, "move_right"
    // Key_K, "move_down"
    // Key_J, "move_left"
    // Key_Space, "stop" (as above)
    // Key_O, "dig_right"
    // Key_U, "dig_left"

548
    setupEditToolbarActions();		// Uses pixmaps from "renderer".
549

550 551 552 553
    // Authors' debugging aids, effective when Pause is hit.  Options include
    // stepping through the animation, toggling a debug patch or log messages
    // on or off during gameplay and printing the states of runners or tiles.

Laurent Montel's avatar
Laurent Montel committed
554
    KConfigGroup debugGroup (KSharedConfig::openConfig(), "Debugging");
555
    bool addDebuggingShortcuts = debugGroup.readEntry
556
                        ("DebuggingShortcuts", false);	// Get debug option.
557
    if (! addDebuggingShortcuts)
558 559
        return;

560
    QSignalMapper * dbgMapper = new QSignalMapper (this);
Laurent Montel's avatar
Laurent Montel committed
561
    connect (dbgMapper, SIGNAL (mapped(int)), game, SLOT(dbgControl(int)));
562
    tempMapper = dbgMapper;
563 564 565

    keyControl ("do_step",      i18n ("Do a Step"), Qt::Key_Period, DO_STEP);
    keyControl ("bug_fix",      i18n ("Test Bug Fix"), Qt::Key_B, BUG_FIX);
566
    keyControl ("show_positions", i18n ("Show Positions"), Qt::Key_W, S_POSNS);
567
    keyControl ("logging",      i18n ("Start Logging"), Qt::Key_G, LOGGING);
568
    keyControl ("show_hero",    i18n ("Show Hero"), Qt::Key_E, S_HERO);
569
    keyControl ("show_obj",     i18n ("Show Object"), Qt::Key_Slash, S_OBJ);
570 571 572 573 574 575 576 577

    keyControl ("show_enemy_0", i18n ("Show Enemy") + '0', Qt::Key_0, ENEMY_0);
    keyControl ("show_enemy_1", i18n ("Show Enemy") + '1', Qt::Key_1, ENEMY_1);
    keyControl ("show_enemy_2", i18n ("Show Enemy") + '2', Qt::Key_2, ENEMY_2);
    keyControl ("show_enemy_3", i18n ("Show Enemy") + '3', Qt::Key_3, ENEMY_3);
    keyControl ("show_enemy_4", i18n ("Show Enemy") + '4', Qt::Key_4, ENEMY_4);
    keyControl ("show_enemy_5", i18n ("Show Enemy") + '5', Qt::Key_5, ENEMY_5);
    keyControl ("show_enemy_6", i18n ("Show Enemy") + '6', Qt::Key_6, ENEMY_6);
578
}
Ian Wadham's avatar
Ian Wadham committed
579

Laurent Montel's avatar
Laurent Montel committed
580
QAction * KGoldrunner::gameAction (const QString & name,
581 582 583 584 585 586
                                   const int       code,
                                   const QString & text,
                                   const QString & toolTip,
                                   const QString & whatsThis,
                                   const QKeySequence & key)
{
Laurent Montel's avatar
Laurent Montel committed
587
    QAction * ga = actionCollection()->addAction (name);
588 589 590
    ga->setText (text);
    ga->setToolTip (toolTip);
    ga->setWhatsThis (whatsThis);
591
    if (! key.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
592
        actionCollection()->setDefaultShortcut(ga, key);
593
    }
Laurent Montel's avatar
Laurent Montel committed
594
    connect (ga, SIGNAL (triggered(bool)), tempMapper, SLOT (map()));
595 596 597 598
    tempMapper->setMapping (ga, code);
    return ga;
}

Laurent Montel's avatar
Laurent Montel committed
599
QAction * KGoldrunner::editAction (const QString & name,
600 601 602 603 604
                                   const int       code,
                                   const QString & text,
                                   const QString & toolTip,
                                   const QString & whatsThis)
{
Laurent Montel's avatar
Laurent Montel committed
605
    QAction * ed = actionCollection()->addAction (name);
606 607 608
    ed->setText (text);
    ed->setToolTip (toolTip);
    ed->setWhatsThis (whatsThis);
Laurent Montel's avatar
Laurent Montel committed
609
    connect (ed, SIGNAL (triggered(bool)), tempMapper, SLOT (map()));
610 611 612 613
    tempMapper->setMapping (ed, code);
    return ed;
}

614 615 616 617 618 619 620 621 622 623
KToggleAction * KGoldrunner::settingAction (const QString & name,
                                            const int       code,
                                            const QString & text,
                                            const QString & toolTip,
                                            const QString & whatsThis)
{
    KToggleAction * s = new KToggleAction (text, this);
    actionCollection()->addAction (name, s);
    s->setToolTip (toolTip);
    s->setWhatsThis (whatsThis);
Laurent Montel's avatar
Laurent Montel committed
624
    connect (s, SIGNAL (triggered(bool)), tempMapper, SLOT (map()));
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
    tempMapper->setMapping (s, code);
    return s;
}

KToggleAction * KGoldrunner::editToolbarAction (const QString & name,
                                                const char      code,
                                                const QString & shortText,
                                                const QString & text,
                                                const QString & toolTip,
                                                const QString & whatsThis)
{
    int mapCode = code;
    KToggleAction * ed = new KToggleAction (text, this);
    actionCollection()->addAction (name, ed);
    ed->setIconText (shortText);
    ed->setToolTip (toolTip);
    ed->setWhatsThis (whatsThis);
Laurent Montel's avatar
Laurent Montel committed
642
    connect (ed, SIGNAL (triggered(bool)), tempMapper, SLOT (map()));
643 644 645 646
    tempMapper->setMapping (ed, mapCode);
    return ed;
}

647
void KGoldrunner::keyControl (const QString & name, const QString & text,
648 649
                              const QKeySequence & shortcut, const int code,
                              const bool mover)
650
{
Laurent Montel's avatar
Laurent Montel committed
651
    QAction * a = actionCollection()->addAction (name);
652
    a->setText (text);
Laurent Montel's avatar
Laurent Montel committed
653
    actionCollection()->setDefaultShortcut(a, shortcut);
654 655 656 657 658 659 660 661 662

    // If this is a move-key, let keyPressEvent() through, instead of signal.
    if (mover) {
        a->setEnabled (false);
    }
    else {
        a->setAutoRepeat (false);	// Else, prevent QAction signal repeat.
    }

Laurent Montel's avatar
Laurent Montel committed
663
    connect (a, SIGNAL (triggered(bool)), tempMapper, SLOT (map()));
664
    tempMapper->setMapping (a, code);
665 666 667
    addAction (a);
}

668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
void KGoldrunner::keyPressEvent (QKeyEvent * event)
{
    // For movement keys, all presses and releases are processed, thus allowing
    // the hold-key option to work correctly when two keys are held down.

    if (! identifyMoveAction (event, true)) {
        QWidget::keyPressEvent (event);
    }
}

void KGoldrunner::keyReleaseEvent (QKeyEvent * event)
{
    if (! identifyMoveAction (event, false)) {
        QWidget::keyReleaseEvent (event);
    }
}

bool KGoldrunner::identifyMoveAction (QKeyEvent * event, bool pressed)
{
    bool result = false;
    if (! event->isAutoRepeat()) {
        QKeySequence keystroke (event->key() + event->modifiers());
        result = true;

        if ((ACTION ("move_left"))->shortcuts().contains(keystroke)) {
            game->kbControl (LEFT, pressed);
        }
        else if ((ACTION ("move_right"))->shortcuts().contains(keystroke)) {
            game->kbControl (RIGHT, pressed);
        }
        else if ((ACTION ("move_up"))->shortcuts().contains(keystroke)) {
            game->kbControl (UP, pressed);
        }
        else if ((ACTION ("move_down"))->shortcuts().contains(keystroke)) {
            game->kbControl (DOWN, pressed);
        }
        else {
            result = false;
        }
    }
    return result;
}

711
void KGoldrunner::viewFullScreen (bool activation)
Luciano Montanaro's avatar
Luciano Montanaro committed
712
{
713
    KToggleFullScreenAction::setFullScreen (this, activation);
Luciano Montanaro's avatar
Luciano Montanaro committed
714 715
}

716
void KGoldrunner::gameFreeze (bool on_off)
Ian Wadham's avatar
Ian Wadham committed
717
{
718
    myPause->setChecked (on_off);
719
    frozen = on_off;	// Remember the state (for the configure-keys case).
720
    QStringList pauseKeys;
Laurent Montel's avatar
Laurent Montel committed
721
#if 0 //QT5
722 723 724
    foreach (const QKeySequence &s, myPause->shortcut().toList()) {
        pauseKeys.append(s.toString(QKeySequence::NativeText));
    }
Laurent Montel's avatar
Laurent Montel committed
725
#endif
726
    QString msg;
727 728
    if (on_off) {
        if (pauseKeys.size() == 0) {
729
            msg = i18n("The game is paused");
730
        } else if (pauseKeys.size() == 1) {
731
            msg = i18n("Press \"%1\" to RESUME", pauseKeys.at(0));
732
        } else {
733 734
            msg = i18n("Press \"%1\" or \"%2\" to RESUME", pauseKeys.at(0),
                                                           pauseKeys.at(1));
735 736 737
        }
    } else {
        if (pauseKeys.size() == 0) {
738
            msg = "";
739
        } else if (pauseKeys.size() == 1) {
740
            msg = i18n("Press \"%1\" to PAUSE", pauseKeys.at(0));
741
        } else {
742 743
            msg = i18n("Press \"%1\" or \"%2\" to PAUSE", pauseKeys.at(0),
                                                          pauseKeys.at(1));
744 745
        }
    }
746
    scene->setPauseResumeText (msg);
Ian Wadham's avatar
Ian Wadham committed
747 748
}

749
void KGoldrunner::adjustHintAction (bool hintAvailable)
Ian Wadham's avatar
Ian Wadham committed
750
{
751
    hintAction->setEnabled (hintAvailable);
Ian Wadham's avatar
Ian Wadham committed
752

753 754 755
    QString msg;
    msg = hintAvailable ? i18n("Has hint") : i18n("No hint");
    scene->setHasHintText (msg);
Dirk Mueller's avatar
compile  
Dirk Mueller committed
756
}
Ian Wadham's avatar
Ian Wadham committed
757

758 759 760 761 762 763 764
void KGoldrunner::setToggle (const char * actionName, const bool onOff)
{
    ((KToggleAction *) ACTION (actionName))->setChecked (onOff);
}

void KGoldrunner::setAvail (const char * actionName, const bool onOff)
{
Laurent Montel's avatar
Laurent Montel committed
765
    ((QAction *) ACTION (actionName))->setEnabled (onOff);
766 767
}

768
void KGoldrunner::setEditMenu (bool on_off)
Ian Wadham's avatar
Ian Wadham committed
769
{
770
    saveEdits->setEnabled  (on_off);
Ian Wadham's avatar
Ian Wadham committed
771

772 773 774 775
    saveGame->setEnabled   (! on_off);
    hintAction->setEnabled (! on_off);
    killHero->setEnabled   (! on_off);
    highScore->setEnabled  (! on_off);
776 777
    setAvail ("instant_replay", (! on_off));
    setAvail ("game_pause",     (! on_off));
Ian Wadham's avatar
Ian Wadham committed
778

779
    if (on_off){
780
        // Set the editToolbar icons to the current tile-size.
Laurent Montel's avatar
Laurent Montel committed
781
        //qCDebug(KGOLDRUNNER_LOG) << "ToolBar icon size:" << scene->tileSize ();
782
        toolBar ("editToolbar")->setIconSize (scene->tileSize ());
783 784 785 786 787 788

        // Set the editToolbar icons up with pixmaps of the current theme.
        setEditIcon ("brickbg",   BRICK);
        setEditIcon ("fbrickbg",  FBRICK);
        setEditIcon ("freebg",    FREE);
        setEditIcon ("nuggetbg",  NUGGET);
789 790
        setEditIcon ("polebg",    BAR);
        setEditIcon ("concretebg", CONCRETE);
791 792 793 794
        setEditIcon ("ladderbg",  LADDER);
        setEditIcon ("hladderbg", HLADDER);
        setEditIcon ("edherobg",  HERO);
        setEditIcon ("edenemybg", ENEMY);
795
        setToggle   ("brickbg", true);		// Default edit-object is BRICK.
796 797

        toolBar ("editToolbar")->show();
Ian Wadham's avatar
Ian Wadham committed
798
    }
799
    else {
800
        toolBar ("editToolbar")->hide();
Ian Wadham's avatar
Ian Wadham committed
801
    }
802
}
Ian Wadham's avatar
Ian Wadham committed
803

804
void KGoldrunner::setEditIcon (const QString & actionName, const char iconType)
805
{
806
    ((KToggleAction *) (actionCollection()->action (actionName)))->
Laurent Montel's avatar
Laurent Montel committed
807
                setIcon (QIcon(renderer->getPixmap (iconType)));
808
}
809

Ian Wadham's avatar
Ian Wadham committed
810
/******************************************************************************/
811
/*******************   SLOTS FOR MENU AND KEYBOARD ACTIONS  *******************/
Ian Wadham's avatar
Ian Wadham committed
812 813
/******************************************************************************/

814
void KGoldrunner::changeTheme ()
815
{
816
    renderer->selectTheme ();
817
}
818

819 820 821
void KGoldrunner::redrawEditToolbar ()
{
    // Signalled by the scene after the theme or tile size has changed.
822
    if (game->inEditMode()) {
823
        setEditMenu (true);
824
    }
825 826
}

827
void KGoldrunner::saveProperties (KConfigGroup & /* config - unused */)
828 829 830 831
{
    // The 'config' object points to the session managed
    // config file.  Anything you write here will be available
    // later when this app is restored.
Ian Wadham's avatar
Ian Wadham committed
832

Laurent Montel's avatar
Laurent Montel committed
833
    //qCDebug(KGOLDRUNNER_LOG) << "I am in KGoldrunner::saveProperties.";
Ian Wadham's avatar
Ian Wadham committed
834 835
}

836
void KGoldrunner::readProperties (const KConfigGroup & /* config - unused */)
Ian Wadham's avatar
Ian Wadham committed
837
{
838 839 840 841
    // The 'config' object points to the session managed
    // config file.  This function is automatically called whenever
    // the app is being restored.  Read in here whatever you wrote
    // in 'saveProperties'
Ian Wadham's avatar
Ian Wadham committed
842

Laurent Montel's avatar
Laurent Montel committed
843
    //qCDebug(KGOLDRUNNER_LOG) << "I am in KGoldrunner::readProperties.";
Ian Wadham's avatar
Ian Wadham committed
844 845
}

846
void KGoldrunner::optionsConfigureKeys()
Ian Wadham's avatar
Ian Wadham committed
847
{
848 849 850 851 852 853
    // First run the standard KDE dialog for shortcut key settings.
    KShortcutsDialog::configure (actionCollection(),
	KShortcutsEditor::LetterShortcutsAllowed,	// Single letters OK.
	this,						// Parent widget.
	true);						// saveSettings value.

Ian Wadham's avatar
Ian Wadham committed
854
    gameFreeze (frozen);		// Update the pause/resume text.
Ian Wadham's avatar
Ian Wadham committed
855 856
}

857
bool KGoldrunner::getDirectories()
Ian Wadham's avatar
Ian Wadham committed
858
{
Jaison Lee's avatar
Jaison Lee committed
859
    bool result = true;
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877

    // WHERE THINGS ARE: In the KDE 3 environment (Release 3.1.1), application
    // documentation and data files are in a directory structure given by
    // $KDEDIRS (e.g. "/usr/local/kde" or "/opt/kde3/").  Application user data
    // files are in a directory structure given by $KDEHOME ("$HOME/.kde").
    // Within those two structures, the three sub-directories will typically be
    // "share/doc/HTML/en/kgoldrunner/", "share/apps/kgoldrunner/system/" and
    // "share/apps/kgoldrunner/user/".  Note that it is necessary to have
    // an extra path level ("system" or "user") after "kgoldrunner", otherwise
    // all the KGoldrunner files have similar path names (after "apps") and
    // KDE always locates directories in $KDEHOME and never the released games.

    // The directory strings are set by KDE at run time and might change in
    // later releases, so use them with caution and only if something gets lost.

    KStandardDirs * dirs = new KStandardDirs();

    QString myDir = "kgoldrunner";
Ian Wadham's avatar
Ian Wadham committed
878

879
    // Find the KGoldrunner Users' Guide, English version (en).
Dmitry Suzdalev's avatar
Dmitry Suzdalev committed
880
    systemHTMLDir = dirs->findResourceDir ("html", "en/" + myDir + '/');
881
    if (systemHTMLDir.length() <= 0) {
882 883 884
        KGrMessage::information (this, i18n ("Get Folders"),
                i18n ("Cannot find documentation sub-folder 'en/%1/' "
                "in area '%2' of the KDE folder ($KDEDIRS).",
885
                myDir, dirs->resourceDirs ("html").join ( QLatin1String( ":" ))));
886
        // result = false;		// Don't abort if the doc is missing.
887 888
    }
    else
889
        systemHTMLDir.append ("en/" + myDir + '/');
Ian Wadham's avatar
Ian Wadham committed
890

891 892 893
    // Find the system collections in a directory of the required KDE type.
    systemDataDir = dirs->findResourceDir ("data", myDir + "/system/");
    if (systemDataDir.length() <= 0) {