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