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}