File indexing completed on 2024-04-28 07:54:41
0001 /* 0002 SPDX-FileCopyrightText: 2008 Ian Wadham <iandw.au@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 // Own header 0008 #include "kubrick.h" 0009 0010 // Qt includes. 0011 #include <QAction> 0012 #include <QActionGroup> 0013 #include <QHBoxLayout> 0014 #include <QLineEdit> 0015 #include <QStatusBar> 0016 #include <QString> 0017 0018 // KDE includes. 0019 #include <KActionCollection> 0020 #include <KLocalizedString> 0021 #include <KMessageBox> 0022 #include <KGameStandardAction> 0023 #include <KToggleAction> 0024 0025 // Local includes. 0026 #include "game.h" 0027 #include "gameglview.h" 0028 0029 Kubrick::Kubrick () : 0030 singmasterMoves (nullptr) 0031 { 0032 // Window title. 0033 // setWindowTitle("Rubik's Cube"); // DELETED - This is a *trademark*. 0034 0035 // use multi-sample (anti-aliased) OpenGL if available 0036 /* Disable it for now, was causing black screens in some configurations 0037 QGLFormat defFormat = QGLFormat::defaultFormat(); 0038 defFormat.setSampleBuffers(true); 0039 QGLFormat::setDefaultFormat(defFormat); 0040 */ 0041 0042 game = new Game (this); 0043 0044 gameView = new GameGLView (game, this); 0045 0046 // Set the view as the central widget 0047 setCentralWidget(gameView); 0048 0049 // Set up the menus, keystrokes, etc. 0050 initGUI(); 0051 0052 // Enable the help menu. 0053 setHelpMenuEnabled (true); 0054 0055 // Load the GUI from the kubrickui.rc file. 0056 setupGUI (); 0057 0058 // Demos menu. This needs to be after setupGUI() call. 0059 auto slot = &Kubrick::patternSelected; 0060 Q_UNUSED(slot) 0061 fillDemoList (patterns, patternList, 0062 QStringLiteral("patterns_list"), &Kubrick::patternSelected); 0063 fillDemoList (solvingMoves, movesList, 0064 QStringLiteral("demo_moves_list"), &Kubrick::movesSelected); 0065 0066 // Set up a status bar. 0067 statusBar()->show (); 0068 statusBarLabel = new QLabel(i18n("Welcome to Kubrick"), this); 0069 statusBarLabel->setAlignment (Qt::AlignCenter); 0070 statusBar()->addWidget (statusBarLabel, 1); 0071 0072 // Set a larger font than toolbar-default for the Singmaster-moves display. 0073 QFont f = statusBar()->font(); 0074 f.setPointSize (f.pointSize()); // Needed to force a size-change. 0075 singmasterLabel->setFont (f); 0076 singmasterMoves->setFont (f); 0077 0078 // Start the game with a randomised demo. 0079 game->initGame (gameView, this); 0080 } 0081 0082 0083 Kubrick::~Kubrick () 0084 { 0085 } 0086 0087 0088 const Kubrick::PuzzleItem Kubrick::easyItems [] = { 0089 {kli18n("2x2x1 mat, 1 move"), 2, 2, 1, 1, 1, 1}, 0090 {kli18n("2x2x1 mat, 2 moves"), 2, 2, 1, 2, 1, 1}, 0091 {kli18n("2x2x1 mat, 3 moves"), 2, 2, 1, 3, 1, 1}, 0092 {kli18n("2x2x2 cube, 2 moves"), 2, 2, 2, 2, 1, 1}, 0093 {kli18n("2x2x2 cube, 3 moves"), 2, 2, 2, 3, 1, 1}, 0094 {kli18n("2x2x2 cube, 4 moves"), 2, 2, 2, 4, 1, 0}, 0095 {kli18n("3x3x1 mat, 4 moves"), 3, 3, 1, 4, 1, 0}, 0096 {kli18n("3x3x3 cube, 3 moves"), 3, 3, 3, 3, 1, 0}, 0097 {kli18n("3x3x3 cube, 4 moves"), 3, 3, 3, 4, 1, 0}, 0098 {KLazyLocalizedString(), 0, 0, 0, 0, 0, 0} 0099 }; 0100 0101 0102 const Kubrick::PuzzleItem Kubrick::notSoEasyItems [] = { 0103 {kli18n("3x3x3 cube, 3 moves"), 3, 3, 3, 3, 0, 0}, 0104 {kli18n("3x3x3 cube, 4 moves"), 3, 3, 3, 4, 0, 0}, 0105 {kli18n("4x4x4 cube, 4 moves"), 4, 4, 4, 4, 0, 0}, 0106 {kli18n("5x5x5 cube, 4 moves"), 5, 5, 5, 4, 0, 0}, 0107 {kli18n("6x3x2 brick, 4 moves"), 6, 3, 2, 4, 0, 0}, 0108 {KLazyLocalizedString(), 0, 0, 0, 0, 0, 0} 0109 }; 0110 0111 0112 const Kubrick::PuzzleItem Kubrick::hardItems [] = { 0113 {kli18n("3x3x3 cube, 7 moves"), 3, 3, 3, 7, 0, 0}, 0114 {kli18n("4x4x4 cube, 5 moves"), 4, 4, 4, 5, 0, 0}, 0115 {kli18n("5x5x5 cube, 6 moves"), 5, 5, 5, 6, 0, 0}, 0116 {kli18n("6x6x6 cube, 6 moves"), 6, 6, 6, 6, 0, 0}, 0117 {kli18n("6x4x1 mat, 9 moves"), 6, 4, 1, 9, 0, 0}, 0118 {kli18n("6x3x2 brick, 6 moves"), 6, 3, 2, 7, 0, 0}, 0119 {KLazyLocalizedString(), 0, 0, 0, 0, 0, 0} 0120 }; 0121 0122 0123 const Kubrick::PuzzleItem Kubrick::veryHardItems [] = { 0124 {kli18n("3x3x3 cube, 12 moves"), 3, 3, 3, 12, 0, 0}, 0125 {kli18n("3x3x3 cube, 15 moves"), 3, 3, 3, 15, 0, 0}, 0126 {kli18n("3x3x3 cube, 20 moves"), 3, 3, 3, 20, 0, 0}, 0127 {kli18n("4x4x4 cube, 12 moves"), 4, 4, 4, 12, 0, 0}, 0128 {kli18n("5x5x5 cube, 15 moves"), 5, 5, 5, 15, 0, 0}, 0129 {kli18n("6x6x6 cube, 25 moves"), 6, 6, 6, 25, 0, 0}, 0130 {KLazyLocalizedString(), 0, 0, 0, 0, 0, 0} 0131 }; 0132 0133 0134 const KLazyLocalizedString Kubrick::patternMovesInfo = kli18n( 0135 "Rubik's Cube can be moved into many interesting patterns. Here are " 0136 "a few from David Singmaster's classic book 'Notes on Rubik's Magic Cube, " 0137 "Fifth Edition', pages 47-49, published in 1981. After a pattern has " 0138 "formed, you can use the Solve action (default key S) to undo and redo it " 0139 "as often as you like." 0140 ); 0141 0142 0143 const Kubrick::DemoItem Kubrick::patterns [] = { 0144 {QString(), kli18n("Info")}, 0145 {QStringLiteral("p333X6.kbk"), kli18n("3x3x3, 6 X")}, 0146 {QStringLiteral("p333X2.kbk"), kli18n("3x3x3, 2 X")}, 0147 {QStringLiteral("p333Spot6.kbk"), kli18n("3x3x3, 6 Spot")}, 0148 {QStringLiteral("p333Spot4.kbk"), kli18n("3x3x3, 4 Spot")}, 0149 {QStringLiteral("p333Plus4.kbk"), kli18n("3x3x3, 4 Plus")}, 0150 {QStringLiteral("p333Bar4.kbk"), kli18n("3x3x3, 4 Bar")}, 0151 {QStringLiteral("p333U6.kbk"), kli18n("3x3x3, 6 U")}, 0152 {QStringLiteral("p333U4.kbk"), kli18n("3x3x3, 4 U")}, 0153 {QStringLiteral("p333Snake.kbk"), kli18n("3x3x3, Snake")}, 0154 {QStringLiteral("p333Worm.kbk"), kli18n("3x3x3, Worm")}, 0155 {QStringLiteral("p333Tricolor6.kbk"), kli18n("3x3x3, Tricolor")}, 0156 {QStringLiteral("p333DoubleCube.kbk"), kli18n("3x3x3, Double Cube")}, 0157 {QStringLiteral("END"), KLazyLocalizedString()} 0158 }; 0159 0160 0161 const KLazyLocalizedString Kubrick::solvingMovesInfo = kli18n( 0162 "<qt>Mathematicians calculate that a 3x3x3 cube can be shuffled into " 0163 "43,252,003,274,489,856,000 different patterns, yet they conjecture " 0164 "that all positions can be solved in 20 moves or less. The method " 0165 "that can do that (as yet undiscovered) is called God's Algorithm." 0166 "<br><br>" 0167 "Many longer methods are known. See the two Wikipedia articles on " 0168 "Rubik's Cube and Optimal Solutions for Rubik's Cube." 0169 "<br><br>" 0170 "Several methods work systematically by building the solution one layer " 0171 "at a time, using sequences of moves that solve a few pieces without " 0172 "disturbing what has already been done. The 'Beginner Solution' " 0173 "demonstrated here uses that approach. Just over 100 moves solve a cube " 0174 "that is shuffled in 20.</qt>" 0175 ); 0176 0177 0178 const Kubrick::DemoItem Kubrick::solvingMoves [] = { 0179 {QString(), kli18n("Info")}, 0180 {QStringLiteral("m333Layer1.kbk"), kli18n("3x3x3 Layer 1, Edges First")}, 0181 {QStringLiteral("m333MEdge1.kbk"), kli18n("3x3x3 Layer 2, Edge from Bottom Right")}, 0182 {QStringLiteral("m333MEdge2.kbk"), kli18n("3x3x3 Layer 2, Edge from Bottom Left")}, 0183 {QStringLiteral("m333LLEdgeFlip.kbk"), kli18n("3x3x3 Layer 3, Flip Edge Pieces")}, 0184 {QStringLiteral("m333LLCornerPos.kbk"), kli18n("3x3x3 Layer 3, Place Corners")}, 0185 {QStringLiteral("m333LLCornerRot.kbk"), kli18n("3x3x3 Layer 3, Twist Corners")}, 0186 {QStringLiteral("m333LLEdgePos.kbk"), kli18n("3x3x3 Layer 3, Place Edges and DONE!")}, 0187 {QStringLiteral("m333Complete.kbk"), kli18n("3x3x3 Cube, Complete Solution")}, 0188 {QStringLiteral("m333E2prX.kbk"), kli18n("3x3x3 Swap 2 Pairs of Edges")}, 0189 {QStringLiteral("m333CTwirl2.kbk"), kli18n("3x3x3 Untwist 2 Corners")}, 0190 {QStringLiteral("m333EFlip2.kbk"), kli18n("3x3x3 Flip 2 Edges")}, 0191 {QStringLiteral("END"), KLazyLocalizedString()} 0192 }; 0193 0194 0195 // Create an action and set some help text for all menu items 0196 // See also the *ui.rc file for the XML definitions 0197 void Kubrick::initGUI() 0198 { 0199 // Game menu. 0200 QAction * newAction = KGameStandardAction::gameNew ( 0201 game, &Game::newPuzzle, this); 0202 actionCollection()->addAction (newAction->objectName(), newAction); 0203 newAction->setText (i18n("&New Puzzle")); 0204 newAction->setToolTip (i18n("Start a new puzzle.")); 0205 newAction->setWhatsThis (i18n("Finish the puzzle you are working on " 0206 "and start a new puzzle with the same " 0207 "dimensions and number of shuffling moves.")); 0208 0209 QAction * 0210 a = KGameStandardAction::load ( 0211 game, &Game::load, this); 0212 actionCollection()->addAction (a->objectName(), a); 0213 a->setText (i18n("&Load Puzzle...")); 0214 a->setToolTip (i18n("Reload a saved puzzle from a file.")); 0215 a->setWhatsThis (i18n("Reload a puzzle you have previously " 0216 "saved on a file, including its dimensions, " 0217 "settings, current state and history of " 0218 "moves.")); 0219 0220 a = KGameStandardAction::save ( 0221 game, &Game::save, this); 0222 actionCollection()->addAction (a->objectName(), a); 0223 a->setText (i18n("&Save Puzzle...")); 0224 a->setToolTip (i18n("Save the puzzle on a file.")); 0225 a->setWhatsThis (i18n("Save the puzzle on a file, including " 0226 "its dimensions, settings, current state and " 0227 "history of moves.")); 0228 0229 a = KGameStandardAction::saveAs ( 0230 game, &Game::saveAs, this); 0231 actionCollection()->addAction (a->objectName(), a); 0232 a->setText (i18n("&Save Puzzle As...")); 0233 0234 a = KGameStandardAction:: 0235 restart (game, &Game::undoAll, this); 0236 actionCollection()->addAction (a->objectName(), a); 0237 a->setText (i18n("Restart &Puzzle...")); 0238 a->setToolTip (i18n("Undo all previous moves and start " 0239 "again.")); 0240 a->setWhatsThis (i18n("Undo all previous moves and start " 0241 "again.")); 0242 0243 a = KGameStandardAction:: 0244 quit (this, &Kubrick::close, this); 0245 actionCollection()->addAction (a->objectName(), a); 0246 // NOTE: KXmlGuiWindow::close() calls Kubrick::queryClose(), our real "quit" 0247 0248 // Move menu. 0249 a = KGameStandardAction:: 0250 undo (game, &Game::undoMove, this); 0251 actionCollection()->addAction (a->objectName(), a); 0252 a->setToolTip (i18n("Undo the last move.")); 0253 a->setWhatsThis (i18n("Undo the last move.")); 0254 0255 a = KGameStandardAction:: 0256 redo (game, &Game::redoMove, this); 0257 actionCollection()->addAction (a->objectName(), a); 0258 a->setToolTip (i18n("Redo a previously undone move.")); 0259 a->setWhatsThis (i18n("Redo a previously undone move " 0260 "(repeatedly from the start if required).")); 0261 0262 a = KGameStandardAction:: 0263 solve (game, &Game::solveCube, this); 0264 actionCollection()->addAction (a->objectName(), a); 0265 a->setToolTip (i18n("Show the solution of the puzzle.")); 0266 a->setWhatsThis (i18n("Show the solution of the puzzle by " 0267 "undoing and re-doing all shuffling moves.")); 0268 0269 a = KGameStandardAction:: 0270 demo (game, &Game::toggleDemo, this); 0271 actionCollection()->addAction (a->objectName(), a); 0272 a->setText (i18n("Main &Demo")); 0273 a->setToolTip (i18n("Run a demonstration of puzzle moves.")); 0274 a->setWhatsThis (i18n("Run a demonstration of puzzle moves, " 0275 "in which randomly chosen cubes, bricks or " 0276 "mats are shuffled and solved.")); 0277 0278 a = actionCollection()->addAction ( QStringLiteral( "standard_view" )); 0279 a->setText (i18n("Realign Cube")); 0280 a->setToolTip (i18n("Realign the cube so that the top, " 0281 "front and right faces are visible together.")); 0282 a->setWhatsThis (i18n("Realign the cube so that the top, " 0283 "front and right faces are visible together " 0284 "and the cube's axes are parallel to the XYZ " 0285 "axes, thus making keyboard moves properly " 0286 "meaningful.")); 0287 a->setIcon (QIcon::fromTheme( QStringLiteral( "go-home" ))); 0288 KActionCollection::setDefaultShortcut(a, Qt::Key_Home); 0289 connect (a, &QAction::triggered, game, &Game::setStandardView); 0290 0291 a = actionCollection()->addAction ( QStringLiteral( "redo_all" )); 0292 a->setText (i18n("Redo All")); 0293 KActionCollection::setDefaultShortcut(a, Qt::SHIFT | Qt::Key_R); 0294 connect (a, &QAction::triggered, game, &Game::redoAll); 0295 0296 // Read-only display of Singmaster moves on the toolbar. 0297 singmasterLabel = new QLabel (i18n("Singmaster Moves"), this); 0298 singmasterMoves = new QLineEdit (this); 0299 0300 QWidget *sigmasterWidget = new QWidget(this); 0301 QHBoxLayout *sigmasterLayout = new QHBoxLayout (sigmasterWidget); 0302 sigmasterLayout->setContentsMargins(0, 0, 0, 0); 0303 sigmasterLayout->addWidget(singmasterLabel); 0304 sigmasterLayout->addWidget(singmasterMoves); 0305 0306 QWidgetAction *w = new QWidgetAction (this); 0307 actionCollection()->addAction ( QStringLiteral( "singmaster_label" ), w); 0308 w->setDefaultWidget (sigmasterWidget); 0309 0310 actionCollection()->addAction ( QStringLiteral( "singmaster_moves" ), w); 0311 w->setText (i18n("Singmaster Moves")); 0312 0313 QString singmasterToolTip = i18n("This area shows Singmaster moves."); 0314 QString singmasterWhatsThis = i18nc("The letters RLFBUD are mathematical " 0315 "notation based on English words. Please leave those " 0316 "letters and words untranslated in some form.", 0317 0318 "This area shows Singmaster moves. " 0319 "They are based on the letters RLFBUD, representing " 0320 "(in English) the Right, Left, Front, Back, Up and " 0321 "Down faces. In normal view, the letters RFU represent " 0322 "clockwise moves of the three visible faces and LBD " 0323 "appear as anticlockwise moves of the hidden faces. " 0324 "Adding a ' (apostrophe) to a letter gives the reverse " 0325 "of that letter's move. To move inner slices, add " 0326 "periods (or dots) before the letter of the nearest " 0327 "face."); 0328 0329 singmasterLabel->setToolTip (singmasterToolTip); 0330 singmasterLabel->setWhatsThis (singmasterWhatsThis); 0331 singmasterMoves->setToolTip (singmasterToolTip); 0332 singmasterMoves->setWhatsThis (singmasterWhatsThis); 0333 0334 singmasterMoves->setReadOnly (true); 0335 singmasterLabel->setBuddy (singmasterMoves); 0336 singmasterMoves->show(); 0337 singmasterLabel->show(); 0338 singmasterMoves->setFocusPolicy (Qt::NoFocus); 0339 singmasterMoves->clearFocus(); 0340 0341 // "Choose Puzzle Type" sub-menu. 0342 easyList = new KSelectAction (i18n("&Easy"), this); 0343 actionCollection()->addAction ( QStringLiteral( "easy_list" ), easyList); 0344 fillPuzzleList (easyList, easyItems); 0345 connect(easyList, &KSelectAction::indexTriggered, this, &Kubrick::easySelected); 0346 0347 notSoEasyList = new KSelectAction (i18n("&Not So Easy"), this); 0348 actionCollection()->addAction ( QStringLiteral( "not_easy_list" ), notSoEasyList); 0349 fillPuzzleList (notSoEasyList, notSoEasyItems); 0350 connect(notSoEasyList, &KSelectAction::indexTriggered, this, &Kubrick::notSoEasySelected); 0351 0352 hardList = new KSelectAction (i18n("&Hard"), this); 0353 actionCollection()->addAction ( QStringLiteral( "hard_list" ), hardList); 0354 fillPuzzleList (hardList, hardItems); 0355 connect(hardList, &KSelectAction::indexTriggered, this, &Kubrick::hardSelected); 0356 0357 veryHardList = new KSelectAction (i18n("&Very Hard"), this); 0358 actionCollection()->addAction ( QStringLiteral( "very_hard_list" ), veryHardList); 0359 fillPuzzleList (veryHardList, veryHardItems); 0360 connect(veryHardList, &KSelectAction::indexTriggered, this, &Kubrick::veryHardSelected); 0361 0362 a = actionCollection()->addAction ( QStringLiteral( "new_cube" )); 0363 a->setText (i18n("Make your own...")); 0364 connect (a, &QAction::triggered, game, &Game::newCubeDialog); 0365 0366 // View menu. 0367 KToggleAction * b; 0368 QActionGroup * viewGroup = new QActionGroup (this); 0369 viewGroup->setExclusive (true); 0370 0371 b = new KToggleAction (i18n ("1 Cube"), this); 0372 actionCollection()->addAction ( QStringLiteral( "scene_1" ), b); 0373 b->setToolTip (i18n ("Show one view of this cube.")); 0374 b->setWhatsThis (i18n ("Show one view of this cube, " 0375 "from the front.")); 0376 b->setIcon (QIcon::fromTheme( QStringLiteral( "arrow-left" ))); // IDW - Temporary. 0377 connect(b, &KToggleAction::triggered, game, [this] { game->changeScene(OneCube); }); 0378 b->setChecked (true); 0379 viewGroup->addAction (b); 0380 0381 b = new KToggleAction (i18n ("2 Cubes"), this); 0382 actionCollection()->addAction ( QStringLiteral( "scene_2" ), b); 0383 b->setToolTip (i18n ("Show two views of this cube.")); 0384 b->setWhatsThis (i18n ("Show two views of this cube, from " 0385 "the front and the back. Both can rotate.")); 0386 b->setIcon (QIcon::fromTheme( QStringLiteral( "arrow-up" ))); // IDW - Temporary. 0387 connect(b, &KToggleAction::triggered, game, [this] { game->changeScene(TwoCubes); }); 0388 viewGroup->addAction (b); 0389 0390 b = new KToggleAction (i18n ("3 Cubes"), this); 0391 actionCollection()->addAction ( QStringLiteral( "scene_3" ), b); 0392 b->setToolTip (i18n ("Show three views of this cube.")); 0393 b->setWhatsThis (i18n ("Show three views of this cube, a " 0394 "large one, from the front, and two small " 0395 "ones, from the front and the back. Only " 0396 "the large one can rotate.")); 0397 b->setIcon (QIcon::fromTheme( QStringLiteral( "arrow-right" ))); // IDW - Temporary. 0398 connect(b, &KToggleAction::triggered, game, [this] { game->changeScene(ThreeCubes); }); 0399 viewGroup->addAction (b); 0400 0401 // Demos menu. See the code after "setupGUI ();". 0402 0403 // Settings menu. 0404 b = new KToggleAction (i18n("&Watch Shuffling"), this); 0405 actionCollection()->addAction ( QStringLiteral( "watch_shuffling" ), b); 0406 KActionCollection::setDefaultShortcut(b, Qt::Key_W); 0407 connect(b, &KToggleAction::triggered, game, &Game::watchShuffling); 0408 0409 b = new KToggleAction (i18n("Watch Your &Own Moves"), this); 0410 actionCollection()->addAction ( QStringLiteral( "watch_moves" ), b); 0411 KActionCollection::setDefaultShortcut(b, Qt::Key_O); 0412 connect(b, &KToggleAction::triggered, game, &Game::watchMoves); 0413 0414 // DISCONTINUED a = actionCollection()->addAction ( QLatin1String( "enable_messages" )); 0415 // a->setText (i18n("Show Beginners' &Messages")); 0416 // connect (a, &QAction::triggered, game, &Game::enableMessages); 0417 0418 // Sorry to be "non-standard" (below), but I am an English-speaker, born and 0419 // bred, and I just don't find the KDE standard texts "Configure Kubrick" 0420 // and "Configure Shortcuts" to be meaningful in everyday language. Neither 0421 // would my wife, children and friends, I am sure. 0422 0423 a = KStandardAction::preferences (game, &Game::optionsDialog, actionCollection()); 0424 a->setText (i18n("Kubri&ck Game Settings")); 0425 0426 // Configure Shortcuts... 0427 a = KStandardAction::keyBindings (this, &Kubrick::optionsConfigureKeys, actionCollection()); 0428 a->setText (i18n("Keyboard S&hortcut Settings")); 0429 0430 /**************************************************************************/ 0431 /************************** KEYSTROKE ACTIONS **************************/ 0432 /**************************************************************************/ 0433 0434 // Keys to choose the axis for a slice move (X, Y or Z). 0435 a = actionCollection()->addAction ( QStringLiteral( "x_axis" )); 0436 a->setText (i18n("X Axis")); 0437 KActionCollection::setDefaultShortcut(a, Qt::Key_X); 0438 connect(a, &QAction::triggered, game, [this] { game->setMoveAxis(0); }); 0439 0440 a = actionCollection()->addAction ( QStringLiteral( "y_axis" )); 0441 a->setText (i18n("Y Axis")); 0442 KActionCollection::setDefaultShortcut(a, Qt::Key_Y); 0443 connect(a, &QAction::triggered, game, [this] { game->setMoveAxis(1); }); 0444 0445 a = actionCollection()->addAction ( QStringLiteral( "z_axis" )); 0446 a->setText (i18n("Z Axis")); 0447 KActionCollection::setDefaultShortcut(a, Qt::Key_Z); 0448 connect(a, &QAction::triggered, game, [this] { game->setMoveAxis(2); }); 0449 0450 // Keys to choose the slice number for a slice move. 0451 const QString ident = QStringLiteral("slice %1"); 0452 for (int i = 1; i <= 6; i++) { 0453 a = actionCollection()->addAction (ident.arg(i)); 0454 a->setText (i18n("Slice %1", i)); 0455 KActionCollection::setDefaultShortcut(a, Qt::Key_0 + i); 0456 connect(a, &QAction::triggered, game, [this, i] { game->setMoveSlice(i); }); 0457 } 0458 0459 // Key to select a rotation of the whole cube (mapped as "slice 0"). 0460 a = actionCollection()->addAction ( QStringLiteral( "turn_cube" )); 0461 a->setText (i18n("Turn whole cube")); 0462 KActionCollection::setDefaultShortcut(a, Qt::Key_C); 0463 connect(a, &QAction::triggered, game, [this] { game->setMoveSlice(0); }); 0464 0465 // Keys to choose the direction for a slice move (clock or anti-clock). 0466 a = actionCollection()->addAction ( QStringLiteral( "anti_clockwise" )); 0467 a->setText (i18n("Anti-clockwise")); 0468 KActionCollection::setDefaultShortcut(a, Qt::Key_Left); 0469 connect (a, &QAction::triggered, game, [this] { game->setMoveDirection(0); }); 0470 0471 a = actionCollection()->addAction ( QStringLiteral( "clockwise" )); 0472 a->setText (i18n("Clockwise")); 0473 KActionCollection::setDefaultShortcut(a, Qt::Key_Right); 0474 connect (a, &QAction::triggered, game, [this] { game->setMoveDirection(1); }); 0475 0476 // Keys for Singmaster (sm) moves. 0477 a = mapAction (QStringLiteral("sm_u"), i18n("Move 'Up' face"), 0478 Qt::Key_U, SM_UP); 0479 a = mapAction (QStringLiteral("sm_d"), i18n("Move 'Down' face"), 0480 Qt::Key_D, SM_DOWN); 0481 a = mapAction (QStringLiteral("sm_l"), i18n("Move 'Left' face"), 0482 Qt::Key_L, SM_LEFT); 0483 a = mapAction (QStringLiteral("sm_r"), i18n("Move 'Right' face"), 0484 Qt::Key_R, SM_RIGHT); 0485 a = mapAction (QStringLiteral("sm_f"), i18n("Move 'Front' face"), 0486 Qt::Key_F, SM_FRONT); 0487 a = mapAction (QStringLiteral("sm_b"), i18n("Move 'Back' face"), 0488 Qt::Key_B, SM_BACK); 0489 a = mapAction (QStringLiteral("sm_anti"), i18n("Anti-clockwise move"), 0490 Qt::Key_Apostrophe, SM_ANTICLOCKWISE); 0491 a = mapAction (QStringLiteral("sm_plus"), i18n("Singmaster two-slice move"), 0492 Qt::Key_Plus, SM_2_SLICE); 0493 a = mapAction (QStringLiteral("sm_minus"), i18n("Singmaster anti-slice move"), 0494 Qt::Key_Minus, SM_ANTISLICE); 0495 a = mapAction (QStringLiteral("sm_dot"), i18n("Move an inner slice"), 0496 Qt::Key_Period, SM_INNER); 0497 a = mapAction (QStringLiteral("sm_return"), i18n("Complete a Singmaster move"), 0498 Qt::Key_Return, SM_EXECUTE); 0499 a = mapAction (QStringLiteral("sm_enter"), i18n("Complete a Singmaster move"), 0500 Qt::Key_Enter, SM_EXECUTE); 0501 a = mapAction (QStringLiteral("sm_space"), i18n("Add space to Singmaster moves"), 0502 Qt::Key_Space, SM_SPACER); 0503 0504 // IDW - Key for switching the background (temporary) - FIX IT FOR KDE 4.2. 0505 a = actionCollection()->addAction ( QStringLiteral( "switch_background" )); 0506 a->setText (i18n("Switch Background")); 0507 KActionCollection::setDefaultShortcut(a, Qt::Key_K); 0508 connect (a, &QAction::triggered, game, &Game::switchBackground); 0509 } 0510 0511 0512 QAction * Kubrick::mapAction (const QString & name, 0513 const QString & text, const Qt::Key key, SingmasterMove mapping) 0514 { 0515 QAction * a; 0516 a = actionCollection()->addAction (name); 0517 a->setText (text); 0518 KActionCollection::setDefaultShortcut(a, key); 0519 connect (a, &QAction::triggered, game, [this, mapping] { game->smInput(mapping); }); 0520 return a; 0521 } 0522 0523 0524 void Kubrick::setToggle (const QString &actionName, bool onOff) 0525 { 0526 ((KToggleAction *) actionCollection()->action (actionName))->setChecked (onOff); 0527 } 0528 0529 0530 void Kubrick::setAvail (const QString &actionName, bool onOff) 0531 { 0532 ((QAction *) actionCollection()->action (actionName))->setEnabled (onOff); 0533 } 0534 0535 0536 void Kubrick::setSingmaster (const QString & smString) 0537 { 0538 singmasterMoves->setText (smString); 0539 } 0540 0541 0542 void Kubrick::setSingmasterSelection (const int start, const int length) 0543 { 0544 singmasterMoves->setSelection (start, length); 0545 } 0546 0547 0548 int Kubrick::fillPuzzleList (KSelectAction * s, const PuzzleItem itemList []) 0549 { 0550 QStringList list; 0551 0552 for (uint i=0; (!itemList[i].menuText.isEmpty()); i++) { 0553 list.append (KLocalizedString(itemList[i].menuText).toString()); 0554 } 0555 s->setItems(list); 0556 return (list.count() - 1); 0557 } 0558 0559 0560 void Kubrick::fillDemoList (const DemoItem itemList [], QList<QAction *> & list, 0561 const QString &uilist, void(Kubrick::*slot)()) 0562 { 0563 // Generate an action list with one action for each item in the demo list. 0564 for (uint i = 0; itemList[i].filename != QLatin1String("END"); i++) { 0565 QAction * t = new QAction (KLocalizedString(itemList[i].menuText).toString(), this); 0566 actionCollection()->addAction ( QStringLiteral("%1%2" ).arg(uilist).arg(i), t); 0567 t->setData (i); // Save the index of the item inside the action. 0568 list.append (t); 0569 connect (t, &QAction::triggered, this, slot); 0570 } 0571 0572 // Plug the action list into the Demos menu. 0573 plugActionList (uilist, list); 0574 } 0575 0576 0577 void Kubrick::saveNewToolbarConfig() 0578 { 0579 // This destroys our actions lists ... 0580 KXmlGuiWindow::saveNewToolbarConfig(); 0581 0582 // ... so plug them again 0583 plugActionList (QStringLiteral("patterns_list"), patternList); 0584 plugActionList (QStringLiteral("demo_moves_list"), movesList); 0585 } 0586 0587 0588 void Kubrick::easySelected (int index) 0589 { 0590 statusBarLabel->setText (KLocalizedString(easyItems [index].menuText).toString()); 0591 game->changePuzzle (easyItems [index]); 0592 } 0593 0594 0595 void Kubrick::notSoEasySelected (int index) 0596 { 0597 statusBarLabel->setText (KLocalizedString(notSoEasyItems [index].menuText).toString()); 0598 game->changePuzzle (notSoEasyItems [index]); 0599 } 0600 0601 0602 void Kubrick::hardSelected (int index) 0603 { 0604 statusBarLabel->setText (KLocalizedString (hardItems [index].menuText).toString()); 0605 game->changePuzzle (hardItems [index]); 0606 } 0607 0608 0609 void Kubrick::veryHardSelected (int index) 0610 { 0611 statusBarLabel->setText (KLocalizedString (veryHardItems [index].menuText).toString()); 0612 game->changePuzzle (veryHardItems [index]); 0613 } 0614 0615 0616 void Kubrick::patternSelected() 0617 { 0618 // Retrieve the index of the demo item from the action. 0619 const QAction * action = static_cast <const QAction *> (sender()); 0620 int index = action->data().toInt(); 0621 0622 if (index > 0) { 0623 game->loadDemo (patterns[index].filename); 0624 statusBarLabel->setText (KLocalizedString(patterns[index].menuText).toString()); 0625 } 0626 else { 0627 KMessageBox::information (this, 0628 KLocalizedString (patternMovesInfo).toString(), 0629 i18n ("Pretty Patterns")); 0630 } 0631 } 0632 0633 0634 void Kubrick::movesSelected() 0635 { 0636 // Retrieve the index of the demo item from the action. 0637 const QAction * action = static_cast <const QAction *> (sender()); 0638 int index = action->data().toInt(); 0639 0640 if (index > 0) { 0641 game->loadDemo (solvingMoves[index].filename); 0642 statusBarLabel->setText (KLocalizedString(solvingMoves[index].menuText).toString()); 0643 } 0644 else { 0645 KMessageBox::information (this, 0646 KLocalizedString (solvingMovesInfo).toString(), 0647 i18n ("Solution Moves")); 0648 } 0649 } 0650 0651 0652 void Kubrick::describePuzzle (int xDim, int yDim, int zDim, int shMoves) 0653 { 0654 QString descr; 0655 if ((xDim == yDim) && (yDim == zDim)) { 0656 descr = i18n ("%1x%2x%3 cube, %4 shuffling moves", 0657 xDim, yDim, zDim, shMoves); 0658 } 0659 else if ((xDim != 1) && (yDim != 1) && (zDim != 1)) { 0660 descr = i18n ("%1x%2x%3 brick, %4 shuffling moves", 0661 xDim, yDim, zDim, shMoves); 0662 } 0663 else { 0664 descr = i18n ("%1x%2x%3 mat, %4 shuffling moves", 0665 xDim, yDim, zDim, shMoves); 0666 } 0667 statusBarLabel->setText (descr); 0668 } 0669 0670 0671 void Kubrick::optionsConfigureKeys() 0672 { 0673 KShortcutsDialog::showDialog(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed, this); 0674 } 0675 0676 0677 // This method is invoked by KXmlGuiWindow when the window is closed, whether by 0678 // selecting the "Quit" action or by clicking the "X" widget at the top right. 0679 0680 bool Kubrick::queryClose () 0681 { 0682 game->saveState (); // Save the current state of the cube. 0683 return (true); 0684 } 0685 0686