src/platform/qt/OverrideView.cpp (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "OverrideView.h"
7
8#include <QColorDialog>
9#include <QPushButton>
10
11#include "ConfigController.h"
12#include "GameController.h"
13
14#ifdef M_CORE_GBA
15#include "GBAOverride.h"
16#include <mgba/internal/gba/gba.h>
17#endif
18
19#ifdef M_CORE_GB
20#include "GBOverride.h"
21#include <mgba/internal/gb/gb.h>
22#endif
23
24using namespace QGBA;
25
26#ifdef M_CORE_GB
27QList<enum GBModel> OverrideView::s_gbModelList;
28QList<enum GBMemoryBankControllerType> OverrideView::s_mbcList;
29#endif
30
31OverrideView::OverrideView(GameController* controller, ConfigController* config, QWidget* parent)
32 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
33 , m_controller(controller)
34 , m_config(config)
35{
36#ifdef M_CORE_GB
37 if (s_mbcList.isEmpty()) {
38 // NB: Keep in sync with OverrideView.ui
39 s_mbcList.append(GB_MBC_AUTODETECT);
40 s_mbcList.append(GB_MBC_NONE);
41 s_mbcList.append(GB_MBC1);
42 s_mbcList.append(GB_MBC2);
43 s_mbcList.append(GB_MBC3);
44 s_mbcList.append(GB_MBC3_RTC);
45 s_mbcList.append(GB_MBC5);
46 s_mbcList.append(GB_MBC5_RUMBLE);
47 s_mbcList.append(GB_MBC7);
48 s_mbcList.append(GB_HuC3);
49 }
50 if (s_gbModelList.isEmpty()) {
51 // NB: Keep in sync with OverrideView.ui
52 s_gbModelList.append(GB_MODEL_AUTODETECT);
53 s_gbModelList.append(GB_MODEL_DMG);
54 s_gbModelList.append(GB_MODEL_CGB);
55 s_gbModelList.append(GB_MODEL_AGB);
56 }
57#endif
58 m_ui.setupUi(this);
59
60 connect(controller, &GameController::gameStarted, this, &OverrideView::gameStarted);
61 connect(controller, &GameController::gameStopped, this, &OverrideView::gameStopped);
62
63 connect(m_ui.hwAutodetect, &QAbstractButton::toggled, [this] (bool enabled) {
64 m_ui.hwRTC->setEnabled(!enabled);
65 m_ui.hwGyro->setEnabled(!enabled);
66 m_ui.hwLight->setEnabled(!enabled);
67 m_ui.hwTilt->setEnabled(!enabled);
68 m_ui.hwRumble->setEnabled(!enabled);
69 });
70
71 connect(m_ui.savetype, &QComboBox::currentTextChanged, this, &OverrideView::updateOverrides);
72 connect(m_ui.hwAutodetect, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
73 connect(m_ui.hwRTC, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
74 connect(m_ui.hwGyro, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
75 connect(m_ui.hwLight, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
76 connect(m_ui.hwTilt, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
77 connect(m_ui.hwRumble, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
78 connect(m_ui.hwGBPlayer, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
79
80 connect(m_ui.gbModel, &QComboBox::currentTextChanged, this, &OverrideView::updateOverrides);
81 connect(m_ui.mbc, &QComboBox::currentTextChanged, this, &OverrideView::updateOverrides);
82
83 QPalette palette = m_ui.color0->palette();
84 palette.setColor(backgroundRole(), QColor(0xF8, 0xF8, 0xF8));
85 m_ui.color0->setPalette(palette);
86 palette.setColor(backgroundRole(), QColor(0xA8, 0xA8, 0xA8));
87 m_ui.color1->setPalette(palette);
88 palette.setColor(backgroundRole(), QColor(0x50, 0x50, 0x50));
89 m_ui.color2->setPalette(palette);
90 palette.setColor(backgroundRole(), QColor(0x00, 0x00, 0x00));
91 m_ui.color3->setPalette(palette);
92
93 m_ui.color0->installEventFilter(this);
94 m_ui.color1->installEventFilter(this);
95 m_ui.color2->installEventFilter(this);
96 m_ui.color3->installEventFilter(this);
97
98 connect(m_ui.tabWidget, &QTabWidget::currentChanged, this, &OverrideView::updateOverrides);
99#ifndef M_CORE_GBA
100 m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.tabGBA));
101#endif
102#ifndef M_CORE_GB
103 m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.tabGB));
104#endif
105
106 connect(m_ui.buttonBox, &QDialogButtonBox::accepted, this, &OverrideView::saveOverride);
107 connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &QWidget::close);
108
109 if (controller->isLoaded()) {
110 gameStarted(controller->thread());
111 }
112}
113
114bool OverrideView::eventFilter(QObject* obj, QEvent* event) {
115#ifdef M_CORE_GB
116 if (event->type() != QEvent::MouseButtonRelease) {
117 return false;
118 }
119 int colorId;
120 if (obj == m_ui.color0) {
121 colorId = 0;
122 } else if (obj == m_ui.color1) {
123 colorId = 1;
124 } else if (obj == m_ui.color2) {
125 colorId = 2;
126 } else if (obj == m_ui.color3) {
127 colorId = 3;
128 } else {
129 return false;
130 }
131
132 QWidget* swatch = static_cast<QWidget*>(obj);
133
134 QColorDialog* colorPicker = new QColorDialog;
135 colorPicker->setAttribute(Qt::WA_DeleteOnClose);
136 colorPicker->open();
137 connect(colorPicker, &QColorDialog::colorSelected, [this, swatch, colorId](const QColor& color) {
138 QPalette palette = swatch->palette();
139 palette.setColor(backgroundRole(), color);
140 swatch->setPalette(palette);
141 m_gbColors[colorId] = color.rgb();
142 updateOverrides();
143 });
144 return true;
145#else
146 return false;
147#endif
148}
149
150void OverrideView::saveOverride() {
151 Override* override = m_controller->override();
152 if (!override) {
153 return;
154 }
155 if (m_controller->isLoaded()) {
156 m_config->saveOverride(*override);
157 } else {
158 m_savePending = true;
159 }
160}
161
162void OverrideView::updateOverrides() {
163#ifdef M_CORE_GBA
164 if (m_ui.tabWidget->currentWidget() == m_ui.tabGBA) {
165 GBAOverride* gba = new GBAOverride;
166 memset(gba->override.id, 0, 4);
167 gba->override.savetype = static_cast<SavedataType>(m_ui.savetype->currentIndex() - 1);
168 gba->override.hardware = HW_NO_OVERRIDE;
169 gba->override.idleLoop = IDLE_LOOP_NONE;
170 gba->override.mirroring = false;
171
172 if (!m_ui.hwAutodetect->isChecked()) {
173 gba->override.hardware = HW_NONE;
174 if (m_ui.hwRTC->isChecked()) {
175 gba->override.hardware |= HW_RTC;
176 }
177 if (m_ui.hwGyro->isChecked()) {
178 gba->override.hardware |= HW_GYRO;
179 }
180 if (m_ui.hwLight->isChecked()) {
181 gba->override.hardware |= HW_LIGHT_SENSOR;
182 }
183 if (m_ui.hwTilt->isChecked()) {
184 gba->override.hardware |= HW_TILT;
185 }
186 if (m_ui.hwRumble->isChecked()) {
187 gba->override.hardware |= HW_RUMBLE;
188 }
189 }
190 if (m_ui.hwGBPlayer->isChecked()) {
191 gba->override.hardware |= HW_GB_PLAYER_DETECTION;
192 }
193
194 bool ok;
195 uint32_t parsedIdleLoop = m_ui.idleLoop->text().toInt(&ok, 16);
196 if (ok) {
197 gba->override.idleLoop = parsedIdleLoop;
198 }
199
200 if (gba->override.savetype != SAVEDATA_AUTODETECT || gba->override.hardware != HW_NO_OVERRIDE ||
201 gba->override.idleLoop != IDLE_LOOP_NONE) {
202 m_controller->setOverride(gba);
203 } else {
204 m_controller->clearOverride();
205 delete gba;
206 }
207 }
208#endif
209#ifdef M_CORE_GB
210 if (m_ui.tabWidget->currentWidget() == m_ui.tabGB) {
211 GBOverride* gb = new GBOverride;
212 gb->override.mbc = s_mbcList[m_ui.mbc->currentIndex()];
213 gb->override.model = s_gbModelList[m_ui.gbModel->currentIndex()];
214 gb->override.gbColors[0] = m_gbColors[0];
215 gb->override.gbColors[1] = m_gbColors[1];
216 gb->override.gbColors[2] = m_gbColors[2];
217 gb->override.gbColors[3] = m_gbColors[3];
218 bool hasOverride = gb->override.mbc != GB_MBC_AUTODETECT || gb->override.model != GB_MODEL_AUTODETECT;
219 hasOverride = hasOverride || (m_gbColors[0] | m_gbColors[1] | m_gbColors[2] | m_gbColors[3]);
220 if (hasOverride) {
221 m_controller->setOverride(gb);
222 } else {
223 m_controller->clearOverride();
224 delete gb;
225 }
226 }
227#endif
228}
229
230void OverrideView::gameStarted(mCoreThread* thread) {
231 if (!thread->core) {
232 gameStopped();
233 return;
234 }
235
236 m_ui.tabWidget->setEnabled(false);
237
238 switch (thread->core->platform(thread->core)) {
239#ifdef M_CORE_GBA
240 case PLATFORM_GBA: {
241 m_ui.tabWidget->setCurrentWidget(m_ui.tabGBA);
242 GBA* gba = static_cast<GBA*>(thread->core->board);
243 m_ui.savetype->setCurrentIndex(gba->memory.savedata.type + 1);
244 m_ui.hwRTC->setChecked(gba->memory.hw.devices & HW_RTC);
245 m_ui.hwGyro->setChecked(gba->memory.hw.devices & HW_GYRO);
246 m_ui.hwLight->setChecked(gba->memory.hw.devices & HW_LIGHT_SENSOR);
247 m_ui.hwTilt->setChecked(gba->memory.hw.devices & HW_TILT);
248 m_ui.hwRumble->setChecked(gba->memory.hw.devices & HW_RUMBLE);
249 m_ui.hwGBPlayer->setChecked(gba->memory.hw.devices & HW_GB_PLAYER_DETECTION);
250
251 if (gba->idleLoop != IDLE_LOOP_NONE) {
252 m_ui.idleLoop->setText(QString::number(gba->idleLoop, 16));
253 } else {
254 m_ui.idleLoop->clear();
255 }
256 break;
257 }
258#endif
259#ifdef M_CORE_GB
260 case PLATFORM_GB: {
261 m_ui.tabWidget->setCurrentWidget(m_ui.tabGB);
262 GB* gb = static_cast<GB*>(thread->core->board);
263 int mbc = s_mbcList.indexOf(gb->memory.mbcType);
264 if (mbc >= 0) {
265 m_ui.mbc->setCurrentIndex(mbc);
266 } else {
267 m_ui.mbc->setCurrentIndex(0);
268 }
269 int model = s_gbModelList.indexOf(gb->model);
270 if (model >= 0) {
271 m_ui.gbModel->setCurrentIndex(model);
272 } else {
273 m_ui.gbModel->setCurrentIndex(0);
274 }
275 break;
276 }
277#endif
278 case PLATFORM_NONE:
279 break;
280 }
281
282 if (m_savePending) {
283 m_savePending = false;
284 saveOverride();
285 }
286}
287
288void OverrideView::gameStopped() {
289 m_ui.tabWidget->setEnabled(true);
290 m_ui.savetype->setCurrentIndex(0);
291 m_ui.idleLoop->clear();
292
293 m_ui.mbc->setCurrentIndex(0);
294 m_ui.gbModel->setCurrentIndex(0);
295
296 updateOverrides();
297}