1 /*******************************************************************************
2 Copyright 2008 Ian Wadham <ianw2@optusnet.com.au>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *******************************************************************************/
27 #include <QSignalMapper>
32 #include <kstandardgameaction.h>
33 #include <KToggleAction>
34 #include <KActionCollection>
36 #include <KStandardDirs>
37 #include <KMessageBox>
39 #include <KShortcutsDialog>
43 #include "gameglview.h"
45 // Shorthand for reference to actions.
46 #define ACTION(x) (actionCollection()->action(x))
52 // setCaption("Rubik's Cube"); // DELETED - This is a *trademark*.
54 // use multi-sample (anti-aliased) OpenGL if available
55 QGLFormat defFormat
= QGLFormat::defaultFormat();
56 defFormat
.setSampleBuffers(true);
57 QGLFormat::setDefaultFormat(defFormat
);
59 game
= new Game (this);
61 gameView
= new GameGLView (game
, this);
63 // Set the view as the central widget
64 setCentralWidget(gameView
);
66 // Set up the menus, keystrokes, etc.
69 // Enable the help menu.
70 setHelpMenuEnabled (true);
72 // Load the GUI from the kubrickui.rc file.
75 // Set up a status bar.
77 statusBar()->insertItem (i18n("Welcome to Kubrick"), 1001, 1);
79 // Set a larger font than toolbar-default for the Singmaster-moves display.
80 QFont f
= statusBar()->font();
81 f
.setPointSize (f
.pointSize()); // Needed to force a size-change.
82 singmasterLabel
->setFont (f
);
83 singmasterMoves
->setFont (f
);
88 setAutoSaveSettings ();
90 // Start the game with a randomised demo.
91 game
->initGame (gameView
, this);
100 const Kubrick::PuzzleItem
Kubrick::easyItems
[] = {
101 {I18N_NOOP("2x2x1 mat, 1 move"), 2, 2, 1, 1, 1, 1},
102 {I18N_NOOP("2x2x1 mat, 2 moves"), 2, 2, 1, 2, 1, 1},
103 {I18N_NOOP("2x2x1 mat, 3 moves"), 2, 2, 1, 3, 1, 1},
104 {I18N_NOOP("2x2x2 cube, 2 moves"), 2, 2, 2, 2, 1, 1},
105 {I18N_NOOP("2x2x2 cube, 3 moves"), 2, 2, 2, 3, 1, 1},
106 {I18N_NOOP("2x2x2 cube, 4 moves"), 2, 2, 2, 4, 1, 0},
107 {I18N_NOOP("3x3x1 mat, 4 moves"), 3, 3, 1, 4, 1, 0},
108 {I18N_NOOP("3x3x3 cube, 3 moves"), 3, 3, 3, 3, 1, 0},
109 {I18N_NOOP("3x3x3 cube, 4 moves"), 3, 3, 3, 4, 1, 0},
110 {"END", 0, 0, 0, 0, 0, 0}
114 const Kubrick::PuzzleItem
Kubrick::notSoEasyItems
[] = {
115 {I18N_NOOP("3x3x3 cube, 3 moves"), 3, 3, 3, 3, 0, 0},
116 {I18N_NOOP("3x3x3 cube, 4 moves"), 3, 3, 3, 4, 0, 0},
117 {I18N_NOOP("4x4x4 cube, 4 moves"), 4, 4, 4, 4, 0, 0},
118 {I18N_NOOP("5x5x5 cube, 4 moves"), 5, 5, 5, 4, 0, 0},
119 {I18N_NOOP("6x3x2 brick, 4 moves"), 6, 3, 2, 4, 0, 0},
120 {"END", 0, 0, 0, 0, 0, 0}
124 const Kubrick::PuzzleItem
Kubrick::hardItems
[] = {
125 {I18N_NOOP("3x3x3 cube, 7 moves"), 3, 3, 3, 7, 0, 0},
126 {I18N_NOOP("4x4x4 cube, 5 moves"), 4, 4, 4, 5, 0, 0},
127 {I18N_NOOP("5x5x5 cube, 6 moves"), 5, 5, 5, 6, 0, 0},
128 {I18N_NOOP("6x6x6 cube, 6 moves"), 6, 6, 6, 6, 0, 0},
129 {I18N_NOOP("6x4x1 mat, 9 moves"), 6, 4, 1, 9, 0, 0},
130 {I18N_NOOP("6x3x2 brick, 6 moves"), 6, 3, 2, 7, 0, 0},
131 {"END", 0, 0, 0, 0, 0, 0}
135 const Kubrick::PuzzleItem
Kubrick::veryHardItems
[] = {
136 {I18N_NOOP("3x3x3 cube, 12 moves"), 3, 3, 3, 12, 0, 0},
137 {I18N_NOOP("3x3x3 cube, 15 moves"), 3, 3, 3, 15, 0, 0},
138 {I18N_NOOP("3x3x3 cube, 20 moves"), 3, 3, 3, 20, 0, 0},
139 {I18N_NOOP("4x4x4 cube, 12 moves"), 4, 4, 4, 12, 0, 0},
140 {I18N_NOOP("5x5x5 cube, 15 moves"), 5, 5, 5, 15, 0, 0},
141 {I18N_NOOP("6x6x6 cube, 25 moves"), 6, 6, 6, 25, 0, 0},
142 {"END", 0, 0, 0, 0, 0, 0}
146 const QString
Kubrick::patternMovesInfo
= I18N_NOOP(
147 "Rubik's Cube can be moved into many interesting patterns. Here are "
148 "a few from David Singmaster's classic book 'Notes on Rubik's Magic Cube, "
149 "Fifth Edition', pages 47-49, published in 1981. After a pattern has "
150 "formed, you can use the Solve action (default key S) to undo and redo it "
151 "as often as you like."
155 const Kubrick::DemoItem
Kubrick::patterns
[] = {
156 {"", I18N_NOOP("Info")},
157 {"p333X6.kbk", I18N_NOOP("3x3x3, 6 X")},
158 {"p333X2.kbk", I18N_NOOP("3x3x3, 2 X")},
159 {"p333Spot6.kbk", I18N_NOOP("3x3x3, 6 Spot")},
160 {"p333Spot4.kbk", I18N_NOOP("3x3x3, 4 Spot")},
161 {"p333Plus4.kbk", I18N_NOOP("3x3x3, 4 Plus")},
162 {"p333Bar4.kbk", I18N_NOOP("3x3x3, 4 Bar")},
163 {"p333U6.kbk", I18N_NOOP("3x3x3, 6 U")},
164 {"p333U4.kbk", I18N_NOOP("3x3x3, 4 U")},
165 {"p333Snake.kbk", I18N_NOOP("3x3x3, Snake")},
166 {"p333Worm.kbk", I18N_NOOP("3x3x3, Worm")},
167 {"p333Tricolor6.kbk", I18N_NOOP("3x3x3, Tricolor")},
168 {"p333DoubleCube.kbk", I18N_NOOP("3x3x3, Double Cube")},
173 const QString
Kubrick::solvingMovesInfo
= I18N_NOOP(
174 "<qt>Mathematicians calculate that a 3x3x3 cube can be shuffled into "
175 "43,252,003,274,489,856,000 different patterns, yet they conjecture "
176 "that all positions can be solved in 20 moves or less. The method "
177 "that can do that (as yet undiscovered) is called God's Algorithm."
179 "Many longer methods are known (see <a href=en.wikipedia.org>Optimal "
180 "Solutions for Rubik's Cube at en.wikipedia.org</a>)."
182 "Several methods work systematically by building the solution one layer "
183 "at a time, using sequences of moves that solve a few pieces without "
184 "disturbing what has already been done. The 'Beginner Solution' "
185 "demonstrated here is from "
186 "<a href=www.geocities.com/jasmine_ellen/RubiksCubeSolution.html>"
187 "www.geocities.com/jasmine_ellen/RubiksCubeSolution.html</a> (see that "
188 "site for a full description and other solution ideas). Just over "
189 "100 moves solve a cube that is shuffled in 20.</qt>"
191 // Setup the GUI, menus, ...
192 const Kubrick::DemoItem
Kubrick::solvingMoves
[] = {
193 {"", I18N_NOOP("Info")},
194 {"m333Layer1.kbk", I18N_NOOP("3x3x3 Layer 1, Edges First")},
195 {"m333MEdge1.kbk", I18N_NOOP("3x3x3 Layer 2, Edge from Bottom Right")},
196 {"m333MEdge2.kbk", I18N_NOOP("3x3x3 Layer 2, Edge from Bottom Left")},
197 {"m333LLEdgeFlip.kbk", I18N_NOOP("3x3x3 Layer 3, Flip Edge Pieces")},
198 {"m333LLCornerPos.kbk", I18N_NOOP("3x3x3 Layer 3, Place Corners")},
199 {"m333LLCornerRot.kbk", I18N_NOOP("3x3x3 Layer 3, Twist Corners")},
200 {"m333LLEdgePos.kbk", I18N_NOOP("3x3x3 Layer 3, Place Edges and DONE!")},
201 {"m333Complete.kbk", I18N_NOOP("3x3x3 Cube, Complete Solution")},
202 {"m333E2prX.kbk", I18N_NOOP("3x3x3 Swap 2 Pairs of Edges")},
203 {"m333CTwirl2.kbk", I18N_NOOP("3x3x3 Untwist 2 Corners")},
204 {"m333EFlip2.kbk", I18N_NOOP("3x3x3 Flip 2 Edges")},
209 // Create an action and set some help text for all menu items
210 // See also the *ui.rc file for the XML definitions
211 void Kubrick::initGUI()
214 QAction
* newAction
= KStandardGameAction::gameNew (
215 game
, SLOT (newPuzzle()), this);
216 actionCollection()->addAction (newAction
->objectName(), newAction
);
217 newAction
->setText (i18n("&New Puzzle"));
218 newAction
->setToolTip (i18n("Start a new puzzle."));
219 newAction
->setWhatsThis (i18n("Finish the puzzle you are working on "
220 "and start a new puzzle with the same "
221 "dimensions and number of shuffling moves."));
224 a
= KStandardGameAction::load (
225 game
, SLOT (load()), this);
226 actionCollection()->addAction (a
->objectName(), a
);
227 a
->setText (i18n("&Load Puzzle..."));
228 a
->setToolTip (i18n("Reload a saved puzzle from a file."));
229 a
->setWhatsThis (i18n("Reload a puzzle you have previously "
230 "saved on a file, including its dimensions, "
231 "settings, current state and history of "
234 a
= KStandardGameAction::save (
235 game
, SLOT (save()), this);
236 actionCollection()->addAction (a
->objectName(), a
);
237 a
->setText (i18n("&Save Puzzle..."));
238 a
->setToolTip (i18n("Save the puzzle on a file."));
239 a
->setWhatsThis (i18n("Save the puzzle on a file, including "
240 "its dimensions, settings, current state and "
241 "history of moves."));
243 a
= KStandardGameAction::saveAs (
244 game
, SLOT (saveAs()), this);
245 actionCollection()->addAction (a
->objectName(), a
);
246 a
->setText (i18n("&Save Puzzle As..."));
248 a
= KStandardGameAction::
249 restart (game
, SLOT (undoAll()), this);
250 actionCollection()->addAction (a
->objectName(), a
);
251 a
->setText (i18n("Restart &Puzzle..."));
252 a
->setToolTip (i18n("Undo all previous moves and start "
254 a
->setWhatsThis (i18n("Undo all previous moves and start "
257 a
= KStandardGameAction::
258 quit (this, SLOT (close()), this);
259 actionCollection()->addAction (a
->objectName(), a
);
260 // NOTE: KXmlGuiWindow::close() calls Kubrick::queryClose(), our real "quit"
263 a
= KStandardGameAction::
264 undo (game
, SLOT (undoMove()), this);
265 actionCollection()->addAction (a
->objectName(), a
);
266 a
->setToolTip (i18n("Undo the last move."));
267 a
->setWhatsThis (i18n("Undo the last move."));
269 a
= KStandardGameAction::
270 redo (game
, SLOT (redoMove()), this);
271 actionCollection()->addAction (a
->objectName(), a
);
272 a
->setToolTip (i18n("Redo a previously undone move."));
273 a
->setWhatsThis (i18n("Redo a previously undone move "
274 "(repeatedly from the start if required)."));
276 a
= KStandardGameAction::
277 solve (game
, SLOT (solveCube()), this);
278 actionCollection()->addAction (a
->objectName(), a
);
279 a
->setToolTip (i18n("Show the solution of the puzzle."));
280 a
->setWhatsThis (i18n("Show the solution of the puzzle by "
281 "undoing and re-doing all shuffling moves."));
283 a
= KStandardGameAction::
284 demo (game
, SLOT (toggleDemo()), this);
285 actionCollection()->addAction (a
->objectName(), a
);
286 a
->setText (i18n("Main &Demo"));
287 a
->setToolTip (i18n("Run a demonstration of puzzle moves."));
288 a
->setWhatsThis (i18n("Run a demonstration of puzzle moves, "
289 "in which randomly chosen cubes, bricks or "
290 "mats are shuffled and solved."));
292 a
= actionCollection()->addAction ("standard_view");
293 a
->setText (i18n("Realign Cube"));
294 a
->setToolTip (i18n("Realign the cube so that the top, "
295 "front and right faces are visible together."));
296 a
->setWhatsThis (i18n("Realign the cube so that the top, "
297 "front and right faces are visible together "
298 "and the cube's axes are parallel to the XYZ "
299 "axes, thus making keyboard moves properly "
301 a
->setIcon (KIcon("go-home"));
302 a
->setShortcut (Qt::Key_Home
);
303 connect (a
, SIGNAL (triggered (bool)), game
, SLOT (setStandardView()));
305 a
= actionCollection()->addAction ("redo_all");
306 a
->setText (i18n("Redo All"));
307 a
->setShortcut (Qt::SHIFT
+ Qt::Key_R
);
308 connect (a
, SIGNAL (triggered (bool)), game
, SLOT (redoAll()));
310 // Read-only display of Singmaster moves on the toolbar.
311 singmasterLabel
= new QLabel (i18n("Singmaster Moves"), this);
312 singmasterMoves
= new QLineEdit (this);
314 KAction
* w
= new KAction (this);
315 actionCollection()->addAction ("singmaster_label", w
);
316 w
->setDefaultWidget (singmasterLabel
);
318 w
= new KAction (this);
319 actionCollection()->addAction ("singmaster_moves", w
);
320 w
->setDefaultWidget (singmasterMoves
);
322 QString singmasterToolTip
= i18n("This area shows Singmaster moves.");
323 QString singmasterWhatsThis
= i18nc("The letters RLFBUD are mathematical "
324 "notation based on English words. Please leave those "
325 "letters and words untranslated in some form.",
327 "This area shows Singmaster moves. "
328 "They are based on the letters RLFBUD, representing "
329 "(in English) the Right, Left, Front, Back, Up and "
330 "Down faces. In normal view, the letters RFU represent "
331 "clockwise moves of the three visible faces and LBD "
332 "appear as anticlockwise moves of the hidden faces. "
333 "Adding a ' (apostrophe) to a letter gives the reverse "
334 "of that letter's move. To move inner slices, add "
335 "periods (or dots) before the letter of the nearest "
338 singmasterLabel
->setToolTip (singmasterToolTip
);
339 singmasterLabel
->setWhatsThis (singmasterWhatsThis
);
340 singmasterMoves
->setToolTip (singmasterToolTip
);
341 singmasterMoves
->setWhatsThis (singmasterWhatsThis
);
343 singmasterMoves
->setReadOnly (true);
344 singmasterLabel
->setBuddy (singmasterMoves
);
345 singmasterMoves
->show();
346 singmasterLabel
->show();
347 singmasterMoves
->setFocusPolicy (Qt::NoFocus
);
348 singmasterMoves
->clearFocus();
350 // "Choose Puzzle Type" sub-menu.
351 easyList
= new KSelectAction (i18n("&Easy"), this);
352 actionCollection()->addAction ("easy_list", easyList
);
353 fillPuzzleList (easyList
, easyItems
);
354 connect (easyList
, SIGNAL(triggered(int)), SLOT(easySelected(int)));
356 notSoEasyList
= new KSelectAction (i18n("&Not So Easy"), this);
357 actionCollection()->addAction ("not_easy_list", notSoEasyList
);
358 fillPuzzleList (notSoEasyList
, notSoEasyItems
);
359 connect (notSoEasyList
,SIGNAL(triggered(int)),SLOT(notSoEasySelected(int)));
361 hardList
= new KSelectAction (i18n("&Hard"), this);
362 actionCollection()->addAction ("hard_list", hardList
);
363 fillPuzzleList (hardList
, hardItems
);
364 connect (hardList
, SIGNAL(triggered(int)), SLOT(hardSelected(int)));
366 veryHardList
= new KSelectAction (i18n("&Very Hard"), this);
367 actionCollection()->addAction ("very_hard_list", veryHardList
);
368 fillPuzzleList (veryHardList
, veryHardItems
);
369 connect (veryHardList
, SIGNAL(triggered(int)), SLOT(veryHardSelected(int)));
371 a
= actionCollection()->addAction ("new_cube");
372 a
->setText (i18n("Make your own..."));
373 connect (a
, SIGNAL (triggered (bool)), game
, SLOT (newCubeDialog()));
377 QActionGroup
* viewGroup
= new QActionGroup (this);
378 viewGroup
->setExclusive (true);
380 QSignalMapper
* viewMapper
= new QSignalMapper (this);
381 connect (viewMapper
, SIGNAL (mapped (const int)),
382 game
, SLOT (changeScene (const int)));
384 b
= new KToggleAction (i18n ("1 Cube"), this);
385 actionCollection()->addAction ("scene_1", b
);
386 b
->setToolTip (i18n ("Show one view of this cube."));
387 b
->setWhatsThis (i18n ("Show one view of this cube, "
389 b
->setIcon (KIcon("arrow-left")); // IDW - Temporary.
390 connect (b
, SIGNAL(triggered (bool)), viewMapper
, SLOT(map()));
391 b
->setChecked (true);
392 viewMapper
->setMapping (b
, OneCube
);
393 viewGroup
->addAction (b
);
395 b
= new KToggleAction (i18n ("2 Cubes"), this);
396 actionCollection()->addAction ("scene_2", b
);
397 b
->setToolTip (i18n ("Show two views of this cube."));
398 b
->setWhatsThis (i18n ("Show two views of this cube, from "
399 "the front and the back. Both can rotate."));
400 b
->setIcon (KIcon("arrow-up")); // IDW - Temporary.
401 connect (b
, SIGNAL(triggered (bool)), viewMapper
, SLOT(map()));
402 viewMapper
->setMapping (b
, TwoCubes
);
403 viewGroup
->addAction (b
);
405 b
= new KToggleAction (i18n ("3 Cubes"), this);
406 actionCollection()->addAction ("scene_3", b
);
407 b
->setToolTip (i18n ("Show three views of this cube."));
408 b
->setWhatsThis (i18n ("Show three views of this cube, a "
409 "large one, from the front, and two small "
410 "ones, from the front and the back. Only "
411 "the large one can rotate."));
412 b
->setIcon (KIcon("arrow-right")); // IDW - Temporary.
413 connect (b
, SIGNAL(triggered (bool)), viewMapper
, SLOT(map()));
414 viewMapper
->setMapping (b
, ThreeCubes
);
415 viewGroup
->addAction (b
);
418 patternList
= new KSelectAction (i18n("&Pretty Patterns"), this);
419 actionCollection()->addAction ("patterns_list", patternList
);
420 maxPatternsIndex
= fillDemoList (patternList
, patterns
);
421 connect (patternList
, SIGNAL(triggered(int)), SLOT(patternSelected(int)));
423 movesList
= new KSelectAction (i18n("&Solution Moves"), this);
424 actionCollection()->addAction ("demo_moves_list", movesList
);
425 maxMovesIndex
= fillDemoList (movesList
, solvingMoves
);
426 connect (movesList
, SIGNAL(triggered(int)), SLOT(movesSelected(int)));
429 b
= new KToggleAction (i18n("&Watch Shuffling"), this);
430 actionCollection()->addAction ("watch_shuffling", b
);
431 b
->setShortcut (Qt::Key_W
);
432 connect (b
, SIGNAL (triggered (bool)), game
, SLOT (watchShuffling()));
434 b
= new KToggleAction (i18n("Watch Your &Own Moves"), this);
435 actionCollection()->addAction ("watch_moves", b
);
436 b
->setShortcut (Qt::Key_O
);
437 connect (b
, SIGNAL (triggered (bool)), game
, SLOT (watchMoves()));
439 // DISCONTINUED a = actionCollection()->addAction ("enable_messages");
440 // a->setText (i18n("Show Beginners' &Messages"));
441 // connect (a, SIGNAL (triggered (bool)), game, SLOT (enableMessages()));
443 // Sorry to be "non-standard" (below), but I am an English-speaker, born and
444 // bred, and I just don't find the KDE standard texts "Configure Kubrick"
445 // and "Configure Shortcuts" to be meaningful in everyday language. Neither
446 // would my wife, children and friends, I am sure.
448 a
= KStandardAction::preferences (game
, SLOT(optionsDialog()),
450 a
->setText (i18n("Kubri&ck Game Settings"));
452 // Configure Shortcuts...
453 a
= KStandardAction::keyBindings (this, SLOT(optionsConfigureKeys()),
455 a
->setText (i18n("Keyboard S&hortcut Settings"));
457 /**************************************************************************/
458 /************************** KEYSTROKE ACTIONS **************************/
459 /**************************************************************************/
461 // Keys to choose the axis for a slice move (X, Y or Z).
462 QSignalMapper
* moveAxis
= new QSignalMapper (this);
464 a
= actionCollection()->addAction ("x_axis");
465 a
->setText (i18n("X Axis"));
466 a
->setShortcut (Qt::Key_X
);
467 connect (a
, SIGNAL (triggered (bool)), moveAxis
, SLOT (map()));
468 moveAxis
->setMapping (a
, 0);
470 a
= actionCollection()->addAction ("y_axis");
471 a
->setText (i18n("Y Axis"));
472 a
->setShortcut (Qt::Key_Y
);
473 connect (a
, SIGNAL (triggered (bool)), moveAxis
, SLOT (map()));
474 moveAxis
->setMapping (a
, 1);
476 a
= actionCollection()->addAction ("z_axis");
477 a
->setText (i18n("Z Axis"));
478 a
->setShortcut (Qt::Key_Z
);
479 connect (a
, SIGNAL (triggered (bool)), moveAxis
, SLOT (map()));
480 moveAxis
->setMapping (a
, 2);
482 connect (moveAxis
, SIGNAL (mapped (int)), game
, SLOT (setMoveAxis (int)));
484 // Keys to choose the slice number for a slice move.
485 QSignalMapper
* moveSlice
= new QSignalMapper (this);
488 strcpy (ident
, "slice n");
489 for (int i
= 1; i
<= 6; i
++) {
490 sprintf (ident
, "slice %d", i
);
491 a
= actionCollection()->addAction (ident
);
492 a
->setText (i18n("Slice %1", i
));
493 a
->setShortcut (Qt::Key_0
+ i
);
494 connect (a
, SIGNAL (triggered (bool)), moveSlice
, SLOT (map()));
495 moveSlice
->setMapping (a
, i
);
498 // Key to select a rotation of the whole cube (mapped as "slice 0").
499 a
= actionCollection()->addAction ("turn_cube");
500 a
->setText (i18n("Turn whole cube"));
501 a
->setShortcut (Qt::Key_C
);
502 connect (a
, SIGNAL (triggered (bool)), moveSlice
, SLOT (map()));
503 moveSlice
->setMapping (a
, 0);
505 connect (moveSlice
, SIGNAL (mapped (int)), game
, SLOT (setMoveSlice(int)));
507 // Keys to choose the direction for a slice move (clock or anti-clock).
508 QSignalMapper
* moveDirection
= new QSignalMapper (this);
510 a
= actionCollection()->addAction ("anti_clockwise");
511 a
->setText (i18n("Anti-clockwise"));
512 a
->setShortcut (Qt::Key_Left
);
513 connect (a
, SIGNAL (triggered (bool)), moveDirection
, SLOT (map()));
514 moveDirection
->setMapping (a
, 0);
516 a
= actionCollection()->addAction ("clockwise");
517 a
->setText (i18n("Clockwise"));
518 a
->setShortcut (Qt::Key_Right
);
519 connect (a
, SIGNAL (triggered (bool)), moveDirection
, SLOT (map()));
520 moveDirection
->setMapping (a
, 1);
522 connect (moveDirection
, SIGNAL (mapped (int)),
523 game
, SLOT (setMoveDirection (int)));
525 // Keys for Singmaster (sm) moves.
526 QSignalMapper
* smMove
= new QSignalMapper (this);
527 a
= mapAction (smMove
, "sm_u", i18n("Move 'Up' face"),
529 a
= mapAction (smMove
, "sm_d", i18n("Move 'Down' face"),
531 // IDW Qt::Key_D, SM_DOWN);
532 a
= mapAction (smMove
, "sm_l", i18n("Move 'Left' face"),
534 a
= mapAction (smMove
, "sm_r", i18n("Move 'Right' face"),
535 Qt::Key_R
, SM_RIGHT
);
536 a
= mapAction (smMove
, "sm_f", i18n("Move 'Front' face"),
537 Qt::Key_F
, SM_FRONT
);
538 a
= mapAction (smMove
, "sm_b", i18n("Move 'Back' face"),
540 a
= mapAction (smMove
, "sm_anti", i18n("Anti-clockwise move"),
541 Qt::Key_Apostrophe
, SM_ANTICLOCKWISE
);
542 a
= mapAction (smMove
, "sm_plus", i18n("Singmaster two-slice move"),
543 Qt::Key_Plus
, SM_2_SLICE
);
544 a
= mapAction (smMove
, "sm_minus", i18n("Singmaster anti-slice move"),
545 Qt::Key_Minus
, SM_ANTISLICE
);
546 a
= mapAction (smMove
, "sm_dot", i18n("Move an inner slice"),
547 Qt::Key_Period
, SM_INNER
);
548 a
= mapAction (smMove
, "sm_return", i18n("Complete a Singmaster move"),
549 Qt::Key_Return
, SM_EXECUTE
);
550 a
= mapAction (smMove
, "sm_enter", i18n("Complete a Singmaster move"),
551 Qt::Key_Enter
, SM_EXECUTE
);
552 a
= mapAction (smMove
, "sm_space", i18n("Add space to Singmaster moves"),
553 Qt::Key_Space
, SM_SPACER
);
554 connect (smMove
, SIGNAL (mapped (int)), game
, SLOT (smInput (int)));
558 QAction
* Kubrick::mapAction (QSignalMapper
* mapper
, const QString
& name
,
559 const QString
& text
, const Qt::Key key
, SingmasterMove mapping
)
562 a
= actionCollection()->addAction (name
);
563 kDebug() << name
<< text
<< key
<< mapping
;
565 a
->setShortcut (key
);
566 connect (a
, SIGNAL (triggered (bool)), mapper
, SLOT (map()));
567 mapper
->setMapping (a
, mapping
);
572 void Kubrick::setToggle (const char * actionName
, bool onOff
)
574 ((KToggleAction
*) ACTION (actionName
))->setChecked (onOff
);
578 void Kubrick::setAvail (const char * actionName
, bool onOff
)
580 ((KAction
*) ACTION (actionName
))->setEnabled (onOff
);
584 void Kubrick::setSingmaster (const QString
& smString
)
586 singmasterMoves
->setText (smString
);
590 void Kubrick::setSingmasterSelection (const int start
, const int length
)
592 kDebug() << "Set selection" << start
<< length
;
593 singmasterMoves
->setSelection (start
, length
);
597 int Kubrick::fillPuzzleList (KSelectAction
* s
, const PuzzleItem itemList
[])
601 for (uint i
=0; (strcmp (itemList
[i
].menuText
, "END") != 0); i
++) {
602 list
.append (i18n(itemList
[i
].menuText
));
604 list
.append ("."); // Add dummy item to hold unwanted checkbox.
606 return (list
.count() - 1);
610 int Kubrick::fillDemoList (KSelectAction
* s
, const DemoItem itemList
[])
614 for (uint i
=0; (strcmp (itemList
[i
].filename
, "END") != 0); i
++) {
615 list
.append (i18n(itemList
[i
].menuText
));
617 list
.append ("."); // Add dummy item to hold unwanted checkbox.
619 return (list
.count() - 1);
623 void Kubrick::easySelected (int index
)
625 statusBar()->changeItem (easyItems
[index
].menuText
, 1001);
626 game
->changePuzzle (easyItems
[index
]);
630 void Kubrick::notSoEasySelected (int index
)
632 statusBar()->changeItem (notSoEasyItems
[index
].menuText
, 1001);
633 game
->changePuzzle (notSoEasyItems
[index
]);
637 void Kubrick::hardSelected (int index
)
639 statusBar()->changeItem (hardItems
[index
].menuText
, 1001);
640 game
->changePuzzle (hardItems
[index
]);
644 void Kubrick::veryHardSelected (int index
)
646 statusBar()->changeItem (veryHardItems
[index
].menuText
, 1001);
647 game
->changePuzzle (veryHardItems
[index
]);
651 void Kubrick::patternSelected (int index
)
653 kDebug() << "Pattern" << index
;
655 game
->loadDemo (patterns
[index
].filename
);
656 statusBar()->changeItem (patterns
[index
].menuText
, 1001);
659 KMessageBox::information (this,
661 i18n("Pretty Patterns"));
663 // Kludge to make the unwanted KSelectAction checkbox go onto a dummy item.
664 patternList
->setCurrentItem (maxPatternsIndex
);
668 void Kubrick::movesSelected (int index
)
671 game
->loadDemo (solvingMoves
[index
].filename
);
672 statusBar()->changeItem (solvingMoves
[index
].menuText
, 1001);
675 KMessageBox::information (this,
677 i18n("Solution Moves"));
679 // Kludge to make the unwanted KSelectAction checkbox go onto a dummy item.
680 movesList
->setCurrentItem (maxMovesIndex
);
684 void Kubrick::describePuzzle (int xDim
, int yDim
, int zDim
, int shMoves
)
687 if ((xDim
== yDim
) && (yDim
== zDim
)) {
688 descr
= i18n ("%1x%2x%3 cube, %4 moves", xDim
, yDim
, zDim
, shMoves
);
690 else if ((xDim
!= 1) && (yDim
!= 1) && (zDim
!= 1)) {
691 descr
= i18n ("%1x%2x%3 brick, %4 moves", xDim
, yDim
, zDim
, shMoves
);
694 descr
= i18n ("%1x%2x%3 mat, %4 moves", xDim
, yDim
, zDim
, shMoves
);
696 statusBar()->changeItem (descr
, 1001);
700 void Kubrick::optionsConfigureKeys()
702 KShortcutsDialog::configure(actionCollection());
706 // This method is invoked by KXmlGuiWindow when the window is closed, whether by
707 // selecting the "Quit" action or by clicking the "X" widget at the top right.
709 bool Kubrick::queryClose ()
711 game
->saveState (); // Save the current state of the cube.
715 #include "kubrick.moc"