1 // Copyright 2015 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include "DolphinQt/Settings.h"
6
7 #include <QApplication>
8 #include <QDir>
9 #include <QFile>
10 #include <QFileInfo>
11 #include <QFontDatabase>
12 #include <QSize>
13
14 #include "AudioCommon/AudioCommon.h"
15
16 #include "Common/Config/Config.h"
17 #include "Common/FileUtil.h"
18 #include "Common/StringUtil.h"
19
20 #include "Core/Config/MainSettings.h"
21 #include "Core/ConfigManager.h"
22 #include "Core/Core.h"
23 #include "Core/IOS/IOS.h"
24 #include "Core/NetPlayClient.h"
25 #include "Core/NetPlayServer.h"
26
27 #include "DolphinQt/GameList/GameListModel.h"
28 #include "DolphinQt/QtUtils/QueueOnObject.h"
29
30 #include "InputCommon/ControllerInterface/ControllerInterface.h"
31 #include "InputCommon/InputConfig.h"
32
33 #include "VideoCommon/NetPlayChatUI.h"
34 #include "VideoCommon/NetPlayGolfUI.h"
35 #include "VideoCommon/RenderBase.h"
36
Settings()37 Settings::Settings()
38 {
39 qRegisterMetaType<Core::State>();
40 Core::SetOnStateChangedCallback([this](Core::State new_state) {
41 QueueOnObject(this, [this, new_state] { emit EmulationStateChanged(new_state); });
42 });
43
44 Config::AddConfigChangedCallback(
45 [this] { QueueOnObject(this, [this] { emit ConfigChanged(); }); });
46
47 g_controller_interface.RegisterDevicesChangedCallback(
48 [this] { QueueOnObject(this, [this] { emit DevicesChanged(); }); });
49
50 SetCurrentUserStyle(GetCurrentUserStyle());
51 }
52
53 Settings::~Settings() = default;
54
Instance()55 Settings& Settings::Instance()
56 {
57 static Settings settings;
58 return settings;
59 }
60
GetQSettings()61 QSettings& Settings::GetQSettings()
62 {
63 static QSettings settings(
64 QStringLiteral("%1/Qt.ini").arg(QString::fromStdString(File::GetUserPath(D_CONFIG_IDX))),
65 QSettings::IniFormat);
66 return settings;
67 }
68
SetThemeName(const QString & theme_name)69 void Settings::SetThemeName(const QString& theme_name)
70 {
71 SConfig::GetInstance().theme_name = theme_name.toStdString();
72 emit ThemeChanged();
73 }
74
GetCurrentUserStyle() const75 QString Settings::GetCurrentUserStyle() const
76 {
77 if (GetQSettings().contains(QStringLiteral("userstyle/name")))
78 return GetQSettings().value(QStringLiteral("userstyle/name")).toString();
79
80 // Migration code for the old way of storing this setting
81 return QFileInfo(GetQSettings().value(QStringLiteral("userstyle/path")).toString()).fileName();
82 }
83
SetCurrentUserStyle(const QString & stylesheet_name)84 void Settings::SetCurrentUserStyle(const QString& stylesheet_name)
85 {
86 QString stylesheet_contents;
87
88 if (!stylesheet_name.isEmpty() && AreUserStylesEnabled())
89 {
90 // Load custom user stylesheet
91 QDir directory = QDir(QString::fromStdString(File::GetUserPath(D_STYLES_IDX)));
92 QFile stylesheet(directory.filePath(stylesheet_name));
93
94 if (stylesheet.open(QFile::ReadOnly))
95 stylesheet_contents = QString::fromUtf8(stylesheet.readAll().data());
96 }
97
98 qApp->setStyleSheet(stylesheet_contents);
99
100 GetQSettings().setValue(QStringLiteral("userstyle/name"), stylesheet_name);
101 }
102
AreUserStylesEnabled() const103 bool Settings::AreUserStylesEnabled() const
104 {
105 return GetQSettings().value(QStringLiteral("userstyle/enabled"), false).toBool();
106 }
107
SetUserStylesEnabled(bool enabled)108 void Settings::SetUserStylesEnabled(bool enabled)
109 {
110 GetQSettings().setValue(QStringLiteral("userstyle/enabled"), enabled);
111 }
112
GetPaths() const113 QStringList Settings::GetPaths() const
114 {
115 QStringList list;
116 for (const auto& path : SConfig::GetInstance().m_ISOFolder)
117 list << QString::fromStdString(path);
118 return list;
119 }
120
AddPath(const QString & qpath)121 void Settings::AddPath(const QString& qpath)
122 {
123 std::string path = qpath.toStdString();
124
125 std::vector<std::string>& paths = SConfig::GetInstance().m_ISOFolder;
126 if (std::find(paths.begin(), paths.end(), path) != paths.end())
127 return;
128
129 paths.emplace_back(path);
130 emit PathAdded(qpath);
131 }
132
RemovePath(const QString & qpath)133 void Settings::RemovePath(const QString& qpath)
134 {
135 std::string path = qpath.toStdString();
136 std::vector<std::string>& paths = SConfig::GetInstance().m_ISOFolder;
137
138 auto new_end = std::remove(paths.begin(), paths.end(), path);
139 if (new_end == paths.end())
140 return;
141
142 paths.erase(new_end, paths.end());
143 emit PathRemoved(qpath);
144 }
145
RefreshGameList()146 void Settings::RefreshGameList()
147 {
148 emit GameListRefreshRequested();
149 }
150
NotifyRefreshGameListComplete()151 void Settings::NotifyRefreshGameListComplete()
152 {
153 emit GameListRefreshCompleted();
154 }
155
RefreshMetadata()156 void Settings::RefreshMetadata()
157 {
158 emit MetadataRefreshRequested();
159 }
160
NotifyMetadataRefreshComplete()161 void Settings::NotifyMetadataRefreshComplete()
162 {
163 emit MetadataRefreshCompleted();
164 }
165
ReloadTitleDB()166 void Settings::ReloadTitleDB()
167 {
168 emit TitleDBReloadRequested();
169 }
170
IsAutoRefreshEnabled() const171 bool Settings::IsAutoRefreshEnabled() const
172 {
173 return GetQSettings().value(QStringLiteral("gamelist/autorefresh"), true).toBool();
174 }
175
SetAutoRefreshEnabled(bool enabled)176 void Settings::SetAutoRefreshEnabled(bool enabled)
177 {
178 if (IsAutoRefreshEnabled() == enabled)
179 return;
180
181 GetQSettings().setValue(QStringLiteral("gamelist/autorefresh"), enabled);
182
183 emit AutoRefreshToggled(enabled);
184 }
185
GetDefaultGame() const186 QString Settings::GetDefaultGame() const
187 {
188 return QString::fromStdString(Config::Get(Config::MAIN_DEFAULT_ISO));
189 }
190
SetDefaultGame(QString path)191 void Settings::SetDefaultGame(QString path)
192 {
193 if (GetDefaultGame() != path)
194 {
195 Config::SetBase(Config::MAIN_DEFAULT_ISO, path.toStdString());
196 emit DefaultGameChanged(path);
197 }
198 }
199
GetPreferredView() const200 bool Settings::GetPreferredView() const
201 {
202 return GetQSettings().value(QStringLiteral("PreferredView"), true).toBool();
203 }
204
SetPreferredView(bool list)205 void Settings::SetPreferredView(bool list)
206 {
207 GetQSettings().setValue(QStringLiteral("PreferredView"), list);
208 }
209
GetStateSlot() const210 int Settings::GetStateSlot() const
211 {
212 return GetQSettings().value(QStringLiteral("Emulation/StateSlot"), 1).toInt();
213 }
214
SetStateSlot(int slot)215 void Settings::SetStateSlot(int slot)
216 {
217 GetQSettings().setValue(QStringLiteral("Emulation/StateSlot"), slot);
218 }
219
SetHideCursor(bool hide_cursor)220 void Settings::SetHideCursor(bool hide_cursor)
221 {
222 SConfig::GetInstance().bHideCursor = hide_cursor;
223 emit HideCursorChanged();
224 }
225
GetHideCursor() const226 bool Settings::GetHideCursor() const
227 {
228 return SConfig::GetInstance().bHideCursor;
229 }
230
SetKeepWindowOnTop(bool top)231 void Settings::SetKeepWindowOnTop(bool top)
232 {
233 if (IsKeepWindowOnTopEnabled() == top)
234 return;
235
236 Config::SetBaseOrCurrent(Config::MAIN_KEEP_WINDOW_ON_TOP, top);
237 emit KeepWindowOnTopChanged(top);
238 }
239
IsKeepWindowOnTopEnabled() const240 bool Settings::IsKeepWindowOnTopEnabled() const
241 {
242 return Config::Get(Config::MAIN_KEEP_WINDOW_ON_TOP);
243 }
244
GetVolume() const245 int Settings::GetVolume() const
246 {
247 return SConfig::GetInstance().m_Volume;
248 }
249
SetVolume(int volume)250 void Settings::SetVolume(int volume)
251 {
252 if (GetVolume() != volume)
253 {
254 SConfig::GetInstance().m_Volume = volume;
255 emit VolumeChanged(volume);
256 }
257 }
258
IncreaseVolume(int volume)259 void Settings::IncreaseVolume(int volume)
260 {
261 AudioCommon::IncreaseVolume(volume);
262 emit VolumeChanged(GetVolume());
263 }
264
DecreaseVolume(int volume)265 void Settings::DecreaseVolume(int volume)
266 {
267 AudioCommon::DecreaseVolume(volume);
268 emit VolumeChanged(GetVolume());
269 }
270
IsLogVisible() const271 bool Settings::IsLogVisible() const
272 {
273 return GetQSettings().value(QStringLiteral("logging/logvisible")).toBool();
274 }
275
SetLogVisible(bool visible)276 void Settings::SetLogVisible(bool visible)
277 {
278 if (IsLogVisible() != visible)
279 {
280 GetQSettings().setValue(QStringLiteral("logging/logvisible"), visible);
281 emit LogVisibilityChanged(visible);
282 }
283 }
284
IsLogConfigVisible() const285 bool Settings::IsLogConfigVisible() const
286 {
287 return GetQSettings().value(QStringLiteral("logging/logconfigvisible")).toBool();
288 }
289
SetLogConfigVisible(bool visible)290 void Settings::SetLogConfigVisible(bool visible)
291 {
292 if (IsLogConfigVisible() != visible)
293 {
294 GetQSettings().setValue(QStringLiteral("logging/logconfigvisible"), visible);
295 emit LogConfigVisibilityChanged(visible);
296 }
297 }
298
GetGameListModel() const299 GameListModel* Settings::GetGameListModel() const
300 {
301 static GameListModel* model = new GameListModel;
302 return model;
303 }
304
GetNetPlayClient()305 std::shared_ptr<NetPlay::NetPlayClient> Settings::GetNetPlayClient()
306 {
307 return m_client;
308 }
309
ResetNetPlayClient(NetPlay::NetPlayClient * client)310 void Settings::ResetNetPlayClient(NetPlay::NetPlayClient* client)
311 {
312 m_client.reset(client);
313
314 g_netplay_chat_ui.reset();
315 g_netplay_golf_ui.reset();
316 }
317
GetNetPlayServer()318 std::shared_ptr<NetPlay::NetPlayServer> Settings::GetNetPlayServer()
319 {
320 return m_server;
321 }
322
ResetNetPlayServer(NetPlay::NetPlayServer * server)323 void Settings::ResetNetPlayServer(NetPlay::NetPlayServer* server)
324 {
325 m_server.reset(server);
326 }
327
GetCheatsEnabled() const328 bool Settings::GetCheatsEnabled() const
329 {
330 return SConfig::GetInstance().bEnableCheats;
331 }
332
SetCheatsEnabled(bool enabled)333 void Settings::SetCheatsEnabled(bool enabled)
334 {
335 if (SConfig::GetInstance().bEnableCheats != enabled)
336 {
337 SConfig::GetInstance().bEnableCheats = enabled;
338 emit EnableCheatsChanged(enabled);
339 }
340 }
341
SetDebugModeEnabled(bool enabled)342 void Settings::SetDebugModeEnabled(bool enabled)
343 {
344 if (IsDebugModeEnabled() != enabled)
345 {
346 SConfig::GetInstance().bEnableDebugging = enabled;
347 emit DebugModeToggled(enabled);
348 }
349 if (enabled)
350 SetCodeVisible(true);
351 }
352
IsDebugModeEnabled() const353 bool Settings::IsDebugModeEnabled() const
354 {
355 return SConfig::GetInstance().bEnableDebugging;
356 }
357
SetRegistersVisible(bool enabled)358 void Settings::SetRegistersVisible(bool enabled)
359 {
360 if (IsRegistersVisible() != enabled)
361 {
362 GetQSettings().setValue(QStringLiteral("debugger/showregisters"), enabled);
363
364 emit RegistersVisibilityChanged(enabled);
365 }
366 }
367
IsThreadsVisible() const368 bool Settings::IsThreadsVisible() const
369 {
370 return GetQSettings().value(QStringLiteral("debugger/showthreads")).toBool();
371 }
372
SetThreadsVisible(bool enabled)373 void Settings::SetThreadsVisible(bool enabled)
374 {
375 if (IsThreadsVisible() == enabled)
376 return;
377
378 GetQSettings().setValue(QStringLiteral("debugger/showthreads"), enabled);
379 emit ThreadsVisibilityChanged(enabled);
380 }
381
IsRegistersVisible() const382 bool Settings::IsRegistersVisible() const
383 {
384 return GetQSettings().value(QStringLiteral("debugger/showregisters")).toBool();
385 }
386
SetWatchVisible(bool enabled)387 void Settings::SetWatchVisible(bool enabled)
388 {
389 if (IsWatchVisible() != enabled)
390 {
391 GetQSettings().setValue(QStringLiteral("debugger/showwatch"), enabled);
392
393 emit WatchVisibilityChanged(enabled);
394 }
395 }
396
IsWatchVisible() const397 bool Settings::IsWatchVisible() const
398 {
399 return GetQSettings().value(QStringLiteral("debugger/showwatch")).toBool();
400 }
401
SetBreakpointsVisible(bool enabled)402 void Settings::SetBreakpointsVisible(bool enabled)
403 {
404 if (IsBreakpointsVisible() != enabled)
405 {
406 GetQSettings().setValue(QStringLiteral("debugger/showbreakpoints"), enabled);
407
408 emit BreakpointsVisibilityChanged(enabled);
409 }
410 }
411
IsBreakpointsVisible() const412 bool Settings::IsBreakpointsVisible() const
413 {
414 return GetQSettings().value(QStringLiteral("debugger/showbreakpoints")).toBool();
415 }
416
SetCodeVisible(bool enabled)417 void Settings::SetCodeVisible(bool enabled)
418 {
419 if (IsCodeVisible() != enabled)
420 {
421 GetQSettings().setValue(QStringLiteral("debugger/showcode"), enabled);
422
423 emit CodeVisibilityChanged(enabled);
424 }
425 }
426
IsCodeVisible() const427 bool Settings::IsCodeVisible() const
428 {
429 return GetQSettings().value(QStringLiteral("debugger/showcode")).toBool();
430 }
431
SetMemoryVisible(bool enabled)432 void Settings::SetMemoryVisible(bool enabled)
433 {
434 if (IsMemoryVisible() == enabled)
435 return;
436 QSettings().setValue(QStringLiteral("debugger/showmemory"), enabled);
437
438 emit MemoryVisibilityChanged(enabled);
439 }
440
IsMemoryVisible() const441 bool Settings::IsMemoryVisible() const
442 {
443 return QSettings().value(QStringLiteral("debugger/showmemory")).toBool();
444 }
445
SetNetworkVisible(bool enabled)446 void Settings::SetNetworkVisible(bool enabled)
447 {
448 if (IsNetworkVisible() == enabled)
449 return;
450
451 GetQSettings().setValue(QStringLiteral("debugger/shownetwork"), enabled);
452 emit NetworkVisibilityChanged(enabled);
453 }
454
IsNetworkVisible() const455 bool Settings::IsNetworkVisible() const
456 {
457 return GetQSettings().value(QStringLiteral("debugger/shownetwork")).toBool();
458 }
459
SetJITVisible(bool enabled)460 void Settings::SetJITVisible(bool enabled)
461 {
462 if (IsJITVisible() == enabled)
463 return;
464 QSettings().setValue(QStringLiteral("debugger/showjit"), enabled);
465
466 emit JITVisibilityChanged(enabled);
467 }
468
IsJITVisible() const469 bool Settings::IsJITVisible() const
470 {
471 return QSettings().value(QStringLiteral("debugger/showjit")).toBool();
472 }
473
RefreshWidgetVisibility()474 void Settings::RefreshWidgetVisibility()
475 {
476 emit DebugModeToggled(IsDebugModeEnabled());
477 emit LogVisibilityChanged(IsLogVisible());
478 emit LogConfigVisibilityChanged(IsLogConfigVisible());
479 }
480
SetDebugFont(QFont font)481 void Settings::SetDebugFont(QFont font)
482 {
483 if (GetDebugFont() != font)
484 {
485 GetQSettings().setValue(QStringLiteral("debugger/font"), font);
486
487 emit DebugFontChanged(font);
488 }
489 }
490
GetDebugFont() const491 QFont Settings::GetDebugFont() const
492 {
493 QFont default_font = QFont(QFontDatabase::systemFont(QFontDatabase::FixedFont).family());
494
495 return GetQSettings().value(QStringLiteral("debugger/font"), default_font).value<QFont>();
496 }
497
SetAutoUpdateTrack(const QString & mode)498 void Settings::SetAutoUpdateTrack(const QString& mode)
499 {
500 if (mode == GetAutoUpdateTrack())
501 return;
502
503 SConfig::GetInstance().m_auto_update_track = mode.toStdString();
504
505 emit AutoUpdateTrackChanged(mode);
506 }
507
GetAutoUpdateTrack() const508 QString Settings::GetAutoUpdateTrack() const
509 {
510 return QString::fromStdString(SConfig::GetInstance().m_auto_update_track);
511 }
512
SetAnalyticsEnabled(bool enabled)513 void Settings::SetAnalyticsEnabled(bool enabled)
514 {
515 if (enabled == IsAnalyticsEnabled())
516 return;
517
518 Config::SetBase(Config::MAIN_ANALYTICS_ENABLED, enabled);
519
520 emit AnalyticsToggled(enabled);
521 }
522
IsAnalyticsEnabled() const523 bool Settings::IsAnalyticsEnabled() const
524 {
525 return Config::Get(Config::MAIN_ANALYTICS_ENABLED);
526 }
527
SetToolBarVisible(bool visible)528 void Settings::SetToolBarVisible(bool visible)
529 {
530 if (IsToolBarVisible() == visible)
531 return;
532
533 GetQSettings().setValue(QStringLiteral("toolbar/visible"), visible);
534
535 emit ToolBarVisibilityChanged(visible);
536 }
537
IsToolBarVisible() const538 bool Settings::IsToolBarVisible() const
539 {
540 return GetQSettings().value(QStringLiteral("toolbar/visible"), true).toBool();
541 }
542
SetWidgetsLocked(bool locked)543 void Settings::SetWidgetsLocked(bool locked)
544 {
545 if (AreWidgetsLocked() == locked)
546 return;
547
548 GetQSettings().setValue(QStringLiteral("widgets/locked"), locked);
549
550 emit WidgetLockChanged(locked);
551 }
552
AreWidgetsLocked() const553 bool Settings::AreWidgetsLocked() const
554 {
555 return GetQSettings().value(QStringLiteral("widgets/locked"), true).toBool();
556 }
557
IsBatchModeEnabled() const558 bool Settings::IsBatchModeEnabled() const
559 {
560 return m_batch;
561 }
SetBatchModeEnabled(bool batch)562 void Settings::SetBatchModeEnabled(bool batch)
563 {
564 m_batch = batch;
565 }
566
IsSDCardInserted() const567 bool Settings::IsSDCardInserted() const
568 {
569 return SConfig::GetInstance().m_WiiSDCard;
570 }
571
SetSDCardInserted(bool inserted)572 void Settings::SetSDCardInserted(bool inserted)
573 {
574 if (IsSDCardInserted() != inserted)
575 {
576 SConfig::GetInstance().m_WiiSDCard = inserted;
577 emit SDCardInsertionChanged(inserted);
578
579 auto* ios = IOS::HLE::GetIOS();
580 if (ios)
581 ios->SDIO_EventNotify();
582 }
583 }
584
IsUSBKeyboardConnected() const585 bool Settings::IsUSBKeyboardConnected() const
586 {
587 return SConfig::GetInstance().m_WiiKeyboard;
588 }
589
SetUSBKeyboardConnected(bool connected)590 void Settings::SetUSBKeyboardConnected(bool connected)
591 {
592 if (IsUSBKeyboardConnected() != connected)
593 {
594 SConfig::GetInstance().m_WiiKeyboard = connected;
595 emit USBKeyboardConnectionChanged(connected);
596 }
597 }
598