MainWindow.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  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. Logger.RestartTime();
  173. if (Directory.Exists(path))
  174. {
  175. string[] romFsFiles = Directory.GetFiles(path, "*.istorage");
  176. if (romFsFiles.Length == 0)
  177. {
  178. romFsFiles = Directory.GetFiles(path, "*.romfs");
  179. }
  180. if (romFsFiles.Length > 0)
  181. {
  182. Logger.PrintInfo(LogClass.Application, "Loading as cart with RomFS.");
  183. _device.LoadCart(path, romFsFiles[0]);
  184. }
  185. else
  186. {
  187. Logger.PrintInfo(LogClass.Application, "Loading as cart WITHOUT RomFS.");
  188. _device.LoadCart(path);
  189. }
  190. }
  191. else if (File.Exists(path))
  192. {
  193. switch (System.IO.Path.GetExtension(path).ToLowerInvariant())
  194. {
  195. case ".xci":
  196. Logger.PrintInfo(LogClass.Application, "Loading as XCI.");
  197. _device.LoadXci(path);
  198. break;
  199. case ".nca":
  200. Logger.PrintInfo(LogClass.Application, "Loading as NCA.");
  201. _device.LoadNca(path);
  202. break;
  203. case ".nsp":
  204. case ".pfs0":
  205. Logger.PrintInfo(LogClass.Application, "Loading as NSP.");
  206. _device.LoadNsp(path);
  207. break;
  208. default:
  209. Logger.PrintInfo(LogClass.Application, "Loading as homebrew.");
  210. try
  211. {
  212. _device.LoadProgram(path);
  213. }
  214. catch (ArgumentOutOfRangeException)
  215. {
  216. Logger.PrintError(LogClass.Application, "The file which you have specified is unsupported by Ryujinx.");
  217. }
  218. break;
  219. }
  220. }
  221. else
  222. {
  223. Logger.PrintWarning(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file.");
  224. End();
  225. }
  226. new Thread(new ThreadStart(CreateGameWindow)).Start();
  227. _gameLoaded = true;
  228. _stopEmulation.Sensitive = true;
  229. if (DiscordIntegrationEnabled)
  230. {
  231. if (File.ReadAllLines(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "RPsupported.dat")).Contains(_device.System.TitleID))
  232. {
  233. DiscordPresence.Assets.LargeImageKey = _device.System.TitleID;
  234. }
  235. string state = _device.System.TitleID;
  236. if (state == null)
  237. {
  238. state = "Ryujinx";
  239. }
  240. else
  241. {
  242. state = state.ToUpper();
  243. }
  244. string details = "Idling";
  245. if (_device.System.TitleName != null)
  246. {
  247. details = $"Playing {_device.System.TitleName}";
  248. }
  249. DiscordPresence.Details = details;
  250. DiscordPresence.State = state;
  251. DiscordPresence.Assets.LargeImageText = _device.System.TitleName;
  252. DiscordPresence.Assets.SmallImageKey = "ryujinx";
  253. DiscordPresence.Assets.SmallImageText = "Ryujinx is an emulator for the Nintendo Switch";
  254. DiscordPresence.Timestamps = new Timestamps(DateTime.UtcNow);
  255. DiscordClient.SetPresence(DiscordPresence);
  256. }
  257. try
  258. {
  259. string savePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFS", "nand", "user", "save", "0000000000000000", _userId, _device.System.TitleID);
  260. if (File.Exists(System.IO.Path.Combine(savePath, "TimePlayed.dat")) == false)
  261. {
  262. Directory.CreateDirectory(savePath);
  263. using (FileStream stream = File.OpenWrite(System.IO.Path.Combine(savePath, "TimePlayed.dat")))
  264. {
  265. stream.Write(Encoding.ASCII.GetBytes("0"));
  266. }
  267. }
  268. if (File.Exists(System.IO.Path.Combine(savePath, "LastPlayed.dat")) == false)
  269. {
  270. Directory.CreateDirectory(savePath);
  271. using (FileStream stream = File.OpenWrite(System.IO.Path.Combine(savePath, "LastPlayed.dat")))
  272. {
  273. stream.Write(Encoding.ASCII.GetBytes("Never"));
  274. }
  275. }
  276. using (FileStream stream = File.OpenWrite(System.IO.Path.Combine(savePath, "LastPlayed.dat")))
  277. {
  278. using (StreamWriter writer = new StreamWriter(stream))
  279. {
  280. writer.WriteLine(DateTime.UtcNow);
  281. }
  282. }
  283. }
  284. catch (ArgumentNullException)
  285. {
  286. Logger.PrintWarning(LogClass.Application, $"Could not access save path to retrieve time/last played data using: UserID: {_userId}, TitleID: {_device.System.TitleID}");
  287. }
  288. }
  289. }
  290. private static void CreateGameWindow()
  291. {
  292. Configuration.ConfigureHid(_device, SwitchSettings.SwitchConfig);
  293. using (GlScreen screen = new GlScreen(_device, _renderer))
  294. {
  295. screen.MainLoop();
  296. End();
  297. }
  298. }
  299. private static void End()
  300. {
  301. if (_gameLoaded)
  302. {
  303. try
  304. {
  305. string savePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFS", "nand", "user", "save", "0000000000000000", _userId, _device.System.TitleID);
  306. double currentPlayTime = 0;
  307. using (FileStream stream = File.OpenRead(System.IO.Path.Combine(savePath, "LastPlayed.dat")))
  308. {
  309. using (StreamReader reader = new StreamReader(stream))
  310. {
  311. DateTime startTime = DateTime.Parse(reader.ReadLine());
  312. using (FileStream lastPlayedStream = File.OpenRead(System.IO.Path.Combine(savePath, "TimePlayed.dat")))
  313. {
  314. using (StreamReader lastPlayedReader = new StreamReader(lastPlayedStream))
  315. {
  316. currentPlayTime = double.Parse(lastPlayedReader.ReadLine());
  317. }
  318. }
  319. using (FileStream timePlayedStream = File.OpenWrite(System.IO.Path.Combine(savePath, "TimePlayed.dat")))
  320. {
  321. using (StreamWriter timePlayedWriter = new StreamWriter(timePlayedStream))
  322. {
  323. timePlayedWriter.WriteLine(currentPlayTime + Math.Round(DateTime.UtcNow.Subtract(startTime).TotalSeconds, MidpointRounding.AwayFromZero));
  324. }
  325. }
  326. }
  327. }
  328. }
  329. catch (ArgumentNullException)
  330. {
  331. Logger.PrintWarning(LogClass.Application, $"Could not access save path to retrieve time/last played data using: UserID: {_userId}, TitleID: {_device.System.TitleID}");
  332. }
  333. }
  334. Profile.FinishProfiling();
  335. _device.Dispose();
  336. _audioOut.Dispose();
  337. DiscordClient?.Dispose();
  338. Logger.Shutdown();
  339. Environment.Exit(0);
  340. }
  341. /// <summary>
  342. /// Picks an <see cref="IAalOutput"/> audio output renderer supported on this machine
  343. /// </summary>
  344. /// <returns>An <see cref="IAalOutput"/> supported by this machine</returns>
  345. private static IAalOutput InitializeAudioEngine()
  346. {
  347. if (SoundIoAudioOut.IsSupported)
  348. {
  349. return new SoundIoAudioOut();
  350. }
  351. else if (OpenALAudioOut.IsSupported)
  352. {
  353. return new OpenALAudioOut();
  354. }
  355. else
  356. {
  357. return new DummyAudioOut();
  358. }
  359. }
  360. //Events
  361. private void Row_Activated(object o, RowActivatedArgs args)
  362. {
  363. _tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path.ToString()));
  364. string path = (string)_tableStore.GetValue(treeIter, 8);
  365. LoadApplication(path);
  366. }
  367. private void Load_Application_File(object o, EventArgs args)
  368. {
  369. FileChooserDialog fileChooser = new FileChooserDialog("Choose the file to open", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
  370. fileChooser.Filter = new FileFilter();
  371. fileChooser.Filter.AddPattern("*.nsp" );
  372. fileChooser.Filter.AddPattern("*.pfs0");
  373. fileChooser.Filter.AddPattern("*.xci" );
  374. fileChooser.Filter.AddPattern("*.nca" );
  375. fileChooser.Filter.AddPattern("*.nro" );
  376. fileChooser.Filter.AddPattern("*.nso" );
  377. if (fileChooser.Run() == (int)ResponseType.Accept)
  378. {
  379. LoadApplication(fileChooser.Filename);
  380. }
  381. fileChooser.Destroy();
  382. }
  383. private void Load_Application_Folder(object o, EventArgs args)
  384. {
  385. FileChooserDialog fileChooser = new FileChooserDialog("Choose the folder to open", this, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
  386. if (fileChooser.Run() == (int)ResponseType.Accept)
  387. {
  388. LoadApplication(fileChooser.Filename);
  389. }
  390. fileChooser.Destroy();
  391. }
  392. private void Open_Ryu_Folder(object o, EventArgs args)
  393. {
  394. Process.Start(new ProcessStartInfo()
  395. {
  396. FileName = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFs"),
  397. UseShellExecute = true,
  398. Verb = "open"
  399. });
  400. }
  401. private void Exit_Pressed(object o, EventArgs args)
  402. {
  403. End();
  404. }
  405. private void Window_Close(object o, DeleteEventArgs args)
  406. {
  407. End();
  408. }
  409. private void StopEmulation_Pressed(object o, EventArgs args)
  410. {
  411. // TODO: Write logic to kill running game
  412. }
  413. private void FullScreen_Toggled(object o, EventArgs args)
  414. {
  415. if (_fullScreen.Active)
  416. {
  417. Fullscreen();
  418. }
  419. else
  420. {
  421. Unfullscreen();
  422. }
  423. }
  424. private void Settings_Pressed(object o, EventArgs args)
  425. {
  426. SwitchSettings SettingsWin = new SwitchSettings(_device);
  427. _gtkApplication.Register(GLib.Cancellable.Current);
  428. _gtkApplication.AddWindow(SettingsWin);
  429. SettingsWin.Show();
  430. }
  431. private void Update_Pressed(object o, EventArgs args)
  432. {
  433. string ryuUpdater = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFS", "RyuUpdater.exe");
  434. try
  435. {
  436. Process.Start(new ProcessStartInfo(ryuUpdater, "/U") { UseShellExecute = true });
  437. }
  438. catch(System.ComponentModel.Win32Exception)
  439. {
  440. CreateErrorDialog("Update canceled by user or updater was not found");
  441. }
  442. }
  443. private void About_Pressed(object o, EventArgs args)
  444. {
  445. AboutWindow AboutWin = new AboutWindow();
  446. _gtkApplication.Register(GLib.Cancellable.Current);
  447. _gtkApplication.AddWindow(AboutWin);
  448. AboutWin.Show();
  449. }
  450. private void Icon_Toggled(object o, EventArgs args)
  451. {
  452. SwitchSettings.SwitchConfig.GuiColumns[0] = _iconToggle.Active;
  453. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  454. }
  455. private void Title_Toggled(object o, EventArgs args)
  456. {
  457. SwitchSettings.SwitchConfig.GuiColumns[1] = _titleToggle.Active;
  458. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  459. }
  460. private void Developer_Toggled(object o, EventArgs args)
  461. {
  462. SwitchSettings.SwitchConfig.GuiColumns[2] = _developerToggle.Active;
  463. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  464. }
  465. private void Version_Toggled(object o, EventArgs args)
  466. {
  467. SwitchSettings.SwitchConfig.GuiColumns[3] = _versionToggle.Active;
  468. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  469. }
  470. private void TimePlayed_Toggled(object o, EventArgs args)
  471. {
  472. SwitchSettings.SwitchConfig.GuiColumns[4] = _timePlayedToggle.Active;
  473. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  474. }
  475. private void LastPlayed_Toggled(object o, EventArgs args)
  476. {
  477. SwitchSettings.SwitchConfig.GuiColumns[5] = _lastPlayedToggle.Active;
  478. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  479. }
  480. private void FileExt_Toggled(object o, EventArgs args)
  481. {
  482. SwitchSettings.SwitchConfig.GuiColumns[6] = _fileExtToggle.Active;
  483. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  484. }
  485. private void FileSize_Toggled(object o, EventArgs args)
  486. {
  487. SwitchSettings.SwitchConfig.GuiColumns[7] = _fileSizeToggle.Active;
  488. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  489. }
  490. private void Path_Toggled(object o, EventArgs args)
  491. {
  492. SwitchSettings.SwitchConfig.GuiColumns[8] = _pathToggle.Active;
  493. Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
  494. }
  495. }
  496. }