all repos — mgba @ 6560db2ef58e1a192a2356fd8ae1de65379b838c

mGBA Game Boy Advance Emulator

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}