all repos — mgba @ 3ce0472963ea747edb1e7233e2fdfe9b1d8db4b8

mGBA Game Boy Advance Emulator

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