File indexing completed on 2024-10-13 03:44:25
0001 /* 0002 SPDX-FileCopyrightText: 2004-2005 Andi Peredri <andi@ukr.net> 0003 SPDX-FileCopyrightText: 2007 Simon Hürlimann <simon.huerlimann@huerlisi.ch> 0004 SPDX-FileCopyrightText: 2007-2008 Fela Winkelmolen <fela.kde@gmail.com> 0005 SPDX-FileCopyrightText: 2013 Ashwin Rajeev <ashwin_rajeev@hotmail.com> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "mainwindow.h" 0011 0012 #include <KConfigDialog> 0013 #include <KLocalizedString> 0014 #include <KStandardAction> 0015 #include <QAction> 0016 #include <KToggleAction> 0017 #include <KActionCollection> 0018 #include <KGameStandardAction> 0019 #include <QStatusBar> 0020 0021 #include <KGameDifficulty> 0022 #include <KGameHighScoreDialog> 0023 #include <KGameThemeSelector> 0024 #include <KGameRenderer> 0025 #include <KGameClock> 0026 #include <KGameSound> 0027 0028 #include <ctime> 0029 #include <cmath> 0030 0031 #include "ui_general.h" 0032 #include "ui_customgame.h" 0033 0034 #include "globals.h" 0035 #include "gameview.h" 0036 #include "settings.h" 0037 #include "abstractgrid.h" 0038 0039 class GeneralConfig : public QWidget 0040 { 0041 public: 0042 GeneralConfig(QWidget *parent) 0043 : QWidget(parent) 0044 { 0045 ui.setupUi(this); 0046 } 0047 private: 0048 Ui::GeneralConfig ui; 0049 }; 0050 0051 class CustomGameConfig : public QWidget 0052 { 0053 public: 0054 CustomGameConfig(QWidget *parent) 0055 : QWidget(parent) 0056 { 0057 ui.setupUi(this); 0058 } 0059 private: 0060 Ui::CustomGameConfig ui; 0061 }; 0062 0063 MainWindow::MainWindow(QWidget *parent) 0064 : KXmlGuiWindow(parent), m_clickCount(0), 0065 m_view(new GameView(this)) 0066 { 0067 connect(m_view, &GameView::gameOver, this, &MainWindow::gameOver); 0068 connect(m_view, &GameView::rotationStarted, this, &MainWindow::rotationStarted); 0069 connect(this, SIGNAL(pause(QVariant)), m_view->rootObject(), SLOT(pause(QVariant))); 0070 0071 m_movesLabel = new QLabel(this); 0072 m_movesLabel->setAlignment(Qt::AlignCenter); 0073 m_timeLabel = new QLabel(this); 0074 m_timeLabel->setAlignment(Qt::AlignCenter); 0075 0076 statusBar()->insertPermanentWidget(0, m_movesLabel, 1); 0077 statusBar()->insertPermanentWidget(1, m_timeLabel, 1); 0078 0079 // Difficulty 0080 KGameDifficulty::global()->addStandardLevelRange( 0081 KGameDifficultyLevel::Easy, KGameDifficultyLevel::VeryHard 0082 ); 0083 KGameDifficulty::global()->addLevel( 0084 new KGameDifficultyLevel(100, QByteArray("Custom"), i18n("Custom")) 0085 ); 0086 KGameDifficultyGUI::init(this); 0087 connect(KGameDifficulty::global(), &KGameDifficulty::currentLevelChanged, this, &MainWindow::startNewGame); 0088 0089 0090 setCentralWidget(m_view); 0091 0092 setupActions(); 0093 0094 setupGUI(); 0095 0096 setAutoSaveSettings(); 0097 0098 m_gameClock = new KGameClock(this, KGameClock::FlexibleHourMinSec); 0099 connect(m_gameClock, &KGameClock::timeChanged, this, &MainWindow::updateStatusBar); 0100 0101 m_soundStart = new KGameSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/start.wav")), this); 0102 m_soundWin = new KGameSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/win.wav")), this); 0103 0104 0105 startNewGame(); 0106 } 0107 0108 void MainWindow::setupActions() 0109 { 0110 // Game 0111 KGameStandardAction::gameNew(this, &MainWindow::startNewGame, 0112 actionCollection()); 0113 0114 m_pauseAction = KGameStandardAction::pause(this, &MainWindow::pauseGame, 0115 actionCollection()); 0116 connect(KGameDifficulty::global(), &KGameDifficulty::gameRunningChanged, m_pauseAction, 0117 &QAction::setEnabled); 0118 0119 QAction *action = KGameStandardAction::solve(m_view, &GameView::solve, actionCollection()); 0120 connect(KGameDifficulty::global(), &KGameDifficulty::gameRunningChanged, action, &QAction::setEnabled); 0121 0122 KGameStandardAction::highscores(this, &MainWindow::showHighscores, 0123 actionCollection()); 0124 0125 KGameStandardAction::quit(this, &MainWindow::close, actionCollection()); 0126 0127 // Settings 0128 KStandardAction::preferences(this, &MainWindow::configureSettings, actionCollection()); 0129 0130 action = new QAction(i18n("&Unlock All"), this); 0131 connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(unlockAll())); 0132 connect(KGameDifficulty::global(), &KGameDifficulty::gameRunningChanged, action, &QAction::setEnabled); 0133 actionCollection()->addAction( QStringLiteral( "unlock_all" ), action); 0134 0135 action = new QAction(i18n("Keyboard: Field right"), this); 0136 KActionCollection::setDefaultShortcut(action, Qt::Key_Right); 0137 connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(kbGoRight())); 0138 actionCollection()->addAction( QStringLiteral( "kb_go_right" ), action); 0139 0140 action = new QAction(i18n("Keyboard: Field left"),this); 0141 KActionCollection::setDefaultShortcut(action, Qt::Key_Left); 0142 connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(kbGoLeft())); 0143 actionCollection()->addAction( QStringLiteral( "kb_go_left" ), action); 0144 0145 action = new QAction(i18n("Keyboard: Field up"),this); 0146 KActionCollection::setDefaultShortcut(action, Qt::Key_Up); 0147 connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(kbGoUp())); 0148 actionCollection()->addAction( QStringLiteral( "kb_go_up" ), action); 0149 0150 action = new QAction(i18n("Keyboard: Field down"),this); 0151 KActionCollection::setDefaultShortcut(action, Qt::Key_Down); 0152 connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(kbGoDown())); 0153 actionCollection()->addAction( QStringLiteral( "kb_go_down" ), action); 0154 0155 action = new QAction(i18n("Keyboard: Turn clockwise"),this); 0156 KActionCollection::setDefaultShortcut(action, Qt::Key_Return); 0157 connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(rotateClockwise())); 0158 actionCollection()->addAction( QStringLiteral( "kb_turn_clockwise" ), action); 0159 0160 action = new QAction(i18n("Keyboard: Turn counterclockwise"),this); 0161 KActionCollection::setDefaultShortcut(action, Qt::CTRL | Qt::Key_Return); 0162 connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(rotateCounterclockwise())); 0163 actionCollection()->addAction( QStringLiteral( "kb_turn_counterclockwise" ), action); 0164 0165 action = new QAction(i18n("Keyboard: Toggle lock"),this); 0166 KActionCollection::setDefaultShortcut(action, Qt::Key_Space); 0167 connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(toggleLock())); 0168 actionCollection()->addAction( QStringLiteral( "kb_lock" ), action); 0169 } 0170 0171 void MainWindow::configureSettings() 0172 { 0173 if (KConfigDialog::showDialog(QStringLiteral("settings"))) 0174 return; 0175 KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("settings"), Settings::self()); 0176 dialog->addPage(new GeneralConfig(dialog), i18n("General"), QStringLiteral("games-config-options")); 0177 dialog->addPage(new KGameThemeSelector(m_view->getProvider()), i18n("Theme"), QStringLiteral("games-config-theme")); 0178 dialog->addPage(new CustomGameConfig(dialog), i18n("Custom Game"), QStringLiteral("games-config-custom")); 0179 connect(dialog, &KConfigDialog::settingsChanged, m_view, &GameView::updateSettings); 0180 // dialog->setHelp(QString(),QLatin1String("knetwalk")); 0181 dialog->show(); 0182 } 0183 0184 void MainWindow::showHighscores() 0185 { 0186 KGameHighScoreDialog scoreDialog(KGameHighScoreDialog::Name | KGameHighScoreDialog::Time, this); 0187 scoreDialog.addField(KGameHighScoreDialog::Custom1, i18n("Moves Penalty"), QStringLiteral( "moves" )); 0188 scoreDialog.initFromDifficulty(KGameDifficulty::global()); 0189 scoreDialog.exec(); 0190 } 0191 0192 void MainWindow::startNewGame() 0193 { 0194 if(Settings::playSounds()) 0195 m_soundStart->start(); 0196 0197 const KGameDifficultyLevel::StandardLevel l = KGameDifficulty::globalLevel(); 0198 0199 bool isWrapped = (l == KGameDifficultyLevel::VeryHard); 0200 if (KGameDifficulty::globalLevel() == KGameDifficultyLevel::Custom) 0201 isWrapped = Settings::wrapping(); 0202 const QSize size = boardSize(); 0203 m_view->startNewGame(size.width(), size.height(), (Wrapping)isWrapped); 0204 m_clickCount = -m_view->minimumMoves(); 0205 m_gameClock->restart(); 0206 0207 if(m_pauseAction->isChecked()) 0208 { 0209 m_pauseAction->setChecked(false); 0210 } 0211 KGameDifficulty::global()->setGameRunning(true); 0212 0213 updateStatusBar(); 0214 } 0215 0216 void MainWindow::gameOver(const QVariant &msg) 0217 { 0218 m_gameClock->pause(); 0219 KGameDifficulty::global()->setGameRunning(false); 0220 0221 if (msg.toString() != QLatin1String("won")) 0222 return; 0223 0224 if(Settings::playSounds()) 0225 m_soundWin->start(); 0226 0227 //=== calculate the score ====// 0228 0229 double penalty = m_gameClock->seconds() / 2.0 * (m_clickCount/2 + 1); 0230 0231 // normalize the penalty 0232 penalty = std::sqrt(penalty/m_view->cellCount()); 0233 0234 int score = static_cast<int>(100.0 / penalty); 0235 0236 // create the new scoreInfo 0237 KGameHighScoreDialog::FieldInfo scoreInfo; 0238 scoreInfo[KGameHighScoreDialog::Score].setNum(score); 0239 scoreInfo[KGameHighScoreDialog::Custom1].setNum(m_clickCount/2); 0240 scoreInfo[KGameHighScoreDialog::Time] = m_gameClock->timeString(); 0241 0242 // show the new dialog and add the new score to it 0243 KGameHighScoreDialog scoreDialog(KGameHighScoreDialog::Name | KGameHighScoreDialog::Time, this); 0244 scoreDialog.addField(KGameHighScoreDialog::Custom1, i18n("Moves Penalty"), QStringLiteral( "moves" )); 0245 scoreDialog.initFromDifficulty(KGameDifficulty::global()); 0246 bool madeIt = scoreDialog.addScore(scoreInfo); 0247 if (!madeIt) { 0248 QString comment = i18np("Your score was %1, you did not make it to the high score list.", 0249 "Your score was %1, you did not make it to the high score list.", score); 0250 scoreDialog.setComment(comment); 0251 } 0252 scoreDialog.exec(); 0253 } 0254 0255 void MainWindow::rotationStarted() 0256 { 0257 m_clickCount++; 0258 updateStatusBar(); 0259 } 0260 0261 void MainWindow::pauseGame(bool paused) 0262 { 0263 pause(paused); 0264 if(paused) { 0265 m_gameClock->pause(); 0266 } else { 0267 m_gameClock->resume(); 0268 } 0269 } 0270 0271 void MainWindow::updateStatusBar() 0272 { 0273 QString moves = i18nc("Number of mouse clicks", "Moves: %1", m_clickCount); 0274 QString time = i18nc("Time elapsed", "Time: %1", m_gameClock->timeString()); 0275 m_movesLabel->setText(moves); 0276 m_timeLabel->setText(time); 0277 } 0278 0279 QSize MainWindow::boardSize() 0280 { 0281 switch (KGameDifficulty::globalLevel()) { 0282 case KGameDifficultyLevel::Easy: return QSize(5, 5); 0283 case KGameDifficultyLevel::Medium: return QSize(7, 7); 0284 case KGameDifficultyLevel::Hard: return QSize(9, 9); 0285 case KGameDifficultyLevel::Custom: return QSize(Settings::width(), Settings::height()); 0286 default: return QSize(9, 9); 0287 } 0288 } 0289 0290 #include "moc_mainwindow.cpp"