Warning, file /games/killbots/src/mainwindow.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 This file is part of Killbots. 0003 0004 SPDX-FileCopyrightText: 2006-2009 Parker Coates <coates@kde.org> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "mainwindow.h" 0010 0011 #include "coordinator.h" 0012 #include "engine.h" 0013 #include "optionspage.h" 0014 #include "renderer.h" 0015 #include "rulesetselector.h" 0016 #include "scene.h" 0017 #include "settings.h" 0018 #include "view.h" 0019 0020 #include <KgThemeProvider> 0021 #include <KgThemeSelector> 0022 #include <highscore/kscoredialog.h> 0023 #include <kstandardgameaction.h> 0024 0025 #include <QAction> 0026 #include <kwidgetsaddons_version.h> 0027 #include <KActionCollection> 0028 #include <KConfigDialog> 0029 #include <KLocalizedString> 0030 #include <KMessageBox> 0031 #include <KShortcutsDialog> 0032 #include <KStandardAction> 0033 0034 #include <QDir> 0035 #include <QIcon> 0036 #include <QTimer> 0037 0038 #include "killbots_debug.h" 0039 0040 Killbots::MainWindow::MainWindow(QWidget *parent) 0041 : KXmlGuiWindow(parent), 0042 m_scoreDialog(nullptr), 0043 m_rulesetChanged(false) 0044 { 0045 setAcceptDrops(false); 0046 0047 m_coordinator = new Coordinator(this); 0048 m_coordinator->setAnimationSpeed(Settings::animationSpeed()); 0049 0050 m_engine = new Engine(m_coordinator, this); 0051 m_coordinator->setEngine(m_engine); 0052 connect(m_engine, &Engine::gameOver, this, &MainWindow::onGameOver); 0053 0054 m_scene = new Scene(this); 0055 m_coordinator->setScene(m_scene); 0056 connect(m_scene, &Scene::clicked, m_coordinator, &Coordinator::requestAction); 0057 connect(Renderer::self()->themeProvider(), &KgThemeProvider::currentThemeChanged, m_scene, &Scene::doLayout); 0058 0059 m_view = new View(m_scene, this); 0060 m_view->setMinimumSize(400, 280); 0061 m_view->setWhatsThis(i18n("This is the main game area used to interact with Killbots. It shows the current state of the game grid and allows one to control the hero using the mouse. It also displays certain statistics about the game in progress.")); 0062 setCentralWidget(m_view); 0063 connect(m_view, &View::sizeChanged, m_scene, &Scene::doLayout); 0064 0065 setupActions(); 0066 connect(m_engine, &Engine::teleportAllowed, actionCollection()->action(QStringLiteral("teleport")), &QAction::setEnabled); 0067 connect(m_engine, &Engine::teleportAllowed, actionCollection()->action(QStringLiteral("teleport_sip")), &QAction::setEnabled); 0068 connect(m_engine, &Engine::teleportSafelyAllowed, actionCollection()->action(QStringLiteral("teleport_safely")), &QAction::setEnabled); 0069 connect(m_engine, &Engine::vaporizerAllowed, actionCollection()->action(QStringLiteral("vaporizer")), &QAction::setEnabled); 0070 connect(m_engine, &Engine::waitOutRoundAllowed, actionCollection()->action(QStringLiteral("wait_out_round")), &QAction::setEnabled); 0071 0072 setupGUI(Save | Create | ToolBar | Keys); 0073 0074 // Delaying the start of the first game by 50ms to avoid resize events after 0075 // the game has been started. Delaying by 0ms doesn't seem to be enough. 0076 QTimer::singleShot(50, m_coordinator, &Coordinator::requestNewGame); 0077 } 0078 0079 Killbots::MainWindow::~MainWindow() 0080 { 0081 Killbots::Renderer::cleanup(); 0082 } 0083 0084 void Killbots::MainWindow::configurePreferences() 0085 { 0086 // An instance of the dialog could be already created and could be cached, 0087 // in which case we want to display the cached dialog instead of creating 0088 // another one 0089 if (!KConfigDialog::showDialog(QStringLiteral("configurePreferencesDialog"))) { 0090 // Creating a dialog because KConfigDialog didn't find an instance of it 0091 KConfigDialog *configDialog = new KConfigDialog(this, QStringLiteral("configurePreferencesDialog"), Settings::self()); 0092 0093 // Creating setting pages and adding them to the dialog 0094 configDialog->addPage(new OptionsPage(this), 0095 i18nc("@title", "General"), 0096 QStringLiteral("configure"), 0097 i18nc("@info", "Configure general settings") 0098 ); 0099 configDialog->addPage(new RulesetSelector(this), 0100 i18nc("@title", "Game Type"), 0101 QStringLiteral("games-config-custom"), 0102 i18nc("@info", "Select a game type") 0103 ); 0104 configDialog->addPage(new KgThemeSelector(Renderer::self()->themeProvider()), 0105 i18nc("@title", "Appearance"), 0106 QStringLiteral("games-config-theme"), 0107 i18nc("@info", "Select a graphical theme") 0108 ); 0109 0110 configDialog->setMaximumSize(800, 600); 0111 0112 // Update the sprite style if it has changed 0113 connect(configDialog, &KConfigDialog::settingsChanged, this, &MainWindow::onSettingsChanged); 0114 0115 configDialog->show(); 0116 } 0117 } 0118 0119 void Killbots::MainWindow::onSettingsChanged() 0120 { 0121 m_coordinator->setAnimationSpeed(Settings::animationSpeed()); 0122 0123 if (m_engine->ruleset()->fileName() != Settings::ruleset()) { 0124 qCDebug(KILLBOTS_LOG) << "Detected a changed in ruleset. From" << m_engine->ruleset()->fileName() << "to" << Settings::ruleset(); 0125 0126 // We don't act on the changed ruleset here because the config dialog 0127 // is still visible. We want the game in progress to be visible when 0128 // we display the message box. We also don't want a new game to start 0129 // while hidden behind the config dialog. So we wait until the config 0130 // dialog is closed. See onConfigDialogClosed below. 0131 m_rulesetChanged = true; 0132 } 0133 onConfigDialogClosed(); 0134 } 0135 0136 void Killbots::MainWindow::onConfigDialogClosed() 0137 { 0138 if (m_rulesetChanged) { 0139 if (!m_engine->gameHasStarted() 0140 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0141 || KMessageBox::questionTwoActions(this, 0142 #else 0143 || KMessageBox::questionYesNo(this, 0144 #endif 0145 i18n("A new game type has been selected, but there is already a game in progress."), 0146 i18nc("@title:window", "Game Type Changed"), 0147 KGuiItem(i18nc("@action:button", "Continue Current Game")), 0148 KGuiItem(i18nc("@action:button", "Start a New Game")) 0149 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0150 ) == KMessageBox::SecondaryAction 0151 #else 0152 ) == KMessageBox::No 0153 #endif 0154 ) { 0155 m_coordinator->requestNewGame(); 0156 } 0157 0158 m_rulesetChanged = false; 0159 } 0160 } 0161 0162 void Killbots::MainWindow::createScoreDialog() 0163 { 0164 m_scoreDialog = new KScoreDialog(KScoreDialog::Name, this); 0165 m_scoreDialog->addField(KScoreDialog::Level, i18nc("@title:column round of the game", "Round"), QStringLiteral("round")); 0166 m_scoreDialog->setModal(false); 0167 QStringList fileList; 0168 const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("killbots/ruleset"), QStandardPaths::LocateDirectory); 0169 for (const QString &dir : dirs) { 0170 const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.desktop")); 0171 for (const QString &file : fileNames) { 0172 fileList.append(dir + QLatin1Char('/') + file); 0173 } 0174 } 0175 for (const QString &fileName : std::as_const(fileList)) { 0176 const Ruleset *ruleset = Ruleset::load(fileName); 0177 if (ruleset) { 0178 m_scoreDialog->addLocalizedConfigGroupName(qMakePair(ruleset->scoreGroupKey(), ruleset->name())); 0179 } 0180 delete ruleset; 0181 } 0182 } 0183 0184 void Killbots::MainWindow::onGameOver(int score, int round) 0185 { 0186 if (score && m_engine->ruleset()) { 0187 if (!m_scoreDialog) { 0188 createScoreDialog(); 0189 } 0190 0191 m_scoreDialog->setConfigGroup(qMakePair(m_engine->ruleset()->scoreGroupKey(), m_engine->ruleset()->name())); 0192 0193 KScoreDialog::FieldInfo scoreEntry; 0194 scoreEntry[ KScoreDialog::Score ].setNum(score); 0195 scoreEntry[ KScoreDialog::Level ].setNum(round); 0196 0197 if (m_scoreDialog->addScore(scoreEntry)) { 0198 QTimer::singleShot(1000, this, &MainWindow::showHighscores); 0199 } 0200 } 0201 } 0202 0203 void Killbots::MainWindow::showHighscores() 0204 { 0205 if (!m_scoreDialog) { 0206 createScoreDialog(); 0207 } 0208 0209 // TODO: Find out why this line breaks adding high scores. 0210 //m_scoreDialog->setConfigGroup(qMakePair(m_engine->ruleset()->scoreGroupKey(), m_engine->ruleset()->name())); 0211 m_scoreDialog->exec(); 0212 } 0213 0214 QAction *Killbots::MainWindow::createMappedAction(int mapping, 0215 const QString &internalName, 0216 const QString &displayName, 0217 const QString &translatedShortcut, 0218 const int alternateShortcut, 0219 const QString &helpText, 0220 const QString &icon 0221 ) 0222 { 0223 QAction *action = new QAction(displayName, actionCollection()); 0224 action->setObjectName(internalName); 0225 actionCollection()->setDefaultShortcuts(action, QList<QKeySequence>() << QKeySequence(translatedShortcut) << QKeySequence(alternateShortcut) << QKeySequence(alternateShortcut | Qt::KeypadModifier)); 0226 if (!helpText.isEmpty()) { 0227 action->setWhatsThis(helpText); 0228 action->setToolTip(helpText); 0229 } 0230 if (!icon.isEmpty()) { 0231 action->setIcon(QIcon::fromTheme(icon)); 0232 } 0233 0234 connect(action, &QAction::triggered, this, [this, mapping] { m_coordinator->requestAction(mapping); }); 0235 actionCollection()->addAction(internalName, action); 0236 0237 return action; 0238 } 0239 0240 void Killbots::MainWindow::setupActions() 0241 { 0242 KStandardGameAction::gameNew(m_coordinator, &Coordinator::requestNewGame, actionCollection()); 0243 KStandardGameAction::highscores(this, &MainWindow::showHighscores, actionCollection()); 0244 KStandardGameAction::quit(qApp, &QCoreApplication::quit, actionCollection()); 0245 KStandardAction::preferences(this, &MainWindow::configurePreferences, actionCollection()); 0246 0247 createMappedAction(TeleportSafely, 0248 QStringLiteral("teleport_safely"), 0249 i18nc("@action", "Teleport Safely"), 0250 i18nc("Shortcut for teleport safely. See https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "T"), 0251 Qt::Key_Plus, 0252 i18nc("@info:tooltip", "Teleport to a safe location"), 0253 QStringLiteral("games-solve") 0254 ); 0255 createMappedAction(Teleport, 0256 QStringLiteral("teleport"), 0257 i18nc("@action", "Teleport"), 0258 i18nc("Shortcut for teleport. See https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "R"), 0259 Qt::Key_Minus, 0260 i18nc("@info:tooltip", "Teleport to a random location"), 0261 QStringLiteral("roll") 0262 ); 0263 createMappedAction(TeleportSafelyIfPossible, 0264 QStringLiteral("teleport_sip"), 0265 i18nc("@action", "Teleport (Safely if Possible)"), 0266 i18nc("Shortcut for teleport safely if possible. See https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "Space"), 0267 Qt::Key_0, 0268 i18nc("@info:tooltip", "Teleport safely if that action is enabled, otherwise teleport randomly") 0269 ); 0270 createMappedAction(Vaporizer, 0271 QStringLiteral("vaporizer"), 0272 i18nc("@action", "Vaporizer"), 0273 i18nc("Shortcut for vaporizer. See https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "F"), 0274 Qt::Key_Period, 0275 i18nc("@info:tooltip", "Destroy all enemies in neighboring cells"), 0276 QStringLiteral("edit-bomb") 0277 ); 0278 createMappedAction(WaitOutRound, 0279 QStringLiteral("wait_out_round"), 0280 i18nc("@action", "Wait Out Round"), 0281 i18nc("Shortcut for wait out round. See https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "V"), 0282 Qt::Key_Asterisk, 0283 i18nc("@info:tooltip", "Risk remaining in place until the end of the round for bonuses"), 0284 QStringLiteral("process-stop") 0285 ); 0286 createMappedAction(UpLeft, 0287 QStringLiteral("move_up_left"), 0288 i18nc("@action", "Move Up and Left"), 0289 i18nc("Shortcut for move up and left. https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "Q"), 0290 Qt::Key_7 0291 ); 0292 createMappedAction(Up, 0293 QStringLiteral("move_up"), 0294 i18nc("@action", "Move Up"), 0295 i18nc("Shortcut for move up. See https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "W"), 0296 Qt::Key_8 0297 ); 0298 createMappedAction(UpRight, 0299 QStringLiteral("move_up_right"), 0300 i18nc("@action", "Move Up and Right"), 0301 i18nc("Shortcut for move up and right. https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "E"), 0302 Qt::Key_9 0303 ); 0304 createMappedAction(Left, 0305 QStringLiteral("move_left"), 0306 i18nc("@action", "Move Left"), 0307 i18nc("Shortcut for move left. See https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "A"), 0308 Qt::Key_4 0309 ); 0310 createMappedAction(Hold, 0311 QStringLiteral("stand_still"), 0312 i18nc("@action", "Stand Still"), 0313 i18nc("Shortcut for stand still. See https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "S"), 0314 Qt::Key_5 0315 ); 0316 createMappedAction(Right, 0317 QStringLiteral("move_right"), 0318 i18nc("@action", "Move Right"), 0319 i18nc("Shortcut for move right. See https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "D"), 0320 Qt::Key_6 0321 ); 0322 createMappedAction(DownLeft, 0323 QStringLiteral("move_down_left"), 0324 i18nc("@action", "Move Down and Left"), 0325 i18nc("Shortcut for move down and left. See https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "Z"), 0326 Qt::Key_1 0327 ); 0328 createMappedAction(Down, 0329 QStringLiteral("move_down"), 0330 i18nc("@action", "Move Down"), 0331 i18nc("Shortcut for move down. See https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "X"), 0332 Qt::Key_2 0333 ); 0334 createMappedAction(DownRight, 0335 QStringLiteral("move_down_right"), 0336 i18nc("@action", "Move Down and Right"), 0337 i18nc("Shortcut for move down and right. https://quickgit.kde.org/?p=killbots.git&a=blob&f=README.translators&o=plain", "C"), 0338 Qt::Key_3 0339 ); 0340 } 0341 0342 #include "moc_mainwindow.cpp"