all repos — mgba @ a57f911eccd740d3dbc5581cd766cee65f43dee1

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 "AudioDevice.h"
  9#include "GameController.h"
 10#include "GDBWindow.h"
 11#include "GDBController.h"
 12
 13using namespace QGBA;
 14
 15Window::Window(QWidget* parent)
 16	: QMainWindow(parent)
 17	, m_audioThread(nullptr)
 18#ifdef USE_GDB_STUB
 19	, m_gdbController(nullptr)
 20#endif
 21{
 22	setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
 23	setMinimumSize(240, 160);
 24
 25	m_controller = new GameController(this);
 26	m_display = new Display();
 27	setCentralWidget(m_display);
 28	connect(m_controller, SIGNAL(gameStarted(GBAThread*)), this, SLOT(gameStarted(GBAThread*)));
 29	connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_display, SLOT(stopDrawing()));
 30	connect(m_controller, SIGNAL(gameStopped(GBAThread*)), this, SLOT(gameStopped()));
 31	connect(this, SIGNAL(startDrawing(const uint32_t*, GBAThread*)), m_display, SLOT(startDrawing(const uint32_t*, GBAThread*)), Qt::QueuedConnection);
 32	connect(this, SIGNAL(shutdown()), m_display, SLOT(stopDrawing()));
 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	if (!m_audioThread) {
130		m_audioThread = new AudioThread(this);
131		connect(this, SIGNAL(shutdown()), m_audioThread, SLOT(shutdown()));
132		m_audioThread->setInput(context);
133		m_audioThread->start(QThread::HighPriority);
134	} else {
135		m_audioThread->resume();
136	}
137}
138
139void Window::gameStopped() {
140	foreach (QAction* action, m_gameActions) {
141		action->setDisabled(true);
142	}
143	m_audioThread->pause();
144}
145
146void Window::setupMenu(QMenuBar* menubar) {
147	menubar->clear();
148	QMenu* fileMenu = menubar->addMenu(tr("&File"));
149	fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open);
150	fileMenu->addAction(tr("Sh&utdown"), m_controller, SLOT(closeGame()));
151
152	QMenu* emulationMenu = menubar->addMenu(tr("&Emulation"));
153	QAction* pause = new QAction(tr("&Pause"), 0);
154	pause->setChecked(false);
155	pause->setCheckable(true);
156	pause->setShortcut(tr("Ctrl+P"));
157	pause->setDisabled(true);
158	connect(pause, SIGNAL(triggered(bool)), m_controller, SLOT(setPaused(bool)));
159	m_gameActions.append(pause);
160	emulationMenu->addAction(pause);
161
162	QAction* frameAdvance = new QAction(tr("&Next frame"), 0);
163	frameAdvance->setShortcut(tr("Ctrl+N"));
164	frameAdvance->setDisabled(true);
165	connect(frameAdvance, SIGNAL(triggered()), m_controller, SLOT(frameAdvance()));
166	m_gameActions.append(frameAdvance);
167	emulationMenu->addAction(frameAdvance);
168
169	QMenu* debuggingMenu = menubar->addMenu(tr("&Debugging"));
170#ifdef USE_GDB_STUB
171	QAction* gdbWindow = new QAction(tr("Start &GDB server..."), nullptr);
172	connect(gdbWindow, SIGNAL(triggered()), this, SLOT(gdbOpen()));
173	debuggingMenu->addAction(gdbWindow);
174#endif
175}