all repos — mgba @ 1414955da0359fc446ed97f72ce089e0e2ed1a1e

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 <QColorDialog>
  9#include <QPushButton>
 10
 11#include "ConfigController.h"
 12#include "GameController.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 "GBOverride.h"
 21#include <mgba/internal/gb/gb.h>
 22#endif
 23
 24using namespace QGBA;
 25
 26#ifdef M_CORE_GB
 27QList<enum GBModel> OverrideView::s_gbModelList;
 28QList<enum GBMemoryBankControllerType> OverrideView::s_mbcList;
 29#endif
 30
 31OverrideView::OverrideView(GameController* controller, ConfigController* config, QWidget* parent)
 32	: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
 33	, m_controller(controller)
 34	, m_config(config)
 35{
 36#ifdef M_CORE_GB
 37	if (s_mbcList.isEmpty()) {
 38		// NB: Keep in sync with OverrideView.ui
 39		s_mbcList.append(GB_MBC_AUTODETECT);
 40		s_mbcList.append(GB_MBC_NONE);
 41		s_mbcList.append(GB_MBC1);
 42		s_mbcList.append(GB_MBC2);
 43		s_mbcList.append(GB_MBC3);
 44		s_mbcList.append(GB_MBC3_RTC);
 45		s_mbcList.append(GB_MBC5);
 46		s_mbcList.append(GB_MBC5_RUMBLE);
 47		s_mbcList.append(GB_MBC7);
 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(controller, &GameController::gameStarted, this, &OverrideView::gameStarted);
 61	connect(controller, &GameController::gameStopped, this, &OverrideView::gameStopped);
 62
 63	connect(m_ui.hwAutodetect, &QAbstractButton::toggled, [this] (bool enabled) {
 64		m_ui.hwRTC->setEnabled(!enabled);
 65		m_ui.hwGyro->setEnabled(!enabled);
 66		m_ui.hwLight->setEnabled(!enabled);
 67		m_ui.hwTilt->setEnabled(!enabled);
 68		m_ui.hwRumble->setEnabled(!enabled);
 69	});
 70
 71	connect(m_ui.savetype, &QComboBox::currentTextChanged, this, &OverrideView::updateOverrides);
 72	connect(m_ui.hwAutodetect, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
 73	connect(m_ui.hwRTC, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
 74	connect(m_ui.hwGyro, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
 75	connect(m_ui.hwLight, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
 76	connect(m_ui.hwTilt, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
 77	connect(m_ui.hwRumble, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
 78	connect(m_ui.hwGBPlayer, &QAbstractButton::clicked, this, &OverrideView::updateOverrides);
 79
 80	connect(m_ui.gbModel, &QComboBox::currentTextChanged, this, &OverrideView::updateOverrides);
 81	connect(m_ui.mbc, &QComboBox::currentTextChanged, this, &OverrideView::updateOverrides);
 82
 83	QPalette palette = m_ui.color0->palette();
 84	palette.setColor(backgroundRole(), QColor(0xF8, 0xF8, 0xF8));
 85	m_ui.color0->setPalette(palette);
 86	palette.setColor(backgroundRole(), QColor(0xA8, 0xA8, 0xA8));
 87	m_ui.color1->setPalette(palette);
 88	palette.setColor(backgroundRole(), QColor(0x50, 0x50, 0x50));
 89	m_ui.color2->setPalette(palette);
 90	palette.setColor(backgroundRole(), QColor(0x00, 0x00, 0x00));
 91	m_ui.color3->setPalette(palette);
 92
 93	m_ui.color0->installEventFilter(this);
 94	m_ui.color1->installEventFilter(this);
 95	m_ui.color2->installEventFilter(this);
 96	m_ui.color3->installEventFilter(this);
 97
 98	connect(m_ui.tabWidget, &QTabWidget::currentChanged, this, &OverrideView::updateOverrides);
 99#ifndef M_CORE_GBA
100	m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.tabGBA));
101#endif
102#ifndef M_CORE_GB
103	m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.tabGB));
104#endif
105
106	connect(m_ui.buttonBox, &QDialogButtonBox::accepted, this, &OverrideView::saveOverride);
107	connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &QWidget::close);
108
109	if (controller->isLoaded()) {
110		gameStarted(controller->thread());
111	}
112}
113
114bool OverrideView::eventFilter(QObject* obj, QEvent* event) {
115#ifdef M_CORE_GB
116	if (event->type() != QEvent::MouseButtonRelease) {
117		return false;
118	}
119	int colorId;
120	if (obj == m_ui.color0) {
121		colorId = 0;
122	} else if (obj == m_ui.color1) {
123		colorId = 1;
124	} else if (obj == m_ui.color2) {
125		colorId = 2;
126	} else if (obj == m_ui.color3) {
127		colorId = 3;
128	} else {
129		return false;
130	}
131
132	QWidget* swatch = static_cast<QWidget*>(obj);
133
134	QColorDialog* colorPicker = new QColorDialog;
135	colorPicker->setAttribute(Qt::WA_DeleteOnClose);
136	colorPicker->open();
137	connect(colorPicker, &QColorDialog::colorSelected, [this, swatch, colorId](const QColor& color) {
138		QPalette palette = swatch->palette();
139		palette.setColor(backgroundRole(), color);
140		swatch->setPalette(palette);
141		m_gbColors[colorId] = color.rgb();
142		updateOverrides();
143	});
144	return true;
145#else
146	return false;
147#endif
148}
149
150void OverrideView::saveOverride() {
151	Override* override = m_controller->override();
152	if (!override) {
153		return;
154	}
155	if (m_controller->isLoaded()) {
156		m_config->saveOverride(*override);
157	} else {
158		m_savePending = true;
159	}
160}
161
162void OverrideView::updateOverrides() {
163#ifdef M_CORE_GBA
164	if (m_ui.tabWidget->currentWidget() == m_ui.tabGBA) {
165		GBAOverride* gba = new GBAOverride;
166		memset(gba->override.id, 0, 4);
167		gba->override.savetype = static_cast<SavedataType>(m_ui.savetype->currentIndex() - 1);
168		gba->override.hardware = HW_NO_OVERRIDE;
169		gba->override.idleLoop = IDLE_LOOP_NONE;
170		gba->override.mirroring = false;
171
172		if (!m_ui.hwAutodetect->isChecked()) {
173			gba->override.hardware = HW_NONE;
174			if (m_ui.hwRTC->isChecked()) {
175				gba->override.hardware |= HW_RTC;
176			}
177			if (m_ui.hwGyro->isChecked()) {
178				gba->override.hardware |= HW_GYRO;
179			}
180			if (m_ui.hwLight->isChecked()) {
181				gba->override.hardware |= HW_LIGHT_SENSOR;
182			}
183			if (m_ui.hwTilt->isChecked()) {
184				gba->override.hardware |= HW_TILT;
185			}
186			if (m_ui.hwRumble->isChecked()) {
187				gba->override.hardware |= HW_RUMBLE;
188			}
189		}
190		if (m_ui.hwGBPlayer->isChecked()) {
191			gba->override.hardware |= HW_GB_PLAYER_DETECTION;
192		}
193
194		bool ok;
195		uint32_t parsedIdleLoop = m_ui.idleLoop->text().toInt(&ok, 16);
196		if (ok) {
197			gba->override.idleLoop = parsedIdleLoop;
198		}
199
200		if (gba->override.savetype != SAVEDATA_AUTODETECT || gba->override.hardware != HW_NO_OVERRIDE ||
201		    gba->override.idleLoop != IDLE_LOOP_NONE) {
202			m_controller->setOverride(gba);
203		} else {
204			m_controller->clearOverride();
205			delete gba;
206		}
207	}
208#endif
209#ifdef M_CORE_GB
210	if (m_ui.tabWidget->currentWidget() == m_ui.tabGB) {
211		GBOverride* gb = new GBOverride;
212		gb->override.mbc = s_mbcList[m_ui.mbc->currentIndex()];
213		gb->override.model = s_gbModelList[m_ui.gbModel->currentIndex()];
214		gb->override.gbColors[0] = m_gbColors[0];
215		gb->override.gbColors[1] = m_gbColors[1];
216		gb->override.gbColors[2] = m_gbColors[2];
217		gb->override.gbColors[3] = m_gbColors[3];
218		bool hasOverride = gb->override.mbc != GB_MBC_AUTODETECT || gb->override.model != GB_MODEL_AUTODETECT;
219		hasOverride = hasOverride || (m_gbColors[0] | m_gbColors[1] | m_gbColors[2] | m_gbColors[3]);
220		if (hasOverride) {
221			m_controller->setOverride(gb);
222		} else {
223			m_controller->clearOverride();
224			delete gb;
225		}
226	}
227#endif
228}
229
230void OverrideView::gameStarted(mCoreThread* thread) {
231	if (!thread->core) {
232		gameStopped();
233		return;
234	}
235
236	m_ui.tabWidget->setEnabled(false);
237
238	switch (thread->core->platform(thread->core)) {
239#ifdef M_CORE_GBA
240	case PLATFORM_GBA: {
241		m_ui.tabWidget->setCurrentWidget(m_ui.tabGBA);
242		GBA* gba = static_cast<GBA*>(thread->core->board);
243		m_ui.savetype->setCurrentIndex(gba->memory.savedata.type + 1);
244		m_ui.hwRTC->setChecked(gba->memory.hw.devices & HW_RTC);
245		m_ui.hwGyro->setChecked(gba->memory.hw.devices & HW_GYRO);
246		m_ui.hwLight->setChecked(gba->memory.hw.devices & HW_LIGHT_SENSOR);
247		m_ui.hwTilt->setChecked(gba->memory.hw.devices & HW_TILT);
248		m_ui.hwRumble->setChecked(gba->memory.hw.devices & HW_RUMBLE);
249		m_ui.hwGBPlayer->setChecked(gba->memory.hw.devices & HW_GB_PLAYER_DETECTION);
250
251		if (gba->idleLoop != IDLE_LOOP_NONE) {
252			m_ui.idleLoop->setText(QString::number(gba->idleLoop, 16));
253		} else {
254			m_ui.idleLoop->clear();
255		}
256		break;
257	}
258#endif
259#ifdef M_CORE_GB
260	case PLATFORM_GB: {
261		m_ui.tabWidget->setCurrentWidget(m_ui.tabGB);
262		GB* gb = static_cast<GB*>(thread->core->board);
263		int mbc = s_mbcList.indexOf(gb->memory.mbcType);
264		if (mbc >= 0) {
265			m_ui.mbc->setCurrentIndex(mbc);
266		} else {
267			m_ui.mbc->setCurrentIndex(0);
268		}
269		int model = s_gbModelList.indexOf(gb->model);
270		if (model >= 0) {
271			m_ui.gbModel->setCurrentIndex(model);
272		} else {
273			m_ui.gbModel->setCurrentIndex(0);
274		}
275		break;
276	}
277#endif
278	case PLATFORM_NONE:
279		break;
280	}
281
282	if (m_savePending) {
283		m_savePending = false;
284		saveOverride();
285	}
286}
287
288void OverrideView::gameStopped() {
289	m_ui.tabWidget->setEnabled(true);
290	m_ui.savetype->setCurrentIndex(0);
291	m_ui.idleLoop->clear();
292
293	m_ui.mbc->setCurrentIndex(0);
294	m_ui.gbModel->setCurrentIndex(0);
295
296	updateOverrides();
297}