File indexing completed on 2023-10-01 08:02:05

0001 /*
0002     SPDX-FileCopyrightText: 2007-2008 Thomas Gallinari <tg8187@yahoo.fr>
0003     SPDX-FileCopyrightText: 2007-2008 Pierre-Benoit Bessse <besse@gmail.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "kapmanmainwindow.h"
0009 #include "gamescene.h"
0010 #include "settings.h"
0011 // KDEGames
0012 #include <kdegames_version.h>
0013 #include <KgThemeProvider>
0014 #include <KgThemeSelector>
0015 #include <KScoreDialog>
0016 #include <KStandardGameAction>
0017 #include <KgDifficulty>
0018 // KF
0019 #include <kwidgetsaddons_version.h>
0020 #include <KStandardGuiItem>
0021 #include <KActionCollection>
0022 #include <KLocalizedString>
0023 #include <KMessageBox>
0024 #include <KToggleAction>
0025 #include <KToggleFullScreenAction>
0026 // Qt
0027 #include <QAction>
0028 #include <QInputDialog>
0029 #include <QLabel>
0030 #include <QPointer>
0031 #include <QStatusBar>
0032 #include <QMenuBar>
0033 
0034 KapmanMainWindow::KapmanMainWindow()
0035 {
0036     m_themeProvider = new KgThemeProvider(QByteArray(), this); // empty config key to disable internal config
0037     m_themeProvider->discoverThemes(
0038 #if KDEGAMES_VERSION < QT_VERSION_CHECK(7, 4, 0)
0039         "appdata",
0040 #endif
0041         QStringLiteral("themes"),   // theme data location
0042         QStringLiteral("default")); // default theme name
0043 
0044     const QByteArray themeIdentifier = Settings::theme().toUtf8();
0045     const QList<const KgTheme *> themes = m_themeProvider->themes();
0046     for (auto* theme : themes) {
0047         if (theme->identifier() == themeIdentifier) {
0048             m_themeProvider->setCurrentTheme(theme);
0049             break;
0050         }
0051     }
0052     connect(m_themeProvider, &KgThemeProvider::currentThemeChanged, this, &KapmanMainWindow::onThemeChanged);
0053 
0054     m_themeSelector = new KgThemeSelector(m_themeProvider);
0055 
0056     // Initialize the game
0057     m_game = nullptr;
0058     m_view = nullptr;
0059     // Set the window menus
0060     KStandardGameAction::gameNew(this, &KapmanMainWindow::newGame, actionCollection());
0061     KStandardGameAction::highscores(this, &KapmanMainWindow::showHighscores, actionCollection());
0062     KStandardAction::preferences(this, &KapmanMainWindow::showSettings, actionCollection());
0063 
0064     KStandardAction::fullScreen(this, &KapmanMainWindow::viewFullScreen, this, actionCollection());
0065 
0066     KStandardGameAction::quit(this, &KapmanMainWindow::close, actionCollection());
0067     auto soundAction = new KToggleAction(i18n("&Play Sounds"), this);
0068     soundAction->setChecked(Settings::sounds());
0069     actionCollection()->addAction(QStringLiteral("sounds"), soundAction);
0070     connect(soundAction, &KToggleAction::triggered, this, &KapmanMainWindow::setSoundsEnabled);
0071     auto levelAction = new QAction(i18n("&Change Level"), this);
0072     actionCollection()->addAction(QStringLiteral("level"), levelAction);
0073     connect(levelAction, &QAction::triggered, this, &KapmanMainWindow::changeLevel);
0074     // Add a statusbar to show level,score,lives information
0075     m_statusBar = statusBar();
0076     mLevel = new QLabel(i18nc("Used to display the current level of play to the user", "Level: %1", 1));
0077     m_statusBar->addPermanentWidget(mLevel);
0078     mScore = new QLabel(i18nc("Used to inform the user of their current score", "Score: %1", 0));
0079     m_statusBar->addPermanentWidget(mScore);
0080     mLives = new QLabel(i18nc("Used to tell the user how many lives they have left", "Lives: %1", initLives));
0081     m_statusBar->addPermanentWidget(mLives);
0082 
0083     // Initialize the KgDifficulty singleton
0084     Kg::difficulty()->addStandardLevelRange(KgDifficultyLevel::Easy,
0085                                             KgDifficultyLevel::Hard, // range
0086                                             KgDifficultyLevel::Medium // default
0087     );
0088     KgDifficultyGUI::init(this);
0089     connect(Kg::difficulty(), &KgDifficulty::currentLevelChanged, this, &KapmanMainWindow::initGame);
0090     // Setup the window
0091     setupGUI();
0092 
0093     menuBar()->setVisible(!isFullScreen());
0094     statusBar()->setVisible(!isFullScreen());
0095 
0096     initGame();
0097 }
0098 
0099 KapmanMainWindow::~KapmanMainWindow()
0100 {
0101     delete m_themeSelector;
0102     delete m_statusBar;
0103     delete m_game;
0104     delete m_view;
0105 }
0106 
0107 void KapmanMainWindow::initGame()
0108 {
0109     // Create a new Game instance
0110     delete m_game;
0111     m_game = new Game();
0112     connect(m_game, &Game::gameOver, this, &KapmanMainWindow::handleGameOver);
0113     connect(m_game, &Game::levelChanged, this, &KapmanMainWindow::displayLevel);
0114     connect(m_game, &Game::scoreChanged, this, &KapmanMainWindow::displayScore);
0115     connect(m_game, &Game::livesChanged, this, &KapmanMainWindow::displayLives);
0116 
0117     // Create a new GameView instance
0118     delete m_view;
0119     m_view = new GameView(m_game, m_themeProvider->currentTheme());
0120     m_view->setBackgroundBrush(Qt::black);
0121     setCentralWidget(m_view);
0122     m_view->setFocus();
0123     // For some reason, calling setFocus() immediately won't work after the
0124     // score dialog has been shown, so do it again after an eventloop run.
0125     QTimer::singleShot(0, m_view, qOverload<>(&QWidget::setFocus));
0126     resetStatusBar();
0127 }
0128 
0129 void KapmanMainWindow::newGame()
0130 {
0131     bool gameRunning; // True if the game is running (game timer is active), false otherwise
0132 
0133     gameRunning = m_game->getTimer()->isActive();
0134     // If the game is running
0135     if (gameRunning) {
0136         // Pause the game
0137         m_game->pause();
0138     }
0139 
0140     // Confirm before starting a new game
0141 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0142     if (KMessageBox::warningTwoActions(this,
0143 #else
0144     if (KMessageBox::warningYesNo(this,
0145 #endif
0146                                   i18n("Are you sure you want to quit the current game?"),
0147                                   i18nc("@title:window", "New Game"),
0148                                   KGuiItem(i18nc("@action;button", "Quit Game"), QStringLiteral("window-close")),
0149                                   KStandardGuiItem::cancel())
0150 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0151         == KMessageBox::PrimaryAction) {
0152 #else
0153         == KMessageBox::Yes) {
0154 #endif
0155         // Start a new game
0156         initGame();
0157     } else {
0158         // If the game was running
0159         if (gameRunning) {
0160             // Resume the game
0161             m_game->start();
0162         }
0163     }
0164 }
0165 
0166 void KapmanMainWindow::handleGameOver()
0167 {
0168     bool gameRunning; // True if the game is running (game timer is active), false otherwise
0169 
0170     gameRunning = m_game->getTimer()->isActive();
0171     // If the game is running
0172     if (gameRunning) {
0173         // Pause the game
0174         m_game->pause();
0175     }
0176     // Display the score information
0177     KMessageBox::information(this, i18np("Your score is %1 point.", "Your score is %1 points.", m_game->getScore()), i18n("Game Over"));
0178     // manage Highscores only if player did not cheat
0179     if (m_game->isCheater()) {
0180         KMessageBox::information(this, i18n("You cheated, no Highscore for you ;)"), i18n("Cheater!"));
0181     } else {
0182         // Add the score to the highscores table
0183         QPointer<KScoreDialog> dialog = new KScoreDialog(KScoreDialog::Name | KScoreDialog::Score | KScoreDialog::Level, this);
0184         dialog->initFromDifficulty(Kg::difficulty());
0185         KScoreDialog::FieldInfo scoreInfo;
0186         scoreInfo[KScoreDialog::Level].setNum(m_game->getLevel());
0187         scoreInfo[KScoreDialog::Score].setNum(m_game->getScore());
0188         // If the new score is a highscore then display the highscore dialog
0189         if (dialog->addScore(scoreInfo)) {
0190             dialog->exec();
0191         }
0192         delete dialog;
0193     }
0194     // Start a new game
0195     initGame();
0196 }
0197 
0198 void KapmanMainWindow::changeLevel()
0199 {
0200     const int newLevel = QInputDialog::getInt(this, i18n("Change Level"), i18nc("The number of the game level", "Level"), m_game->getLevel(), 1, 1000000, 1);
0201     if (newLevel > 0) {
0202         m_game->setLevel(newLevel);
0203     }
0204 }
0205 
0206 void KapmanMainWindow::showHighscores()
0207 {
0208     QPointer<KScoreDialog> dialog = new KScoreDialog(KScoreDialog::Name | KScoreDialog::Score | KScoreDialog::Level, this);
0209     dialog->initFromDifficulty(Kg::difficulty());
0210     dialog->exec();
0211     delete dialog;
0212 }
0213 
0214 void KapmanMainWindow::setSoundsEnabled(bool p_enabled)
0215 {
0216     m_game->setSoundsEnabled(p_enabled);
0217 }
0218 
0219 void KapmanMainWindow::showSettings()
0220 {
0221     m_themeSelector->showAsDialog();
0222 }
0223 
0224 void KapmanMainWindow::onThemeChanged(const KgTheme *theme)
0225 {
0226     // sync to settings store
0227     Settings::setTheme(QString::fromUtf8(theme->identifier()));
0228     Settings::self()->save();
0229     // trigger update of resources, then display
0230     ((GameScene *)m_view->scene())->loadTheme(theme);
0231 }
0232 
0233 void KapmanMainWindow::close()
0234 {
0235     bool gameRunning; // True if the game is running (game timer is active), false otherwise
0236 
0237     gameRunning = m_game->getTimer()->isActive();
0238     // If the game is running
0239     if (gameRunning) {
0240         // Pause the game
0241         m_game->pause();
0242     }
0243     // Confirm before closing
0244 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0245     if (KMessageBox::warningTwoActions(this,
0246 #else
0247     if (KMessageBox::warningYesNo(this,
0248 #endif
0249                                   i18n("Are you sure you want to quit Kapman?"),
0250                                   i18nc("To quit Kapman", "Quit"),
0251                                   KStandardGuiItem::quit(), KStandardGuiItem::cancel())
0252 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0253         == KMessageBox::PrimaryAction) {
0254 #else
0255         == KMessageBox::Yes) {
0256 #endif
0257         KXmlGuiWindow::close();
0258     } else {
0259         // If the game was running
0260         if (gameRunning) {
0261             // Resume the game
0262             m_game->start();
0263         }
0264     }
0265 }
0266 
0267 void KapmanMainWindow::displayLevel(unsigned int p_level)
0268 {
0269     mLevel->setText(i18nc("Used to display the current level of play to the user", "Level: %1", p_level));
0270 }
0271 
0272 void KapmanMainWindow::displayScore(unsigned int p_score)
0273 {
0274     mScore->setText(i18nc("Used to inform the user of their current score", "Score: %1", p_score));
0275 }
0276 
0277 void KapmanMainWindow::displayLives(unsigned int p_lives)
0278 {
0279     mLives->setText(i18nc("Used to tell the user how many lives they have left", "Lives: %1", p_lives));
0280 }
0281 
0282 void KapmanMainWindow::resetStatusBar()
0283 {
0284     displayLevel(1);
0285     displayScore(0);
0286     displayLives(initLives);
0287 }
0288 
0289 void KapmanMainWindow::viewFullScreen(bool fullScreen)
0290 {
0291     KToggleFullScreenAction::setFullScreen(this, fullScreen);
0292 
0293     menuBar()->setVisible(!fullScreen);
0294     statusBar()->setVisible(!fullScreen);
0295 }
0296 
0297 #include "moc_kapmanmainwindow.cpp"