all repos — mgba @ 9b0393d50ffcd27c487740098c3c0bb72b16529f

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