diff --git a/Ryujinx/ControlSettings.cs b/Ryujinx/ControlSettings.cs
new file mode 100644
index 0000000000..24713c02dd
--- /dev/null
+++ b/Ryujinx/ControlSettings.cs
@@ -0,0 +1,53 @@
+using Gtk;
+using System;
+
+namespace Ryujinx
+{
+ public class ControlSettings
+ {
+ public static void ControlSettingsMenu()
+ {
+ Window CSWin = new Window(WindowType.Toplevel);
+ CSWin.Title = "Control Settings";
+ CSWin.Icon = new Gdk.Pixbuf("./ryujinx.png");
+ CSWin.SetDefaultSize(854, 360);
+ CSWin.Resizable = false;
+ CSWin.WindowPosition = WindowPosition.Center;
+
+ VBox box = new VBox(false, 2);
+
+ //settings stuff will replace this block
+ Label myLabel = new Label { Text = "General Settings" };
+ box.PackStart(myLabel, true, true, 3);
+
+ HBox ButtonBox = new HBox(true, 3);
+ Alignment BoxAlign = new Alignment(1, 0, 0, 0);
+
+ Button ok = new Button("OK");
+ ok.Pressed += (o, args) => OK_Pressed(o, args, CSWin);
+ ButtonBox.Add(ok);
+
+ Button close = new Button("Close");
+ close.Pressed += (o, args) => Close_Pressed(o, args, CSWin);
+ ButtonBox.Add(close);
+
+ BoxAlign.SetPadding(0, 5, 0, 7);
+ BoxAlign.Add(ButtonBox);
+ box.PackStart(BoxAlign, false, false, 3);
+
+ CSWin.Add(box);
+ CSWin.ShowAll();
+ }
+
+ static void OK_Pressed(object o, EventArgs args, Window window)
+ {
+ //save settings stuff will go here
+ window.Destroy();
+ }
+
+ static void Close_Pressed(object o, EventArgs args, Window window)
+ {
+ window.Destroy();
+ }
+ }
+}
diff --git a/Ryujinx/GeneralSettings.cs b/Ryujinx/GeneralSettings.cs
new file mode 100644
index 0000000000..8f64e5a301
--- /dev/null
+++ b/Ryujinx/GeneralSettings.cs
@@ -0,0 +1,53 @@
+using Gtk;
+using System;
+
+namespace Ryujinx
+{
+ public class GeneralSettings
+ {
+ public static void GeneralSettingsMenu()
+ {
+ Window GSWin = new Window(WindowType.Toplevel);
+ GSWin.Title = "General Settings";
+ GSWin.Icon = new Gdk.Pixbuf("./ryujinx.png");
+ GSWin.SetDefaultSize(854, 360);
+ GSWin.Resizable = false;
+ GSWin.WindowPosition = WindowPosition.Center;
+
+ VBox box = new VBox(false, 2);
+
+ //settings stuff will replace this block
+ Label myLabel = new Label { Text = "General Settings" };
+ box.PackStart(myLabel, true, true, 3);
+
+ HBox ButtonBox = new HBox(true, 3);
+ Alignment BoxAlign = new Alignment(1, 0, 0, 0);
+
+ Button ok = new Button("OK");
+ ok.Pressed += (o, args) => OK_Pressed(o, args, GSWin);
+ ButtonBox.Add(ok);
+
+ Button close = new Button("Close");
+ close.Pressed += (o, args) => Close_Pressed(o, args, GSWin);
+ ButtonBox.Add(close);
+
+ BoxAlign.SetPadding(0, 5, 0, 7);
+ BoxAlign.Add(ButtonBox);
+ box.PackStart(BoxAlign, false, false, 3);
+
+ GSWin.Add(box);
+ GSWin.ShowAll();
+ }
+
+ static void OK_Pressed(object o, EventArgs args, Window window)
+ {
+ //save settings stuff will go here
+ window.Destroy();
+ }
+
+ static void Close_Pressed(object o, EventArgs args, Window window)
+ {
+ window.Destroy();
+ }
+ }
+}
diff --git a/Ryujinx/MainMenu.cs b/Ryujinx/MainMenu.cs
new file mode 100644
index 0000000000..f314359387
--- /dev/null
+++ b/Ryujinx/MainMenu.cs
@@ -0,0 +1,280 @@
+using Gtk;
+using Ryujinx.Common.Logging;
+using System;
+using System.IO;
+
+namespace Ryujinx
+{
+ public class MainMenU
+ {
+ public static void MainMenu(HLE.Switch device)
+ {
+ Application.Init();
+
+ Window MainWin = new Window(WindowType.Toplevel);
+ MainWin.Title = "Ryujinx";
+ MainWin.Icon = new Gdk.Pixbuf("./ryujinx.png");
+ MainWin.SetDefaultSize(1280, 745);
+ MainWin.WindowPosition = WindowPosition.Center;
+
+ if (device.System.State.DiscordIntergrationEnabled == true)
+ {
+ Program.DiscordPresence.Details = "Main Menu";
+ Program.DiscordPresence.State = "Idling";
+ Program.DiscordPresence.Timestamps = new DiscordRPC.Timestamps(DateTime.UtcNow);
+
+ Program.DiscordClient.SetPresence(Program.DiscordPresence);
+ }
+
+ VBox box = new VBox();
+ MenuBar MenuBar = new MenuBar();
+ TreeView GameTable = new TreeView();
+
+ //Menu Bar
+ MenuItem FileMenu = new MenuItem("File");
+ MenuBar.Append(FileMenu);
+ Menu FileSubmenu = new Menu();
+ FileMenu.Submenu = FileSubmenu;
+
+ MenuItem LoadApplicationFile = new MenuItem("Load Application from File");
+ FileSubmenu.Append(LoadApplicationFile);
+ LoadApplicationFile.Activated += (o, args) => Load_Application_File(o, args, MainWin, device);
+
+ MenuItem LoadApplicationFolder = new MenuItem("Load Application from Folder");
+ FileSubmenu.Append(LoadApplicationFolder);
+ LoadApplicationFolder.Activated += (o, args) => Load_Application_Folder(o, args, MainWin, device);
+
+ FileSubmenu.Append(new SeparatorMenuItem());
+
+ MenuItem Exit = new MenuItem("Exit");
+ FileSubmenu.Append(Exit);
+ Exit.Activated += (o, args) => Exit_Pressed(o, args, MainWin);
+
+ MenuItem OptionsMenu = new MenuItem("Options");
+ MenuBar.Append(OptionsMenu);
+ Menu OptionsSubmenu = new Menu();
+ OptionsMenu.Submenu = OptionsSubmenu;
+
+ FileSubmenu.Append(new SeparatorMenuItem());
+
+ MenuItem GeneralSettingsMenu = new MenuItem("General Settings");
+ OptionsSubmenu.Append(GeneralSettingsMenu);
+ GeneralSettingsMenu.Activated += new EventHandler(General_Settings_Pressed);
+
+ MenuItem ControlSettingsMenu = new MenuItem("Control Settings");
+ OptionsSubmenu.Append(ControlSettingsMenu);
+ ControlSettingsMenu.Activated += new EventHandler(Control_Settings_Pressed);
+
+ MenuItem ToolsMenu = new MenuItem("Tools");
+ MenuBar.Append(ToolsMenu);
+ Menu ToolsSubmenu = new Menu();
+ ToolsMenu.Submenu = ToolsSubmenu;
+
+ MenuItem NFC = new MenuItem("Scan NFC Tag from File");
+ ToolsSubmenu.Append(NFC);
+ NFC.Sensitive = false;
+ NFC.Activated += (o, args) => NFC_Pressed(o, args, MainWin);
+
+ MenuItem HelpMenu = new MenuItem("Help");
+ MenuBar.Append(HelpMenu);
+ Menu HelpSubmenu = new Menu();
+ HelpMenu.Submenu = HelpSubmenu;
+
+ MenuItem About = new MenuItem("About");
+ HelpSubmenu.Append(About);
+ About.Activated += new EventHandler(About_Pressed);
+
+ box.PackStart(MenuBar, false, false, 0);
+
+ //Games grid thing
+ ListStore TableStore = new ListStore(typeof(Gdk.Pixbuf), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string));
+ GameTable.RowActivated += (o, args) => Row_Activated(o, args, TableStore, MainWin, device);
+
+ GameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 0);
+ GameTable.AppendColumn("Game", new CellRendererText(), "text", 1);
+ GameTable.AppendColumn("Version", new CellRendererText(), "text", 2);
+ GameTable.AppendColumn("Time Played", new CellRendererText(), "text", 3);
+ GameTable.AppendColumn("Last Played", new CellRendererText(), "text", 4);
+ GameTable.AppendColumn("Path", new CellRendererText(), "text", 5);
+
+ string dat = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "GameDirs.dat");
+ if (File.Exists(dat) == false) { File.Create(dat).Close(); }
+ string[] GameDirs = File.ReadAllLines(dat);
+ string[] Games = new string[] { };
+
+ foreach (string GameDir in GameDirs)
+ {
+ if (Directory.Exists(GameDir) == false) { Logger.PrintError(LogClass.Application, "There is an invalid game directory in \"GameDirs.dat\""); return; }
+ DirectoryInfo GameDirInfo = new DirectoryInfo(GameDir);
+ foreach (var Game in GameDirInfo.GetFiles())
+ {
+ if ((Path.GetExtension(Game.ToString()) == ".xci") || (Path.GetExtension(Game.ToString()) == ".nca") || (Path.GetExtension(Game.ToString()) == ".nsp") || (Path.GetExtension(Game.ToString()) == ".pfs0") || (Path.GetExtension(Game.ToString()) == ".nro") || (Path.GetExtension(Game.ToString()) == ".nso"))
+ {
+ Array.Resize(ref Games, Games.Length + 1);
+ Games[Games.Length - 1] = Game.ToString();
+ }
+ }
+ }
+ foreach (string GamePath in Games)
+ {
+ TableStore.AppendValues(new Gdk.Pixbuf("./ryujinx.png", 50, 50), "", "", "", "", GamePath);
+ }
+
+ GameTable.Model = TableStore;
+ box.PackStart(GameTable, true, true, 0);
+
+ MainWin.DeleteEvent += (obj, args) => Window_Close(obj, args, MainWin);
+ MainWin.Add(box);
+ MainWin.ShowAll();
+
+ Application.Run();
+ }
+
+ static void Row_Activated(object obj, RowActivatedArgs args, ListStore TableStore, Window window, HLE.Switch device)
+ {
+ TableStore.GetIter(out TreeIter treeiter, new TreePath(args.Path.ToString()));
+ string path = (string)TableStore.GetValue(treeiter, 5);
+
+ switch (Path.GetExtension(path).ToLowerInvariant())
+ {
+ case ".xci":
+ Logger.PrintInfo(LogClass.Application, "Loading as XCI.");
+ device.LoadXci(path);
+ break;
+ case ".nca":
+ Logger.PrintInfo(LogClass.Application, "Loading as NCA.");
+ device.LoadNca(path);
+ break;
+ case ".nsp":
+ case ".pfs0":
+ Logger.PrintInfo(LogClass.Application, "Loading as NSP.");
+ device.LoadNsp(path);
+ break;
+ default:
+ Logger.PrintInfo(LogClass.Application, "Loading as homebrew.");
+ device.LoadProgram(path);
+ break;
+ }
+ window.Destroy();
+ Application.Quit();
+ }
+
+ static void Load_Application_File(object o, EventArgs args, Window window, HLE.Switch device)
+ {
+ FileChooserDialog fc = new FileChooserDialog("Choose the file to open", window, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
+ fc.Filter = new FileFilter();
+ fc.Filter.AddPattern("*.nsp");
+ fc.Filter.AddPattern("*.xci");
+ fc.Filter.AddPattern("*.nca");
+ fc.Filter.AddPattern("*.nro");
+ fc.Filter.AddPattern("*.nso");
+
+ if (fc.Run() == (int)ResponseType.Accept)
+ {
+ switch (Path.GetExtension(fc.Filename).ToLowerInvariant())
+ {
+ case ".xci":
+ Logger.PrintInfo(LogClass.Application, "Loading as XCI.");
+ device.LoadXci(fc.Filename);
+ break;
+ case ".nca":
+ Logger.PrintInfo(LogClass.Application, "Loading as NCA.");
+ device.LoadNca(fc.Filename);
+ break;
+ case ".nsp":
+ case ".pfs0":
+ Logger.PrintInfo(LogClass.Application, "Loading as NSP.");
+ device.LoadNsp(fc.Filename);
+ break;
+ default:
+ Logger.PrintInfo(LogClass.Application, "Loading as homebrew.");
+ device.LoadProgram(fc.Filename);
+ break;
+ }
+ window.Destroy();
+ Application.Quit();
+ }
+ fc.Destroy();
+ }
+
+ static void Load_Application_Folder(object o, EventArgs args, Window window, HLE.Switch device)
+ {
+ FileChooserDialog fc = new FileChooserDialog("Choose the folder to open", window, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
+
+ if (fc.Run() == (int)ResponseType.Accept)
+ {
+ string[] romFsFiles = Directory.GetFiles(fc.Filename, "*.istorage");
+
+ if (romFsFiles.Length == 0)
+ {
+ romFsFiles = Directory.GetFiles(fc.Filename, "*.romfs");
+ }
+
+ if (romFsFiles.Length > 0)
+ {
+ Logger.PrintInfo(LogClass.Application, "Loading as cart with RomFS.");
+ device.LoadCart(fc.Filename, romFsFiles[0]);
+ }
+ else
+ {
+ Logger.PrintInfo(LogClass.Application, "Loading as cart WITHOUT RomFS.");
+ device.LoadCart(fc.Filename);
+ }
+ window.Destroy();
+ Application.Quit();
+ }
+ fc.Destroy();
+ }
+
+ static void Exit_Pressed(object o, EventArgs args, Window window)
+ {
+ window.Destroy();
+ Application.Quit();
+ }
+
+ static void Window_Close(object obj, DeleteEventArgs args, Window window)
+ {
+ window.Destroy();
+ Application.Quit();
+ args.RetVal = true;
+ }
+
+ static void General_Settings_Pressed(object o, EventArgs args)
+ {
+ GeneralSettings.GeneralSettingsMenu();
+ }
+
+ static void Control_Settings_Pressed(object o, EventArgs args)
+ {
+ ControlSettings.ControlSettingsMenu();
+ }
+
+ static void NFC_Pressed(object o, EventArgs args, Window window)
+ {
+ FileChooserDialog fc = new FileChooserDialog("Choose the file to open", window, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
+ fc.Filter = new FileFilter();
+ fc.Filter.AddPattern("*.bin");
+
+ if (fc.Run() == (int)ResponseType.Accept)
+ {
+ Console.WriteLine(fc.Filename);
+ }
+ fc.Destroy();
+ }
+
+ static void About_Pressed(object o, EventArgs args)
+ {
+ AboutDialog about = new AboutDialog();
+ about.ProgramName = "Ryujinx";
+ about.Version = "Version x.x.x";
+ about.Authors = new string[] { "gdkchan", "Ac_K", "LDj3SNuD", "emmauss", "MerryMage", "MS-DOS1999", "Thog", "jD", "BaronKiko", "Dr.Hacknik", "Lordmau5", "(and Xpl0itR did a bit of work too :D)" };
+ about.Copyright = "Unlicense";
+ about.Comments = "Ryujinx is an emulator for the Nintendo Switch";
+ about.Website = "https://github.com/Ryujinx/Ryujinx";
+ about.Copyright = "Unlicense";
+ about.WindowPosition = WindowPosition.Center;
+ about.Run();
+ about.Destroy();
+ }
+ }
+}
diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs
index ac6682903a..fc624a97c0 100644
--- a/Ryujinx/Program.cs
+++ b/Ryujinx/Program.cs
@@ -53,7 +53,11 @@ namespace Ryujinx
DiscordClient.SetPresence(DiscordPresence);
}
- if (args.Length == 1)
+ if (args.Length == 0)
+ {
+ MainMenU.MainMenu(device);
+ }
+ else
{
if (Directory.Exists(args[0]))
{
@@ -103,10 +107,6 @@ namespace Ryujinx
Logger.PrintWarning(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file");
}
}
- else
- {
- Logger.PrintWarning(LogClass.Application, "Please specify the folder with the NSOs/IStorage or a NSO/NRO.");
- }
if (device.System.State.DiscordIntegrationEnabled == true)
{
@@ -116,7 +116,7 @@ namespace Ryujinx
}
DiscordPresence.Details = $"Playing {device.System.TitleName}";
- DiscordPresence.State = device.System.TitleID.ToUpper();
+ DiscordPresence.State = string.IsNullOrWhiteSpace(device.System.TitleID) ? string.Empty : device.System.TitleID.ToUpper();
DiscordPresence.Assets.LargeImageText = device.System.TitleName;
DiscordPresence.Assets.SmallImageKey = "ryujinx";
DiscordPresence.Assets.SmallImageText = "Ryujinx is an emulator for the Nintendo Switch";
diff --git a/Ryujinx/Ryujinx.csproj b/Ryujinx/Ryujinx.csproj
index 80b03f46b3..9c2eb11093 100644
--- a/Ryujinx/Ryujinx.csproj
+++ b/Ryujinx/Ryujinx.csproj
@@ -20,6 +20,7 @@
+
@@ -39,6 +40,9 @@
PreserveNewest
+
+ PreserveNewest
+
diff --git a/Ryujinx/ryujinx.png b/Ryujinx/ryujinx.png
new file mode 100644
index 0000000000..9bd88fab59
Binary files /dev/null and b/Ryujinx/ryujinx.png differ