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}