1/*
2 Copyright 2007 Dmitry Suzdalev <dimsuz@gmail.com>
3 Copyright 2010 Brian Croom <brian.s.croom@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19#include "mainwindow.h"
20#include "minefielditem.h"
21#include "scene.h"
22#include "settings.h"
23
24#include <KGameClock>
25#include <KgDifficulty>
26#include <KStandardGameAction>
27#include <KActionCollection>
28#include <KToggleAction>
29#include <KStatusBar>
30#include <KScoreDialog>
31#include <KConfigDialog>
32#include <KgThemeSelector>
33#include <KMessageBox>
34#include <KLocale>
35#include <QDesktopWidget>
36#include <QPointer>
37
38#include "ui_customgame.h"
39#include "ui_generalopts.h"
40
41/*
42 * Classes for config dlg pages
43 */
44class CustomGameConfig : public QWidget
45{
46 Q_OBJECT
47
48public:
49 CustomGameConfig(QWidget *parent)
50 : QWidget(parent)
51 {
52 ui.setupUi(this);
53 connect(ui.kcfg_CustomWidth, SIGNAL(valueChanged(int)), this, SLOT(updateMaxMines()));
54 connect(ui.kcfg_CustomHeight, SIGNAL(valueChanged(int)), this, SLOT(updateMaxMines()));
55 }
56
57private slots:
58 void updateMaxMines()
59 {
60 int width = ui.kcfg_CustomWidth->value();
61 int height = ui.kcfg_CustomHeight->value();
62 int max = qMax(1, width * height - MineFieldItem::MINIMAL_FREE);
63 ui.kcfg_CustomMines->setMaximum(max);
64 }
65
66private:
67 Ui::CustomGameConfig ui;
68};
69
70class GeneralOptsConfig : public QWidget
71{
72public:
73 GeneralOptsConfig(QWidget *parent)
74 : QWidget(parent)
75 {
76 ui.setupUi(this);
77 }
78
79private:
80 Ui::GeneralOptsConfig ui;
81};
82
83/*
84 * Main window
85 */
86
87KMinesMainWindow::KMinesMainWindow()
88{
89 m_scene = new KMinesScene(this);
90 connect(m_scene, SIGNAL(minesCountChanged(int)), SLOT(onMinesCountChanged(int)));
91 connect(m_scene, SIGNAL(gameOver(bool)), SLOT(onGameOver(bool)));
92 connect(m_scene, SIGNAL(firstClickDone()), SLOT(onFirstClick()));
93
94 m_view = new KMinesView( m_scene, this );
95 m_view->setCacheMode( QGraphicsView::CacheBackground );
96 m_view->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
97 m_view->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
98 m_view->setFrameStyle(QFrame::NoFrame);
99
100 m_view->setOptimizationFlags( QGraphicsView::DontClipPainter |
101 QGraphicsView::DontSavePainterState |
102 QGraphicsView::DontAdjustForAntialiasing );
103
104
105 m_gameClock = new KGameClock(this, KGameClock::MinSecOnly);
106 connect(m_gameClock, SIGNAL(timeChanged(QString)), SLOT(advanceTime(QString)));
107
108 statusBar()->insertItem( i18n("Mines: 0/0"), 0 );
109 statusBar()->insertItem( i18n("Time: 00:00"), 1);
110 setCentralWidget(m_view);
111 setupActions();
112
113 newGame();
114}
115
116void KMinesMainWindow::setupActions()
117{
118 KStandardGameAction::gameNew(this, SLOT(newGame()), actionCollection());
119 KStandardGameAction::highscores(this, SLOT(showHighscores()), actionCollection());
120
121 KStandardGameAction::quit(this, SLOT(close()), actionCollection());
122 KStandardAction::preferences( this, SLOT(configureSettings()), actionCollection() );
123 m_actionPause = KStandardGameAction::pause( this, SLOT(pauseGame(bool)), actionCollection() );
124
125 Kg::difficulty()->addStandardLevelRange(
126 KgDifficultyLevel::Easy, KgDifficultyLevel::Hard
127 );
128 Kg::difficulty()->addLevel(new KgDifficultyLevel(1000,
129 QByteArray( "Custom" ), i18n( "Custom" )
130 ));
131 KgDifficultyGUI::init(this);
132 connect(Kg::difficulty(), SIGNAL(currentLevelChanged(const KgDifficultyLevel*)), SLOT(newGame()));
133
134 setupGUI(qApp->desktop()->availableGeometry().size()*0.4);
135}
136
137void KMinesMainWindow::onMinesCountChanged(int count)
138{
139 statusBar()->changeItem( i18n("Mines: %1/%2", count, m_scene->totalMines()), 0 );
140}
141
142void KMinesMainWindow::newGame()
143{
144 m_gameClock->restart();
145 m_gameClock->pause(); // start only with the 1st click
146
147 // some things to manage pause
148 if( m_actionPause->isChecked() )
149 {
150 m_scene->setGamePaused(false);
151 m_actionPause->setChecked(false);
152 }
153 m_actionPause->setEnabled(false);
154
155 Kg::difficulty()->setGameRunning(false);
156 switch(Kg::difficultyLevel())
157 {
158 case KgDifficultyLevel::Easy:
159 m_scene->startNewGame(9, 9, 10);
160 break;
161 case KgDifficultyLevel::Medium:
162 m_scene->startNewGame(16,16,40);
163 break;
164 case KgDifficultyLevel::Hard:
165 m_scene->startNewGame(16,30,99);
166 break;
167 case KgDifficultyLevel::Custom:
168 m_scene->startNewGame(Settings::customHeight(),
169 Settings::customWidth(),
170 Settings::customMines());
171 default:
172 //unsupported
173 break;
174 }
175 statusBar()->changeItem( i18n("Time: 00:00"), 1);
176}
177
178void KMinesMainWindow::onGameOver(bool won)
179{
180 m_gameClock->pause();
181 m_actionPause->setEnabled(false);
182 Kg::difficulty()->setGameRunning(false);
183 if(won)
184 {
185 QPointer<KScoreDialog> scoreDialog = new KScoreDialog(KScoreDialog::Name | KScoreDialog::Time, this);
186 scoreDialog->initFromDifficulty(Kg::difficulty());
187 scoreDialog->hideField(KScoreDialog::Score);
188
189 KScoreDialog::FieldInfo scoreInfo;
190 // score-in-seconds will be hidden
191 scoreInfo[KScoreDialog::Score].setNum(m_gameClock->seconds());
192 //score-as-time will be shown
193 scoreInfo[KScoreDialog::Time] = m_gameClock->timeString();
194
195 // we keep highscores as number of seconds
196 if( scoreDialog->addScore(scoreInfo, KScoreDialog::LessIsMore) != 0 )
197 scoreDialog->exec();
198
199 delete scoreDialog;
200 }
201}
202
203void KMinesMainWindow::advanceTime(const QString& timeStr)
204{
205 statusBar()->changeItem( i18n("Time: %1", timeStr), 1 );
206}
207
208void KMinesMainWindow::onFirstClick()
209{
210 // enable pause action
211 m_actionPause->setEnabled(true);
212 // start clock
213 m_gameClock->resume();
214 Kg::difficulty()->setGameRunning(true);
215}
216
217void KMinesMainWindow::showHighscores()
218{
219 QPointer<KScoreDialog> scoreDialog = new KScoreDialog(KScoreDialog::Name | KScoreDialog::Time, this);
220 scoreDialog->initFromDifficulty(Kg::difficulty());
221 scoreDialog->hideField(KScoreDialog::Score);
222 scoreDialog->exec();
223 delete scoreDialog;
224}
225
226void KMinesMainWindow::configureSettings()
227{
228 if ( KConfigDialog::showDialog( QLatin1String( "settings" ) ) )
229 return;
230 KConfigDialog *dialog = new KConfigDialog( this, QLatin1String( "settings" ), Settings::self() );
231 dialog->addPage( new GeneralOptsConfig( dialog ), i18n("General"), QLatin1String( "games-config-options" ));
232 dialog->addPage( new KgThemeSelector( m_scene->renderer().themeProvider() ), i18n( "Theme" ), QLatin1String( "games-config-theme" ));
233 dialog->addPage( new CustomGameConfig( dialog ), i18n("Custom Game"), QLatin1String( "games-config-custom" ));
234 connect( m_scene->renderer().themeProvider(), SIGNAL(currentThemeChanged(const KgTheme*)), SLOT(loadSettings()) );
235 connect( dialog, SIGNAL(settingsChanged(QString)), this, SLOT(loadSettings()) );
236 dialog->setHelp(QString(),QLatin1String( "kmines" ));
237 dialog->show();
238}
239
240void KMinesMainWindow::pauseGame(bool paused)
241{
242 m_scene->setGamePaused( paused );
243 if( paused )
244 m_gameClock->pause();
245 else
246 m_gameClock->resume();
247}
248
249void KMinesMainWindow::loadSettings()
250{
251 m_view->resetCachedContent();
252 // trigger complete redraw
253 m_scene->resizeScene( (int)m_scene->sceneRect().width(),
254 (int)m_scene->sceneRect().height() );
255}
256
257#include "mainwindow.moc"
258#include "moc_mainwindow.cpp"
259