File indexing completed on 2024-04-28 04:02:29

0001 /*
0002     SPDX-FileCopyrightText: 2007 Dmitry Suzdalev <dimsuz@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 "minefielditem.h"
0012 #include "scene.h"
0013 #include "settings.h"
0014 #include "kmines_debug.h"
0015 #include "ui_customgame.h"
0016 #include "ui_generalopts.h"
0017 // KDEGames
0018 #include <KGameClock>
0019 #include <KGameDifficulty>
0020 #include <KGameHighScoreDialog>
0021 #include <KGameStandardAction>
0022 #include <KGameThemeSelector>
0023 // KF
0024 #include <KActionCollection>
0025 #include <KConfigDialog>
0026 #include <KLocalizedString>
0027 #include <KMessageBox>
0028 // Qt
0029 #include <QStatusBar>
0030 #include <QScreen>
0031 /*
0032  * Classes for config dlg pages
0033  */
0034 class CustomGameConfig : public QWidget
0035 {
0036     Q_OBJECT
0037 
0038 public:
0039     CustomGameConfig(QWidget *parent)
0040         : QWidget(parent)
0041     {
0042         ui.setupUi(this);
0043         connect(ui.kcfg_CustomWidth, &QSpinBox::valueChanged,
0044                 this, &CustomGameConfig::updateMaxMines);
0045         connect(ui.kcfg_CustomHeight, &QSpinBox::valueChanged,
0046                 this, &CustomGameConfig::updateMaxMines);
0047     }
0048 
0049 private Q_SLOTS:
0050     void updateMaxMines()
0051     {
0052         int width = ui.kcfg_CustomWidth->value();
0053         int height = ui.kcfg_CustomHeight->value();
0054         int max = qMax(1, width * height - MineFieldItem::MINIMAL_FREE);
0055         ui.kcfg_CustomMines->setMaximum(max);
0056     }
0057 
0058 private:
0059     Ui::CustomGameConfig ui;
0060 };
0061 
0062 class GeneralOptsConfig : public QWidget
0063 {
0064 public:
0065     GeneralOptsConfig(QWidget *parent)
0066         : QWidget(parent)
0067     {
0068         ui.setupUi(this);
0069     }
0070 
0071 private:
0072     Ui::GeneralOptsConfig ui;
0073 };
0074 
0075 /*
0076  * Main window
0077  */
0078 
0079 KMinesMainWindow::KMinesMainWindow()
0080 {
0081     m_scene = new KMinesScene(this);
0082     
0083     connect(m_scene, &KMinesScene::minesCountChanged, this, &KMinesMainWindow::onMinesCountChanged);
0084     connect(m_scene, &KMinesScene::gameOver, this, &KMinesMainWindow::onGameOver);
0085     connect(m_scene, &KMinesScene::firstClickDone, this, &KMinesMainWindow::onFirstClick);
0086 
0087     m_view = new KMinesView( m_scene, this );
0088     m_view->setCacheMode( QGraphicsView::CacheBackground );
0089     m_view->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
0090     m_view->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
0091     m_view->setFrameStyle(QFrame::NoFrame);
0092 
0093     m_view->setOptimizationFlags( 
0094                                 QGraphicsView::DontSavePainterState |
0095                                 QGraphicsView::DontAdjustForAntialiasing );
0096 
0097 
0098     m_gameClock = new KGameClock(this, KGameClock::FlexibleHourMinSec);
0099     connect(m_gameClock, &KGameClock::timeChanged, this, &KMinesMainWindow::advanceTime);
0100 
0101     mineLabel->setText(i18n("Mines: 0/0"));
0102     timeLabel->setText(i18n("Time: 00:00"));
0103     
0104     statusBar()->insertPermanentWidget( 0, mineLabel );
0105     statusBar()->insertPermanentWidget( 1, timeLabel );
0106     setCentralWidget(m_view);
0107     setupActions();
0108 
0109     newGame();
0110 }
0111 
0112 void KMinesMainWindow::setupActions()
0113 {
0114     KGameStandardAction::gameNew(this, &KMinesMainWindow::newGame, actionCollection());
0115     KGameStandardAction::highscores(this, &KMinesMainWindow::showHighscores, actionCollection());
0116 
0117     KGameStandardAction::quit(this, &KMinesMainWindow::close, actionCollection());
0118     KStandardAction::preferences(this, &KMinesMainWindow::configureSettings, actionCollection());
0119     m_actionPause = KGameStandardAction::pause(this, &KMinesMainWindow::pauseGame, actionCollection());
0120 
0121     KGameDifficulty::global()->addStandardLevelRange(
0122         KGameDifficultyLevel::Easy, KGameDifficultyLevel::Hard
0123     );
0124     KGameDifficulty::global()->addLevel(new KGameDifficultyLevel(1000,
0125         QByteArray( "Custom" ), i18n( "Custom" )
0126     ));
0127     KGameDifficultyGUI::init(this);
0128     connect(KGameDifficulty::global(), &KGameDifficulty::currentLevelChanged, this, &KMinesMainWindow::newGame);
0129 
0130     setupGUI(screen()->availableGeometry().size() * 0.4);
0131 }
0132 
0133 void KMinesMainWindow::onMinesCountChanged(int count)
0134 {
0135     mineLabel->setText(i18n("Mines: %1/%2", count, m_scene->totalMines()));
0136 }
0137 
0138 void KMinesMainWindow::newGame()
0139 {
0140     qCDebug(KMINES_LOG) << "Inside game";
0141     m_gameClock->restart();
0142     m_gameClock->pause(); // start only with the 1st click
0143 
0144     // some things to manage pause
0145     if( m_actionPause->isChecked() )
0146     {
0147             m_scene->setGamePaused(false);
0148             m_actionPause->setChecked(false);
0149     }
0150     m_actionPause->setEnabled(false);
0151 
0152     KGameDifficulty::global()->setGameRunning(false);
0153     switch(KGameDifficulty::globalLevel())
0154     {
0155         case KGameDifficultyLevel::Easy:
0156             m_scene->startNewGame(9, 9, 10);
0157             break;
0158         case KGameDifficultyLevel::Medium:
0159             m_scene->startNewGame(16,16,40);
0160             break;
0161         case KGameDifficultyLevel::Hard:
0162             m_scene->startNewGame(16,30,99);
0163             break;
0164         case KGameDifficultyLevel::Custom:
0165             m_scene->startNewGame(Settings::customHeight(),
0166                                   Settings::customWidth(),
0167                                   Settings::customMines());
0168         default:
0169             //unsupported
0170             break;
0171     }
0172     
0173     timeLabel->setText(i18n("Time: 00:00"));
0174 }
0175 
0176 void KMinesMainWindow::onGameOver(bool won)
0177 {
0178     m_gameClock->pause();
0179     m_actionPause->setEnabled(false);
0180     KGameDifficulty::global()->setGameRunning(false);
0181     if(won && m_scene->canScore())
0182     {
0183         QPointer<KGameHighScoreDialog> scoreDialog = new KGameHighScoreDialog(KGameHighScoreDialog::Name | KGameHighScoreDialog::Time, this);
0184         scoreDialog->initFromDifficulty(KGameDifficulty::global());
0185         scoreDialog->hideField(KGameHighScoreDialog::Score);
0186 
0187         KGameHighScoreDialog::FieldInfo scoreInfo;
0188         // score-in-seconds will be hidden
0189         scoreInfo[KGameHighScoreDialog::Score].setNum(m_gameClock->seconds());
0190         //score-as-time will be shown
0191         scoreInfo[KGameHighScoreDialog::Time] = m_gameClock->timeString();
0192 
0193         // we keep highscores as number of seconds
0194         if( scoreDialog->addScore(scoreInfo, KGameHighScoreDialog::LessIsMore) != 0 )
0195             scoreDialog->exec();
0196 
0197         delete scoreDialog;
0198     } else if (!won)
0199     {
0200         //ask to reset
0201         if (Settings::allowKminesReset() &&
0202             KMessageBox::questionTwoActions(this,
0203                                             i18n("Reset the Game?"),
0204                                             QString(),
0205                                             KGuiItem(i18nc("@action;button", "Reset"), QStringLiteral("view-refresh")),
0206                                             KStandardGuiItem::cancel()) == KMessageBox::PrimaryAction) {
0207             m_scene->reset();
0208             m_gameClock->restart();
0209             m_actionPause->setEnabled(true);
0210             m_scene->setCanScore(!Settings::disableScoreOnReset());
0211         }
0212     }
0213 }
0214 
0215 void KMinesMainWindow::advanceTime(const QString& timeStr)
0216 {
0217     timeLabel->setText(i18n("Time: %1", timeStr));
0218 }
0219 
0220 void KMinesMainWindow::onFirstClick()
0221 {
0222     // enable pause action
0223     m_actionPause->setEnabled(true);
0224     // start clock
0225     m_gameClock->resume();
0226     KGameDifficulty::global()->setGameRunning(true);
0227 }
0228 
0229 void KMinesMainWindow::showHighscores()
0230 {
0231     QPointer<KGameHighScoreDialog> scoreDialog = new KGameHighScoreDialog(KGameHighScoreDialog::Name | KGameHighScoreDialog::Time, this);
0232     scoreDialog->initFromDifficulty(KGameDifficulty::global());
0233     scoreDialog->hideField(KGameHighScoreDialog::Score);
0234     scoreDialog->exec();
0235     delete scoreDialog;
0236 }
0237 
0238 void KMinesMainWindow::configureSettings()
0239 {
0240     if ( KConfigDialog::showDialog( QStringLiteral(  "settings" ) ) )
0241         return;
0242     auto *dialog = new KConfigDialog( this, QStringLiteral( "settings" ), Settings::self() );
0243     dialog->addPage( new GeneralOptsConfig( dialog ), i18n("General"), QStringLiteral( "games-config-options" ));
0244     dialog->addPage( new KGameThemeSelector( m_scene->renderer().themeProvider() ), i18n( "Theme" ), QStringLiteral( "games-config-theme" ));
0245     dialog->addPage( new CustomGameConfig( dialog ), i18n("Custom Game"), QStringLiteral( "games-config-custom" ));
0246     connect( m_scene->renderer().themeProvider(), &KGameThemeProvider::currentThemeChanged, this, &KMinesMainWindow::loadSettings );
0247     connect(dialog, &KConfigDialog::settingsChanged, this, &KMinesMainWindow::loadSettings);
0248     
0249     dialog->show();
0250 }
0251 
0252 void KMinesMainWindow::pauseGame(bool paused)
0253 {
0254     m_scene->setGamePaused( paused );
0255     if( paused )
0256         m_gameClock->pause();
0257     else
0258         m_gameClock->resume();
0259 }
0260 
0261 void KMinesMainWindow::loadSettings()
0262 {
0263     m_view->resetCachedContent();
0264     // trigger complete redraw
0265     m_scene->resizeScene( (int)m_scene->sceneRect().width(),
0266                           (int)m_scene->sceneRect().height() );
0267 }
0268 
0269 #include "mainwindow.moc"
0270 #include "moc_mainwindow.cpp"