kgoldrunner.cpp 42.6 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
port++    
Laurent Montel committed
37
#include <QDebug>
38
#include <QDebug>
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
port++    
Laurent Montel committed
169
170
    //qDebug() << "QMetaObject::invokeMethod (this, \"KGoldrunner_2\") done ... ";
    //qDebug() << "1st scan of event-queue ...";
171
172
173
174
}

void KGoldrunner::KGoldrunner_2()
{
Laurent Montel's avatar
port++    
Laurent Montel committed
175
    //qDebug() << "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
port++    
Laurent Montel committed
181
182
    //qDebug() << "QMetaObject::invokeMethod (game, \"initGame\") done ... ";
    //qDebug() << "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
228
    gameMapper->setMapping (saveGame, SAVE_GAME);
    saveGame->setText (i18n ("&Save Game..."));
    saveGame->setShortcut (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
592
593
    if (! key.isEmpty()) {
        ga->setShortcut (key);
    }
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
653
    a->setText (text);
    a->setShortcut (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
port++    
Laurent Montel committed
781
        //qDebug() << "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
port++    
Laurent Montel committed
833
    //qDebug() << "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
port++    
Laurent Montel committed
843
    //qDebug() << "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) {
894
895
896
        KGrMessage::information (this, i18n ("Get Folders"),
        i18n ("Cannot find system games sub-folder '%1/system/' "
        "in area '%2' of the KDE folder ($KDEDIRS).",
897
         myDir, dirs->resourceDirs ("data").join ( QLatin1String( ":" ))));
898
        result = false;			// ABORT if the games data is missing.
Ian Wadham's avatar
Ian Wadham committed
899
    }
900
    else
901
        systemDataDir.append (myDir + "/system/");
Ian Wadham's avatar
Ian Wadham committed
902

903
    // Locate and optionally create directories for user collections and levels.
Jaison Lee's avatar
Jaison Lee committed
904
    bool create = true;
905
906
    userDataDir   = dirs->saveLocation ("data", myDir + "/user/", create);
    if (userDataDir.length() <= 0) {
907
908
909
        KGrMessage::information (this, i18n ("Get Folders"),
        i18n ("Cannot find or create user games sub-folder '%1/user/' "
        "in area '%2' of the KDE user area ($KDEHOME).",
910
         myDir, dirs->resourceDirs ("data").join ( QLatin1String( ":" ))));
911
        // result = false;		// Don't abort if user area is missing.
Ian Wadham's avatar
Ian Wadham committed
912
    }
913
    else {
914
915
916
917
918
919
920
        create = dirs->makeDir (userDataDir + "levels/");
        if (! create) {
            KGrMessage::information (this, i18n ("Get Folders"),
            i18n ("Cannot find or create 'levels/' folder in "
            "sub-folder '%1/user/' in the KDE user area ($KDEHOME).", myDir));
            // result = false;		// Don't abort if user area is missing.
        }
Ian Wadham's avatar
Ian Wadham committed
921
    }
Laurent Montel's avatar
Laurent Montel committed
922
    delete dirs;
923
    return (result);
Ian Wadham's avatar
Ian Wadham committed
924
925
}

926
// This method is invoked when the main window is closed, whether by selecting
927
928
// "Quit" from the menu or by clicking the "X" at the top right of the window.

929
930
931
932
// If we return true, game-edits were saved or abandoned or there was no editing
// in progress, so the main window will close.  If we return false, the user has
// asked to go on editing, so the main window stays open.

933
bool KGoldrunner::queryClose()
Ian Wadham's avatar
Ian Wadham committed
934
{
935
    return (game->saveOK());
Ian Wadham's avatar
Ian Wadham committed
936
937
}

938
939
940
941
/******************************************************************************/
/**********************  MAKE A TOOLBAR FOR THE EDITOR   **********************/
/******************************************************************************/

942
void KGoldrunner::setupEditToolbarActions()
Ian Wadham's avatar
Ian Wadham committed
943
{
944
    QSignalMapper * editToolbarMapper = new QSignalMapper (this);
Laurent Montel's avatar
Laurent Montel committed
945
946
    connect (editToolbarMapper, SIGNAL (mapped(int)),
             game, SLOT (editToolbarActions(int)));
947
948
    tempMapper = editToolbarMapper;

Laurent Montel's avatar
Laurent Montel committed
949
    QAction * ed = editAction ("edit_hint", EDIT_HINT,
950
951
952
953
                               i18n ("Edit Name/Hint"),
                               i18n ("Edit level name or hint"),
                               i18n ("Edit text for the name or hint "
                                     "of a level"));