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 <QPushButton>
9
10#include "ConfigController.h"
11#include "CoreController.h"
12
13#ifdef M_CORE_GBA
14#include "GBAOverride.h"
15#include <mgba/internal/gba/gba.h>
16#endif
17
18#ifdef M_CORE_GB
19#include "GBOverride.h"
20#include <mgba/internal/gb/gb.h>
21#endif
22
23using namespace QGBA;
24
25#ifdef M_CORE_GB
26QList<enum GBModel> OverrideView::s_gbModelList;
27QList<enum GBMemoryBankControllerType> OverrideView::s_mbcList;
28#endif
29
30OverrideView::OverrideView(ConfigController* config, QWidget* parent)
31 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
32 , m_config(config)
33{
34#ifdef M_CORE_GB
35 if (s_mbcList.isEmpty()) {
36 // NB: Keep in sync with OverrideView.ui
37 s_mbcList.append(GB_MBC_AUTODETECT);
38 s_mbcList.append(GB_MBC_NONE);
39 s_mbcList.append(GB_MBC1);
40 s_mbcList.append(GB_MBC2);
41 s_mbcList.append(GB_MBC3);
42 s_mbcList.append(GB_MBC3_RTC);
43 s_mbcList.append(GB_MBC5);
44 s_mbcList.append(GB_MBC5_RUMBLE);
45 s_mbcList.append(GB_MBC6);
46 s_mbcList.append(GB_MBC7);
47 s_mbcList.append(GB_MMM01);
48 s_mbcList.append(GB_POCKETCAM);
49 s_mbcList.append(GB_TAMA5);
50 s_mbcList.append(GB_HuC1);
51 s_mbcList.append(GB_HuC3);
52 s_mbcList.append(GB_UNL_WISDOM_TREE);
53 s_mbcList.append(GB_UNL_BBD);
54 s_mbcList.append(GB_UNL_HITEK);
55 s_mbcList.append(GB_UNL_PKJD);
56 }
57 if (s_gbModelList.isEmpty()) {
58 // NB: Keep in sync with OverrideView.ui
59 s_gbModelList.append(GB_MODEL_AUTODETECT);
60 s_gbModelList.append(GB_MODEL_DMG);
61 s_gbModelList.append(GB_MODEL_SGB);
62 s_gbModelList.append(GB_MODEL_CGB);
63 s_gbModelList.append(GB_MODEL_AGB);
64 }
65#endif
66 m_ui.setupUi(this);
67
68 connect(m_ui.hwAutodetect, &QAbstractButton::toggled, [this] (bool enabled) {
69 m_ui.hwRTC->setEnabled(!enabled);
70 m_ui.hwGyro->setEnabled(!enabled);
71 m_ui.hwLight->setEnabled(!enabled);
72 m_ui.hwTilt->setEnabled(!enabled);
73 m_ui.hwRumble->setEnabled(!enabled);
74 });
75
76#ifdef M_CORE_GB
77 m_colorPickers[0] = ColorPicker(m_ui.color0, QColor(0xF8, 0xF8, 0xF8));
78 m_colorPickers[1] = ColorPicker(m_ui.color1, QColor(0xA8, 0xA8, 0xA8));
79 m_colorPickers[2] = ColorPicker(m_ui.color2, QColor(0x50, 0x50, 0x50));
80 m_colorPickers[3] = ColorPicker(m_ui.color3, QColor(0x00, 0x00, 0x00));
81 m_colorPickers[4] = ColorPicker(m_ui.color4, QColor(0xF8, 0xF8, 0xF8));
82 m_colorPickers[5] = ColorPicker(m_ui.color5, QColor(0xA8, 0xA8, 0xA8));
83 m_colorPickers[6] = ColorPicker(m_ui.color6, QColor(0x50, 0x50, 0x50));
84 m_colorPickers[7] = ColorPicker(m_ui.color7, QColor(0x00, 0x00, 0x00));
85 m_colorPickers[8] = ColorPicker(m_ui.color8, QColor(0xF8, 0xF8, 0xF8));
86 m_colorPickers[9] = ColorPicker(m_ui.color9, QColor(0xA8, 0xA8, 0xA8));
87 m_colorPickers[10] = ColorPicker(m_ui.color10, QColor(0x50, 0x50, 0x50));
88 m_colorPickers[11] = ColorPicker(m_ui.color11, QColor(0x00, 0x00, 0x00));
89 for (int colorId = 0; colorId < 12; ++colorId) {
90 connect(&m_colorPickers[colorId], &ColorPicker::colorChanged, this, [this, colorId](const QColor& color) {
91 m_gbColors[colorId] = color.rgb() | 0xFF000000;
92 });
93 }
94#endif
95
96#ifndef M_CORE_GBA
97 m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.tabGBA));
98#endif
99#ifndef M_CORE_GB
100 m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.tabGB));
101#endif
102
103 connect(m_ui.buttonBox, &QDialogButtonBox::accepted, this, &OverrideView::saveOverride);
104 connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &QWidget::close);
105
106 m_recheck.setInterval(200);
107 connect(&m_recheck, &QTimer::timeout, this, &OverrideView::recheck);
108}
109
110void OverrideView::setController(std::shared_ptr<CoreController> controller) {
111 m_controller = controller;
112 connect(controller.get(), &CoreController::started, this, &OverrideView::gameStarted);
113 connect(controller.get(), &CoreController::stopping, this, &OverrideView::gameStopped);
114 recheck();
115}
116
117void OverrideView::saveOverride() {
118 if (!m_controller) {
119 m_savePending = true;
120 return;
121 }
122
123 Override* override = m_controller->override();
124 if (!override) {
125 return;
126 }
127 m_config->saveOverride(*override);
128}
129
130void OverrideView::recheck() {
131 if (!m_controller) {
132 return;
133 }
134 if (m_controller->hasStarted()) {
135 gameStarted();
136 } else {
137 updateOverrides();
138 }
139}
140
141void OverrideView::updateOverrides() {
142 if (!m_controller) {
143 return;
144 }
145#ifdef M_CORE_GBA
146 if (m_ui.tabWidget->currentWidget() == m_ui.tabGBA) {
147 std::unique_ptr<GBAOverride> gba(new GBAOverride);
148 memset(gba->override.id, 0, 4);
149 gba->override.savetype = static_cast<SavedataType>(m_ui.savetype->currentIndex() - 1);
150 gba->override.hardware = HW_NO_OVERRIDE;
151 gba->override.idleLoop = IDLE_LOOP_NONE;
152 gba->override.mirroring = false;
153
154 if (!m_ui.hwAutodetect->isChecked()) {
155 gba->override.hardware = HW_NONE;
156 if (m_ui.hwRTC->isChecked()) {
157 gba->override.hardware |= HW_RTC;
158 }
159 if (m_ui.hwGyro->isChecked()) {
160 gba->override.hardware |= HW_GYRO;
161 }
162 if (m_ui.hwLight->isChecked()) {
163 gba->override.hardware |= HW_LIGHT_SENSOR;
164 }
165 if (m_ui.hwTilt->isChecked()) {
166 gba->override.hardware |= HW_TILT;
167 }
168 if (m_ui.hwRumble->isChecked()) {
169 gba->override.hardware |= HW_RUMBLE;
170 }
171 }
172 if (m_ui.hwGBPlayer->isChecked()) {
173 gba->override.hardware |= HW_GB_PLAYER_DETECTION;
174 }
175
176 bool ok;
177 uint32_t parsedIdleLoop = m_ui.idleLoop->text().toInt(&ok, 16);
178 if (ok) {
179 gba->override.idleLoop = parsedIdleLoop;
180 }
181
182 if (gba->override.savetype != SAVEDATA_AUTODETECT || gba->override.hardware != HW_NO_OVERRIDE ||
183 gba->override.idleLoop != IDLE_LOOP_NONE) {
184 m_controller->setOverride(std::move(gba));
185 } else {
186 m_controller->clearOverride();
187 }
188 }
189#endif
190#ifdef M_CORE_GB
191 if (m_ui.tabWidget->currentWidget() == m_ui.tabGB) {
192 std::unique_ptr<GBOverride> gb(new GBOverride);
193 gb->override.mbc = s_mbcList[m_ui.mbc->currentIndex()];
194 gb->override.model = s_gbModelList[m_ui.gbModel->currentIndex()];
195 bool hasColor = false;
196 for (int i = 0; i < 12; ++i) {
197 gb->override.gbColors[i] = m_gbColors[i];
198 hasColor = hasColor || (m_gbColors[i] & 0xFF000000);
199 }
200 bool hasOverride = gb->override.mbc != GB_MBC_AUTODETECT || gb->override.model != GB_MODEL_AUTODETECT;
201 hasOverride = hasOverride || hasColor;
202 if (hasOverride) {
203 m_controller->setOverride(std::move(gb));
204 } else {
205 m_controller->clearOverride();
206 }
207 }
208#endif
209}
210
211void OverrideView::gameStarted() {
212 CoreController::Interrupter interrupter(m_controller);
213 mCoreThread* thread = m_controller->thread();
214
215 m_ui.tabWidget->setEnabled(false);
216 m_recheck.start();
217
218 switch (thread->core->platform(thread->core)) {
219#ifdef M_CORE_GBA
220 case PLATFORM_GBA: {
221 m_ui.tabWidget->setCurrentWidget(m_ui.tabGBA);
222 GBA* gba = static_cast<GBA*>(thread->core->board);
223 m_ui.savetype->setCurrentIndex(gba->memory.savedata.type + 1);
224 m_ui.hwRTC->setChecked(gba->memory.hw.devices & HW_RTC);
225 m_ui.hwGyro->setChecked(gba->memory.hw.devices & HW_GYRO);
226 m_ui.hwLight->setChecked(gba->memory.hw.devices & HW_LIGHT_SENSOR);
227 m_ui.hwTilt->setChecked(gba->memory.hw.devices & HW_TILT);
228 m_ui.hwRumble->setChecked(gba->memory.hw.devices & HW_RUMBLE);
229 m_ui.hwGBPlayer->setChecked(gba->memory.hw.devices & HW_GB_PLAYER_DETECTION);
230
231 if (gba->idleLoop != IDLE_LOOP_NONE) {
232 m_ui.idleLoop->setText(QString::number(gba->idleLoop, 16));
233 } else {
234 m_ui.idleLoop->clear();
235 }
236 break;
237 }
238#endif
239#ifdef M_CORE_GB
240 case PLATFORM_GB: {
241 m_ui.tabWidget->setCurrentWidget(m_ui.tabGB);
242 GB* gb = static_cast<GB*>(thread->core->board);
243 int mbc = s_mbcList.indexOf(gb->memory.mbcType);
244 if (mbc >= 0) {
245 m_ui.mbc->setCurrentIndex(mbc);
246 } else {
247 m_ui.mbc->setCurrentIndex(0);
248 }
249 int model = s_gbModelList.indexOf(gb->model);
250 if (model >= 0) {
251 m_ui.gbModel->setCurrentIndex(model);
252 } else {
253 m_ui.gbModel->setCurrentIndex(0);
254 }
255 break;
256 }
257#endif
258 case PLATFORM_NONE:
259 break;
260 }
261
262 if (m_savePending) {
263 m_savePending = false;
264 saveOverride();
265 }
266}
267
268void OverrideView::gameStopped() {
269 m_recheck.stop();
270 m_controller.reset();
271 m_ui.tabWidget->setEnabled(true);
272 m_ui.savetype->setCurrentIndex(0);
273 m_ui.idleLoop->clear();
274
275 m_ui.mbc->setCurrentIndex(0);
276 m_ui.gbModel->setCurrentIndex(0);
277}