File indexing completed on 2025-04-27 03:48:34
0001 /* 0002 SPDX-FileCopyrightText: 2007-2009 Fela Winkelmolen <fela.kde@gmail.com> 0003 SPDX-FileCopyrightText: 2010 Brian Croom <brian.s.croom@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "mainwindow.h" 0009 0010 // own 0011 #include "gameengine.h" 0012 #include "canvaswidget.h" 0013 #include "ui_generalsettings.h" 0014 #include "settings.h" 0015 #include "globals.h" 0016 // KDEGames 0017 #include <KGameHighScoreDialog> 0018 #include <KGameThemeSelector> 0019 #include <KGameStandardAction> 0020 // KF 0021 #include <KStandardAction> 0022 #include <KToggleFullScreenAction> 0023 #include <KActionCollection> 0024 #include <KMessageBox> 0025 #include <KConfigDialog> 0026 #include <KConfig> 0027 // Qt 0028 #include <QPointer> 0029 #include <QMenuBar> 0030 #include <QIcon> 0031 #include <QAction> 0032 #include <QKeySequence> 0033 0034 class GeneralSettings : public QWidget 0035 { 0036 Q_OBJECT 0037 public: 0038 explicit GeneralSettings(QWidget *parent) 0039 : QWidget(parent) 0040 { 0041 ui.setupUi(this); 0042 } 0043 ~GeneralSettings() override {} 0044 private: 0045 Ui::GeneralSettings ui; 0046 }; 0047 0048 MainWindow::MainWindow(QWidget *parent) 0049 : KXmlGuiWindow(parent), 0050 canvasWidget(new CanvasWidget(this)) 0051 { 0052 gameEngine = new GameEngine(this); 0053 0054 m_cheatsEnabled = !qEnvironmentVariableIsEmpty("KDE_DEBUG"); 0055 0056 connect(canvasWidget, &CanvasWidget::focusLost, this, &MainWindow::pauseGame); 0057 0058 connect(canvasWidget, &CanvasWidget::levelComplete, gameEngine, &GameEngine::loadNextLevel); 0059 connect(canvasWidget, &CanvasWidget::gameEnded, this, &MainWindow::handleEndedGame); 0060 connect(canvasWidget, &CanvasWidget::mousePressed, this, &MainWindow::handleMousePressed); 0061 0062 connect(gameEngine, &GameEngine::loadingNewGame, canvasWidget, &CanvasWidget::newGame); 0063 connect(gameEngine, &GameEngine::newLine, canvasWidget, &CanvasWidget::showLine); 0064 connect(gameEngine, &GameEngine::newGift, canvasWidget, &CanvasWidget::putGift); 0065 connect(gameEngine, &GameEngine::ready, canvasWidget, &CanvasWidget::startGame); 0066 0067 setCentralWidget(canvasWidget); 0068 0069 setupActions(); 0070 setFocusProxy(canvasWidget); 0071 0072 QSize defaultSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 0073 setupGUI(defaultSize, 0074 KXmlGuiWindow::Keys | KXmlGuiWindow::Save | KXmlGuiWindow::Create); 0075 0076 if (isFullScreen()) { 0077 menuBar()->hide(); 0078 } else { 0079 menuBar()->show(); 0080 } 0081 0082 // show here (instead of in main) else the mouse can't be grabbed 0083 show(); 0084 gameEngine->start(QStringLiteral("default")); 0085 } 0086 0087 MainWindow::~MainWindow() 0088 { 0089 delete gameEngine; 0090 delete canvasWidget; 0091 } 0092 0093 void MainWindow::setupActions() 0094 { 0095 KGameStandardAction::gameNew(this, &MainWindow::startNewGame, actionCollection()); 0096 0097 KGameStandardAction::quit(this, &MainWindow::close, actionCollection()); 0098 0099 KGameStandardAction::highscores(this, &MainWindow::showHighscores, actionCollection()); 0100 0101 KStandardAction::preferences(this, &MainWindow::configureSettings, actionCollection()); 0102 0103 QAction *fullScreenAction = KStandardAction::fullScreen(this, 0104 &MainWindow::viewFullScreen, this, actionCollection()); 0105 // set the default primary shortcut as alternate shortcut 0106 // and make F the default 0107 QKeySequence fullScreenShortcut(i18nc("Key (shortcut) to toggle full screen", "F")); 0108 fullScreenAction->setShortcut(fullScreenShortcut); 0109 QAction *fireAction = new QAction(this); 0110 fireAction->setText(i18n("Fire the ball")); 0111 KActionCollection::setDefaultShortcut(fireAction, Qt::Key_Space); 0112 fireAction->setIcon(QIcon::fromTheme(QStringLiteral("kbreakout"))); 0113 connect(fireAction, &QAction::triggered, this, &MainWindow::fire); 0114 connect(fireAction, &QAction::changed, canvasWidget, &CanvasWidget::updateFireShortcut); 0115 actionCollection()->addAction(QStringLiteral("fire"), fireAction); 0116 0117 if (m_cheatsEnabled) { 0118 QAction *cheatSkipLevelAction = new QAction(this); 0119 cheatSkipLevelAction->setText(i18n("Skip level")); 0120 KActionCollection::setDefaultShortcut(cheatSkipLevelAction, Qt::Key_S); 0121 cheatSkipLevelAction->setIcon(QIcon::fromTheme(QStringLiteral("kbreakout"))); 0122 connect(cheatSkipLevelAction, &QAction::triggered, this, &MainWindow::cheatSkipLevel); 0123 actionCollection()->addAction(QStringLiteral("cheatSkipLevel"), cheatSkipLevelAction); 0124 0125 QAction *cheatAddLifeAction = new QAction(this); 0126 cheatAddLifeAction->setText(i18n("Add life")); 0127 KActionCollection::setDefaultShortcut(cheatAddLifeAction, Qt::Key_L); 0128 cheatAddLifeAction->setIcon(QIcon::fromTheme(QStringLiteral("kbreakout"))); 0129 connect(cheatAddLifeAction, &QAction::triggered, this, &MainWindow::cheatAddLife); 0130 actionCollection()->addAction(QStringLiteral("cheatAddLife"), cheatAddLifeAction); 0131 } 0132 0133 pauseAction = KGameStandardAction::pause(this, &MainWindow::setGamePaused, actionCollection()); 0134 // set custom keys 0135 QList<QKeySequence> keys; 0136 keys.append(i18nc("Key (shortcut) to pause the game", "P")); 0137 keys.append(Qt::Key_Escape); 0138 // the following won't work (no more than 2 shortcuts allowed..) 0139 // TODO: make the pause key work 0140 //keys.append(Qt::Key_Pause); 0141 pauseAction->setShortcuts(keys); 0142 } 0143 0144 void MainWindow::configureSettings() 0145 { 0146 if (KConfigDialog::showDialog(QStringLiteral("settings"))) { 0147 return; 0148 } 0149 // else it doesn't exist, thus create the dialog 0150 0151 KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("settings"), 0152 Settings::self()); 0153 dialog->setModal(true); 0154 0155 dialog->addPage(new KGameThemeSelector(canvasWidget->getProvider()), 0156 i18n("Theme"), QStringLiteral("games-config-theme")); 0157 0158 // TODO: when will the page be destroyed? 0159 dialog->addPage(new GeneralSettings(dialog), 0160 i18nc("General settings", "General"), 0161 QStringLiteral("games-config-options")); 0162 0163 dialog->show(); 0164 } 0165 0166 void MainWindow::showHighscores() 0167 { 0168 KGameHighScoreDialog ksdialog(KGameHighScoreDialog::Name | KGameHighScoreDialog::Level, this); 0169 ksdialog.addField(KGameHighScoreDialog::Custom1, i18n(" Time (hh:mm)"), QStringLiteral("moves")); 0170 0171 ksdialog.exec(); 0172 } 0173 0174 void MainWindow::startNewGame() 0175 { 0176 int ret = KMessageBox::warningTwoActions( 0177 this, 0178 i18n("Starting a new game will end the current one!"), 0179 i18n("New Game"), 0180 KGuiItem(i18n("Start a New Game")), 0181 KStandardGuiItem::cancel()); 0182 0183 if (ret == KMessageBox::PrimaryAction) { 0184 pauseAction->setChecked(false); 0185 gameEngine->start(QStringLiteral("default")); 0186 } 0187 } 0188 0189 void MainWindow::pauseGame() 0190 { 0191 if (!pauseAction->isChecked()) { 0192 pauseAction->activate(QAction::Trigger); 0193 } 0194 } 0195 0196 void MainWindow::setGamePaused(bool paused) 0197 { 0198 canvasWidget->setGamePaused(paused); 0199 } 0200 0201 void MainWindow::handleEndedGame(int score, int level, int time) 0202 { 0203 0204 QTime t = QTime(0, 0).addSecs(time); 0205 // TODO: check int overflow and fix 24 hours "overflow" 0206 QString timeString = t.toString(QStringLiteral("HH:mm")); 0207 0208 const int ALL_LEVELS = -1; 0209 0210 KGameHighScoreDialog::FieldInfo scoreInfo; 0211 scoreInfo[KGameHighScoreDialog::Score].setNum(score); 0212 scoreInfo[KGameHighScoreDialog::Custom1] = timeString; 0213 if (level == ALL_LEVELS) { 0214 scoreInfo[KGameHighScoreDialog::Level] = i18n("Game won!"); 0215 } else { 0216 scoreInfo[KGameHighScoreDialog::Level].setNum(level); 0217 } 0218 0219 QPointer<KGameHighScoreDialog> ksdialog = 0220 new KGameHighScoreDialog(KGameHighScoreDialog::Name | KGameHighScoreDialog::Level, this); 0221 ksdialog->addField(KGameHighScoreDialog::Custom1, i18n("Time (hh:mm)"), QStringLiteral("moves")); 0222 ksdialog->addScore(scoreInfo); 0223 ksdialog->exec(); 0224 0225 if (ksdialog) { 0226 gameEngine->start(QStringLiteral("default")); 0227 delete ksdialog; 0228 } 0229 } 0230 0231 void MainWindow::fire() 0232 { 0233 if (pauseAction->isChecked()) { 0234 pauseAction->activate(QAction::Trigger); 0235 } else { 0236 canvasWidget->fire(); 0237 } 0238 } 0239 0240 void MainWindow::cheatSkipLevel() 0241 { 0242 if (pauseAction->isChecked()) { 0243 pauseAction->activate(QAction::Trigger); 0244 } else { 0245 canvasWidget->cheatSkipLevel(); 0246 } 0247 } 0248 0249 void MainWindow::cheatAddLife() 0250 { 0251 if (pauseAction->isChecked()) { 0252 pauseAction->activate(QAction::Trigger); 0253 } else { 0254 canvasWidget->cheatAddLife(); 0255 } 0256 } 0257 0258 void MainWindow::viewFullScreen(bool fullScreen) 0259 { 0260 KToggleFullScreenAction::setFullScreen(this, fullScreen); 0261 if (fullScreen) { 0262 menuBar()->hide(); 0263 } else { 0264 menuBar()->show(); 0265 } 0266 } 0267 0268 void MainWindow::handleMousePressed() 0269 { 0270 if (pauseAction->isChecked()) { 0271 pauseAction->activate(QAction::Trigger); 0272 return; 0273 } 0274 0275 if (Settings::fireOnClick()) { 0276 canvasWidget->fire(); 0277 return; 0278 } 0279 0280 // not fire on click 0281 0282 // check if dontAskFireOnClick is set 0283 // we want to override it's default effect 0284 // if it's set to _any_ value we want to keep the 0285 // settings of fireOnClick at false 0286 bool dontAsk = false; // true if dontAskFireOnClick was set 0287 #if 0 //QT5 0288 KConfig config(componentData(), "kbreakoutrc"); 0289 if (config.hasGroup("Notification Messages")) { 0290 KConfigGroup group(&config, "Notification Messages"); 0291 if (group.hasKey("dontAskFireOnClick")) { 0292 dontAsk = true; 0293 } 0294 } 0295 #endif 0296 if (dontAsk == false) { 0297 // ask the user if he wants to fire on mouse click 0298 int res = KMessageBox::questionTwoActions( 0299 this, 0300 i18n("Do you want to fire the ball on mouse click?\n" 0301 "Answering Yes will make the game steal the\n" 0302 "mouse cursor, pause the game to get\n" 0303 "the cursor back."), 0304 i18n("Fire on click?"), 0305 KGuiItem(i18nc("@action;button", "Use Mouse Click"), QStringLiteral("input-mouse")), 0306 KGuiItem(i18nc("@action;button", "Ignore Mouse Click"), QStringLiteral("dialog-cancel")), 0307 QStringLiteral("dontAskFireOnClick") // doesntAskAgainName 0308 ); 0309 0310 if (res == KMessageBox::PrimaryAction) { 0311 Settings::setFireOnClick(true); 0312 Settings::self()->save(); 0313 } 0314 } 0315 } 0316 0317 #include "mainwindow.moc" 0318 #include "moc_mainwindow.cpp"