src/platform/qt/Window.cpp (view raw)
1#include "Window.h"
2
3#include <QFileDialog>
4#include <QKeyEvent>
5#include <QKeySequence>
6#include <QMenuBar>
7
8#include "GameController.h"
9#include "GDBWindow.h"
10#include "GDBController.h"
11
12using namespace QGBA;
13
14Window::Window(QWidget* parent)
15 : QMainWindow(parent)
16#ifdef USE_GDB_STUB
17 , m_gdbController(nullptr)
18#endif
19{
20 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
21 setMinimumSize(240, 160);
22
23 m_controller = new GameController(this);
24 m_display = new Display();
25 setCentralWidget(m_display);
26 connect(m_controller, SIGNAL(gameStarted(GBAThread*)), this, SLOT(gameStarted(GBAThread*)));
27 connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_display, SLOT(stopDrawing()));
28 connect(m_controller, SIGNAL(gameStopped(GBAThread*)), this, SLOT(gameStopped()));
29 connect(this, SIGNAL(startDrawing(const uint32_t*, GBAThread*)), m_display, SLOT(startDrawing(const uint32_t*, GBAThread*)), Qt::QueuedConnection);
30 connect(this, SIGNAL(shutdown()), m_display, SLOT(stopDrawing()));
31 connect(this, SIGNAL(audioBufferSamplesChanged(int)), m_controller, SLOT(setAudioBufferSamples(int)));
32 connect(this, SIGNAL(fpsTargetChanged(float)), m_controller, SLOT(setFPSTarget(float)));
33
34 setupMenu(menuBar());
35}
36
37GBAKey Window::mapKey(int qtKey) {
38 switch (qtKey) {
39 case Qt::Key_Z:
40 return GBA_KEY_A;
41 break;
42 case Qt::Key_X:
43 return GBA_KEY_B;
44 break;
45 case Qt::Key_A:
46 return GBA_KEY_L;
47 break;
48 case Qt::Key_S:
49 return GBA_KEY_R;
50 break;
51 case Qt::Key_Return:
52 return GBA_KEY_START;
53 break;
54 case Qt::Key_Backspace:
55 return GBA_KEY_SELECT;
56 break;
57 case Qt::Key_Up:
58 return GBA_KEY_UP;
59 break;
60 case Qt::Key_Down:
61 return GBA_KEY_DOWN;
62 break;
63 case Qt::Key_Left:
64 return GBA_KEY_LEFT;
65 break;
66 case Qt::Key_Right:
67 return GBA_KEY_RIGHT;
68 break;
69 default:
70 return GBA_KEY_NONE;
71 }
72}
73
74void Window::selectROM() {
75 QString filename = QFileDialog::getOpenFileName(this, tr("Select ROM"));
76 if (!filename.isEmpty()) {
77 m_controller->loadGame(filename);
78 }
79}
80
81#ifdef USE_GDB_STUB
82void Window::gdbOpen() {
83 if (!m_gdbController) {
84 m_gdbController = new GDBController(m_controller, this);
85 }
86 GDBWindow* window = new GDBWindow(m_gdbController);
87 window->show();
88}
89#endif
90
91void Window::keyPressEvent(QKeyEvent* event) {
92 if (event->isAutoRepeat()) {
93 QWidget::keyPressEvent(event);
94 return;
95 }
96 GBAKey key = mapKey(event->key());
97 if (key == GBA_KEY_NONE) {
98 QWidget::keyPressEvent(event);
99 return;
100 }
101 m_controller->keyPressed(key);
102 event->accept();
103}
104
105void Window::keyReleaseEvent(QKeyEvent* event) {
106 if (event->isAutoRepeat()) {
107 QWidget::keyReleaseEvent(event);
108 return;
109 }
110 GBAKey key = mapKey(event->key());
111 if (key == GBA_KEY_NONE) {
112 QWidget::keyPressEvent(event);
113 return;
114 }
115 m_controller->keyReleased(key);
116 event->accept();
117}
118
119void Window::closeEvent(QCloseEvent* event) {
120 emit shutdown();
121 QMainWindow::closeEvent(event);
122}
123
124void Window::gameStarted(GBAThread* context) {
125 emit startDrawing(m_controller->drawContext(), context);
126 foreach (QAction* action, m_gameActions) {
127 action->setDisabled(false);
128 }
129}
130
131void Window::gameStopped() {
132 foreach (QAction* action, m_gameActions) {
133 action->setDisabled(true);
134 }
135}
136
137void Window::setupMenu(QMenuBar* menubar) {
138 menubar->clear();
139 QMenu* fileMenu = menubar->addMenu(tr("&File"));
140 fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open);
141
142 QMenu* emulationMenu = menubar->addMenu(tr("&Emulation"));
143 QAction* reset = new QAction(tr("&Reset"), nullptr);
144 reset->setShortcut(tr("Ctrl+R"));
145 connect(reset, SIGNAL(triggered()), m_controller, SLOT(reset()));
146 m_gameActions.append(reset);
147 emulationMenu->addAction(reset);
148
149 QAction* shutdown = new QAction(tr("Sh&utdown"), nullptr);
150 connect(shutdown, SIGNAL(triggered()), m_controller, SLOT(closeGame()));
151 m_gameActions.append(shutdown);
152 emulationMenu->addAction(shutdown);
153 emulationMenu->addSeparator();
154
155 QAction* pause = new QAction(tr("&Pause"), nullptr);
156 pause->setChecked(false);
157 pause->setCheckable(true);
158 pause->setShortcut(tr("Ctrl+P"));
159 connect(pause, SIGNAL(triggered(bool)), m_controller, SLOT(setPaused(bool)));
160 connect(m_controller, &GameController::gamePaused, [pause]() { pause->setChecked(true); });
161 connect(m_controller, &GameController::gameUnpaused, [pause]() { pause->setChecked(false); });
162 m_gameActions.append(pause);
163 emulationMenu->addAction(pause);
164
165 QAction* frameAdvance = new QAction(tr("&Next frame"), nullptr);
166 frameAdvance->setShortcut(tr("Ctrl+N"));
167 connect(frameAdvance, SIGNAL(triggered()), m_controller, SLOT(frameAdvance()));
168 m_gameActions.append(frameAdvance);
169 emulationMenu->addAction(frameAdvance);
170
171 QMenu* target = emulationMenu->addMenu("FPS target");
172 QAction* setTarget = new QAction(tr("15"), nullptr);
173 connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(15); });
174 target->addAction(setTarget);
175 setTarget = new QAction(tr("30"), nullptr);
176 connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(30); });
177 target->addAction(setTarget);
178 setTarget = new QAction(tr("45"), nullptr);
179 connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(45); });
180 target->addAction(setTarget);
181 setTarget = new QAction(tr("60"), nullptr);
182 connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(60); });
183 target->addAction(setTarget);
184 setTarget = new QAction(tr("90"), nullptr);
185 connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(90); });
186 target->addAction(setTarget);
187 setTarget = new QAction(tr("120"), nullptr);
188 connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(120); });
189 target->addAction(setTarget);
190 setTarget = new QAction(tr("240"), nullptr);
191 connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(240); });
192 target->addAction(setTarget);
193
194 QMenu* videoMenu = menubar->addMenu(tr("&Video"));
195 QMenu* frameMenu = videoMenu->addMenu(tr("Frame &size"));
196 QAction* setSize = new QAction(tr("1x"), nullptr);
197 connect(setSize, &QAction::triggered, [this]() {
198 showNormal();
199 resize(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
200 });
201 frameMenu->addAction(setSize);
202 setSize = new QAction(tr("2x"), nullptr);
203 connect(setSize, &QAction::triggered, [this]() {
204 showNormal();
205 resize(VIDEO_HORIZONTAL_PIXELS * 2, VIDEO_VERTICAL_PIXELS * 2);
206 });
207 frameMenu->addAction(setSize);
208 setSize = new QAction(tr("3x"), nullptr);
209 connect(setSize, &QAction::triggered, [this]() {
210 showNormal();
211 resize(VIDEO_HORIZONTAL_PIXELS * 3, VIDEO_VERTICAL_PIXELS * 3);
212 });
213 frameMenu->addAction(setSize);
214 setSize = new QAction(tr("4x"), nullptr);
215 connect(setSize, &QAction::triggered, [this]() {
216 showNormal();
217 resize(VIDEO_HORIZONTAL_PIXELS * 4, VIDEO_VERTICAL_PIXELS * 4);
218 });
219 frameMenu->addAction(setSize);
220 frameMenu->addAction(tr("Fullscreen"), this, SLOT(showFullScreen()), QKeySequence("Ctrl+F"));
221
222 QMenu* soundMenu = menubar->addMenu(tr("&Sound"));
223 QMenu* buffersMenu = soundMenu->addMenu(tr("Buffer &size"));
224 QAction* setBuffer = new QAction(tr("512"), nullptr);
225 connect(setBuffer, &QAction::triggered, [this]() { emit audioBufferSamplesChanged(512); });
226 buffersMenu->addAction(setBuffer);
227 setBuffer = new QAction(tr("1024"), nullptr);
228 connect(setBuffer, &QAction::triggered, [this]() { emit audioBufferSamplesChanged(1024); });
229 buffersMenu->addAction(setBuffer);
230 setBuffer = new QAction(tr("2048"), nullptr);
231 connect(setBuffer, &QAction::triggered, [this]() { emit audioBufferSamplesChanged(2048); });
232 buffersMenu->addAction(setBuffer);
233
234 QMenu* debuggingMenu = menubar->addMenu(tr("&Debugging"));
235#ifdef USE_GDB_STUB
236 QAction* gdbWindow = new QAction(tr("Start &GDB server..."), nullptr);
237 connect(gdbWindow, SIGNAL(triggered()), this, SLOT(gdbOpen()));
238 debuggingMenu->addAction(gdbWindow);
239#endif
240
241 foreach (QAction* action, m_gameActions) {
242 action->setDisabled(true);
243 }
244}