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