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_MBC7);
46 s_mbcList.append(GB_POCKETCAM);
47 s_mbcList.append(GB_TAMA5);
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(m_ui.hwAutodetect, &QAbstractButton::toggled, [this] (bool enabled) {
61 m_ui.hwRTC->setEnabled(!enabled);
62 m_ui.hwGyro->setEnabled(!enabled);
63 m_ui.hwLight->setEnabled(!enabled);
64 m_ui.hwTilt->setEnabled(!enabled);
65 m_ui.hwRumble->setEnabled(!enabled);
66 });
67
68 connect(m_ui.savetype, &QComboBox::currentTextChanged, this, &OverrideView::updateOverrides);
69 connect(m_ui.hwAutodetect, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
70 connect(m_ui.hwRTC, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
71 connect(m_ui.hwGyro, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
72 connect(m_ui.hwLight, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
73 connect(m_ui.hwTilt, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
74 connect(m_ui.hwRumble, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
75 connect(m_ui.hwGBPlayer, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
76
77 connect(m_ui.gbModel, &QComboBox::currentTextChanged, this, &OverrideView::updateOverrides);
78 connect(m_ui.mbc, &QComboBox::currentTextChanged, this, &OverrideView::updateOverrides);
79
80 m_colorPickers[0] = ColorPicker(m_ui.color0, QColor(0xF8, 0xF8, 0xF8));
81 m_colorPickers[1] = ColorPicker(m_ui.color1, QColor(0xA8, 0xA8, 0xA8));
82 m_colorPickers[2] = ColorPicker(m_ui.color2, QColor(0x50, 0x50, 0x50));
83 m_colorPickers[3] = ColorPicker(m_ui.color3, QColor(0x00, 0x00, 0x00));
84 for (int colorId = 0; colorId < 4; ++colorId) {
85 connect(&m_colorPickers[colorId], &ColorPicker::colorChanged, this, [this, colorId](const QColor& color) {
86 m_gbColors[colorId] = color.rgb();
87 updateOverrides();
88 });
89 }
90
91 connect(m_ui.tabWidget, &QTabWidget::currentChanged, this, &OverrideView::updateOverrides);
92#ifndef M_CORE_GBA
93 m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.tabGBA));
94#endif
95#ifndef M_CORE_GB
96 m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.tabGB));
97#endif
98
99 connect(m_ui.buttonBox, &QDialogButtonBox::accepted, this, &OverrideView::saveOverride);
100 connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &QWidget::close);
101 m_ui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(false);
102}
103
104void OverrideView::setController(std::shared_ptr<CoreController> controller) {
105 m_controller = controller;
106 gameStarted();
107 connect(controller.get(), &CoreController::stopping, this, &OverrideView::gameStopped);
108 if (m_override) {
109 m_controller->setOverride(std::move(m_override));
110 } else {
111 m_controller->clearOverride();
112 }
113}
114
115void OverrideView::saveOverride() {
116 if (!m_config || !m_controller) {
117 return;
118 }
119 m_config->saveOverride(*m_controller->override());
120}
121
122void OverrideView::updateOverrides() {
123#ifdef M_CORE_GBA
124 if (m_ui.tabWidget->currentWidget() == m_ui.tabGBA) {
125 std::unique_ptr<GBAOverride> gba(new GBAOverride);
126 memset(gba->override.id, 0, 4);
127 gba->override.savetype = static_cast<SavedataType>(m_ui.savetype->currentIndex() - 1);
128 gba->override.hardware = HW_NO_OVERRIDE;
129 gba->override.idleLoop = IDLE_LOOP_NONE;
130 gba->override.mirroring = false;
131
132 if (!m_ui.hwAutodetect->isChecked()) {
133 gba->override.hardware = HW_NONE;
134 if (m_ui.hwRTC->isChecked()) {
135 gba->override.hardware |= HW_RTC;
136 }
137 if (m_ui.hwGyro->isChecked()) {
138 gba->override.hardware |= HW_GYRO;
139 }
140 if (m_ui.hwLight->isChecked()) {
141 gba->override.hardware |= HW_LIGHT_SENSOR;
142 }
143 if (m_ui.hwTilt->isChecked()) {
144 gba->override.hardware |= HW_TILT;
145 }
146 if (m_ui.hwRumble->isChecked()) {
147 gba->override.hardware |= HW_RUMBLE;
148 }
149 }
150 if (m_ui.hwGBPlayer->isChecked()) {
151 gba->override.hardware |= HW_GB_PLAYER_DETECTION;
152 }
153
154 bool ok;
155 uint32_t parsedIdleLoop = m_ui.idleLoop->text().toInt(&ok, 16);
156 if (ok) {
157 gba->override.idleLoop = parsedIdleLoop;
158 }
159
160
161 if (gba->override.savetype != SAVEDATA_AUTODETECT || gba->override.hardware != HW_NO_OVERRIDE ||
162 gba->override.idleLoop != IDLE_LOOP_NONE) {
163 m_override = std::move(gba);
164 } else {
165 m_override.reset();
166 }
167 }
168#endif
169#ifdef M_CORE_GB
170 if (m_ui.tabWidget->currentWidget() == m_ui.tabGB) {
171 std::unique_ptr<GBOverride> gb(new GBOverride);
172 gb->override.mbc = s_mbcList[m_ui.mbc->currentIndex()];
173 gb->override.model = s_gbModelList[m_ui.gbModel->currentIndex()];
174 gb->override.gbColors[0] = m_gbColors[0];
175 gb->override.gbColors[1] = m_gbColors[1];
176 gb->override.gbColors[2] = m_gbColors[2];
177 gb->override.gbColors[3] = m_gbColors[3];
178 bool hasOverride = gb->override.mbc != GB_MBC_AUTODETECT || gb->override.model != GB_MODEL_AUTODETECT;
179 hasOverride = hasOverride || (m_gbColors[0] | m_gbColors[1] | m_gbColors[2] | m_gbColors[3]);
180 if (hasOverride) {
181 m_override = std::move(gb);
182 } else {
183 m_override.reset();
184 }
185 }
186#endif
187}
188
189void OverrideView::gameStarted() {
190 CoreController::Interrupter interrupter(m_controller);
191 mCoreThread* thread = m_controller->thread();
192
193 m_ui.tabWidget->setEnabled(false);
194 m_ui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(true);
195
196 switch (thread->core->platform(thread->core)) {
197#ifdef M_CORE_GBA
198 case PLATFORM_GBA: {
199 m_ui.tabWidget->setCurrentWidget(m_ui.tabGBA);
200 GBA* gba = static_cast<GBA*>(thread->core->board);
201 m_ui.savetype->setCurrentIndex(gba->memory.savedata.type + 1);
202 m_ui.hwRTC->setChecked(gba->memory.hw.devices & HW_RTC);
203 m_ui.hwGyro->setChecked(gba->memory.hw.devices & HW_GYRO);
204 m_ui.hwLight->setChecked(gba->memory.hw.devices & HW_LIGHT_SENSOR);
205 m_ui.hwTilt->setChecked(gba->memory.hw.devices & HW_TILT);
206 m_ui.hwRumble->setChecked(gba->memory.hw.devices & HW_RUMBLE);
207 m_ui.hwGBPlayer->setChecked(gba->memory.hw.devices & HW_GB_PLAYER_DETECTION);
208
209 if (gba->idleLoop != IDLE_LOOP_NONE) {
210 m_ui.idleLoop->setText(QString::number(gba->idleLoop, 16));
211 } else {
212 m_ui.idleLoop->clear();
213 }
214 break;
215 }
216#endif
217#ifdef M_CORE_GB
218 case PLATFORM_GB: {
219 m_ui.tabWidget->setCurrentWidget(m_ui.tabGB);
220 GB* gb = static_cast<GB*>(thread->core->board);
221 int mbc = s_mbcList.indexOf(gb->memory.mbcType);
222 if (mbc >= 0) {
223 m_ui.mbc->setCurrentIndex(mbc);
224 } else {
225 m_ui.mbc->setCurrentIndex(0);
226 }
227 int model = s_gbModelList.indexOf(gb->model);
228 if (model >= 0) {
229 m_ui.gbModel->setCurrentIndex(model);
230 } else {
231 m_ui.gbModel->setCurrentIndex(0);
232 }
233 break;
234 }
235#endif
236 case PLATFORM_NONE:
237 break;
238 }
239}
240
241void OverrideView::gameStopped() {
242 m_controller.reset();
243 m_ui.tabWidget->setEnabled(true);
244 m_ui.savetype->setCurrentIndex(0);
245 m_ui.idleLoop->clear();
246 m_ui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(false);
247
248 m_ui.mbc->setCurrentIndex(0);
249 m_ui.gbModel->setCurrentIndex(0);
250
251 updateOverrides();
252}