all repos — mgba @ b527b7ff9bd48c48158028d2110668e445d8f12c

mGBA Game Boy Advance Emulator

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

  1/* Copyright (c) 2013-2015 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 "ConfigController.h"
  7
  8#include "ActionMapper.h"
  9#include "CoreController.h"
 10
 11#include <QDir>
 12#include <QMenu>
 13
 14#include <mgba/feature/commandline.h>
 15
 16using namespace QGBA;
 17
 18ConfigOption::ConfigOption(const QString& name, QObject* parent)
 19	: QObject(parent)
 20	, m_name(name)
 21{
 22}
 23
 24void ConfigOption::connect(std::function<void(const QVariant&)> slot, QObject* parent) {
 25	m_slots[parent] = slot;
 26	QObject::connect(parent, &QObject::destroyed, [this, slot, parent]() {
 27		m_slots.remove(parent);
 28	});
 29}
 30
 31Action* ConfigOption::addValue(const QString& text, const QVariant& value, ActionMapper* actions, const QString& menu) {
 32	Action* action;
 33	auto function = [this, value]() {
 34		emit valueChanged(value);
 35	};
 36	QString name = QString("%1.%2").arg(m_name).arg(value.toString());
 37	if (actions) {
 38		action = actions->addAction(text, name, function, menu);
 39	} else {
 40		action = new Action(function, name, text);
 41	}
 42	action->setExclusive();
 43	QObject::connect(action, &QObject::destroyed, [this, action, value]() {
 44		m_actions.removeAll(std::make_pair(action, value));
 45	});
 46	m_actions.append(std::make_pair(action, value));
 47	return action;
 48}
 49
 50Action* ConfigOption::addValue(const QString& text, const char* value, ActionMapper* actions, const QString& menu) {
 51	return addValue(text, QString(value), actions, menu);
 52}
 53
 54Action* ConfigOption::addBoolean(const QString& text, ActionMapper* actions, const QString& menu) {
 55	Action* action;
 56	auto function = [this](bool value) {
 57		emit valueChanged(value);
 58	};
 59	if (actions) {
 60		action = actions->addBooleanAction(text, m_name, function, menu);
 61	} else {
 62		action = new Action(function, m_name, text);
 63	}
 64
 65	QObject::connect(action, &QObject::destroyed, [this, action]() {
 66		m_actions.removeAll(std::make_pair(action, 1));
 67	});
 68	m_actions.append(std::make_pair(action, 1));
 69
 70	return action;
 71}
 72
 73void ConfigOption::setValue(bool value) {
 74	setValue(QVariant(value));
 75}
 76
 77void ConfigOption::setValue(int value) {
 78	setValue(QVariant(value));
 79}
 80
 81void ConfigOption::setValue(unsigned value) {
 82	setValue(QVariant(value));
 83}
 84
 85void ConfigOption::setValue(const char* value) {
 86	setValue(QVariant(QString(value)));
 87}
 88
 89void ConfigOption::setValue(const QVariant& value) {
 90	for (std::pair<Action*, QVariant>& action : m_actions) {
 91		action.first->setActive(value == action.second);
 92	}
 93	for (std::function<void(const QVariant&)>& slot : m_slots.values()) {
 94		slot(value);
 95	}
 96}
 97
 98QString ConfigController::s_configDir;
 99
100ConfigController::ConfigController(QObject* parent)
101	: QObject(parent)
102{
103	QString fileName = configDir();
104	fileName.append(QDir::separator());
105	fileName.append("qt.ini");
106	m_settings = new QSettings(fileName, QSettings::IniFormat, this);
107
108	mCoreConfigInit(&m_config, PORT);
109
110	m_opts.audioSync = CoreController::AUDIO_SYNC;
111	m_opts.videoSync = CoreController::VIDEO_SYNC;
112	m_opts.fpsTarget = 60;
113	m_opts.audioBuffers = 1536;
114	m_opts.sampleRate = 44100;
115	m_opts.volume = 0x100;
116	m_opts.logLevel = mLOG_WARN | mLOG_ERROR | mLOG_FATAL;
117	m_opts.rewindEnable = false;
118	m_opts.rewindBufferCapacity = 300;
119	m_opts.useBios = true;
120	m_opts.suspendScreensaver = true;
121	m_opts.lockAspectRatio = true;
122	m_opts.interframeBlending = false;
123	mCoreConfigLoad(&m_config);
124	mCoreConfigLoadDefaults(&m_config, &m_opts);
125	mCoreConfigSetDefaultIntValue(&m_config, "sgb.borders", 1);
126	mCoreConfigSetDefaultIntValue(&m_config, "useCgbColors", 1);
127	mCoreConfigMap(&m_config, &m_opts);
128}
129
130ConfigController::~ConfigController() {
131	mCoreConfigDeinit(&m_config);
132	mCoreConfigFreeOpts(&m_opts);
133}
134
135bool ConfigController::parseArguments(mArguments* args, int argc, char* argv[], mSubParser* subparser) {
136	if (::parseArguments(args, argc, argv, subparser)) {
137		mCoreConfigFreeOpts(&m_opts);
138		applyArguments(args, subparser, &m_config);
139		mCoreConfigMap(&m_config, &m_opts);
140		return true;
141	}
142	return false;
143}
144
145ConfigOption* ConfigController::addOption(const char* key) {
146	QString optionName(key);
147
148	if (m_optionSet.contains(optionName)) {
149		return m_optionSet[optionName];
150	}
151	ConfigOption* newOption = new ConfigOption(optionName, this);
152	m_optionSet[optionName] = newOption;
153	connect(newOption, &ConfigOption::valueChanged, [this, key](const QVariant& value) {
154		setOption(key, value);
155	});
156	return newOption;
157}
158
159void ConfigController::updateOption(const char* key) {
160	if (!key) {
161		return;
162	}
163
164	QString optionName(key);
165
166	if (!m_optionSet.contains(optionName)) {
167		return;
168	}
169	m_optionSet[optionName]->setValue(mCoreConfigGetValue(&m_config, key));
170}
171
172QString ConfigController::getOption(const char* key, const QVariant& defaultVal) const {
173	const char* val = mCoreConfigGetValue(&m_config, key);
174	if (val) {
175		return QString(val);
176	}
177	return defaultVal.toString();
178}
179
180QString ConfigController::getOption(const QString& key, const QVariant& defaultVal) const {
181	return getOption(key.toUtf8().constData(), defaultVal);
182}
183
184QVariant ConfigController::getQtOption(const QString& key, const QString& group) const {
185	if (!group.isNull()) {
186		m_settings->beginGroup(group);
187	}
188	QVariant value = m_settings->value(key);
189	if (!group.isNull()) {
190		m_settings->endGroup();
191	}
192	return value;
193}
194
195void ConfigController::saveOverride(const Override& override) {
196	override.save(overrides());
197	write();
198}
199
200void ConfigController::setOption(const char* key, bool value) {
201	mCoreConfigSetIntValue(&m_config, key, value);
202	QString optionName(key);
203	if (m_optionSet.contains(optionName)) {
204		m_optionSet[optionName]->setValue(value);
205	}
206}
207
208void ConfigController::setOption(const char* key, int value) {
209	mCoreConfigSetIntValue(&m_config, key, value);
210	QString optionName(key);
211	if (m_optionSet.contains(optionName)) {
212		m_optionSet[optionName]->setValue(value);
213	}
214}
215
216void ConfigController::setOption(const char* key, unsigned value) {
217	mCoreConfigSetUIntValue(&m_config, key, value);
218	QString optionName(key);
219	if (m_optionSet.contains(optionName)) {
220		m_optionSet[optionName]->setValue(value);
221	}
222}
223
224void ConfigController::setOption(const char* key, const char* value) {
225	mCoreConfigSetValue(&m_config, key, value);
226	QString optionName(key);
227	if (m_optionSet.contains(optionName)) {
228		m_optionSet[optionName]->setValue(value);
229	}
230}
231
232void ConfigController::setOption(const char* key, const QVariant& value) {
233	if (value.type() == QVariant::Bool) {
234		setOption(key, value.toBool());
235		return;
236	}
237	QString stringValue(value.toString());
238	setOption(key, stringValue.toUtf8().constData());
239}
240
241void ConfigController::setQtOption(const QString& key, const QVariant& value, const QString& group) {
242	if (!group.isNull()) {
243		m_settings->beginGroup(group);
244	}
245	m_settings->setValue(key, value);
246	if (!group.isNull()) {
247		m_settings->endGroup();
248	}
249}
250
251QList<QString> ConfigController::getMRU() const {
252	QList<QString> mru;
253	m_settings->beginGroup("mru");
254	for (int i = 0; i < MRU_LIST_SIZE; ++i) {
255		QString item = m_settings->value(QString::number(i)).toString();
256		if (item.isNull()) {
257			continue;
258		}
259		mru.append(item);
260	}
261	m_settings->endGroup();
262	return mru;
263}
264
265void ConfigController::setMRU(const QList<QString>& mru) {
266	int i = 0;
267	m_settings->beginGroup("mru");
268	for (const QString& item : mru) {
269		m_settings->setValue(QString::number(i), item);
270		++i;
271		if (i >= MRU_LIST_SIZE) {
272			break;
273		}
274	}
275	for (; i < MRU_LIST_SIZE; ++i) {
276		m_settings->remove(QString::number(i));
277	}
278	m_settings->endGroup();
279}
280
281void ConfigController::write() {
282	mCoreConfigSave(&m_config);
283	m_settings->sync();
284
285	mCoreConfigFreeOpts(&m_opts);
286	mCoreConfigMap(&m_config, &m_opts);
287}
288
289void ConfigController::makePortable() {
290	mCoreConfigMakePortable(&m_config);
291
292	QString fileName(configDir());
293	fileName.append(QDir::separator());
294	fileName.append("qt.ini");
295	QSettings* settings2 = new QSettings(fileName, QSettings::IniFormat, this);
296	for (const auto& key : m_settings->allKeys()) {
297		settings2->setValue(key, m_settings->value(key));
298	}
299	delete m_settings;
300	m_settings = settings2;
301}
302
303bool ConfigController::isPortable() {
304	return mCoreConfigIsPortable();
305}
306
307const QString& ConfigController::configDir() {
308	if (s_configDir.isNull()) {
309		char path[PATH_MAX];
310		mCoreConfigDirectory(path, sizeof(path));
311		s_configDir = QString::fromUtf8(path);
312	}
313	return s_configDir;
314}