1 /***********************************************************************
2 *
3 * Copyright (C) 2007, 2008, 2009, 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 "new_game_dialog.h"
25 #include "scores.h"
26 #include "settings.h"
27
28 #include <QAction>
29 #include <QApplication>
30 #include <QDir>
31 #include <QIcon>
32 #include <QList>
33 #include <QMenu>
34 #include <QMenuBar>
35 #include <QMessageBox>
36 #include <QPair>
37 #include <QProcess>
38 #include <QSettings>
39 #include <QString>
40 #include <QTimer>
41 #include <QToolBar>
42 #include <QWheelEvent>
43
44 // ============================================================================
45
fetchIcon(const QString & name)46 static QIcon fetchIcon(const QString& name)
47 {
48 QIcon icon(QString(":/oxygen/64x64/%1.png").arg(name));
49 icon.addFile(QString(":/oxygen/48x48/%1.png").arg(name));
50 icon.addFile(QString(":/oxygen/32x32/%1.png").arg(name));
51 icon.addFile(QString(":/oxygen/22x22/%1.png").arg(name));
52 icon.addFile(QString(":/oxygen/16x16/%1.png").arg(name));
53 return QIcon::fromTheme(name, icon);
54 }
55
56 // ============================================================================
57
Window()58 Window::Window()
59 : m_pause_action(0)
60 {
61 // Create game object
62 m_board = new Board(this);
63 setCentralWidget(m_board);
64 m_board->setFocus();
65
66 // Create scores window
67 m_scores = new Scores(this);
68 connect(m_board, &Board::finished, m_scores, &Scores::addScore);
69
70 // Create actions
71 if (iconSize().width() == 26) {
72 setIconSize(QSize(24, 24));
73 }
74 initActions();
75 m_pause_action->setCheckable(true);
76 connect(m_pause_action, &QAction::toggled, m_board, &Board::pauseGame);
77 connect(m_board, &Board::pauseAvailable, m_pause_action, &QAction::setEnabled);
78 connect(m_board, &Board::pauseChecked, m_pause_action, &QAction::setChecked);
79 connect(m_board, &Board::hintAvailable, m_hint_action, &QAction::setEnabled);
80
81 // Setup window
82 restoreGeometry(QSettings().value("Geometry").toByteArray());
83
84 // Create auto-save timer
85 QTimer *timer = new QTimer(this);
86 connect(timer, &QTimer::timeout, m_board, &Board::saveGame);
87 timer->start(300000);
88 }
89
90 // ============================================================================
91
closeEvent(QCloseEvent * event)92 void Window::closeEvent(QCloseEvent* event)
93 {
94 QSettings().setValue("Geometry", saveGeometry());
95 m_board->saveGame();
96 QMainWindow::closeEvent(event);
97 }
98
99 // ============================================================================
100
event(QEvent * event)101 bool Window::event(QEvent* event)
102 {
103 if ((event->type() == QEvent::WindowBlocked || event->type() == QEvent::WindowDeactivate) && m_pause_action && m_pause_action->isEnabled()) {
104 m_pause_action->setChecked(true);
105 }
106 return QMainWindow::event(event);
107 }
108
109 // ============================================================================
110
wheelEvent(QWheelEvent * event)111 void Window::wheelEvent(QWheelEvent* event)
112 {
113 if (event->angleDelta().y() > 0) {
114 m_board->zoomIn();
115 } else {
116 m_board->zoomOut();
117 }
118 QMainWindow::wheelEvent(event);
119 }
120
121 // ============================================================================
122
initActions()123 void Window::initActions()
124 {
125 // Create menubar
126 #if defined(Q_OS_MAC)
127 qApp->setAttribute(Qt::AA_DontShowIconsInMenus);
128 #endif
129
130 QMenu* game_menu = menuBar()->addMenu(tr("&Game"));
131 QAction* new_action = game_menu->addAction(fetchIcon("document-new"), tr("&New"), this, SLOT(newGame()), QKeySequence::New);
132 m_pause_action = game_menu->addAction(fetchIcon("media-playback-pause"), tr("&Pause"));
133 m_pause_action->setShortcut(tr("P"));
134 m_hint_action = game_menu->addAction(fetchIcon("games-hint"), tr("&Hint"), m_board, SLOT(hint()));
135 game_menu->addSeparator();
136 game_menu->addAction(fetchIcon("games-highscores"), tr("High &Scores"), m_scores, SLOT(exec()));
137 game_menu->addSeparator();
138 QAction* quit_action = game_menu->addAction(fetchIcon("application-exit"), tr("&Quit"), this, SLOT(close()), QKeySequence::Quit);
139 quit_action->setMenuRole(QAction::QuitRole);
140
141 QMenu* view_menu = menuBar()->addMenu(tr("View"));
142 QAction* zoom_in_action = view_menu->addAction(fetchIcon("zoom-in"), tr("Zoom &In"), m_board, SLOT(zoomIn()), tr("Ctrl++"));
143 connect(m_board, &Board::zoomInAvailable, zoom_in_action, &QAction::setEnabled);
144 QAction* zoom_out_action = view_menu->addAction(fetchIcon("zoom-out"), tr("Zoom &Out"), m_board, SLOT(zoomOut()), tr("Ctrl+-"));
145 connect(m_board, &Board::zoomOutAvailable, zoom_out_action, &QAction::setEnabled);
146
147 QMenu* settings_menu = menuBar()->addMenu(tr("&Settings"));
148 settings_menu->addAction(fetchIcon("preferences-desktop-locale"), tr("Application &Language..."), this, SLOT(setLocale()));
149 settings_menu->addAction(fetchIcon("games-config-options"), tr("&Preferences..."), this, SLOT(showSettings()));
150
151 QMenu* help_menu = menuBar()->addMenu(tr("&Help"));
152 QAction* about_action = help_menu->addAction(fetchIcon("help-about"), tr("&About"), this, SLOT(about()));
153 about_action->setMenuRole(QAction::AboutRole);
154 about_action = help_menu->addAction(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), qApp, SLOT(aboutQt()));
155 about_action->setMenuRole(QAction::AboutQtRole);
156
157 // Create toolbar
158 QToolBar* toolbar = new QToolBar(this);
159 toolbar->setFloatable(false);
160 toolbar->setMovable(false);
161 toolbar->setToolButtonStyle(Qt::ToolButtonFollowStyle);
162 toolbar->addAction(new_action);
163 toolbar->addAction(m_pause_action);
164 toolbar->addAction(m_hint_action);
165 toolbar->addSeparator();
166 toolbar->addAction(zoom_in_action);
167 toolbar->addAction(zoom_out_action);
168 addToolBar(toolbar);
169 setContextMenuPolicy(Qt::NoContextMenu);
170 }
171
172 // ============================================================================
173
about()174 void Window::about()
175 {
176 QMessageBox::about(this, tr("About"), QString("<p><center><big><b>%1 %2</b></big><br/>%3<br/><small>%4<br/>%5</small></center></p><p><center>%6<br/><small>%7</small></center></p>")
177 .arg(tr("CuteMaze"), QCoreApplication::applicationVersion(),
178 tr("A top-down maze game"),
179 tr("Copyright © 2007-%1 Graeme Gott").arg("2020"),
180 tr("Released under the <a href=%1>GPL 3</a> license").arg("\"http://www.gnu.org/licenses/gpl.html\""),
181 tr("Icons are from the <a href=%1>Oxygen</a> theme").arg("\"http://www.oxygen-icons.org/\""),
182 tr("Used under the <a href=%1>LGPL 3</a> license").arg("\"http://www.gnu.org/licenses/lgpl.html\""))
183 );
184 }
185
186 // ============================================================================
187
newGame()188 void Window::newGame()
189 {
190 NewGameDialog dialog(this);
191 if (dialog.exec() == QDialog::Accepted) {
192 m_board->newGame();
193 }
194 }
195
196 // ============================================================================
197
showSettings()198 void Window::showSettings()
199 {
200 Settings settings(this);
201 connect(&settings, &Settings::settingsChanged, m_board, &Board::loadSettings);
202 settings.exec();
203 }
204
205 // ============================================================================
206
setLocale()207 void Window::setLocale()
208 {
209 LocaleDialog dialog;
210 dialog.exec();
211 }
212
213 // ============================================================================
214