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 "GDBWindow.h"
9#include "GDBController.h"
10
11using namespace QGBA;
12
13Window::Window(QWidget* parent)
14 : QMainWindow(parent)
15 , m_audioThread(nullptr)
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
32 setupMenu(menuBar());
33}
34
35GBAKey Window::mapKey(int qtKey) {
36 switch (qtKey) {
37 case Qt::Key_Z:
38 return GBA_KEY_A;
39 break;
40 case Qt::Key_X:
41 return GBA_KEY_B;
42 break;
43 case Qt::Key_A:
44 return GBA_KEY_L;
45 break;
46 case Qt::Key_S:
47 return GBA_KEY_R;
48 break;
49 case Qt::Key_Return:
50 return GBA_KEY_START;
51 break;
52 case Qt::Key_Backspace:
53 return GBA_KEY_SELECT;
54 break;
55 case Qt::Key_Up:
56 return GBA_KEY_UP;
57 break;
58 case Qt::Key_Down:
59 return GBA_KEY_DOWN;
60 break;
61 case Qt::Key_Left:
62 return GBA_KEY_LEFT;
63 break;
64 case Qt::Key_Right:
65 return GBA_KEY_RIGHT;
66 break;
67 default:
68 return GBA_KEY_NONE;
69 }
70}
71
72void Window::selectROM() {
73 QString filename = QFileDialog::getOpenFileName(this, tr("Select ROM"));
74 if (!filename.isEmpty()) {
75 m_controller->loadGame(filename);
76 }
77}
78
79#ifdef USE_GDB_STUB
80void Window::gdbOpen() {
81 if (!m_gdbController) {
82 m_gdbController = new GDBController(m_controller, this);
83 }
84 GDBWindow* window = new GDBWindow(m_gdbController);
85 window->show();
86}
87#endif
88
89void Window::keyPressEvent(QKeyEvent* event) {
90 if (event->isAutoRepeat()) {
91 QWidget::keyPressEvent(event);
92 return;
93 }
94 GBAKey key = mapKey(event->key());
95 if (key == GBA_KEY_NONE) {
96 QWidget::keyPressEvent(event);
97 return;
98 }
99 m_controller->keyPressed(key);
100 event->accept();
101}
102
103void Window::keyReleaseEvent(QKeyEvent* event) {
104 if (event->isAutoRepeat()) {
105 QWidget::keyReleaseEvent(event);
106 return;
107 }
108 GBAKey key = mapKey(event->key());
109 if (key == GBA_KEY_NONE) {
110 QWidget::keyPressEvent(event);
111 return;
112 }
113 m_controller->keyReleased(key);
114 event->accept();
115}
116
117void Window::closeEvent(QCloseEvent* event) {
118 emit shutdown();
119 QMainWindow::closeEvent(event);
120}
121
122void Window::gameStarted(GBAThread* context) {
123 emit startDrawing(m_controller->drawContext(), context);
124 foreach (QAction* action, m_gameActions) {
125 action->setDisabled(false);
126 }
127 if (!m_audioThread) {
128 m_audioThread = new AudioThread(this);
129 connect(this, SIGNAL(shutdown()), m_audioThread, SLOT(shutdown()));
130 m_audioThread->setInput(context);
131 m_audioThread->start(QThread::HighPriority);
132 } else {
133 m_audioThread->resume();
134 }
135}
136
137void Window::gameStopped() {
138 foreach (QAction* action, m_gameActions) {
139 action->setDisabled(true);
140 }
141 m_audioThread->pause();
142}
143
144void Window::setupMenu(QMenuBar* menubar) {
145 menubar->clear();
146 QMenu* fileMenu = menubar->addMenu(tr("&File"));
147 fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open);
148 fileMenu->addAction(tr("Sh&utdown"), m_controller, SLOT(closeGame()));
149
150 QMenu* emulationMenu = menubar->addMenu(tr("&Emulation"));
151 QAction* pause = new QAction(tr("&Pause"), 0);
152 pause->setChecked(false);
153 pause->setCheckable(true);
154 pause->setShortcut(tr("Ctrl+P"));
155 pause->setDisabled(true);
156 connect(pause, SIGNAL(triggered(bool)), m_controller, SLOT(setPaused(bool)));
157 m_gameActions.append(pause);
158 emulationMenu->addAction(pause);
159
160 QAction* frameAdvance = new QAction(tr("&Next frame"), 0);
161 frameAdvance->setShortcut(tr("Ctrl+N"));
162 frameAdvance->setDisabled(true);
163 connect(frameAdvance, SIGNAL(triggered()), m_controller, SLOT(frameAdvance()));
164 m_gameActions.append(frameAdvance);
165 emulationMenu->addAction(frameAdvance);
166
167 QMenu* debuggingMenu = menubar->addMenu(tr("&Debugging"));
168#ifdef USE_GDB_STUB
169 QAction* gdbWindow = new QAction(tr("Start &GDB server..."), nullptr);
170 connect(gdbWindow, SIGNAL(triggered()), this, SLOT(gdbOpen()));
171 debuggingMenu->addAction(gdbWindow);
172#endif
173}