all repos — mgba @ 475c7790c5ddd94127eaa0f4b6b569e7beae2f79

mGBA Game Boy Advance Emulator

src/platform/qt/BattleChipView.cpp (view raw)

  1/* Copyright (c) 2013-2019 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 "BattleChipView.h"
  7
  8#include "ConfigController.h"
  9#include "CoreController.h"
 10#include "GBAApp.h"
 11
 12#include <QtAlgorithms>
 13#include <QFile>
 14#include <QFontMetrics>
 15#include <QResource>
 16#include <QSettings>
 17#include <QStringList>
 18
 19using namespace QGBA;
 20
 21BattleChipView::BattleChipView(std::shared_ptr<CoreController> controller, QWidget* parent)
 22	: QDialog(parent)
 23	, m_controller(controller)
 24{
 25	QResource::registerResource(GBAApp::dataDir() + "/chips.rcc");
 26	QResource::registerResource(ConfigController::configDir() + "/chips.rcc");
 27
 28	m_ui.setupUi(this);
 29
 30	char title[9];
 31	CoreController::Interrupter interrupter(m_controller);
 32	mCore* core = m_controller->thread()->core;
 33	title[8] = '\0';
 34	core->getGameCode(core, title);
 35	QString qtitle(title);
 36
 37#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
 38	int size = QFontMetrics(QFont()).height() / ((int) ceil(devicePixelRatioF()) * 16);
 39#else
 40	int size = QFontMetrics(QFont()).height() / (devicePixelRatio() * 16);
 41#endif
 42	m_ui.chipList->setGridSize(m_ui.chipList->gridSize() * size);
 43	m_ui.chipList->setIconSize(m_ui.chipList->iconSize() * size);
 44
 45	connect(m_ui.chipId, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), m_ui.inserted, [this]() {
 46		m_ui.inserted->setChecked(Qt::Unchecked);
 47	});
 48	connect(m_ui.chipName, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), m_ui.chipId, [this](int id) {
 49		m_ui.chipId->setValue(m_chipIndexToId[id]);
 50	});
 51
 52	connect(m_ui.inserted, &QAbstractButton::toggled, this, &BattleChipView::insertChip);
 53	connect(m_ui.insert, &QAbstractButton::clicked, this, &BattleChipView::reinsert);
 54	connect(m_ui.add, &QAbstractButton::clicked, this, &BattleChipView::addChip);
 55	connect(m_ui.remove, &QAbstractButton::clicked, this, &BattleChipView::removeChip);
 56	connect(controller.get(), &CoreController::stopping, this, &QWidget::close);
 57	connect(m_ui.save, &QAbstractButton::clicked, this, &BattleChipView::saveDeck);
 58	connect(m_ui.load, &QAbstractButton::clicked, this, &BattleChipView::loadDeck);
 59
 60	connect(m_ui.gateBattleChip, &QAbstractButton::toggled, this, [this](bool on) {
 61		if (on) {
 62			setFlavor(GBA_FLAVOR_BATTLECHIP_GATE);
 63		}
 64	});
 65	connect(m_ui.gateProgress, &QAbstractButton::toggled, this, [this](bool on) {
 66		if (on) {
 67			setFlavor(GBA_FLAVOR_PROGRESS_GATE);
 68		}
 69	});
 70	connect(m_ui.gateBeastLink, &QAbstractButton::toggled, this, [this, qtitle](bool on) {
 71		if (on) {
 72			if (qtitle.endsWith('E') || qtitle.endsWith('P')) {
 73				setFlavor(GBA_FLAVOR_BEAST_LINK_GATE_US);
 74			} else {
 75				setFlavor(GBA_FLAVOR_BEAST_LINK_GATE);
 76			}
 77		}
 78	});
 79
 80	connect(m_controller.get(), &CoreController::frameAvailable, this, &BattleChipView::advanceFrameCounter);
 81
 82	connect(m_ui.chipList, &QListWidget::itemClicked, this, [this](QListWidgetItem* item) {
 83		QVariant chip = item->data(Qt::UserRole);
 84		bool blocked = m_ui.chipId->blockSignals(true);
 85		m_ui.chipId->setValue(chip.toInt());
 86		m_ui.chipId->blockSignals(blocked);
 87		reinsert();
 88	});
 89
 90	m_controller->attachBattleChipGate();
 91	setFlavor(4);
 92	if (qtitle.startsWith("AGB-B4B") || qtitle.startsWith("AGB-B4W") || qtitle.startsWith("AGB-BR4") || qtitle.startsWith("AGB-BZ3")) {
 93		m_ui.gateBattleChip->setChecked(Qt::Checked);
 94	} else if (qtitle.startsWith("AGB-BRB") || qtitle.startsWith("AGB-BRK")) {
 95		m_ui.gateProgress->setChecked(Qt::Checked);
 96	} else if (qtitle.startsWith("AGB-BR5") || qtitle.startsWith("AGB-BR6")) {
 97		m_ui.gateBeastLink->setChecked(Qt::Checked);
 98	}
 99}
100
101BattleChipView::~BattleChipView() {
102	m_controller->detachBattleChipGate();
103}
104
105void BattleChipView::setFlavor(int flavor) {
106	m_controller->setBattleChipFlavor(flavor);
107	loadChipNames(flavor);
108}
109
110void BattleChipView::insertChip(bool inserted) {
111	bool blocked = m_ui.inserted->blockSignals(true);
112	m_ui.inserted->setChecked(inserted);
113	m_ui.inserted->blockSignals(blocked);
114	if (inserted) {
115		m_controller->setBattleChipId(m_ui.chipId->value());
116	} else {
117		m_controller->setBattleChipId(0);
118	}
119}
120
121void BattleChipView::reinsert() {
122	if (m_ui.inserted->isChecked()) {
123		insertChip(false);
124		m_next = true;
125		m_frameCounter = UNINSERTED_TIME;
126	} else {
127		insertChip(true);
128	}
129}
130
131void BattleChipView::addChip() {
132	int insertedChip = m_ui.chipId->value();
133	if (insertedChip < 1) {
134		return;
135	}
136	addChipId(insertedChip);
137}
138
139void BattleChipView::addChipId(int id) {
140	QListWidgetItem* add = new QListWidgetItem(m_chipIdToName[id]);
141	add->setData(Qt::UserRole, id);
142	QString path = QString(":/res/exe%1/%2.png").arg(m_flavor).arg(id, 3, 10, QLatin1Char('0'));
143	if (!QFile(path).exists()) {
144		path = QString(":/res/exe%1/placeholder.png").arg(m_flavor);
145	}
146	add->setIcon(QIcon(path));
147	m_ui.chipList->addItem(add);
148}
149
150void BattleChipView::removeChip() {
151	qDeleteAll(m_ui.chipList->selectedItems());
152}
153
154void BattleChipView::loadChipNames(int flavor) {
155	QStringList chipNames;
156	chipNames.append(tr("(None)"));
157
158	m_chipIndexToId.clear();
159	m_chipIdToName.clear();
160	if (flavor == GBA_FLAVOR_BEAST_LINK_GATE_US) {
161		flavor = GBA_FLAVOR_BEAST_LINK_GATE;
162	}
163	m_flavor = flavor;
164
165	QFile file(QString(":/res/exe%1/chip-names.txt").arg(flavor));
166	file.open(QIODevice::ReadOnly | QIODevice::Text);
167	int id = 0;
168	while (true) {
169		QByteArray line = file.readLine();
170		if (line.isEmpty()) {
171			break;
172		}
173		++id;
174		if (line.trimmed().isEmpty()) {
175			continue;
176		}
177		QString name = QString::fromUtf8(line).trimmed();
178		m_chipIndexToId[chipNames.length()] = id;
179		m_chipIdToName[id] = name;
180		chipNames.append(name);
181	}
182
183	m_ui.chipName->clear();
184	m_ui.chipName->addItems(chipNames);
185}
186
187void BattleChipView::advanceFrameCounter() {
188	if (m_frameCounter == 0) {
189		insertChip(m_next);
190	}
191	if (m_frameCounter >= 0) {
192		--m_frameCounter;
193	}
194}
195
196void BattleChipView::saveDeck() {
197	QString filename = GBAApp::app()->getSaveFileName(this, tr("Select deck file"), tr(("BattleChip deck file (*.deck)")));
198	if (filename.isEmpty()) {
199		return;
200	}
201
202	QStringList deck;
203	for (int i = 0; i < m_ui.chipList->count(); ++i) {
204		deck.append(m_ui.chipList->item(i)->data(Qt::UserRole).toString());
205	}
206
207	QSettings ini(filename, QSettings::IniFormat);
208	ini.clear();
209	ini.beginGroup("BattleChipDeck");
210	ini.setValue("version", m_flavor);
211	ini.setValue("deck", deck.join(','));
212	ini.sync();
213}
214
215void BattleChipView::loadDeck() {
216	QString filename = GBAApp::app()->getOpenFileName(this, tr("Select deck file"), tr(("BattleChip deck file (*.deck)")));
217	if (filename.isEmpty()) {
218		return;
219	}
220
221	QSettings ini(filename, QSettings::IniFormat);
222	ini.beginGroup("BattleChipDeck");
223	int flavor = ini.value("version").toInt();
224	if (flavor != m_flavor) {
225		return;
226	}
227
228	while (m_ui.chipList->count()) {
229		delete m_ui.chipList->takeItem(m_ui.chipList->count() - 1);
230	}
231	QStringList deck = ini.value("deck").toString().split(',');
232	for (const auto& item : deck) {
233		bool ok;
234		int id = item.toInt(&ok);
235		if (ok) {
236			addChipId(id);
237		}
238	}
239}