MainWindow.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. using DiscordRPC;
  2. using Gtk;
  3. using GUI = Gtk.Builder.ObjectAttribute;
  4. using Ryujinx.Audio;
  5. using Ryujinx.Common.Logging;
  6. using Ryujinx.Graphics.Gal;
  7. using Ryujinx.Graphics.Gal.OpenGL;
  8. using Ryujinx.Profiler;
  9. using System;
  10. using System.Diagnostics;
  11. using System.IO;
  12. using System.Linq;
  13. using System.Reflection;
  14. using System.Text;
  15. using System.Threading;
  16. namespace Ryujinx.UI
  17. {
  18. public class MainWindow : Window
  19. {
  20. internal static HLE.Switch _device;
  21. private static IGalRenderer _renderer;
  22. private static IAalOutput _audioOut;
  23. private static Application _gtkApplication;
  24. private static ListStore _tableStore;
  25. private static bool _gameLoaded = false;
  26. private static string _userId = "00000000000000000000000000000001";
  27. public static bool DiscordIntegrationEnabled { get; set; }
  28. public static DiscordRpcClient DiscordClient;
  29. public static RichPresence DiscordPresence;
  30. #pragma warning disable 649
  31. [GUI] Window _mainWin;
  32. [GUI] CheckMenuItem _fullScreen;
  33. [GUI] MenuItem _stopEmulation;
  34. [GUI] CheckMenuItem _iconToggle;
  35. [GUI] CheckMenuItem _titleToggle;
  36. [GUI] CheckMenuItem _developerToggle;
  37. [GUI] CheckMenuItem _versionToggle;
  38. [GUI] CheckMenuItem _timePlayedToggle;
  39. [GUI] CheckMenuItem _lastPlayedToggle;
  40. [GUI] CheckMenuItem _fileExtToggle;
  41. [GUI] CheckMenuItem _fileSizeToggle;
  42. [GUI] CheckMenuItem _pathToggle;
  43. [GUI] Box _box;
  44. [GUI] TreeView _gameTable;
  45. [GUI] GLArea _glScreen;
  46. #pragma warning restore 649
  47. public MainWindow(string[] args, Application gtkApplication) : this(new Builder("Ryujinx.Ui.MainWindow.glade"), args, gtkApplication) { }
  48. private MainWindow(Builder builder, string[] args, Application gtkApplication) : base(builder.GetObject("_mainWin").Handle)
  49. {
  50. _renderer = new OglRenderer();
  51. _audioOut = InitializeAudioEngine();
  52. _device = new HLE.Switch(_renderer, _audioOut);
  53. Configuration.Load(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  54. Configuration.InitialConfigure(_device);
  55. ApplicationLibrary.Init(SwitchSettings.SwitchConfig.GameDirs, _device.System.KeySet, _device.System.State.DesiredTitleLanguage);
  56. _gtkApplication = gtkApplication;
  57. ApplyTheme();
  58. if (DiscordIntegrationEnabled)
  59. {
  60. DiscordClient = new DiscordRpcClient("568815339807309834");
  61. DiscordPresence = new RichPresence
  62. {
  63. Assets = new Assets
  64. {
  65. LargeImageKey = "ryujinx",
  66. LargeImageText = "Ryujinx is an emulator for the Nintendo Switch"
  67. },
  68. Details = "Main Menu",
  69. State = "Idling",
  70. Timestamps = new Timestamps(DateTime.UtcNow)
  71. };
  72. DiscordClient.Initialize();
  73. DiscordClient.SetPresence(DiscordPresence);
  74. }
  75. builder.Autoconnect(this);
  76. DeleteEvent += Window_Close;
  77. _mainWin.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.ryujinxIcon.png");
  78. _stopEmulation.Sensitive = false;
  79. if (SwitchSettings.SwitchConfig.GuiColumns[0]) { _iconToggle.Active = true; }
  80. if (SwitchSettings.SwitchConfig.GuiColumns[1]) { _titleToggle.Active = true; }
  81. if (SwitchSettings.SwitchConfig.GuiColumns[2]) { _developerToggle.Active = true; }
  82. if (SwitchSettings.SwitchConfig.GuiColumns[3]) { _versionToggle.Active = true; }
  83. if (SwitchSettings.SwitchConfig.GuiColumns[4]) { _timePlayedToggle.Active = true; }
  84. if (SwitchSettings.SwitchConfig.GuiColumns[5]) { _lastPlayedToggle.Active = true; }
  85. if (SwitchSettings.SwitchConfig.GuiColumns[6]) { _fileExtToggle.Active = true; }
  86. if (SwitchSettings.SwitchConfig.GuiColumns[7]) { _fileSizeToggle.Active = true; }
  87. if (SwitchSettings.SwitchConfig.GuiColumns[8]) { _pathToggle.Active = true; }
  88. if (args.Length == 1)
  89. {
  90. // Temporary code section start, remove this section when game is rendered to the GLArea in the GUI
  91. _box.Remove(_glScreen);
  92. if (SwitchSettings.SwitchConfig.GuiColumns[0]) { _gameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 0); }
  93. if (SwitchSettings.SwitchConfig.GuiColumns[1]) { _gameTable.AppendColumn("Application", new CellRendererText(), "text", 1); }
  94. if (SwitchSettings.SwitchConfig.GuiColumns[2]) { _gameTable.AppendColumn("Developer", new CellRendererText(), "text", 2); }
  95. if (SwitchSettings.SwitchConfig.GuiColumns[3]) { _gameTable.AppendColumn("Version", new CellRendererText(), "text", 3); }
  96. if (SwitchSettings.SwitchConfig.GuiColumns[4]) { _gameTable.AppendColumn("Time Played", new CellRendererText(), "text", 4); }
  97. if (SwitchSettings.SwitchConfig.GuiColumns[5]) { _gameTable.AppendColumn("Last Played", new CellRendererText(), "text", 5); }
  98. if (SwitchSettings.SwitchConfig.GuiColumns[6]) { _gameTable.AppendColumn("File Ext", new CellRendererText(), "text", 6); }
  99. if (SwitchSettings.SwitchConfig.GuiColumns[7]) { _gameTable.AppendColumn("File Size", new CellRendererText(), "text", 7); }
  100. if (SwitchSettings.SwitchConfig.GuiColumns[8]) { _gameTable.AppendColumn("Path", new CellRendererText(), "text", 8); }
  101. _tableStore = new ListStore(typeof(Gdk.Pixbuf), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string));
  102. _gameTable.Model = _tableStore;
  103. UpdateGameTable();
  104. // Temporary code section end
  105. }
  106. else
  107. {
  108. _box.Remove(_glScreen);
  109. if (SwitchSettings.SwitchConfig.GuiColumns[0]) { _gameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 0); }
  110. if (SwitchSettings.SwitchConfig.GuiColumns[1]) { _gameTable.AppendColumn("Application", new CellRendererText(), "text", 1); }
  111. if (SwitchSettings.SwitchConfig.GuiColumns[2]) { _gameTable.AppendColumn("Developer", new CellRendererText(), "text", 2); }
  112. if (SwitchSettings.SwitchConfig.GuiColumns[3]) { _gameTable.AppendColumn("Version", new CellRendererText(), "text", 3); }
  113. if (SwitchSettings.SwitchConfig.GuiColumns[4]) { _gameTable.AppendColumn("Time Played", new CellRendererText(), "text", 4); }
  114. if (SwitchSettings.SwitchConfig.GuiColumns[5]) { _gameTable.AppendColumn("Last Played", new CellRendererText(), "text", 5); }
  115. if (SwitchSettings.SwitchConfig.GuiColumns[6]) { _gameTable.AppendColumn("File Ext", new CellRendererText(), "text", 6); }
  116. if (SwitchSettings.SwitchConfig.GuiColumns[7]) { _gameTable.AppendColumn("File Size", new CellRendererText(), "text", 7); }
  117. if (SwitchSettings.SwitchConfig.GuiColumns[8]) { _gameTable.AppendColumn("Path", new CellRendererText(), "text", 8); }
  118. _tableStore = new ListStore(typeof(Gdk.Pixbuf), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string));
  119. _gameTable.Model = _tableStore;
  120. UpdateGameTable();
  121. }
  122. }
  123. public static void CreateErrorDialog(string errorMessage)
  124. {
  125. MessageDialog errorDialog = new MessageDialog(null, DialogFlags.Modal, MessageType.Error, ButtonsType.Ok, errorMessage)
  126. {
  127. Title = "Ryujinx - Error",
  128. Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.ryujinxIcon.png"),
  129. WindowPosition = WindowPosition.Center
  130. };
  131. errorDialog.SetSizeRequest(100, 20);
  132. errorDialog.Run();
  133. errorDialog.Destroy();
  134. }
  135. public static void UpdateGameTable()
  136. {
  137. _tableStore.Clear();
  138. ApplicationLibrary.Init(SwitchSettings.SwitchConfig.GameDirs, _device.System.KeySet, _device.System.State.DesiredTitleLanguage);
  139. foreach (ApplicationLibrary.ApplicationData AppData in ApplicationLibrary.ApplicationLibraryData)
  140. {
  141. _tableStore.AppendValues(new Gdk.Pixbuf(AppData.Icon, 75, 75), $"{AppData.TitleName}\n{AppData.TitleId.ToUpper()}", AppData.Developer, AppData.Version, AppData.TimePlayed, AppData.LastPlayed, AppData.FileExt, AppData.FileSize, AppData.Path);
  142. }
  143. }
  144. public static void ApplyTheme()
  145. {
  146. CssProvider cssProvider = new CssProvider();
  147. if (SwitchSettings.SwitchConfig.EnableCustomTheme)
  148. {
  149. if (File.Exists(SwitchSettings.SwitchConfig.CustomThemePath) && (System.IO.Path.GetExtension(SwitchSettings.SwitchConfig.CustomThemePath) == ".css"))
  150. {
  151. cssProvider.LoadFromPath(SwitchSettings.SwitchConfig.CustomThemePath);
  152. }
  153. else
  154. {
  155. Logger.PrintWarning(LogClass.Application, $"The \"custom_theme_path\" section in \"Config.json\" contains an invalid path: \"{SwitchSettings.SwitchConfig.CustomThemePath}\"");
  156. }
  157. }
  158. else
  159. {
  160. cssProvider.LoadFromPath(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Theme.css"));
  161. }
  162. StyleContext.AddProviderForScreen(Gdk.Screen.Default, cssProvider, 800);
  163. }
  164. internal void LoadApplication(string path)
  165. {
  166. if (_gameLoaded)
  167. {
  168. CreateErrorDialog("A game has already been loaded. Please close the emulator and try again");
  169. }
  170. else
  171. {
  172. if (Directory.Exists(path))
  173. {
  174. string[] romFsFiles = Directory.GetFiles(path, "*.istorage");
  175. if (romFsFiles.Length == 0)
  176. {
  177. romFsFiles = Directory.GetFiles(path, "*.romfs");
  178. }
  179. if (romFsFiles.Length > 0)
  180. {
  181. Logger.PrintInfo(LogClass.Application, "Loading as cart with RomFS.");
  182. _device.LoadCart(path, romFsFiles[0]);
  183. }
  184. else
  185. {
  186. Logger.PrintInfo(LogClass.Application, "Loading as cart WITHOUT RomFS.");
  187. _device.LoadCart(path);
  188. }
  189. }
  190. else if (File.Exists(path))
  191. {
  192. switch (System.IO.Path.GetExtension(path).ToLowerInvariant())
  193. {
  194. case ".xci":
  195. Logger.PrintInfo(LogClass.Application, "Loading as XCI.");
  196. _device.LoadXci(path);
  197. break;
  198. case ".nca":
  199. Logger.PrintInfo(LogClass.Application, "Loading as NCA.");
  200. _device.LoadNca(path);
  201. break;
  202. case ".nsp":
  203. case ".pfs0":
  204. Logger.PrintInfo(LogClass.Application, "Loading as NSP.");
  205. _device.LoadNsp(path);
  206. break;
  207. default:
  208. Logger.PrintInfo(LogClass.Application, "Loading as homebrew.");
  209. try
  210. {
  211. _device.LoadProgram(path);
  212. }
  213. catch (ArgumentOutOfRangeException)
  214. {
  215. Logger.PrintError(LogClass.Application, $"The file which you have specified is unsupported by Ryujinx");
  216. }
  217. break;
  218. }
  219. }
  220. else
  221. {
  222. Logger.PrintWarning(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file");
  223. End();
  224. }
  225. new Thread(new ThreadStart(CreateGameWindow)).Start();
  226. _gameLoaded = true;
  227. _stopEmulation.Sensitive = true;
  228. if (DiscordIntegrationEnabled)
  229. {
  230. if (File.ReadAllLines(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "RPsupported.dat")).Contains(_device.System.TitleID))
  231. {
  232. DiscordPresence.Assets.LargeImageKey = _device.System.TitleID;
  233. }
  234. string state = _device.System.TitleID;
  235. if (state == null)
  236. {
  237. state = "Ryujinx";
  238. }
  239. else
  240. {
  241. state = state.ToUpper();
  242. }
  243. string details = "Idling";
  244. if (_device.System.TitleName != null)
  245. {
  246. details = $"Playing {_device.System.TitleName}";
  247. }
  248. DiscordPresence.Details = details;
  249. DiscordPresence.State = state;
  250. DiscordPresence.Assets.LargeImageText = _device.System.TitleName;
  251. DiscordPresence.Assets.SmallImageKey = "ryujinx";
  252. DiscordPresence.Assets.SmallImageText = "Ryujinx is an emulator for the Nintendo Switch";
  253. DiscordPresence.Timestamps = new Timestamps(DateTime.UtcNow);
  254. DiscordClient.SetPresence(DiscordPresence);
  255. }
  256. try
  257. {
  258. string savePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFS", "nand", "user", "save", "0000000000000000", _userId, _device.System.TitleID);
  259. if (File.Exists(System.IO.Path.Combine(savePath, "TimePlayed.dat")) == false)
  260. {
  261. Directory.CreateDirectory(savePath);
  262. using (FileStream stream = File.OpenWrite(System.IO.Path.Combine(savePath, "TimePlayed.dat")))
  263. {
  264. stream.Write(Encoding.ASCII.GetBytes("0"));
  265. }
  266. }
  267. if (File.Exists(System.IO.Path.Combine(savePath, "LastPlayed.dat")) == false)
  268. {
  269. Directory.CreateDirectory(savePath);
  270. using (FileStream stream = File.OpenWrite(System.IO.Path.Combine(savePath, "LastPlayed.dat")))
  271. {
  272. stream.Write(Encoding.ASCII.GetBytes("Never"));
  273. }
  274. }
  275. using (FileStream stream = File.OpenWrite(System.IO.Path.Combine(savePath, "LastPlayed.dat")))
  276. {
  277. using (StreamWriter writer = new StreamWriter(stream))
  278. {
  279. writer.WriteLine(DateTime.UtcNow);
  280. }
  281. }
  282. }
  283. catch (ArgumentNullException)
  284. {
  285. Logger.PrintWarning(LogClass.Application, $"Could not access save path to retrieve time/last played data using: UserID: {_userId}, TitleID: {_device.System.TitleID}");
  286. }
  287. }
  288. }
  289. private static void CreateGameWindow()
  290. {
  291. Configuration.ConfigureHid(_device, SwitchSettings.SwitchConfig);
  292. using (GlScreen screen = new GlScreen(_device, _renderer))
  293. {
  294. screen.MainLoop();
  295. End();
  296. }
  297. }
  298. private static void End()
  299. {
  300. if (_gameLoaded)
  301. {
  302. try
  303. {
  304. string savePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFS", "nand", "user", "save", "0000000000000000", _userId, _device.System.TitleID);
  305. double currentPlayTime = 0;
  306. using (FileStream stream = File.OpenRead(System.IO.Path.Combine(savePath, "LastPlayed.dat")))
  307. {
  308. using (StreamReader reader = new StreamReader(stream))
  309. {
  310. DateTime startTime = DateTime.Parse(reader.ReadLine());
  311. using (FileStream lastPlayedStream = File.OpenRead(System.IO.Path.Combine(savePath, "TimePlayed.dat")))
  312. {
  313. using (StreamReader lastPlayedReader = new StreamReader(lastPlayedStream))
  314. {
  315. currentPlayTime = double.Parse(lastPlayedReader.ReadLine());
  316. }
  317. }
  318. using (FileStream timePlayedStream = File.OpenWrite(System.IO.Path.Combine(savePath, "TimePlayed.dat")))
  319. {
  320. using (StreamWriter timePlayedWriter = new StreamWriter(timePlayedStream))
  321. {
  322. timePlayedWriter.WriteLine(currentPlayTime + Math.Round(DateTime.UtcNow.Subtract(startTime).TotalSeconds, MidpointRounding.AwayFromZero));
  323. }
  324. }
  325. }
  326. }
  327. }
  328. catch (ArgumentNullException)
  329. {
  330. Logger.PrintWarning(LogClass.Application, $"Could not access save path to retrieve time/last played data using: UserID: {_userId}, TitleID: {_device.System.TitleID}");
  331. }
  332. }
  333. Profile.FinishProfiling();
  334. _device.Dispose();
  335. _audioOut.Dispose();
  336. DiscordClient.Dispose();
  337. Logger.Shutdown();
  338. Environment.Exit(0);
  339. }
  340. /// <summary>
  341. /// Picks an <see cref="IAalOutput"/> audio output renderer supported on this machine
  342. /// </summary>
  343. /// <returns>An <see cref="IAalOutput"/> supported by this machine</returns>
  344. private static IAalOutput InitializeAudioEngine()
  345. {
  346. if (SoundIoAudioOut.IsSupported)
  347. {
  348. return new SoundIoAudioOut();
  349. }
  350. else if (OpenALAudioOut.IsSupported)
  351. {
  352. return new OpenALAudioOut();
  353. }
  354. else
  355. {
  356. return new DummyAudioOut();
  357. }
  358. }
  359. //Events
  360. private void Row_Activated(object o, RowActivatedArgs args)
  361. {
  362. _tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path.ToString()));
  363. string path = (string)_tableStore.GetValue(treeIter, 8);
  364. LoadApplication(path);
  365. }
  366. private void Load_Application_File(object o, EventArgs args)
  367. {
  368. FileChooserDialog fileChooser = new FileChooserDialog("Choose the file to open", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
  369. fileChooser.Filter = new FileFilter();
  370. fileChooser.Filter.AddPattern("*.nsp" );
  371. fileChooser.Filter.AddPattern("*.pfs0");
  372. fileChooser.Filter.AddPattern("*.xci" );
  373. fileChooser.Filter.AddPattern("*.nca" );
  374. fileChooser.Filter.AddPattern("*.nro" );
  375. fileChooser.Filter.AddPattern("*.nso" );
  376. if (fileChooser.Run() == (int)ResponseType.Accept)
  377. {
  378. LoadApplication(fileChooser.Filename);
  379. }
  380. fileChooser.Destroy();
  381. }
  382. private void Load_Application_Folder(object o, EventArgs args)
  383. {
  384. FileChooserDialog fileChooser = new FileChooserDialog("Choose the folder to open", this, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
  385. if (fileChooser.Run() == (int)ResponseType.Accept)
  386. {
  387. LoadApplication(fileChooser.Filename);
  388. }
  389. fileChooser.Destroy();
  390. }
  391. private void Open_Ryu_Folder(object o, EventArgs args)
  392. {
  393. Process.Start(new ProcessStartInfo()
  394. {
  395. FileName = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFs"),
  396. UseShellExecute = true,
  397. Verb = "open"
  398. });
  399. }
  400. private void Exit_Pressed(object o, EventArgs args)
  401. {
  402. End();
  403. }
  404. private void Window_Close(object o, DeleteEventArgs args)
  405. {
  406. End();
  407. }
  408. private void StopEmulation_Pressed(object o, EventArgs args)
  409. {
  410. // TODO: Write logic to kill running game
  411. }
  412. private void FullScreen_Toggled(object o, EventArgs args)
  413. {
  414. if (_fullScreen.Active)
  415. {
  416. Fullscreen();
  417. }
  418. else
  419. {
  420. Unfullscreen();
  421. }
  422. }
  423. private void Settings_Pressed(object o, EventArgs args)
  424. {
  425. SwitchSettings SettingsWin = new SwitchSettings(_device);
  426. _gtkApplication.Register(GLib.Cancellable.Current);
  427. _gtkApplication.AddWindow(SettingsWin);
  428. SettingsWin.Show();
  429. }
  430. private void Update_Pressed(object o, EventArgs args)
  431. {
  432. string ryuUpdater = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFS", "RyuUpdater.exe");
  433. try
  434. {
  435. Process.Start(new ProcessStartInfo(ryuUpdater, "/U") { UseShellExecute = true });
  436. }
  437. catch(System.ComponentModel.Win32Exception)
  438. {
  439. CreateErrorDialog("Update canceled by user or updater was not found");
  440. }
  441. }
  442. private void About_Pressed(object o, EventArgs args)
  443. {
  444. AboutWindow AboutWin = new AboutWindow();
  445. _gtkApplication.Register(GLib.Cancellable.Current);
  446. _gtkApplication.AddWindow(AboutWin);
  447. AboutWin.Show();
  448. }
  449. private void Icon_Toggled(object o, EventArgs args)
  450. {
  451. SwitchSettings.SwitchConfig.GuiColumns[0] = _iconToggle.Active;
  452. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  453. }
  454. private void Title_Toggled(object o, EventArgs args)
  455. {
  456. SwitchSettings.SwitchConfig.GuiColumns[1] = _titleToggle.Active;
  457. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  458. }
  459. private void Developer_Toggled(object o, EventArgs args)
  460. {
  461. SwitchSettings.SwitchConfig.GuiColumns[2] = _developerToggle.Active;
  462. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  463. }
  464. private void Version_Toggled(object o, EventArgs args)
  465. {
  466. SwitchSettings.SwitchConfig.GuiColumns[3] = _versionToggle.Active;
  467. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  468. }
  469. private void TimePlayed_Toggled(object o, EventArgs args)
  470. {
  471. SwitchSettings.SwitchConfig.GuiColumns[4] = _timePlayedToggle.Active;
  472. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  473. }
  474. private void LastPlayed_Toggled(object o, EventArgs args)
  475. {
  476. SwitchSettings.SwitchConfig.GuiColumns[5] = _lastPlayedToggle.Active;
  477. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  478. }
  479. private void FileExt_Toggled(object o, EventArgs args)
  480. {
  481. SwitchSettings.SwitchConfig.GuiColumns[6] = _fileExtToggle.Active;
  482. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  483. }
  484. private void FileSize_Toggled(object o, EventArgs args)
  485. {
  486. SwitchSettings.SwitchConfig.GuiColumns[7] = _fileSizeToggle.Active;
  487. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  488. }
  489. private void Path_Toggled(object o, EventArgs args)
  490. {
  491. SwitchSettings.SwitchConfig.GuiColumns[8] = _pathToggle.Active;
  492. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  493. }
  494. }
  495. }