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