File indexing completed on 2024-04-28 07:51:30

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"