all repos — mgba @ 7df5b67a71d4406d1261510ae6296e879db33c39

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		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}