Warning, file /games/kreversi/src/mainwindow.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2006 Dmitry Suzdalev <dimsuz@gmail.com> 0003 SPDX-FileCopyrightText: 2010 Brian Croom <brian.s.croom@gmail.com> 0004 SPDX-FileCopyrightText: 2013 Denis Kuplyakov <dener.kup@gmail.com> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "mainwindow.h" 0010 0011 #include <QDebug> 0012 #include <QIcon> 0013 #include <QStatusBar> 0014 #include <QScreen> 0015 // KF 0016 #include <KActionCollection> 0017 #include <KLocalizedString> 0018 #include <KMessageBox> 0019 // KDEGames 0020 #include <KGameStandardAction> 0021 0022 #include "commondefs.h" 0023 #include "kreversihumanplayer.h" 0024 #include "kreversicomputerplayer.h" 0025 #include "kexthighscore.h" 0026 0027 KReversiMainWindow::KReversiMainWindow(QWidget* parent, bool startDemo) 0028 : KXmlGuiWindow(parent), 0029 m_startDialog(nullptr), 0030 m_view(nullptr), 0031 m_game(nullptr), 0032 m_historyDock(nullptr), 0033 m_historyView(nullptr), 0034 m_firstShow(true), 0035 m_startInDemoMode(startDemo), 0036 m_undoAct(nullptr), 0037 m_hintAct(nullptr) 0038 { 0039 memset(m_player, 0, sizeof(m_player)); 0040 0041 m_provider = new KGameThemeProvider(); 0042 m_provider->discoverThemes(QStringLiteral("pics")); 0043 0044 for (auto &label : m_statusBarLabel) { 0045 label = new QLabel(this); 0046 label->setAlignment(Qt::AlignCenter); 0047 statusBar()->addWidget(label, 1); 0048 } 0049 m_statusBarLabel[common]->setText(i18n("Press start game!")); 0050 0051 // initialize difficulty stuff 0052 KGameDifficulty::global()->addStandardLevelRange( 0053 KGameDifficultyLevel::VeryEasy, KGameDifficultyLevel::Impossible, 0054 KGameDifficultyLevel::Easy //default 0055 ); 0056 0057 KGameDifficultyGUI::init(this); 0058 connect(KGameDifficulty::global(), &KGameDifficulty::currentLevelChanged, this, &KReversiMainWindow::levelChanged); 0059 KGameDifficulty::global()->setEditable(false); 0060 0061 // initialize history dock 0062 m_historyView = new QListWidget(this); 0063 m_historyView->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); 0064 m_historyDock = new QDockWidget(i18n("Move History")); 0065 m_historyDock->setWidget(m_historyView); 0066 m_historyDock->setObjectName(QStringLiteral("history_dock")); 0067 0068 m_historyDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); 0069 addDockWidget(Qt::RightDockWidgetArea, m_historyDock); 0070 0071 // create main game view 0072 m_view = new KReversiView(m_game, this, m_provider); 0073 setCentralWidget(m_view); 0074 0075 // initialise dialog handler 0076 m_startDialog = new StartGameDialog(this, m_provider); 0077 connect(m_startDialog, &StartGameDialog::startGame, this, &KReversiMainWindow::slotDialogReady); 0078 0079 // initialise actions 0080 setupActionsInit(); 0081 0082 // load saved settings 0083 loadSettings(); 0084 0085 setupGUI(screen()->availableGeometry().size() * 0.7); 0086 m_historyDock->hide(); 0087 } 0088 0089 KReversiMainWindow::~KReversiMainWindow() 0090 { 0091 clearPlayers(); 0092 delete m_provider; 0093 } 0094 0095 void KReversiMainWindow::setupActionsInit() 0096 { 0097 // Common actions 0098 KGameStandardAction::gameNew(this, &KReversiMainWindow::slotNewGame, actionCollection()); 0099 KGameStandardAction::highscores(this, &KReversiMainWindow::slotHighscores, actionCollection()); 0100 KGameStandardAction::quit(this, &QWidget::close, actionCollection()); 0101 0102 // Undo 0103 m_undoAct = KGameStandardAction::undo(this, &KReversiMainWindow::slotUndo, actionCollection()); 0104 m_undoAct->setEnabled(false); // nothing to undo at the start of the game 0105 0106 // Hint 0107 m_hintAct = KGameStandardAction::hint(m_view, &KReversiView::slotHint, actionCollection()); 0108 m_hintAct->setEnabled(false); 0109 0110 // Last move 0111 m_showLast = new KToggleAction(QIcon::fromTheme(QStringLiteral("lastmoves")), i18n("Show Last Move"), this); 0112 actionCollection()->addAction(QStringLiteral("show_last_move"), m_showLast); 0113 connect(m_showLast, &KToggleAction::triggered, m_view, &KReversiView::setShowLastMove); 0114 0115 // Legal moves 0116 m_showLegal = new KToggleAction(QIcon::fromTheme(QStringLiteral("legalmoves")), i18n("Show Legal Moves"), this); 0117 actionCollection()->addAction(QStringLiteral("show_legal_moves"), m_showLegal); 0118 connect(m_showLegal, &KToggleAction::triggered, m_view, &KReversiView::setShowLegalMoves); 0119 0120 // Animation speed 0121 m_animSpeedAct = new KSelectAction(i18n("Animation Speed"), this); 0122 actionCollection()->addAction(QStringLiteral("anim_speed"), m_animSpeedAct); 0123 0124 QStringList acts; 0125 acts << i18n("Slow") << i18n("Normal") << i18n("Fast"); 0126 m_animSpeedAct->setItems(acts); 0127 connect(m_animSpeedAct, &KSelectAction::indexTriggered, this, &KReversiMainWindow::slotAnimSpeedChanged); 0128 0129 // Chip's color 0130 m_coloredChipsAct = new KToggleAction(i18n("Use Colored Chips"), this); 0131 actionCollection()->addAction(QStringLiteral("use_colored_chips"), m_coloredChipsAct); 0132 connect(m_coloredChipsAct, &KToggleAction::triggered, this, &KReversiMainWindow::slotUseColoredChips); 0133 0134 // Move history 0135 // NOTE: read/write this from/to config file? Or not necessary? 0136 m_showMovesAct = m_historyDock->toggleViewAction(); 0137 m_showMovesAct->setIcon(QIcon::fromTheme(QStringLiteral("view-history"))); 0138 m_showMovesAct->setText(i18n("Show Move History")); 0139 actionCollection()->addAction(QStringLiteral("show_moves"), m_showMovesAct); 0140 connect(m_historyDock, &QDockWidget::visibilityChanged, this, &KReversiMainWindow::slotToggleBoardLabels); 0141 } 0142 0143 void KReversiMainWindow::loadSettings() 0144 { 0145 // Animation speed 0146 m_animSpeedAct->setCurrentItem(Preferences::animationSpeed()); 0147 m_view->setAnimationSpeed(Preferences::animationSpeed()); 0148 0149 // Chip's color 0150 m_coloredChipsAct->setChecked(Preferences::useColoredChips()); 0151 m_view->setChipsPrefix(Preferences::useColoredChips() ? 0152 Colored : BlackWhite); 0153 m_startDialog->setChipsPrefix(Preferences::useColoredChips() ? 0154 Colored : BlackWhite); 0155 } 0156 0157 void KReversiMainWindow::levelChanged() 0158 { 0159 // we are assuming that level can be changed here only when it is 0160 // USER-AI or AI-USER match 0161 0162 int skill = Utils::difficultyLevelToInt(); 0163 0164 if (m_nowPlayingInfo.type[White] == GameStartInformation::AI) 0165 ((KReversiComputerPlayer *)(m_player[White]))->setSkill(skill); 0166 else if (m_nowPlayingInfo.type[Black] == GameStartInformation::Human) 0167 ((KReversiComputerPlayer *)(m_player[Black]))->setSkill(skill); 0168 } 0169 0170 void KReversiMainWindow::slotAnimSpeedChanged(int speed) 0171 { 0172 m_view->setAnimationSpeed(speed); 0173 Preferences::setAnimationSpeed(speed); 0174 Preferences::self()->save(); 0175 } 0176 0177 void KReversiMainWindow::slotUseColoredChips(bool toggled) 0178 { 0179 ChipsPrefix chipsPrefix = m_coloredChipsAct->isChecked() ? 0180 Colored : 0181 BlackWhite; 0182 m_view->setChipsPrefix(chipsPrefix); 0183 m_startDialog->setChipsPrefix(chipsPrefix); 0184 Preferences::setUseColoredChips(toggled); 0185 Preferences::self()->save(); 0186 } 0187 0188 void KReversiMainWindow::slotToggleBoardLabels(bool toggled) 0189 { 0190 m_view->setShowBoardLabels(toggled); 0191 } 0192 0193 void KReversiMainWindow::slotNewGame() 0194 { 0195 m_startDialog->exec(); 0196 } 0197 0198 void KReversiMainWindow::slotGameOver() 0199 { 0200 m_hintAct->setEnabled(false); 0201 m_undoAct->setEnabled(m_game->canUndo()); 0202 0203 int blackScore = m_game->playerScore(Black); 0204 int whiteScore = m_game->playerScore(White); 0205 0206 bool storeScore = false; 0207 KExtHighscore::Score score; 0208 0209 QString res; 0210 if (m_nowPlayingInfo.type[Black] == GameStartInformation::Human 0211 && m_nowPlayingInfo.type[White] == GameStartInformation::AI) { // we are playing black 0212 storeScore = true; 0213 KExtHighscore::setGameType(((KReversiComputerPlayer *)m_player[White])->lowestSkill()); 0214 score.setScore(blackScore); 0215 if (blackScore == whiteScore) { 0216 res = i18n("Game is drawn!"); 0217 score.setType(KExtHighscore::Draw); 0218 } else if (blackScore > whiteScore) { 0219 res = i18n("You win!"); 0220 score.setType(KExtHighscore::Won); 0221 } else { 0222 res = i18n("You have lost!"); 0223 score.setType(KExtHighscore::Lost); 0224 } 0225 } else if (m_nowPlayingInfo.type[White] == GameStartInformation::Human 0226 && m_nowPlayingInfo.type[Black] == GameStartInformation::AI) { // we are playing white 0227 storeScore = true; 0228 KExtHighscore::setGameType(((KReversiComputerPlayer *)m_player[Black])->lowestSkill()); 0229 score.setScore(whiteScore); 0230 if (blackScore == whiteScore) { 0231 res = i18n("Game is drawn!"); 0232 score.setType(KExtHighscore::Draw); 0233 } else if (blackScore < whiteScore) { 0234 res = i18n("You win!"); 0235 score.setType(KExtHighscore::Won); 0236 } else { 0237 res = i18n("You have lost!"); 0238 score.setType(KExtHighscore::Lost); 0239 } 0240 0241 } else if (m_nowPlayingInfo.type[Black] == GameStartInformation::Human 0242 && m_nowPlayingInfo.type[White] == GameStartInformation::Human) { // friends match 0243 if (blackScore == whiteScore) { 0244 res = i18n("Game is drawn!"); 0245 } else if (blackScore > whiteScore) { 0246 res = i18n("%1 has won!", m_nowPlayingInfo.name[Black]); 0247 } else { 0248 res = i18n("%1 has won!", m_nowPlayingInfo.name[White]); 0249 } 0250 } else { // using Black White names in other cases 0251 if (blackScore == whiteScore) { 0252 res = i18n("Game is drawn!"); 0253 } else if (blackScore > whiteScore) { 0254 res = i18n("%1 has won!", Utils::colorToString(Black)); 0255 } else { 0256 res = i18n("%1 has won!", Utils::colorToString(White)); 0257 } 0258 } 0259 0260 if (m_nowPlayingInfo.type[Black] == GameStartInformation::AI 0261 && m_nowPlayingInfo.type[White] == GameStartInformation::AI) { 0262 res += i18n("\n%1: %2", Utils::colorToString(Black), blackScore); 0263 res += i18n("\n%1: %2", Utils::colorToString(White), whiteScore); 0264 } else { 0265 res += i18n("\n%1: %2", m_nowPlayingInfo.name[Black], blackScore); 0266 res += i18n("\n%1: %2", m_nowPlayingInfo.name[White], whiteScore); 0267 } 0268 0269 KMessageBox::information(this, res, i18n("Game over")); 0270 0271 if (storeScore) 0272 KExtHighscore::submitScore(score, this); 0273 } 0274 0275 void KReversiMainWindow::slotMoveFinished() 0276 { 0277 updateHistory(); 0278 updateStatusBar(); 0279 0280 m_hintAct->setEnabled(m_game->isHintAllowed()); 0281 m_undoAct->setEnabled(m_game->canUndo()); 0282 } 0283 0284 void KReversiMainWindow::updateHistory() 0285 { 0286 MoveList history = m_game->getHistory(); 0287 m_historyView->clear(); 0288 0289 for (int i = 0; i < history.size(); i++) { 0290 QString numStr = QString::number(i + 1) + QStringLiteral(". "); 0291 m_historyView->addItem(numStr + Utils::moveToString(history.at(i))); 0292 } 0293 0294 QListWidgetItem *last = m_historyView->item(m_historyView->count() - 1); 0295 m_historyView->setCurrentItem(last); 0296 m_historyView->scrollToItem(last); 0297 } 0298 0299 void KReversiMainWindow::slotUndo() 0300 { 0301 // scene will automatically notice that it needs to update 0302 m_game->undo(); 0303 0304 updateHistory(); 0305 updateStatusBar(); 0306 0307 m_undoAct->setEnabled(m_game->canUndo()); 0308 m_hintAct->setEnabled(m_game->isHintAllowed()); 0309 } 0310 0311 void KReversiMainWindow::slotHighscores() 0312 { 0313 KExtHighscore::show(this); 0314 } 0315 0316 void KReversiMainWindow::slotDialogReady() 0317 { 0318 GameStartInformation info = m_startDialog->createGameStartInformation(); 0319 receivedGameStartInformation(info); 0320 } 0321 0322 void KReversiMainWindow::showEvent(QShowEvent*) 0323 { 0324 if (m_firstShow && m_startInDemoMode) { 0325 qDebug() << "starting demo..."; 0326 startDemo(); 0327 } else if (m_firstShow) { 0328 QTimer::singleShot(0, this, &KReversiMainWindow::slotNewGame); 0329 } 0330 m_firstShow = false; 0331 } 0332 0333 void KReversiMainWindow::updateStatusBar() 0334 { 0335 if (m_game->isGameOver()) { 0336 m_statusBarLabel[common]->setText(i18n("GAME OVER")); 0337 } 0338 0339 if (m_nowPlayingInfo.type[Black] == GameStartInformation::AI 0340 && m_nowPlayingInfo.type[White] == GameStartInformation::AI) { // using Black White names 0341 m_statusBarLabel[black]->setText(i18n("%1: %2", Utils::colorToString(Black), m_game->playerScore(Black))); 0342 m_statusBarLabel[white]->setText(i18n("%1: %2", Utils::colorToString(White), m_game->playerScore(White))); 0343 0344 if (!m_game->isGameOver()) { 0345 m_statusBarLabel[common]->setText(i18n("%1 turn", Utils::colorToString(m_game->currentPlayer()))); 0346 } 0347 } else { // using player's names 0348 m_statusBarLabel[black]->setText(i18n("%1: %2", m_nowPlayingInfo.name[Black], m_game->playerScore(Black))); 0349 m_statusBarLabel[white]->setText(i18n("%1: %2", m_nowPlayingInfo.name[White], m_game->playerScore(White))); 0350 0351 if (!m_game->isGameOver() && m_game->currentPlayer() != NoColor) { 0352 m_statusBarLabel[common]->setText(i18n("%1's turn", m_nowPlayingInfo.name[m_game->currentPlayer()])); 0353 } 0354 } 0355 } 0356 0357 0358 // TODO: test it!!! 0359 void KReversiMainWindow::startDemo() 0360 { 0361 GameStartInformation info; 0362 info.name[0] = info.name[1] = i18n("Computer"); 0363 info.type[0] = info.type[1] = GameStartInformation::AI; 0364 info.skill[0] = info.skill[1] = Utils::difficultyLevelToInt(); 0365 0366 receivedGameStartInformation(info); 0367 } 0368 0369 void KReversiMainWindow::clearPlayers() 0370 { 0371 for (int i = 0; i < 2; i++) // iterating through white to black 0372 if (m_player[i]) { 0373 m_player[i]->disconnect(); 0374 delete m_player[i]; 0375 m_player[i] = nullptr; 0376 } 0377 } 0378 0379 void KReversiMainWindow::receivedGameStartInformation(const GameStartInformation &info) 0380 { 0381 clearPlayers(); 0382 m_nowPlayingInfo = info; 0383 0384 for (int i = 0; i < 2; i++) // iterating through black and white 0385 if (info.type[i] == GameStartInformation::AI) { 0386 m_player[i] = new KReversiComputerPlayer(ChipColor(i), info.name[i]); 0387 ((KReversiComputerPlayer *)(m_player[i]))->setSkill(info.skill[i]); 0388 levelChanged(); 0389 } else { 0390 m_player[i] = new KReversiHumanPlayer(ChipColor(i), info.name[i]); 0391 } 0392 0393 m_game = new KReversiGame(m_player[Black], m_player[White]); 0394 0395 m_view->setGame(m_game); 0396 0397 connect(m_game, &KReversiGame::gameOver, this, &KReversiMainWindow::slotGameOver); 0398 connect(m_game, &KReversiGame::moveFinished, this, &KReversiMainWindow::slotMoveFinished); 0399 0400 for (int i = 0; i < 2; i++) // iterating white to black 0401 if (info.type[i] == GameStartInformation::Human) 0402 connect(m_view, &KReversiView::userMove, 0403 (KReversiHumanPlayer *)(m_player[i]), &KReversiHumanPlayer::onUICellClick); 0404 0405 updateStatusBar(); 0406 updateHistory(); 0407 0408 if (info.type[White] == GameStartInformation::AI 0409 && info.type[Black] == GameStartInformation::Human) { 0410 KGameDifficulty::global()->setEditable(true); 0411 KGameDifficulty::global()->select(Utils::intToDifficultyLevel(info.skill[White])); 0412 } else if (info.type[White] == GameStartInformation::Human 0413 && info.type[Black] == GameStartInformation::AI) { 0414 KGameDifficulty::global()->setEditable(true); 0415 KGameDifficulty::global()->select(Utils::intToDifficultyLevel(info.skill[Black])); 0416 } else 0417 KGameDifficulty::global()->setEditable(false); 0418 0419 m_hintAct->setEnabled(m_game->isHintAllowed()); 0420 m_undoAct->setEnabled(m_game->canUndo()); 0421 } 0422 0423 #include "moc_mainwindow.cpp"