1 /***********************************************************************
2 *
3 * Copyright (C) 2008, 2010, 2012, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Graeme Gott <graeme@gottcode.org>
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 3 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, see <http://www.gnu.org/licenses/>.
17 *
18 ***********************************************************************/
19
20 #include "window.h"
21
22 #include "board.h"
23 #include "locale_dialog.h"
24 #include "score_board.h"
25
26 #include <QAction>
27 #include <QApplication>
28 #include <QCloseEvent>
29 #include <QGridLayout>
30 #include <QLabel>
31 #include <QMenu>
32 #include <QMenuBar>
33 #include <QMessageBox>
34 #include <QPixmap>
35 #include <QSettings>
36
37 /*****************************************************************************/
38
Window(QWidget * parent,Qt::WindowFlags wf)39 Window::Window(QWidget *parent, Qt::WindowFlags wf)
40 : QMainWindow(parent, wf)
41 {
42 QWidget* contents = new QWidget(this);
43 setCentralWidget(contents);
44
45 // Create preview
46 m_preview = new QLabel(contents);
47 m_preview->setFixedSize(80, 100);
48 m_preview->setAutoFillBackground(true);
49 {
50 QPalette palette = m_preview->palette();
51 palette.setColor(m_preview->backgroundRole(), Qt::black);
52 m_preview->setPalette(palette);
53 }
54
55 // Create level display
56 m_level = new QLabel("0", contents);
57 m_level->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
58 m_level->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
59 m_level->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
60
61 // Create lines display
62 m_lines = new QLabel("0", contents);
63 m_lines->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
64 m_lines->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
65 m_lines->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
66
67 // Create score display
68 m_score = new QLabel("0", contents);
69 m_score->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
70 m_score->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
71 m_score->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
72
73 // Create scoreboard
74 m_score_board = new ScoreBoard(this);
75
76 // Create board
77 m_board = new Board(contents);
78 connect(m_board, &Board::pauseAvailable, this, &Window::pauseAvailable);
79 connect(m_board, &Board::nextPieceAvailable, m_preview, &QLabel::setPixmap);
80 connect(m_board, &Board::levelUpdated, m_level, static_cast<void (QLabel::*)(int)>(&QLabel::setNum));
81 connect(m_board, &Board::linesRemovedUpdated, m_lines, static_cast<void (QLabel::*)(int)>(&QLabel::setNum));
82 connect(m_board, &Board::scoreUpdated, this, &Window::scoreUpdated);
83 connect(m_board, static_cast<void (Board::*)(int,int,int)>(&Board::gameOver), m_score_board, &ScoreBoard::addHighScore);
84 connect(m_board, static_cast<void (Board::*)(int,int,int)>(&Board::gameOver), this, &Window::gameOver);
85 connect(m_board, &Board::gameStarted, this, &Window::newGame);
86
87 // Create overlay message
88 QLabel* message = new QLabel(tr("Click to start a new game."), contents);
89 message->setAttribute(Qt::WA_TransparentForMouseEvents);
90 message->setAlignment(Qt::AlignCenter);
91 message->setStyleSheet(
92 "QLabel {"
93 "background-color: rgba(255, 255, 255, 200);"
94 "color: black;"
95 "margin: 0;"
96 "padding: 0.5em;"
97 "border-radius: 0.5em;"
98 "}");
99 message->setWordWrap(true);
100 connect(m_board, &Board::showMessage, message, &QLabel::show);
101 connect(m_board, &Board::showMessage, message, &QLabel::setText);
102 connect(m_board, &Board::hideMessage, message, &QLabel::hide);
103 connect(m_board, &Board::hideMessage, message, &QLabel::clear);
104
105 // Create menus
106 QMenu* menu = menuBar()->addMenu(tr("&Game"));
107 menu->addAction(tr("&New"), m_board, SLOT(newGame()), QKeySequence::New);
108 m_pause_action = menu->addAction(tr("&Pause"), m_board, SLOT(pauseGame()), tr("P"));
109 m_pause_action->setEnabled(false);
110 m_resume_action = menu->addAction(tr("&Resume"), m_board, SLOT(resumeGame()), tr("P"));
111 m_resume_action->setVisible(false);
112 menu->addSeparator();
113 menu->addAction(tr("&Scores"), m_score_board, SLOT(show()));
114 menu->addSeparator();
115 QAction* action = menu->addAction(tr("&Quit"), this, SLOT(close()), QKeySequence::Quit);
116 action->setMenuRole(QAction::QuitRole);
117
118 menu = menuBar()->addMenu(tr("&Settings"));
119 menu->addAction(tr("Application &Language..."), this, SLOT(setLocale()));
120
121 menu = menuBar()->addMenu(tr("&Help"));
122 action = menu->addAction(tr("&About"), this, SLOT(about()));
123 action->setMenuRole(QAction::AboutRole);
124 action = menu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt()));
125 action->setMenuRole(QAction::AboutQtRole);
126
127 // Layout window
128 QGridLayout* layout = new QGridLayout(contents);
129 layout->setContentsMargins(12, 12, 12, 12);
130 layout->setSpacing(0);
131 layout->setColumnStretch(0, 1);
132 layout->setColumnMinimumWidth(1, 12);
133 layout->setRowStretch(11, 1);
134 layout->setRowMinimumHeight(2, 24);
135 layout->setRowMinimumHeight(5, 24);
136 layout->setRowMinimumHeight(8, 24);
137 layout->addWidget(m_board, 0, 0, 12, 1);
138 layout->addWidget(message, 0, 0, 12, 1, Qt::AlignCenter);
139 layout->addWidget(new QLabel(tr("Next Piece"), contents), 0, 2, 1, 1, Qt::AlignCenter);
140 layout->addWidget(m_preview, 1, 2, Qt::AlignCenter);
141 layout->addWidget(new QLabel(tr("Level"), contents), 3, 2, 1, 1, Qt::AlignCenter);
142 layout->addWidget(m_level, 4, 2);
143 layout->addWidget(new QLabel(tr("Removed Lines"), contents), 6, 2, 1, 1, Qt::AlignCenter);
144 layout->addWidget(m_lines, 7, 2);
145 layout->addWidget(new QLabel(tr("Score"), contents), 9, 2, 1, 1, Qt::AlignCenter);
146 layout->addWidget(m_score, 10, 2);
147
148 // Restore window
149 restoreGeometry(QSettings().value("Geometry").toByteArray());
150 }
151
152 /*****************************************************************************/
153
closeEvent(QCloseEvent * event)154 void Window::closeEvent(QCloseEvent* event)
155 {
156 QSettings().setValue("Geometry", saveGeometry());
157 if (!m_board->endGame()) {
158 event->ignore();
159 }
160 }
161
162 /*****************************************************************************/
163
pauseAvailable(bool available)164 void Window::pauseAvailable(bool available)
165 {
166 static QPixmap preview;
167
168 if (available) {
169 m_pause_action->setVisible(true);
170 m_resume_action->setVisible(false);
171 m_preview->setPixmap(preview);
172 } else {
173 m_resume_action->setVisible(true);
174 m_pause_action->setVisible(false);
175 preview = *m_preview->pixmap();
176 m_preview->clear();
177 }
178 }
179
180 /*****************************************************************************/
181
scoreUpdated(int score)182 void Window::scoreUpdated(int score)
183 {
184 m_score->setText(QString("%L1").arg(score));
185
186 int position = m_score_board->highScorePosition(score);
187 QPalette palette = m_score->palette();
188 if (position == 0) {
189 palette.setColor(m_preview->foregroundRole(), Qt::red);
190 } else if (position < 10) {
191 palette.setColor(m_preview->foregroundRole(), Qt::blue);
192 }
193 m_score->setPalette(palette);
194 }
195
196 /*****************************************************************************/
197
newGame()198 void Window::newGame()
199 {
200 m_pause_action->setEnabled(true);
201
202 QPalette palette = m_score->palette();
203 palette.setColor(m_preview->foregroundRole(), Qt::black);
204 m_score->setPalette(palette);
205 }
206
207 /*****************************************************************************/
208
gameOver()209 void Window::gameOver()
210 {
211 m_pause_action->setEnabled(false);
212 }
213
214 /*****************************************************************************/
215
about()216 void Window::about()
217 {
218 QMessageBox::about(this, tr("About"), QString("<p align='center'><big><b>%1 %2</b></big><br/>%3<br/><small>%4<br/>%5</small></p>")
219 .arg(tr("Gottet"), QApplication::applicationVersion(),
220 tr("A tetris clone I made for my wife"),
221 tr("Copyright © 2008-%1 Graeme Gott.").arg("2020"),
222 tr("Released under the <a href=%1>GPL 3</a> license").arg("\"http://www.gnu.org/licenses/gpl.html\""))
223 );
224 }
225
226 /*****************************************************************************/
227
setLocale()228 void Window::setLocale()
229 {
230 LocaleDialog dialog;
231 dialog.exec();
232 }
233
234 /*****************************************************************************/
235