all repos — mgba @ c76f173880830d573c55c4b719aa1eef8e5993ba

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