mainwindow.cpp 10.4 KB
Newer Older
1
/*
Laurent Montel's avatar
Laurent Montel committed
2 3 4
    Copyright 2004-2005 Andi Peredri <andi@ukr.net>
    Copyright 2007 Simon Hürlimann <simon.huerlimann@huerlisi.ch>
    Copyright 2007-2008 Fela Winkelmolen <fela.kde@gmail.com>
Ashwin Rajeev's avatar
Ashwin Rajeev committed
5
    Copyright 2013 Ashwin Rajeev<ashwin_rajeev@hotmail.com>
Laurent Montel's avatar
Laurent Montel committed
6

7 8 9 10
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.
Laurent Montel's avatar
Laurent Montel committed
11

12 13 14 15
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
Laurent Montel's avatar
Laurent Montel committed
16

17 18 19
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
Thomas Nagy's avatar
Thomas Nagy committed
20

21 22
#include "mainwindow.h"

23
#include <KConfigDialog>
24
#include <KLocalizedString>
Cédric Borgese's avatar
Cédric Borgese committed
25
#include <KStandardAction>
26
#include <QAction>
27
#include <KToggleAction>
Cédric Borgese's avatar
Cédric Borgese committed
28 29
#include <KActionCollection>
#include <KStandardGameAction>
30
#include <KMessageBox>
31
#include <QStatusBar>
32

33
#include <KgDifficulty>
Stefan Majewsky's avatar
Stefan Majewsky committed
34 35
#include <KgThemeSelector>
#include <KGameRenderer>
36
#include <KScoreDialog>
37
#include <KGameClock>
Ashwin Rajeev's avatar
Ashwin Rajeev committed
38
#include <KgSound>
39

40 41
#include <ctime>
#include <cmath>
42

43
#include "ui_general.h"
Ashwin Rajeev's avatar
Ashwin Rajeev committed
44 45
#include "ui_customgame.h"

46
#include "globals.h"
Ashwin Rajeev's avatar
Ashwin Rajeev committed
47
#include "gameview.h"
Thomas Nagy's avatar
Thomas Nagy committed
48
#include "settings.h"
49
#include "abstractgrid.h"
Thomas Nagy's avatar
Thomas Nagy committed
50

51 52 53 54 55 56 57 58 59 60 61 62
class GeneralConfig : public QWidget
{
public:
    GeneralConfig(QWidget *parent)
        : QWidget(parent)
    {
        ui.setupUi(this);
    }
private:
    Ui::GeneralConfig ui;
};

Ashwin Rajeev's avatar
Ashwin Rajeev committed
63 64 65 66 67 68 69 70 71 72 73 74
class CustomGameConfig : public QWidget
{
public:
    CustomGameConfig(QWidget *parent)
        : QWidget(parent)
    {
        ui.setupUi(this);
    }
private:
    Ui::CustomGameConfig ui;
};

75
MainWindow::MainWindow(QWidget *parent)
Ashwin Rajeev's avatar
Ashwin Rajeev committed
76 77
    : KXmlGuiWindow(parent), m_clickCount(0),
      m_view(new GameView(this))
Thomas Nagy's avatar
Thomas Nagy committed
78
{
Laurent Montel's avatar
Laurent Montel committed
79 80
    connect(m_view, &GameView::gameOver, this, &MainWindow::gameOver);
    connect(m_view, &GameView::rotationStarted, this, &MainWindow::rotationStarted);
Ashwin Rajeev's avatar
Ashwin Rajeev committed
81
    connect(this, SIGNAL(pause(QVariant)), m_view->rootObject(), SLOT(pause(QVariant)));
82

Albert Astals Cid's avatar
Albert Astals Cid committed
83 84 85 86 87 88 89
    m_movesLabel = new QLabel(this);
    m_movesLabel->setAlignment(Qt::AlignCenter);
    m_timeLabel = new QLabel(this);
    m_timeLabel->setAlignment(Qt::AlignCenter);

    statusBar()->insertPermanentWidget(0, m_movesLabel, 1);
    statusBar()->insertPermanentWidget(1, m_timeLabel, 1);
90 91

    // Difficulty
92 93 94
    Kg::difficulty()->addStandardLevelRange(
        KgDifficultyLevel::Easy, KgDifficultyLevel::VeryHard
    );
Ashwin Rajeev's avatar
Ashwin Rajeev committed
95 96 97
    Kg::difficulty()->addLevel(
                new KgDifficultyLevel(100, QByteArray("Custom"), i18n("Custom"))
    );
98
    KgDifficultyGUI::init(this);
99
    connect(Kg::difficulty(), &KgDifficulty::currentLevelChanged, this, &MainWindow::startNewGame);
100

Ashwin Rajeev's avatar
Ashwin Rajeev committed
101 102

    setCentralWidget(m_view);
Stefan Majewsky's avatar
Stefan Majewsky committed
103

104
    setupActions();
Laurent Montel's avatar
Laurent Montel committed
105

Parker Coates's avatar
Parker Coates committed
106 107
    setupGUI();

108 109
    setAutoSaveSettings();

110
    m_gameClock = new KGameClock(this, KGameClock::MinSecOnly);
Laurent Montel's avatar
Laurent Montel committed
111
    connect(m_gameClock, &KGameClock::timeChanged, this, &MainWindow::updateStatusBar);
112

113 114
    m_soundStart = new KgSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/start.wav")), this);
    m_soundWin = new KgSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/win.wav")), this);
115

Ashwin Rajeev's avatar
Ashwin Rajeev committed
116

117
    startNewGame();
118 119
}

120 121
void MainWindow::setupActions()
{
122
    // Game
Laurent Montel's avatar
Laurent Montel committed
123
    KStandardGameAction::gameNew(this, SLOT(startNewGame()),
124
                                 actionCollection());
125 126 127

    m_pauseAction = KStandardGameAction::pause(this, SLOT(pauseGame(bool)),
                                               actionCollection());
128 129
    connect(Kg::difficulty(), &KgDifficulty::gameRunningChanged, m_pauseAction,
            &QAction::setEnabled);
Laurent Montel's avatar
Laurent Montel committed
130

131
    QAction *action = KStandardGameAction::solve(m_view, SLOT(solve()), actionCollection());
132
    connect(Kg::difficulty(), &KgDifficulty::gameRunningChanged, action, &QAction::setEnabled);
Ashwin Rajeev's avatar
Ashwin Rajeev committed
133

Laurent Montel's avatar
Laurent Montel committed
134
    KStandardGameAction::highscores(this, SLOT(showHighscores()),
135
                                    actionCollection());
Laurent Montel's avatar
Laurent Montel committed
136

137
    KStandardGameAction::quit(this, SLOT(close()), actionCollection());
Laurent Montel's avatar
Laurent Montel committed
138

139
    // Settings
Ashwin Rajeev's avatar
Ashwin Rajeev committed
140
    KStandardAction::preferences(this, SLOT(configureSettings()), actionCollection());
141

142
    action = new QAction(i18n("&Unlock All"), this);
Ashwin Rajeev's avatar
Ashwin Rajeev committed
143
    connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(unlockAll()));
144 145
    connect(Kg::difficulty(), &KgDifficulty::gameRunningChanged, action, &QAction::setEnabled);
    actionCollection()->addAction( QStringLiteral( "unlock_all" ), action);
Ashwin Rajeev's avatar
Ashwin Rajeev committed
146

147
    action = new QAction(i18n("Keyboard: Field right"), this);
Laurent Montel's avatar
Laurent Montel committed
148
    actionCollection()->setDefaultShortcut(action, Qt::Key_Right);
Ashwin Rajeev's avatar
Ashwin Rajeev committed
149
    connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(kbGoRight()));
150
    actionCollection()->addAction( QStringLiteral( "kb_go_right" ), action);
151

152
    action = new QAction(i18n("Keyboard: Field left"),this);
Laurent Montel's avatar
Laurent Montel committed
153
    actionCollection()->setDefaultShortcut(action, Qt::Key_Left);
Ashwin Rajeev's avatar
Ashwin Rajeev committed
154
    connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(kbGoLeft()));
155
    actionCollection()->addAction( QStringLiteral( "kb_go_left" ), action);
156

157
    action = new QAction(i18n("Keyboard: Field up"),this);
Laurent Montel's avatar
Laurent Montel committed
158
    actionCollection()->setDefaultShortcut(action, Qt::Key_Up);
Ashwin Rajeev's avatar
Ashwin Rajeev committed
159
    connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(kbGoUp()));
160
    actionCollection()->addAction( QStringLiteral( "kb_go_up" ), action);
161

162
    action = new QAction(i18n("Keyboard: Field down"),this);
Laurent Montel's avatar
Laurent Montel committed
163
    actionCollection()->setDefaultShortcut(action, Qt::Key_Down);
Ashwin Rajeev's avatar
Ashwin Rajeev committed
164
    connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(kbGoDown()));
165
    actionCollection()->addAction( QStringLiteral( "kb_go_down" ), action);
166

167
    action = new QAction(i18n("Keyboard: Turn clockwise"),this);
Laurent Montel's avatar
Laurent Montel committed
168
    actionCollection()->setDefaultShortcut(action, Qt::Key_Return);
Ashwin Rajeev's avatar
Ashwin Rajeev committed
169
    connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(rotateClockwise()));
170
    actionCollection()->addAction( QStringLiteral( "kb_turn_clockwise" ), action);
171

172
    action = new QAction(i18n("Keyboard: Turn counterclockwise"),this);
173
    actionCollection()->setDefaultShortcut(action, Qt::CTRL | Qt::Key_Return);
Ashwin Rajeev's avatar
Ashwin Rajeev committed
174
    connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(rotateCounterclockwise()));
175
    actionCollection()->addAction( QStringLiteral( "kb_turn_counterclockwise" ), action);
176

177
    action = new QAction(i18n("Keyboard: Toggle lock"),this);
Laurent Montel's avatar
Laurent Montel committed
178
    actionCollection()->setDefaultShortcut(action, Qt::Key_Space);
Ashwin Rajeev's avatar
Ashwin Rajeev committed
179
    connect(action, SIGNAL(triggered()), m_view->rootObject(), SLOT(toggleLock()));
180
    actionCollection()->addAction( QStringLiteral( "kb_lock" ), action);
181 182
}

Ashwin Rajeev's avatar
Ashwin Rajeev committed
183 184
void MainWindow::configureSettings()
{
185
    if (KConfigDialog::showDialog(QStringLiteral("settings")))
Ashwin Rajeev's avatar
Ashwin Rajeev committed
186
        return;
187 188 189 190
    KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("settings"), Settings::self());
    dialog->addPage(new GeneralConfig(dialog), i18n("General"), QStringLiteral("games-config-options"));
    dialog->addPage(new KgThemeSelector(m_view->getProvider()), i18n("Theme"), QStringLiteral("games-config-theme"));
    dialog->addPage(new CustomGameConfig(dialog), i18n("Custom Game"), QStringLiteral("games-config-custom"));
191
    connect(dialog, &KConfigDialog::settingsChanged, m_view, &GameView::updateSettings);
192
//    dialog->setHelp(QString(),QLatin1String("knetwalk"));
Ashwin Rajeev's avatar
Ashwin Rajeev committed
193 194 195
    dialog->show();
}

Laurent Montel's avatar
Laurent Montel committed
196
void MainWindow::showHighscores()
197
{
198
    KScoreDialog scoreDialog(KScoreDialog::Name | KScoreDialog::Time, this);
199
    scoreDialog.addField(KScoreDialog::Custom1, i18n("Moves Penalty"), QStringLiteral( "moves" ));
200
    scoreDialog.initFromDifficulty(Kg::difficulty());
201
    scoreDialog.exec();
Thomas Nagy's avatar
Thomas Nagy committed
202 203
}

Fela Winkelmolen's avatar
Fela Winkelmolen committed
204
void MainWindow::startNewGame()
Thomas Nagy's avatar
Thomas Nagy committed
205
{
Ashwin Rajeev's avatar
Ashwin Rajeev committed
206 207
    if(Settings::playSounds())
        m_soundStart->start();
208

209
    const KgDifficultyLevel::StandardLevel l = Kg::difficultyLevel();
Laurent Montel's avatar
Laurent Montel committed
210

Ashwin Rajeev's avatar
Ashwin Rajeev committed
211 212 213
    bool isWrapped = (l == KgDifficultyLevel::VeryHard);
    if (Kg::difficultyLevel() == KgDifficultyLevel::Custom)
        isWrapped = Settings::wrapping();
214 215
    const QSize size = boardSize();
    m_view->startNewGame(size.width(), size.height(), (Wrapping)isWrapped);
Ashwin Rajeev's avatar
Ashwin Rajeev committed
216
    m_clickCount = -m_view->minimumMoves();
217 218 219 220 221
    m_gameClock->restart();

    if(m_pauseAction->isChecked())
    {
        m_pauseAction->setChecked(false);
222
    }
223
    Kg::difficulty()->setGameRunning(true);
Thomas Nagy's avatar
Thomas Nagy committed
224

225
    updateStatusBar();
226 227
}

Laurent Montel's avatar
Laurent Montel committed
228
void MainWindow::gameOver(const QVariant &msg)
Thomas Nagy's avatar
Thomas Nagy committed
229
{
230
    m_gameClock->pause();
231
    Kg::difficulty()->setGameRunning(false);
232

233
    if (msg.toString() != QLatin1String("won"))
Ashwin Rajeev's avatar
Ashwin Rajeev committed
234 235 236 237 238
        return;

    if(Settings::playSounds())
        m_soundWin->start();

239
    //=== calculate the score ====//
240 241

    double penalty = m_gameClock->seconds() / 2.0 * (m_clickCount/2 + 1);
Laurent Montel's avatar
Laurent Montel committed
242

243
    // normalize the penalty
Ashwin Rajeev's avatar
Ashwin Rajeev committed
244
    penalty = std::sqrt(penalty/m_view->cellCount());
Laurent Montel's avatar
Laurent Montel committed
245

246
    int score = static_cast<int>(100.0 / penalty);
Laurent Montel's avatar
Laurent Montel committed
247

248
    // create the new scoreInfo
249 250
    KScoreDialog::FieldInfo scoreInfo;
    scoreInfo[KScoreDialog::Score].setNum(score);
251 252
    scoreInfo[KScoreDialog::Custom1].setNum(m_clickCount/2);
    scoreInfo[KScoreDialog::Time] = m_gameClock->timeString();
Laurent Montel's avatar
Laurent Montel committed
253

254 255
    // show the new dialog and add the new score to it
    KScoreDialog scoreDialog(KScoreDialog::Name | KScoreDialog::Time, this);
256
    scoreDialog.addField(KScoreDialog::Custom1, i18n("Moves Penalty"), QStringLiteral( "moves" ));
257
    scoreDialog.initFromDifficulty(Kg::difficulty());
258
    bool madeIt = scoreDialog.addScore(scoreInfo);
259
    if (!madeIt) {
260
        QString comment = i18np("Your score was %1, you did not make it to the high score list.",
261
                                "Your score was %1, you did not make it to the high score list.", score);
262 263
        scoreDialog.setComment(comment);
    }
264
    scoreDialog.exec();
Thomas Nagy's avatar
Thomas Nagy committed
265 266
}

267
void MainWindow::rotationStarted()
Fela Winkelmolen's avatar
Fela Winkelmolen committed
268
{
269 270
    m_clickCount++;
    updateStatusBar();
Fela Winkelmolen's avatar
Fela Winkelmolen committed
271 272
}

273
void MainWindow::pauseGame(bool paused)
274
{
Ashwin Rajeev's avatar
Ashwin Rajeev committed
275
    pause(paused);
276 277 278 279 280
    if(paused) {
        m_gameClock->pause();
    } else {
        m_gameClock->resume();
    }
281 282
}

283
void MainWindow::updateStatusBar()
Thomas Nagy's avatar
Thomas Nagy committed
284
{
285 286
    QString moves = i18nc("Number of mouse clicks", "Moves: %1", m_clickCount);
    QString time = i18nc("Time elapsed", "Time: %1", m_gameClock->timeString());
Albert Astals Cid's avatar
Albert Astals Cid committed
287 288
    m_movesLabel->setText(moves);
    m_timeLabel->setText(time);
Thomas Nagy's avatar
Thomas Nagy committed
289 290
}

291
QSize MainWindow::boardSize()
292
{
293
    switch (Kg::difficultyLevel()) {
294 295 296 297 298
    case KgDifficultyLevel::Easy: return QSize(5, 5);
    case KgDifficultyLevel::Medium: return QSize(7, 7);
    case KgDifficultyLevel::Hard: return QSize(9, 9);
    case KgDifficultyLevel::Custom: return QSize(Settings::width(), Settings::height());
    default: return QSize(9, 9);
299
    }
300 301
}