aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx
diff options
context:
space:
mode:
authorAc_K <Acoustik666@gmail.com>2021-01-08 09:14:13 +0100
committerGitHub <noreply@github.com>2021-01-08 09:14:13 +0100
commita9cb31e75fe269519f6be71ae83627ee21d1bc1f (patch)
treed078b6adea185e6bab72bdb79db37b061ca3bcdf /Ryujinx
parent72e94bb089a0f2fef862acee1960dd05083a735b (diff)
gui: Refactoring Part 1 (#1859)
* gui: Refactoring Part 1 * Fix ProfileDialog.glade path * Fix Application.Quit assert * Fix TitleUpdateWindow parent * Fix TitleUpdate selected item * Remove extra line in TitleUpdateWindow * Fix empty assign of Enum.TryParse * Add Patrons list in the About Window * update about error messages
Diffstat (limited to 'Ryujinx')
-rw-r--r--Ryujinx/Modules/DiscordIntegrationModule.cs (renamed from Ryujinx/Configuration/DiscordIntegrationModule.cs)9
-rw-r--r--Ryujinx/Modules/Motion/Client.cs (renamed from Ryujinx/Motion/Client.cs)8
-rw-r--r--Ryujinx/Modules/Motion/MotionDevice.cs (renamed from Ryujinx/Motion/MotionDevice.cs)10
-rw-r--r--Ryujinx/Modules/Motion/MotionInput.cs (renamed from Ryujinx/Motion/MotionInput.cs)4
-rw-r--r--Ryujinx/Modules/Motion/MotionSensorFilter.cs (renamed from Ryujinx/Motion/MotionSensorFilter.cs)12
-rw-r--r--Ryujinx/Modules/Motion/Protocol/ControllerData.cs (renamed from Ryujinx/Motion/Protocol/ControllerData.cs)29
-rw-r--r--Ryujinx/Modules/Motion/Protocol/ControllerInfo.cs (renamed from Ryujinx/Motion/Protocol/ControllerInfo.cs)10
-rw-r--r--Ryujinx/Modules/Motion/Protocol/Header.cs (renamed from Ryujinx/Motion/Protocol/Header.cs)10
-rw-r--r--Ryujinx/Modules/Motion/Protocol/MessageType.cs (renamed from Ryujinx/Motion/Protocol/MessageType.cs)4
-rw-r--r--Ryujinx/Modules/Motion/Protocol/SharedResponse.cs (renamed from Ryujinx/Motion/Protocol/SharedResponse.cs)22
-rw-r--r--Ryujinx/Modules/Updater/UpdateDialog.cs (renamed from Ryujinx/Updater/UpdateDialog.cs)33
-rw-r--r--Ryujinx/Modules/Updater/UpdateDialog.glade (renamed from Ryujinx/Updater/UpdateDialog.glade)0
-rw-r--r--Ryujinx/Modules/Updater/Updater.cs (renamed from Ryujinx/Updater/Updater.cs)7
-rw-r--r--Ryujinx/Program.cs80
-rw-r--r--Ryujinx/Ryujinx.csproj82
-rw-r--r--Ryujinx/Ui/AboutWindow.cs74
-rw-r--r--Ryujinx/Ui/AboutWindow.glade574
-rw-r--r--Ryujinx/Ui/App/ApplicationAddedEventArgs.cs (renamed from Ryujinx/Ui/ApplicationAddedEventArgs.cs)2
-rw-r--r--Ryujinx/Ui/App/ApplicationCountUpdatedEventArgs.cs (renamed from Ryujinx/Ui/ApplicationCountUpdatedEventArgs.cs)2
-rw-r--r--Ryujinx/Ui/App/ApplicationData.cs (renamed from Ryujinx/Ui/ApplicationData.cs)9
-rw-r--r--Ryujinx/Ui/App/ApplicationLibrary.cs (renamed from Ryujinx/Ui/ApplicationLibrary.cs)95
-rw-r--r--Ryujinx/Ui/App/ApplicationMetadata.cs9
-rw-r--r--Ryujinx/Ui/Applet/ErrorAppletDialog.cs (renamed from Ryujinx/Ui/ErrorAppletDialog.cs)7
-rw-r--r--Ryujinx/Ui/Applet/GtkHostUiHandler.cs (renamed from Ryujinx/Ui/GtkHostUiHandler.cs)65
-rw-r--r--Ryujinx/Ui/Applet/SwkbdAppletDialog.cs89
-rw-r--r--Ryujinx/Ui/ApplicationMetadata.cs9
-rw-r--r--Ryujinx/Ui/Diagnostic/GuideDialog.cs36
-rw-r--r--Ryujinx/Ui/Diagnostic/UserErrorDialog.cs137
-rw-r--r--Ryujinx/Ui/GLRenderer.cs11
-rw-r--r--Ryujinx/Ui/Helper/OpenHelper.cs (renamed from Ryujinx/Ui/UrlHelper.cs)16
-rw-r--r--Ryujinx/Ui/Helper/SetupValidator.cs (renamed from Ryujinx/Ui/Diagnostic/SetupValidator.cs)3
-rw-r--r--Ryujinx/Ui/Helper/SortHelper.cs116
-rw-r--r--Ryujinx/Ui/Helper/ThemeHelper.cs35
-rw-r--r--Ryujinx/Ui/InputDialog.cs69
-rw-r--r--Ryujinx/Ui/MainWindow.cs821
-rw-r--r--Ryujinx/Ui/Migration.cs189
-rw-r--r--Ryujinx/Ui/Resources/Controller_JoyConLeft.svg (renamed from Ryujinx/Ui/assets/JoyConLeft.svg)0
-rw-r--r--Ryujinx/Ui/Resources/Controller_JoyConPair.svg (renamed from Ryujinx/Ui/assets/JoyConPair.svg)0
-rw-r--r--Ryujinx/Ui/Resources/Controller_JoyConRight.svg (renamed from Ryujinx/Ui/assets/JoyConRight.svg)0
-rw-r--r--Ryujinx/Ui/Resources/Controller_ProCon.svg (renamed from Ryujinx/Ui/assets/ProCon.svg)0
-rw-r--r--Ryujinx/Ui/Resources/Icon_NCA.png (renamed from Ryujinx/Ui/assets/NCAIcon.png)bin13675 -> 13675 bytes
-rw-r--r--Ryujinx/Ui/Resources/Icon_NRO.png (renamed from Ryujinx/Ui/assets/NROIcon.png)bin13902 -> 13902 bytes
-rw-r--r--Ryujinx/Ui/Resources/Icon_NSO.png (renamed from Ryujinx/Ui/assets/NSOIcon.png)bin13948 -> 13948 bytes
-rw-r--r--Ryujinx/Ui/Resources/Icon_NSP.png (renamed from Ryujinx/Ui/assets/NSPIcon.png)bin13198 -> 13198 bytes
-rw-r--r--Ryujinx/Ui/Resources/Icon_XCI.png (renamed from Ryujinx/Ui/assets/XCIIcon.png)bin13093 -> 13093 bytes
-rw-r--r--Ryujinx/Ui/Resources/Logo_Discord.png (renamed from Ryujinx/Ui/assets/DiscordLogo.png)bin13609 -> 13609 bytes
-rw-r--r--Ryujinx/Ui/Resources/Logo_GitHub.png (renamed from Ryujinx/Ui/assets/GitHubLogo.png)bin26883 -> 26883 bytes
-rw-r--r--Ryujinx/Ui/Resources/Logo_Patreon.png (renamed from Ryujinx/Ui/assets/PatreonLogo.png)bin15483 -> 15483 bytes
-rw-r--r--Ryujinx/Ui/Resources/Logo_Ryujinx.png (renamed from Ryujinx/Ui/assets/Icon.png)bin53785 -> 53785 bytes
-rw-r--r--Ryujinx/Ui/Resources/Logo_Twitter.png (renamed from Ryujinx/Ui/assets/TwitterLogo.png)bin16937 -> 16937 bytes
-rw-r--r--Ryujinx/Ui/SaveImporter.cs219
-rw-r--r--Ryujinx/Ui/StatusUpdatedEventArgs.cs2
-rw-r--r--Ryujinx/Ui/Widgets/GameTableContextMenu.Designer.cs198
-rw-r--r--Ryujinx/Ui/Widgets/GameTableContextMenu.cs (renamed from Ryujinx/Ui/GameTableContextMenu.cs)387
-rw-r--r--Ryujinx/Ui/Widgets/GtkDialog.cs (renamed from Ryujinx/Ui/GtkDialog.cs)41
-rw-r--r--Ryujinx/Ui/Widgets/ProfileDialog.cs (renamed from Ryujinx/Ui/ProfileDialog.cs)9
-rw-r--r--Ryujinx/Ui/Widgets/ProfileDialog.glade (renamed from Ryujinx/Ui/ProfileDialog.glade)0
-rw-r--r--Ryujinx/Ui/Widgets/UserError.cs (renamed from Ryujinx/Ui/Diagnostic/UserError.cs)4
-rw-r--r--Ryujinx/Ui/Widgets/UserErrorDialog.cs122
-rw-r--r--Ryujinx/Ui/Windows/AboutWindow.Designer.cs467
-rw-r--r--Ryujinx/Ui/Windows/AboutWindow.cs73
-rw-r--r--Ryujinx/Ui/Windows/ControllerWindow.cs (renamed from Ryujinx/Ui/ControllerWindow.cs)81
-rw-r--r--Ryujinx/Ui/Windows/ControllerWindow.glade (renamed from Ryujinx/Ui/ControllerWindow.glade)0
-rw-r--r--Ryujinx/Ui/Windows/DlcWindow.cs (renamed from Ryujinx/Ui/DlcWindow.cs)26
-rw-r--r--Ryujinx/Ui/Windows/DlcWindow.glade (renamed from Ryujinx/Ui/DlcWindow.glade)0
-rw-r--r--Ryujinx/Ui/Windows/SettingsWindow.cs (renamed from Ryujinx/Ui/SettingsWindow.cs)82
-rw-r--r--Ryujinx/Ui/Windows/SettingsWindow.glade (renamed from Ryujinx/Ui/SettingsWindow.glade)0
-rw-r--r--Ryujinx/Ui/Windows/TitleUpdateWindow.cs (renamed from Ryujinx/Ui/TitleUpdateWindow.cs)78
-rw-r--r--Ryujinx/Ui/Windows/TitleUpdateWindow.glade (renamed from Ryujinx/Ui/TitleUpdateWindow.glade)0
69 files changed, 1945 insertions, 2532 deletions
diff --git a/Ryujinx/Configuration/DiscordIntegrationModule.cs b/Ryujinx/Modules/DiscordIntegrationModule.cs
index 378e9c3f..3a91cf53 100644
--- a/Ryujinx/Configuration/DiscordIntegrationModule.cs
+++ b/Ryujinx/Modules/DiscordIntegrationModule.cs
@@ -1,15 +1,16 @@
using DiscordRPC;
using Ryujinx.Common;
+using Ryujinx.Configuration;
using System;
using System.Linq;
-namespace Ryujinx.Configuration
+namespace Ryujinx.Modules
{
static class DiscordIntegrationModule
{
private static DiscordRpcClient _discordClient;
- private static string LargeDescription = "Ryujinx is a Nintendo Switch emulator.";
+ private const string LargeDescription = "Ryujinx is a Nintendo Switch emulator.";
public static RichPresence DiscordPresence { get; private set; }
@@ -17,7 +18,7 @@ namespace Ryujinx.Configuration
{
DiscordPresence = new RichPresence
{
- Assets = new Assets
+ Assets = new Assets
{
LargeImageKey = "ryujinx",
LargeImageText = LargeDescription
@@ -169,4 +170,4 @@ namespace Ryujinx.Configuration
"051337133769a000", // RGB-Seizure
};
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Motion/Client.cs b/Ryujinx/Modules/Motion/Client.cs
index 8c5ad20d..3f18fb7f 100644
--- a/Ryujinx/Motion/Client.cs
+++ b/Ryujinx/Modules/Motion/Client.cs
@@ -11,7 +11,7 @@ using System.Net.Sockets;
using System.Numerics;
using System.Threading.Tasks;
-namespace Ryujinx.Motion
+namespace Ryujinx.Modules.Motion
{
public class Client : IDisposable
{
@@ -396,7 +396,7 @@ namespace Ryujinx.Motion
}
}
- public unsafe void RequestData(int clientId, int slot)
+ public unsafe void RequestData(int clientId, int slot)
{
if (!_active)
{
@@ -439,7 +439,7 @@ namespace Ryujinx.Motion
{
Header header = new Header()
{
- ID = (uint)clientId,
+ Id = (uint)clientId,
MagicString = Magic,
Version = Version,
Length = 0,
@@ -456,4 +456,4 @@ namespace Ryujinx.Motion
CloseClients();
}
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Motion/MotionDevice.cs b/Ryujinx/Modules/Motion/MotionDevice.cs
index 2e2050bc..4fb9b422 100644
--- a/Ryujinx/Motion/MotionDevice.cs
+++ b/Ryujinx/Modules/Motion/MotionDevice.cs
@@ -3,7 +3,7 @@ using Ryujinx.Configuration;
using System;
using System.Numerics;
-namespace Ryujinx.Motion
+namespace Ryujinx.Modules.Motion
{
public class MotionDevice
{
@@ -12,7 +12,7 @@ namespace Ryujinx.Motion
public Vector3 Rotation { get; private set; }
public float[] Orientation { get; private set; }
- private Client _motionSource;
+ private readonly Client _motionSource;
public MotionDevice(Client motionSource)
{
@@ -51,8 +51,8 @@ namespace Ryujinx.Motion
}
Gyroscope = Truncate(input.Gyroscrope * 0.0027f, 3);
- Accelerometer = Truncate(input.Accelerometer, 3);
- Rotation = Truncate(input.Rotation * 0.0027f, 3);
+ Accelerometer = Truncate(input.Accelerometer, 3);
+ Rotation = Truncate(input.Rotation * 0.0027f, 3);
Matrix4x4 orientation = input.GetOrientation();
@@ -78,4 +78,4 @@ namespace Ryujinx.Motion
return value;
}
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Motion/MotionInput.cs b/Ryujinx/Modules/Motion/MotionInput.cs
index f767d8cc..3e4d9768 100644
--- a/Ryujinx/Motion/MotionInput.cs
+++ b/Ryujinx/Modules/Motion/MotionInput.cs
@@ -1,7 +1,7 @@
using System;
using System.Numerics;
-namespace Ryujinx.Motion
+namespace Ryujinx.Modules.Motion
{
public class MotionInput
{
@@ -82,4 +82,4 @@ namespace Ryujinx.Motion
return degree * (MathF.PI / 180);
}
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Motion/MotionSensorFilter.cs b/Ryujinx/Modules/Motion/MotionSensorFilter.cs
index 5173a191..b83e61a8 100644
--- a/Ryujinx/Motion/MotionSensorFilter.cs
+++ b/Ryujinx/Modules/Motion/MotionSensorFilter.cs
@@ -1,6 +1,6 @@
using System.Numerics;
-namespace Ryujinx.Motion
+namespace Ryujinx.Modules.Motion
{
// MahonyAHRS class. Madgwick's implementation of Mayhony's AHRS algorithm.
// See: https://x-io.co.uk/open-source-imu-and-ahrs-algorithms/
@@ -43,9 +43,7 @@ namespace Ryujinx.Motion
/// <param name="samplePeriod">
/// Sample period.
/// </param>
- public MotionSensorFilter(float samplePeriod) : this(samplePeriod, 1f, 0f)
- {
- }
+ public MotionSensorFilter(float samplePeriod) : this(samplePeriod, 1f, 0f) { }
/// <summary>
/// Initializes a new instance of the <see cref="MotionSensorFilter"/> class.
@@ -56,9 +54,7 @@ namespace Ryujinx.Motion
/// <param name="kp">
/// Algorithm proportional gain.
/// </param>
- public MotionSensorFilter(float samplePeriod, float kp) : this(samplePeriod, kp, 0f)
- {
- }
+ public MotionSensorFilter(float samplePeriod, float kp) : this(samplePeriod, kp, 0f) { }
/// <summary>
/// Initializes a new instance of the <see cref="MotionSensorFilter"/> class.
@@ -163,4 +159,4 @@ namespace Ryujinx.Motion
Quaternion = Quaternion.Identity;
}
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Motion/Protocol/ControllerData.cs b/Ryujinx/Modules/Motion/Protocol/ControllerData.cs
index 4b4919a1..30972b86 100644
--- a/Ryujinx/Motion/Protocol/ControllerData.cs
+++ b/Ryujinx/Modules/Motion/Protocol/ControllerData.cs
@@ -1,13 +1,13 @@
using System.Runtime.InteropServices;
-namespace Ryujinx.Motion
+namespace Ryujinx.Modules.Motion
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ControllerDataRequest
{
- public MessageType Type;
+ public MessageType Type;
public SubscriberType SubscriberType;
- public byte Slot;
+ public byte Slot;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] MacAddress;
@@ -17,21 +17,22 @@ namespace Ryujinx.Motion
public struct ControllerDataResponse
{
public SharedResponse Shared;
- public byte Connected;
- public uint PacketID;
- public byte ExtraButtons;
- public byte MainButtons;
- public ushort PSExtraInput;
- public ushort LeftStickXY;
- public ushort RightStickXY;
- public uint DPadAnalog;
- public ulong MainButtonsAnalog;
+ public byte Connected;
+ public uint PacketId;
+ public byte ExtraButtons;
+ public byte MainButtons;
+ public ushort PSExtraInput;
+ public ushort LeftStickXY;
+ public ushort RightStickXY;
+ public uint DPadAnalog;
+ public ulong MainButtonsAnalog;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] Touch1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] Touch2;
+
public ulong MotionTimestamp;
public float AccelerometerX;
public float AccelerometerY;
@@ -43,8 +44,8 @@ namespace Ryujinx.Motion
enum SubscriberType : byte
{
- All = 0,
+ All,
Slot,
Mac
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Motion/Protocol/ControllerInfo.cs b/Ryujinx/Modules/Motion/Protocol/ControllerInfo.cs
index 34177ff8..63e2db5b 100644
--- a/Ryujinx/Motion/Protocol/ControllerInfo.cs
+++ b/Ryujinx/Modules/Motion/Protocol/ControllerInfo.cs
@@ -1,21 +1,21 @@
using System.Runtime.InteropServices;
-namespace Ryujinx.Motion
+namespace Ryujinx.Modules.Motion
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ControllerInfoResponse
{
- public SharedResponse Shared;
- private byte _zero;
+ public SharedResponse Shared;
+ private byte _zero;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ControllerInfoRequest
{
public MessageType Type;
- public int PortsCount;
+ public int PortsCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] PortIndices;
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Motion/Protocol/Header.cs b/Ryujinx/Modules/Motion/Protocol/Header.cs
index 1f6ea705..39d8b531 100644
--- a/Ryujinx/Motion/Protocol/Header.cs
+++ b/Ryujinx/Modules/Motion/Protocol/Header.cs
@@ -1,14 +1,14 @@
using System.Runtime.InteropServices;
-namespace Ryujinx.Motion
+namespace Ryujinx.Modules.Motion
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Header
{
- public uint MagicString;
+ public uint MagicString;
public ushort Version;
public ushort Length;
- public uint Crc32;
- public uint ID;
+ public uint Crc32;
+ public uint Id;
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Motion/Protocol/MessageType.cs b/Ryujinx/Modules/Motion/Protocol/MessageType.cs
index 507910dd..3cbb6579 100644
--- a/Ryujinx/Motion/Protocol/MessageType.cs
+++ b/Ryujinx/Modules/Motion/Protocol/MessageType.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Motion
+namespace Ryujinx.Modules.Motion
{
public enum MessageType : uint
{
@@ -6,4 +6,4 @@
Info,
Data
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Motion/Protocol/SharedResponse.cs b/Ryujinx/Modules/Motion/Protocol/SharedResponse.cs
index 8f918ccb..e5b03722 100644
--- a/Ryujinx/Motion/Protocol/SharedResponse.cs
+++ b/Ryujinx/Modules/Motion/Protocol/SharedResponse.cs
@@ -1,45 +1,45 @@
using System.Runtime.InteropServices;
-namespace Ryujinx.Motion
+namespace Ryujinx.Modules.Motion
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SharedResponse
{
- public MessageType Type;
- public byte Slot;
- public SlotState State;
+ public MessageType Type;
+ public byte Slot;
+ public SlotState State;
public DeviceModelType ModelType;
- public ConnectionType ConnectionType;
+ public ConnectionType ConnectionType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
- public byte[] MacAddress;
+ public byte[] MacAddress;
public BatteryStatus BatteryStatus;
}
public enum SlotState : byte
{
- Disconnected = 0,
+ Disconnected,
Reserved,
Connected
}
public enum DeviceModelType : byte
{
- None = 0,
+ None,
PartialGyro,
FullGyro
}
public enum ConnectionType : byte
{
- None = 0,
+ None,
USB,
Bluetooth
}
public enum BatteryStatus : byte
{
- NA = 0,
+ NA,
Dying,
Low,
Medium,
@@ -48,4 +48,4 @@ namespace Ryujinx.Motion
Charging,
Charged
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Updater/UpdateDialog.cs b/Ryujinx/Modules/Updater/UpdateDialog.cs
index ed49ad4a..cb38383a 100644
--- a/Ryujinx/Updater/UpdateDialog.cs
+++ b/Ryujinx/Modules/Updater/UpdateDialog.cs
@@ -1,28 +1,29 @@
using Gdk;
using Gtk;
using Mono.Unix;
+using Ryujinx.Ui;
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
-namespace Ryujinx.Ui
+namespace Ryujinx.Modules
{
public class UpdateDialog : Gtk.Window
{
#pragma warning disable CS0649, IDE0044
- [Builder.Object] public Label MainText;
- [Builder.Object] public Label SecondaryText;
+ [Builder.Object] public Label MainText;
+ [Builder.Object] public Label SecondaryText;
[Builder.Object] public LevelBar ProgressBar;
- [Builder.Object] public Button YesButton;
- [Builder.Object] public Button NoButton;
+ [Builder.Object] public Button YesButton;
+ [Builder.Object] public Button NoButton;
#pragma warning restore CS0649, IDE0044
private readonly MainWindow _mainWindow;
- private readonly string _buildUrl;
- private bool _restartQuery;
+ private readonly string _buildUrl;
+ private bool _restartQuery;
- public UpdateDialog(MainWindow mainWindow, Version newVersion, string buildUrl) : this(new Builder("Ryujinx.Updater.UpdateDialog.glade"), mainWindow, newVersion, buildUrl) { }
+ public UpdateDialog(MainWindow mainWindow, Version newVersion, string buildUrl) : this(new Builder("Ryujinx..Modules.Updater.UpdateDialog.glade"), mainWindow, newVersion, buildUrl) { }
private UpdateDialog(Builder builder, MainWindow mainWindow, Version newVersion, string buildUrl) : base(builder.GetObject("UpdateDialog").Handle)
{
@@ -36,17 +37,17 @@ namespace Ryujinx.Ui
ProgressBar.Hide();
- YesButton.Clicked += YesButton_Pressed;
- NoButton.Clicked += NoButton_Pressed;
+ YesButton.Clicked += YesButton_Clicked;
+ NoButton.Clicked += NoButton_Clicked;
}
- private void YesButton_Pressed(object sender, EventArgs args)
+ private void YesButton_Clicked(object sender, EventArgs args)
{
if (_restartQuery)
{
string ryuName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "Ryujinx.exe" : "Ryujinx";
string ryuExe = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
- string ryuArg = String.Join(" ", Environment.GetCommandLineArgs().AsEnumerable().Skip(1).ToArray());
+ string ryuArg = string.Join(" ", Environment.GetCommandLineArgs().AsEnumerable().Skip(1).ToArray());
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
@@ -60,7 +61,7 @@ namespace Ryujinx.Ui
}
else
{
- this.Window.Functions = _mainWindow.Window.Functions = WMFunction.All & WMFunction.Close;
+ Window.Functions = _mainWindow.Window.Functions = WMFunction.All & WMFunction.Close;
_mainWindow.ExitMenuItem.Sensitive = false;
YesButton.Hide();
@@ -74,7 +75,7 @@ namespace Ryujinx.Ui
}
}
- private void NoButton_Pressed(object sender, EventArgs args)
+ private void NoButton_Clicked(object sender, EventArgs args)
{
Updater.Running = false;
_mainWindow.Window.Functions = WMFunction.All;
@@ -82,7 +83,7 @@ namespace Ryujinx.Ui
_mainWindow.ExitMenuItem.Sensitive = true;
_mainWindow.UpdateMenuItem.Sensitive = true;
- this.Dispose();
+ Dispose();
}
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Updater/UpdateDialog.glade b/Ryujinx/Modules/Updater/UpdateDialog.glade
index cc80167e..cc80167e 100644
--- a/Ryujinx/Updater/UpdateDialog.glade
+++ b/Ryujinx/Modules/Updater/UpdateDialog.glade
diff --git a/Ryujinx/Updater/Updater.cs b/Ryujinx/Modules/Updater/Updater.cs
index 42b97cc8..35d67adf 100644
--- a/Ryujinx/Updater/Updater.cs
+++ b/Ryujinx/Modules/Updater/Updater.cs
@@ -5,6 +5,7 @@ using ICSharpCode.SharpZipLib.Zip;
using Newtonsoft.Json.Linq;
using Ryujinx.Common.Logging;
using Ryujinx.Ui;
+using Ryujinx.Ui.Widgets;
using System;
using System.IO;
using System.Net;
@@ -13,7 +14,7 @@ using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
-namespace Ryujinx
+namespace Ryujinx.Modules
{
public static class Updater
{
@@ -84,7 +85,7 @@ namespace Ryujinx
{
if (showVersionUpToDate)
{
- GtkDialog.CreateInfoDialog("Ryujinx - Updater", "You are already using the most updated version of Ryujinx!", "");
+ GtkDialog.CreateUpdaterInfoDialog("You are already using the most updated version of Ryujinx!", "");
}
return;
@@ -115,7 +116,7 @@ namespace Ryujinx
{
if (showVersionUpToDate)
{
- GtkDialog.CreateInfoDialog("Ryujinx - Updater", "You are already using the most updated version of Ryujinx!", "");
+ GtkDialog.CreateUpdaterInfoDialog("You are already using the most updated version of Ryujinx!", "");
}
Running = false;
diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs
index 12db52a3..29043bb8 100644
--- a/Ryujinx/Program.cs
+++ b/Ryujinx/Program.cs
@@ -3,10 +3,12 @@ using Gtk;
using OpenTK;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
+using Ryujinx.Common.System;
using Ryujinx.Common.SystemInfo;
using Ryujinx.Configuration;
+using Ryujinx.Modules;
using Ryujinx.Ui;
-using Ryujinx.Ui.Diagnostic;
+using Ryujinx.Ui.Widgets;
using System;
using System.IO;
using System.Reflection;
@@ -22,10 +24,11 @@ namespace Ryujinx
static void Main(string[] args)
{
- // Parse Arguments
- string launchPath = null;
- string baseDirPath = null;
- bool startFullscreen = false;
+ // Parse Arguments.
+ string launchPathArg = null;
+ string baseDirPathArg = null;
+ bool startFullscreenArg = false;
+
for (int i = 0; i < args.Length; ++i)
{
string arg = args[i];
@@ -35,28 +38,28 @@ namespace Ryujinx
if (i + 1 >= args.Length)
{
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
+
continue;
}
- baseDirPath = args[++i];
+ baseDirPathArg = args[++i];
}
else if (arg == "-f" || arg == "--fullscreen")
{
- startFullscreen = true;
+ startFullscreenArg = true;
}
- else if (launchPath == null)
+ else if (launchPathArg == null)
{
- launchPath = arg;
+ launchPathArg = arg;
}
}
- // Delete backup files after updating
+ // Delete backup files after updating.
Task.Run(Updater.CleanupUpdate);
Toolkit.Init(new ToolkitOptions
{
- Backend = PlatformBackend.PreferNative,
- EnableHighResolution = true
+ Backend = PlatformBackend.PreferNative
});
Version = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
@@ -66,27 +69,27 @@ namespace Ryujinx
string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine);
Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}");
- // Hook unhandled exception and process exit events
- GLib.ExceptionManager.UnhandledException += (GLib.UnhandledExceptionArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
+ // Hook unhandled exception and process exit events.
+ GLib.ExceptionManager.UnhandledException += (GLib.UnhandledExceptionArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
- AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => ProgramExit();
+ AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit();
- // Setup base data directory
- AppDataManager.Initialize(baseDirPath);
+ // Setup base data directory.
+ AppDataManager.Initialize(baseDirPathArg);
- // Initialize the configuration
+ // Initialize the configuration.
ConfigurationState.Initialize();
- // Initialize the logger system
+ // Initialize the logger system.
LoggerModule.Initialize();
- // Initialize Discord integration
+ // Initialize Discord integration.
DiscordIntegrationModule.Initialize();
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json");
- string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json");
+ string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json");
- // Now load the configuration as the other subsystems are now registered
+ // Now load the configuration as the other subsystems are now registered.
if (File.Exists(localConfigurationPath))
{
ConfigurationPath = localConfigurationPath;
@@ -105,35 +108,42 @@ namespace Ryujinx
}
else
{
- // No configuration, we load the default values and save it on disk
+ // No configuration, we load the default values and save it on disk.
ConfigurationPath = appDataConfigurationPath;
ConfigurationState.Instance.LoadDefault();
ConfigurationState.Instance.ToFileFormat().SaveConfig(appDataConfigurationPath);
}
- if (startFullscreen)
+ if (startFullscreenArg)
{
ConfigurationState.Instance.Ui.StartFullscreen.Value = true;
}
+ // Logging system informations.
PrintSystemInfo();
+ // Initialize Gtk.
Application.Init();
+ // Check if keys exists.
bool hasGlobalProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys"));
bool hasAltProdKeys = !AppDataManager.IsCustomBasePath && File.Exists(Path.Combine(AppDataManager.KeysDirPathAlt, "prod.keys"));
- if (!hasGlobalProdKeys && !hasAltProdKeys && !Migration.IsMigrationNeeded())
+ if (!hasGlobalProdKeys && !hasAltProdKeys)
{
UserErrorDialog.CreateUserErrorDialog(UserError.NoKeys);
}
+ // Force dedicated GPU if we can.
+ ForceDedicatedGpu.Nvidia();
+
+ // Show the main window UI.
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
- if (launchPath != null)
+ if (launchPathArg != null)
{
- mainWindow.LoadApplication(launchPath);
+ mainWindow.LoadApplication(launchPathArg);
}
if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false))
@@ -147,7 +157,6 @@ namespace Ryujinx
private static void PrintSystemInfo()
{
Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}");
-
Logger.Notice.Print(LogClass.Application, $"Operating System: {SystemInfo.Instance.OsDescription}");
Logger.Notice.Print(LogClass.Application, $"CPU: {SystemInfo.Instance.CpuName}");
Logger.Notice.Print(LogClass.Application, $"Total RAM: {SystemInfo.Instance.RamSizeInMB}");
@@ -161,25 +170,30 @@ namespace Ryujinx
}
}
- private static void ProcessUnhandledException(Exception e, bool isTerminating)
+ private static void ProcessUnhandledException(Exception ex, bool isTerminating)
{
Ptc.Close();
PtcProfiler.Stop();
- string message = $"Unhandled exception caught: {e}";
+ string message = $"Unhandled exception caught: {ex}";
Logger.Error?.PrintMsg(LogClass.Application, message);
- if (Logger.Error == null) Logger.Notice.PrintMsg(LogClass.Application, message);
+ if (Logger.Error == null)
+ {
+ Logger.Notice.PrintMsg(LogClass.Application, message);
+ }
if (isTerminating)
{
- ProgramExit();
+ Exit();
}
}
- private static void ProgramExit()
+ public static void Exit()
{
+ DiscordIntegrationModule.Exit();
+
Ptc.Dispose();
PtcProfiler.Dispose();
diff --git a/Ryujinx/Ryujinx.csproj b/Ryujinx/Ryujinx.csproj
index 444cee84..7f0d23e7 100644
--- a/Ryujinx/Ryujinx.csproj
+++ b/Ryujinx/Ryujinx.csproj
@@ -55,53 +55,51 @@
</PropertyGroup>
<ItemGroup>
- <None Remove="Ui\AboutWindow.glade" />
- <None Remove="Ui\assets\JoyConLeft.svg" />
- <None Remove="Ui\assets\JoyConPair.svg" />
- <None Remove="Ui\assets\JoyConRight.svg" />
- <None Remove="Ui\assets\ProCon.svg" />
- <None Remove="Ui\assets\NCAIcon.png" />
- <None Remove="Ui\assets\NROIcon.png" />
- <None Remove="Ui\assets\NSOIcon.png" />
- <None Remove="Ui\assets\NSPIcon.png" />
- <None Remove="Ui\assets\XCIIcon.png" />
- <None Remove="Ui\assets\DiscordLogo.png" />
- <None Remove="Ui\assets\GitHubLogo.png" />
- <None Remove="Ui\assets\PatreonLogo.png" />
- <None Remove="Ui\assets\Icon.png" />
- <None Remove="Ui\assets\TwitterLogo.png" />
- <None Remove="Ui\ControllerWindow.glade" />
- <None Remove="Ui\DlcWindow.glade" />
<None Remove="Ui\MainWindow.glade" />
- <None Remove="Ui\ProfileDialog.glade" />
- <None Remove="Ui\SettingsWindow.glade" />
- <None Remove="Ui\TitleUpdateWindow.glade" />
- <None Remove="Ui\UpdateDialog.glade" />
+ <None Remove="Ui\Resources\Controller_JoyConLeft.svg" />
+ <None Remove="Ui\Resources\Controller_JoyConPair.svg" />
+ <None Remove="Ui\Resources\Controller_JoyConRight.svg" />
+ <None Remove="Ui\Resources\Controller_ProCon.svg" />
+ <None Remove="Ui\Resources\Icon_NCA.png" />
+ <None Remove="Ui\Resources\Icon_NRO.png" />
+ <None Remove="Ui\Resources\Icon_NSO.png" />
+ <None Remove="Ui\Resources\Icon_NSP.png" />
+ <None Remove="Ui\Resources\Icon_XCI.png" />
+ <None Remove="Ui\Resources\Logo_Discord.png" />
+ <None Remove="Ui\Resources\Logo_GitHub.png" />
+ <None Remove="Ui\Resources\Logo_Patreon.png" />
+ <None Remove="Ui\Resources\Logo_Ryujinx.png" />
+ <None Remove="Ui\Resources\Logo_Twitter.png" />
+ <None Remove="Ui\Widgets\ProfileDialog.glade" />
+ <None Remove="Ui\Windows\ControllerWindow.glade" />
+ <None Remove="Ui\Windows\DlcWindow.glade" />
+ <None Remove="Ui\Windows\SettingsWindow.glade" />
+ <None Remove="Ui\Windows\TitleUpdateWindow.glade" />
+ <None Remove="Modules\Updater\UpdateDialog.glade" />
</ItemGroup>
<ItemGroup>
- <EmbeddedResource Include="Ui\AboutWindow.glade" />
- <EmbeddedResource Include="Ui\assets\JoyConLeft.svg" />
- <EmbeddedResource Include="Ui\assets\JoyConPair.svg" />
- <EmbeddedResource Include="Ui\assets\JoyConRight.svg" />
- <EmbeddedResource Include="Ui\assets\ProCon.svg" />
- <EmbeddedResource Include="Ui\assets\NCAIcon.png" />
- <EmbeddedResource Include="Ui\assets\NROIcon.png" />
- <EmbeddedResource Include="Ui\assets\NSOIcon.png" />
- <EmbeddedResource Include="Ui\assets\NSPIcon.png" />
- <EmbeddedResource Include="Ui\assets\XCIIcon.png" />
- <EmbeddedResource Include="Ui\assets\DiscordLogo.png" />
- <EmbeddedResource Include="Ui\assets\GitHubLogo.png" />
- <EmbeddedResource Include="Ui\assets\PatreonLogo.png" />
- <EmbeddedResource Include="Ui\assets\Icon.png" />
- <EmbeddedResource Include="Ui\assets\TwitterLogo.png" />
- <EmbeddedResource Include="Ui\ControllerWindow.glade" />
<EmbeddedResource Include="Ui\MainWindow.glade" />
- <EmbeddedResource Include="Ui\ProfileDialog.glade" />
- <EmbeddedResource Include="Ui\SettingsWindow.glade" />
- <EmbeddedResource Include="Ui\DlcWindow.glade" />
- <EmbeddedResource Include="Ui\TitleUpdateWindow.glade" />
- <EmbeddedResource Include="Updater\UpdateDialog.glade" />
+ <EmbeddedResource Include="Ui\Resources\Controller_JoyConLeft.svg" />
+ <EmbeddedResource Include="Ui\Resources\Controller_JoyConPair.svg" />
+ <EmbeddedResource Include="Ui\Resources\Controller_JoyConRight.svg" />
+ <EmbeddedResource Include="Ui\Resources\Controller_ProCon.svg" />
+ <EmbeddedResource Include="Ui\Resources\Icon_NCA.png" />
+ <EmbeddedResource Include="Ui\Resources\Icon_NRO.png" />
+ <EmbeddedResource Include="Ui\Resources\Icon_NSO.png" />
+ <EmbeddedResource Include="Ui\Resources\Icon_NSP.png" />
+ <EmbeddedResource Include="Ui\Resources\Icon_XCI.png" />
+ <EmbeddedResource Include="Ui\Resources\Logo_Discord.png" />
+ <EmbeddedResource Include="Ui\Resources\Logo_GitHub.png" />
+ <EmbeddedResource Include="Ui\Resources\Logo_Patreon.png" />
+ <EmbeddedResource Include="Ui\Resources\Logo_Ryujinx.png" />
+ <EmbeddedResource Include="Ui\Resources\Logo_Twitter.png" />
+ <EmbeddedResource Include="Ui\Widgets\ProfileDialog.glade" />
+ <EmbeddedResource Include="Ui\Windows\ControllerWindow.glade" />
+ <EmbeddedResource Include="Ui\Windows\DlcWindow.glade" />
+ <EmbeddedResource Include="Ui\Windows\SettingsWindow.glade" />
+ <EmbeddedResource Include="Ui\Windows\TitleUpdateWindow.glade" />
+ <EmbeddedResource Include="Modules\Updater\UpdateDialog.glade" />
</ItemGroup>
</Project>
diff --git a/Ryujinx/Ui/AboutWindow.cs b/Ryujinx/Ui/AboutWindow.cs
deleted file mode 100644
index 23c0d9af..00000000
--- a/Ryujinx/Ui/AboutWindow.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using Gtk;
-using System;
-using System.Reflection;
-
-using GUI = Gtk.Builder.ObjectAttribute;
-
-namespace Ryujinx.Ui
-{
- public class AboutWindow : Window
- {
-#pragma warning disable CS0649
-#pragma warning disable IDE0044
- [GUI] Label _versionText;
- [GUI] Image _ryujinxLogo;
- [GUI] Image _patreonLogo;
- [GUI] Image _gitHubLogo;
- [GUI] Image _discordLogo;
- [GUI] Image _twitterLogo;
-#pragma warning restore CS0649
-#pragma warning restore IDE0044
-
- public AboutWindow() : this(new Builder("Ryujinx.Ui.AboutWindow.glade")) { }
-
- private AboutWindow(Builder builder) : base(builder.GetObject("_aboutWin").Handle)
- {
- builder.Autoconnect(this);
-
- this.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
- _ryujinxLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png" , 100, 100);
- _patreonLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.PatreonLogo.png", 30 , 30 );
- _gitHubLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.GitHubLogo.png" , 30 , 30 );
- _discordLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.DiscordLogo.png", 30 , 30 );
- _twitterLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.TwitterLogo.png", 30 , 30 );
-
- _versionText.Text = Program.Version;
- }
-
- //Events
- private void RyujinxButton_Pressed(object sender, ButtonPressEventArgs args)
- {
- UrlHelper.OpenUrl("https://ryujinx.org");
- }
-
- private void PatreonButton_Pressed(object sender, ButtonPressEventArgs args)
- {
- UrlHelper.OpenUrl("https://www.patreon.com/ryujinx");
- }
-
- private void GitHubButton_Pressed(object sender, ButtonPressEventArgs args)
- {
- UrlHelper.OpenUrl("https://github.com/Ryujinx/Ryujinx");
- }
-
- private void DiscordButton_Pressed(object sender, ButtonPressEventArgs args)
- {
- UrlHelper.OpenUrl("https://discordapp.com/invite/N2FmfVc");
- }
-
- private void TwitterButton_Pressed(object sender, ButtonPressEventArgs args)
- {
- UrlHelper.OpenUrl("https://twitter.com/RyujinxEmu");
- }
-
- private void ContributorsButton_Pressed(object sender, ButtonPressEventArgs args)
- {
- UrlHelper.OpenUrl("https://github.com/Ryujinx/Ryujinx/graphs/contributors?type=a");
- }
-
- private void CloseToggle_Activated(object sender, EventArgs args)
- {
- Dispose();
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx/Ui/AboutWindow.glade b/Ryujinx/Ui/AboutWindow.glade
deleted file mode 100644
index 8a27f372..00000000
--- a/Ryujinx/Ui/AboutWindow.glade
+++ /dev/null
@@ -1,574 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.1 -->
-<interface>
- <requires lib="gtk+" version="3.20"/>
- <object class="GtkDialog" id="_aboutWin">
- <property name="can_focus">False</property>
- <property name="resizable">False</property>
- <property name="modal">True</property>
- <property name="window_position">center</property>
- <property name="default_width">800</property>
- <property name="default_height">350</property>
- <property name="type_hint">dialog</property>
- <child type="titlebar">
- <placeholder/>
- </child>
- <child internal-child="vbox">
- <object class="GtkBox">
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child internal-child="action_area">
- <object class="GtkButtonBox">
- <property name="can_focus">False</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="bigBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkBox" id="leftBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">10</property>
- <property name="margin_right">15</property>
- <property name="margin_top">10</property>
- <property name="margin_bottom">15</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="valign">start</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkImage" id="_ryujinxLogo">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">10</property>
- <property name="margin_right">10</property>
- <property name="margin_top">10</property>
- <property name="margin_bottom">10</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="valign">center</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Ryujinx</property>
- <property name="justify">center</property>
- <attributes>
- <attribute name="scale" value="2.7000000000000002"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">(REE-YOU-JI-NX)</property>
- <property name="justify">center</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEventBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <signal name="button-press-event" handler="RyujinxButton_Pressed" swapped="no"/>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="tooltip_text" translatable="yes">Click to open the Ryujinx website in your default browser</property>
- <property name="label" translatable="yes">www.ryujinx.org</property>
- <property name="justify">center</property>
- <attributes>
- <attribute name="underline" value="True"/>
- </attributes>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="padding">5</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="_versionText">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Version x.x.x (Commit Number)</property>
- <property name="justify">center</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="padding">2</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="license">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">MIT License</property>
- <property name="justify">center</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="padding">5</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="disclaimer">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Ryujinx is not affiliated with Nintendo,
-or any of its partners, in any way</property>
- <property name="justify">center</property>
- <attributes>
- <attribute name="scale" value="0.80000000000000004"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="padding">5</property>
- <property name="position">3</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_top">25</property>
- <child>
- <object class="GtkEventBox" id="PatreonButton">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="tooltip_text" translatable="yes">Click to open the Ryujinx Patreon page in your default browser</property>
- <signal name="button-press-event" handler="PatreonButton_Pressed" swapped="no"/>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkImage" id="_patreonLogo">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Patreon</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEventBox" id="GitHubButton">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="tooltip_text" translatable="yes">Click to open the Ryujinx GitHub page in your default browser</property>
- <signal name="button-press-event" handler="GitHubButton_Pressed" swapped="no"/>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkImage" id="_gitHubLogo">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">GitHub</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEventBox" id="DiscordButton">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="tooltip_text" translatable="yes">Click to open an invite to the Ryujinx Discord server in your default browser</property>
- <signal name="button-press-event" handler="DiscordButton_Pressed" swapped="no"/>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkImage" id="_discordLogo">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Discord</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkEventBox" id="TwitterButton">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="tooltip_text" translatable="yes">Click to open the Ryujinx Twitter page in your default browser</property>
- <signal name="button-press-event" handler="TwitterButton_Pressed" swapped="no"/>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkImage" id="_twitterLogo">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Twitter</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">3</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkSeparator">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_top">10</property>
- <property name="margin_bottom">10</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="rightBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">15</property>
- <property name="margin_right">10</property>
- <property name="margin_top">40</property>
- <property name="margin_bottom">15</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">About</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="margin_left">10</property>
- <property name="label" translatable="yes">Ryujinx is an emulator for the Nintendo Switch.
-Please support us on Patreon.
-Get all the latest news on our Twitter or Discord.
-Developers interested in contributing can find out more on our Discord.</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="padding">5</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">Created By:</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="padding">5</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">10</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkScrolledWindow">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkViewport">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="baseline_position">top</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">gdkchan
-LDj3SNuD
-Ac_K
-Thog</property>
- <property name="yalign">0</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">»jD«
-emmaus
-Thealexbarney
-Andy A (BaronKiko)</property>
- <property name="yalign">0</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEventBox" id="ContributorsButton">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="valign">start</property>
- <signal name="button-press-event" handler="ContributorsButton_Pressed" swapped="no"/>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">end</property>
- <property name="margin_right">5</property>
- <property name="label" translatable="yes">All Contributors...</property>
- <attributes>
- <attribute name="underline" value="True"/>
- </attributes>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">3</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
-</interface>
diff --git a/Ryujinx/Ui/ApplicationAddedEventArgs.cs b/Ryujinx/Ui/App/ApplicationAddedEventArgs.cs
index 5e09389b..53577e67 100644
--- a/Ryujinx/Ui/ApplicationAddedEventArgs.cs
+++ b/Ryujinx/Ui/App/ApplicationAddedEventArgs.cs
@@ -1,6 +1,6 @@
using System;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.App
{
public class ApplicationAddedEventArgs : EventArgs
{
diff --git a/Ryujinx/Ui/ApplicationCountUpdatedEventArgs.cs b/Ryujinx/Ui/App/ApplicationCountUpdatedEventArgs.cs
index 78e2e50c..510ee786 100644
--- a/Ryujinx/Ui/ApplicationCountUpdatedEventArgs.cs
+++ b/Ryujinx/Ui/App/ApplicationCountUpdatedEventArgs.cs
@@ -1,6 +1,6 @@
using System;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.App
{
public class ApplicationCountUpdatedEventArgs : EventArgs
{
diff --git a/Ryujinx/Ui/ApplicationData.cs b/Ryujinx/Ui/App/ApplicationData.cs
index 34784c6c..3940abe9 100644
--- a/Ryujinx/Ui/ApplicationData.cs
+++ b/Ryujinx/Ui/App/ApplicationData.cs
@@ -1,10 +1,9 @@
-using LibHac;
-using LibHac.Common;
+using LibHac.Common;
using LibHac.Ns;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.App
{
- public struct ApplicationData
+ public class ApplicationData
{
public bool Favorite { get; set; }
public byte[] Icon { get; set; }
@@ -19,4 +18,4 @@ namespace Ryujinx.Ui
public string Path { get; set; }
public BlitStruct<ApplicationControlProperty> ControlHolder { get; set; }
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/ApplicationLibrary.cs b/Ryujinx/Ui/App/ApplicationLibrary.cs
index 353b686e..fb0e0664 100644
--- a/Ryujinx/Ui/ApplicationLibrary.cs
+++ b/Ryujinx/Ui/App/ApplicationLibrary.cs
@@ -11,6 +11,7 @@ using Ryujinx.Configuration.System;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using Ryujinx.HLE.Loaders.Npdm;
+using Ryujinx.Ui.Widgets;
using System;
using System.Collections.Generic;
using System.IO;
@@ -20,24 +21,45 @@ using System.Text.Json;
using JsonHelper = Ryujinx.Common.Utilities.JsonHelper;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.App
{
public class ApplicationLibrary
{
- public static event EventHandler<ApplicationAddedEventArgs> ApplicationAdded;
- public static event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated;
+ public event EventHandler<ApplicationAddedEventArgs> ApplicationAdded;
+ public event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated;
- private static readonly byte[] _nspIcon = GetResourceBytes("Ryujinx.Ui.assets.NSPIcon.png");
- private static readonly byte[] _xciIcon = GetResourceBytes("Ryujinx.Ui.assets.XCIIcon.png");
- private static readonly byte[] _ncaIcon = GetResourceBytes("Ryujinx.Ui.assets.NCAIcon.png");
- private static readonly byte[] _nroIcon = GetResourceBytes("Ryujinx.Ui.assets.NROIcon.png");
- private static readonly byte[] _nsoIcon = GetResourceBytes("Ryujinx.Ui.assets.NSOIcon.png");
+ private readonly byte[] _nspIcon;
+ private readonly byte[] _xciIcon;
+ private readonly byte[] _ncaIcon;
+ private readonly byte[] _nroIcon;
+ private readonly byte[] _nsoIcon;
- private static VirtualFileSystem _virtualFileSystem;
- private static Language _desiredTitleLanguage;
- private static bool _loadingError;
+ private VirtualFileSystem _virtualFileSystem;
+ private Language _desiredTitleLanguage;
+ private bool _loadingError;
- public static IEnumerable<string> GetFilesInDirectory(string directory)
+ public ApplicationLibrary(VirtualFileSystem virtualFileSystem)
+ {
+ _virtualFileSystem = virtualFileSystem;
+
+ _nspIcon = GetResourceBytes("Ryujinx.Ui.Resources.Icon_NSP.png");
+ _xciIcon = GetResourceBytes("Ryujinx.Ui.Resources.Icon_XCI.png");
+ _ncaIcon = GetResourceBytes("Ryujinx.Ui.Resources.Icon_NCA.png");
+ _nroIcon = GetResourceBytes("Ryujinx.Ui.Resources.Icon_NRO.png");
+ _nsoIcon = GetResourceBytes("Ryujinx.Ui.Resources.Icon_NSO.png");
+ }
+
+ private byte[] GetResourceBytes(string resourceName)
+ {
+ Stream resourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream(resourceName);
+ byte[] resourceByteArray = new byte[resourceStream.Length];
+
+ resourceStream.Read(resourceByteArray);
+
+ return resourceByteArray;
+ }
+
+ public IEnumerable<string> GetFilesInDirectory(string directory)
{
Stack<string> stack = new Stack<string>();
@@ -46,7 +68,7 @@ namespace Ryujinx.Ui
while (stack.Count > 0)
{
string dir = stack.Pop();
- string[] content = { };
+ string[] content = Array.Empty<string>();
try
{
@@ -84,19 +106,18 @@ namespace Ryujinx.Ui
}
}
- public static void ReadControlData(IFileSystem controlFs, Span<byte> outProperty)
+ public void ReadControlData(IFileSystem controlFs, Span<byte> outProperty)
{
controlFs.OpenFile(out IFile controlFile, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
controlFile.Read(out _, 0, outProperty, ReadOption.None).ThrowIfFailure();
}
- public static void LoadApplications(List<string> appDirs, VirtualFileSystem virtualFileSystem, Language desiredTitleLanguage)
+ public void LoadApplications(List<string> appDirs, Language desiredTitleLanguage)
{
int numApplicationsFound = 0;
int numApplicationsLoaded = 0;
_loadingError = false;
- _virtualFileSystem = virtualFileSystem;
_desiredTitleLanguage = desiredTitleLanguage;
// Builds the applications list with paths to found applications
@@ -442,36 +463,26 @@ namespace Ryujinx.Ui
}
}
- protected static void OnApplicationAdded(ApplicationAddedEventArgs e)
+ protected void OnApplicationAdded(ApplicationAddedEventArgs e)
{
ApplicationAdded?.Invoke(null, e);
}
- protected static void OnApplicationCountUpdated(ApplicationCountUpdatedEventArgs e)
+ protected void OnApplicationCountUpdated(ApplicationCountUpdatedEventArgs e)
{
ApplicationCountUpdated?.Invoke(null, e);
}
- private static byte[] GetResourceBytes(string resourceName)
- {
- Stream resourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream(resourceName);
- byte[] resourceByteArray = new byte[resourceStream.Length];
-
- resourceStream.Read(resourceByteArray);
-
- return resourceByteArray;
- }
-
- private static void GetControlFsAndTitleId(PartitionFileSystem pfs, out IFileSystem controlFs, out string titleId)
+ private void GetControlFsAndTitleId(PartitionFileSystem pfs, out IFileSystem controlFs, out string titleId)
{
(_, _, Nca controlNca) = ApplicationLoader.GetGameData(_virtualFileSystem, pfs, 0);
// Return the ControlFS
controlFs = controlNca?.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None);
- titleId = controlNca?.Header.TitleId.ToString("x16");
+ titleId = controlNca?.Header.TitleId.ToString("x16");
}
- internal static ApplicationMetadata LoadAndSaveMetaData(string titleId, Action<ApplicationMetadata> modifyFunction = null)
+ internal ApplicationMetadata LoadAndSaveMetaData(string titleId, Action<ApplicationMetadata> modifyFunction = null)
{
string metadataFolder = Path.Combine(AppDataManager.GamesDirPath, titleId, "gui");
string metadataFile = Path.Combine(metadataFolder, "metadata.json");
@@ -482,12 +493,7 @@ namespace Ryujinx.Ui
{
Directory.CreateDirectory(metadataFolder);
- appMetadata = new ApplicationMetadata
- {
- Favorite = false,
- TimePlayed = 0,
- LastPlayed = "Never"
- };
+ appMetadata = new ApplicationMetadata();
using (FileStream stream = File.Create(metadataFile, 4096, FileOptions.WriteThrough))
{
@@ -503,12 +509,7 @@ namespace Ryujinx.Ui
{
Logger.Warning?.Print(LogClass.Application, $"Failed to parse metadata json for {titleId}. Loading defaults.");
- appMetadata = new ApplicationMetadata
- {
- Favorite = false,
- TimePlayed = 0,
- LastPlayed = "Never"
- };
+ appMetadata = new ApplicationMetadata();
}
if (modifyFunction != null)
@@ -524,7 +525,7 @@ namespace Ryujinx.Ui
return appMetadata;
}
- private static string ConvertSecondsToReadableString(double seconds)
+ private string ConvertSecondsToReadableString(double seconds)
{
const int secondsPerMinute = 60;
const int secondsPerHour = secondsPerMinute * 60;
@@ -552,9 +553,9 @@ namespace Ryujinx.Ui
return readableString;
}
- private static void GetNameIdDeveloper(ref ApplicationControlProperty controlData, out string titleName, out string titleId, out string publisher)
+ private void GetNameIdDeveloper(ref ApplicationControlProperty controlData, out string titleName, out string titleId, out string publisher)
{
- Enum.TryParse(_desiredTitleLanguage.ToString(), out TitleLanguage desiredTitleLanguage);
+ _ = Enum.TryParse(_desiredTitleLanguage.ToString(), out TitleLanguage desiredTitleLanguage);
if (controlData.Titles.Length > (int)desiredTitleLanguage)
{
@@ -611,7 +612,7 @@ namespace Ryujinx.Ui
}
}
- private static bool IsUpdateApplied(string titleId, out string version)
+ private bool IsUpdateApplied(string titleId, out string version)
{
string updatePath = "(unknown)";
diff --git a/Ryujinx/Ui/App/ApplicationMetadata.cs b/Ryujinx/Ui/App/ApplicationMetadata.cs
new file mode 100644
index 00000000..2bd87c0e
--- /dev/null
+++ b/Ryujinx/Ui/App/ApplicationMetadata.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Ui.App
+{
+ public class ApplicationMetadata
+ {
+ public bool Favorite { get; set; }
+ public double TimePlayed { get; set; }
+ public string LastPlayed { get; set; } = "Never";
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/ErrorAppletDialog.cs b/Ryujinx/Ui/Applet/ErrorAppletDialog.cs
index f7a548b3..a51d5324 100644
--- a/Ryujinx/Ui/ErrorAppletDialog.cs
+++ b/Ryujinx/Ui/Applet/ErrorAppletDialog.cs
@@ -1,16 +1,11 @@
using Gtk;
-using System.Reflection;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.Applet
{
internal class ErrorAppletDialog : MessageDialog
{
- internal static bool _isExitDialogOpen = false;
-
public ErrorAppletDialog(Window parentWindow, DialogFlags dialogFlags, MessageType messageType, string[] buttons) : base(parentWindow, dialogFlags, messageType, ButtonsType.None, null)
{
- Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
-
int responseId = 0;
if (buttons != null)
diff --git a/Ryujinx/Ui/GtkHostUiHandler.cs b/Ryujinx/Ui/Applet/GtkHostUiHandler.cs
index 12ba81c4..804a1a27 100644
--- a/Ryujinx/Ui/GtkHostUiHandler.cs
+++ b/Ryujinx/Ui/Applet/GtkHostUiHandler.cs
@@ -1,12 +1,12 @@
using Gtk;
-using Ryujinx.Common.Logging;
using Ryujinx.HLE;
using Ryujinx.HLE.HOS.Applets;
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
+using Ryujinx.Ui.Widgets;
using System;
using System.Threading;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.Applet
{
internal class GtkHostUiHandler : IHostUiHandler
{
@@ -19,16 +19,13 @@ namespace Ryujinx.Ui
public bool DisplayMessageDialog(ControllerAppletUiArgs args)
{
- string playerCount = args.PlayerCountMin == args.PlayerCountMax
- ? $"exactly {args.PlayerCountMin}"
- : $"{args.PlayerCountMin}-{args.PlayerCountMax}";
+ string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}";
- string message =
- $"Application requests <b>{playerCount}</b> player(s) with:\n\n"
- + $"<tt><b>TYPES:</b> {args.SupportedStyles}</tt>\n\n"
- + $"<tt><b>PLAYERS:</b> {string.Join(", ", args.SupportedPlayers)}</tt>\n\n"
- + (args.IsDocked ? "Docked mode set. <tt>Handheld</tt> is also invalid.\n\n" : "")
- + "<i>Please reconfigure Input now and then press OK.</i>";
+ string message = $"Application requests <b>{playerCount}</b> player(s) with:\n\n"
+ + $"<tt><b>TYPES:</b> {args.SupportedStyles}</tt>\n\n"
+ + $"<tt><b>PLAYERS:</b> {string.Join(", ", args.SupportedPlayers)}</tt>\n\n"
+ + (args.IsDocked ? "Docked mode set. <tt>Handheld</tt> is also invalid.\n\n" : "")
+ + "<i>Please reconfigure Input now and then press OK.</i>";
return DisplayMessageDialog("Controller Applet", message);
}
@@ -36,17 +33,19 @@ namespace Ryujinx.Ui
public bool DisplayMessageDialog(string title, string message)
{
ManualResetEvent dialogCloseEvent = new ManualResetEvent(false);
+
bool okPressed = false;
Application.Invoke(delegate
{
MessageDialog msgDialog = null;
+
try
{
msgDialog = new MessageDialog(_parent, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null)
{
- Title = title,
- Text = message,
+ Title = title,
+ Text = message,
UseMarkup = true
};
@@ -54,16 +53,21 @@ namespace Ryujinx.Ui
msgDialog.Response += (object o, ResponseArgs args) =>
{
- if (args.ResponseId == ResponseType.Ok) okPressed = true;
+ if (args.ResponseId == ResponseType.Ok)
+ {
+ okPressed = true;
+ }
+
dialogCloseEvent.Set();
msgDialog?.Dispose();
};
msgDialog.Show();
}
- catch (Exception e)
+ catch (Exception ex)
{
- Logger.Error?.Print(LogClass.Application, $"Error displaying Message Dialog: {e}");
+ GtkDialog.CreateErrorDialog($"Error displaying Message Dialog: {ex}");
+
dialogCloseEvent.Set();
}
});
@@ -76,24 +80,25 @@ namespace Ryujinx.Ui
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
{
ManualResetEvent dialogCloseEvent = new ManualResetEvent(false);
- bool okPressed = false;
- bool error = false;
+
+ bool okPressed = false;
+ bool error = false;
string inputText = args.InitialText ?? "";
Application.Invoke(delegate
{
try
{
- var swkbdDialog = new InputDialog(_parent)
+ var swkbdDialog = new SwkbdAppletDialog(_parent)
{
- Title = "Software Keyboard",
- Text = args.HeaderText,
+ Title = "Software Keyboard",
+ Text = args.HeaderText,
SecondaryText = args.SubtitleText
};
- swkbdDialog.InputEntry.Text = inputText;
+ swkbdDialog.InputEntry.Text = inputText;
swkbdDialog.InputEntry.PlaceholderText = args.GuideText;
- swkbdDialog.OkButton.Label = args.SubmitText;
+ swkbdDialog.OkButton.Label = args.SubmitText;
swkbdDialog.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax);
@@ -105,10 +110,11 @@ namespace Ryujinx.Ui
swkbdDialog.Dispose();
}
- catch (Exception e)
+ catch (Exception ex)
{
error = true;
- Logger.Error?.Print(LogClass.Application, $"Error displaying Software Keyboard: {e}");
+
+ GtkDialog.CreateErrorDialog($"Error displaying Software Keyboard: {ex}");
}
finally
{
@@ -126,12 +132,13 @@ namespace Ryujinx.Ui
public void ExecuteProgram(HLE.Switch device, ProgramSpecifyKind kind, ulong value)
{
device.UserChannelPersistence.ExecuteProgram(kind, value);
- MainWindow.GlWidget?.Exit();
+ ((MainWindow)_parent).GlRendererWidget?.Exit();
}
public bool DisplayErrorAppletDialog(string title, string message, string[] buttons)
{
ManualResetEvent dialogCloseEvent = new ManualResetEvent(false);
+
bool showDetails = false;
Application.Invoke(delegate
@@ -167,9 +174,9 @@ namespace Ryujinx.Ui
msgDialog.Show();
}
- catch (Exception e)
+ catch (Exception ex)
{
- Logger.Error?.Print(LogClass.Application, $"Error displaying ErrorApplet Dialog: {e}");
+ GtkDialog.CreateErrorDialog($"Error displaying ErrorApplet Dialog: {ex}");
dialogCloseEvent.Set();
}
@@ -180,4 +187,4 @@ namespace Ryujinx.Ui
return showDetails;
}
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs b/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs
new file mode 100644
index 00000000..7c14f0e8
--- /dev/null
+++ b/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs
@@ -0,0 +1,89 @@
+using Gtk;
+using System;
+
+namespace Ryujinx.Ui.Applet
+{
+ public class SwkbdAppletDialog : MessageDialog
+ {
+ private int _inputMin;
+ private int _inputMax;
+
+ private Predicate<int> _checkLength;
+
+ private readonly Label _validationInfo;
+
+ public Entry InputEntry { get; }
+ public Button OkButton { get; }
+ public Button CancelButton { get; }
+
+ public SwkbdAppletDialog(Window parent) : base(parent, DialogFlags.Modal | DialogFlags.DestroyWithParent, MessageType.Question, ButtonsType.None, null)
+ {
+ SetDefaultSize(300, 0);
+
+ _validationInfo = new Label()
+ {
+ Visible = false
+ };
+
+ InputEntry = new Entry()
+ {
+ Visible = true
+ };
+
+ InputEntry.Activated += OnInputActivated;
+ InputEntry.Changed += OnInputChanged;
+
+ OkButton = (Button)AddButton("OK", ResponseType.Ok);
+ CancelButton = (Button)AddButton("Cancel", ResponseType.Cancel);
+
+ ((Box)MessageArea).PackEnd(_validationInfo, true, true, 0);
+ ((Box)MessageArea).PackEnd(InputEntry, true, true, 4);
+
+ SetInputLengthValidation(0, int.MaxValue); // Disable by default.
+ }
+
+ public void SetInputLengthValidation(int min, int max)
+ {
+ _inputMin = Math.Min(min, max);
+ _inputMax = Math.Max(min, max);
+
+ _validationInfo.Visible = false;
+
+ if (_inputMin <= 0 && _inputMax == int.MaxValue) // Disable.
+ {
+ _validationInfo.Visible = false;
+
+ _checkLength = (length) => true;
+ }
+ else if (_inputMin > 0 && _inputMax == int.MaxValue)
+ {
+ _validationInfo.Visible = true;
+ _validationInfo.Markup = $"<i>Must be at least {_inputMin} characters long</i>";
+
+ _checkLength = (length) => _inputMin <= length;
+ }
+ else
+ {
+ _validationInfo.Visible = true;
+ _validationInfo.Markup = $"<i>Must be {_inputMin}-{_inputMax} characters long</i>";
+
+ _checkLength = (length) => _inputMin <= length && length <= _inputMax;
+ }
+
+ OnInputChanged(this, EventArgs.Empty);
+ }
+
+ private void OnInputActivated(object sender, EventArgs e)
+ {
+ if (OkButton.IsSensitive)
+ {
+ Respond(ResponseType.Ok);
+ }
+ }
+
+ private void OnInputChanged(object sender, EventArgs e)
+ {
+ OkButton.Sensitive = _checkLength(InputEntry.Text.Length);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/ApplicationMetadata.cs b/Ryujinx/Ui/ApplicationMetadata.cs
deleted file mode 100644
index cdedf91b..00000000
--- a/Ryujinx/Ui/ApplicationMetadata.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Ryujinx.Ui
-{
- internal class ApplicationMetadata
- {
- public bool Favorite { get; set; }
- public double TimePlayed { get; set; }
- public string LastPlayed { get; set; }
- }
-}
diff --git a/Ryujinx/Ui/Diagnostic/GuideDialog.cs b/Ryujinx/Ui/Diagnostic/GuideDialog.cs
deleted file mode 100644
index c3a0dd38..00000000
--- a/Ryujinx/Ui/Diagnostic/GuideDialog.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using Gtk;
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Text;
-
-namespace Ryujinx.Ui.Diagnostic
-{
- internal class GuideDialog : MessageDialog
- {
- internal static bool _isExitDialogOpen = false;
-
- public GuideDialog(string title, string mainText, string secondaryText) : base(null, DialogFlags.Modal, MessageType.Other, ButtonsType.None, null)
- {
- Title = title;
- Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
- Text = mainText;
- SecondaryText = secondaryText;
- WindowPosition = WindowPosition.Center;
- Response += GtkDialog_Response;
-
- Button guideButton = new Button();
- guideButton.Label = "Open the Setup Guide";
-
- ContentArea.Add(guideButton);
-
- SetSizeRequest(100, 10);
- ShowAll();
- }
-
- private void GtkDialog_Response(object sender, ResponseArgs args)
- {
- Dispose();
- }
- }
-}
diff --git a/Ryujinx/Ui/Diagnostic/UserErrorDialog.cs b/Ryujinx/Ui/Diagnostic/UserErrorDialog.cs
deleted file mode 100644
index ccea9229..00000000
--- a/Ryujinx/Ui/Diagnostic/UserErrorDialog.cs
+++ /dev/null
@@ -1,137 +0,0 @@
-using Gtk;
-using System.Reflection;
-
-namespace Ryujinx.Ui.Diagnostic
-{
- internal class UserErrorDialog : MessageDialog
- {
- private static string SetupGuideUrl = "https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide";
- private const int OkResponseId = 0;
- private const int SetupGuideResponseId = 1;
-
- private UserError _userError;
-
- private UserErrorDialog(UserError error) : base(null, DialogFlags.Modal, MessageType.Error, ButtonsType.None, null)
- {
- _userError = error;
- Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
- WindowPosition = WindowPosition.Center;
- Response += UserErrorDialog_Response;
-
- SetSizeRequest(120, 50);
-
- AddButton("OK", OkResponseId);
-
- bool isInSetupGuide = IsCoveredBySetupGuide(error);
-
- if (isInSetupGuide)
- {
- AddButton("Open the Setup Guide", SetupGuideResponseId);
- }
-
- string errorCode = GetErrorCode(error);
-
- SecondaryUseMarkup = true;
-
- Title = $"Ryujinx error ({errorCode})";
- Text = $"{errorCode}: {GetErrorTitle(error)}";
- SecondaryText = GetErrorDescription(error);
-
- if (isInSetupGuide)
- {
- SecondaryText += "\n<b>For more information on how to fix this error, follow our Setup Guide.</b>";
- }
- }
-
- private static string GetErrorCode(UserError error)
- {
- return $"RYU-{(uint)error:X4}";
- }
-
- private static string GetErrorTitle(UserError error)
- {
- switch (error)
- {
- case UserError.NoKeys:
- return "Keys not found";
- case UserError.NoFirmware:
- return "Firmware not found";
- case UserError.FirmwareParsingFailed:
- return "Firmware parsing error";
- case UserError.ApplicationNotFound:
- return "Application not found";
- case UserError.Unknown:
- return "Unknown error";
- default:
- return "Undefined error";
- }
- }
-
- private static string GetErrorDescription(UserError error)
- {
- switch (error)
- {
- case UserError.NoKeys:
- return "Ryujinx was unable to find your 'prod.keys' file";
- case UserError.NoFirmware:
- return "Ryujinx was unable to find any firmwares installed";
- case UserError.FirmwareParsingFailed:
- return "Ryujinx was unable to parse the provided firmware. This is usually caused by outdated keys.";
- case UserError.ApplicationNotFound:
- return "Ryujinx couldn't find a valid application at the given path.";
- case UserError.Unknown:
- return "An unknown error occured!";
- default:
- return "An undefined error occured! This shouldn't happen, please contact a dev!";
- }
- }
-
- private static bool IsCoveredBySetupGuide(UserError error)
- {
- switch (error)
- {
- case UserError.NoKeys:
- case UserError.NoFirmware:
- case UserError.FirmwareParsingFailed:
- return true;
- default:
- return false;
- }
- }
-
- private static string GetSetupGuideUrl(UserError error)
- {
- if (!IsCoveredBySetupGuide(error))
- {
- return null;
- }
-
- switch (error)
- {
- case UserError.NoKeys:
- return SetupGuideUrl + "#initial-setup---placement-of-prodkeys";
- case UserError.NoFirmware:
- return SetupGuideUrl + "#initial-setup-continued---installation-of-firmware";
- }
-
- return SetupGuideUrl;
- }
-
- private void UserErrorDialog_Response(object sender, ResponseArgs args)
- {
- int responseId = (int)args.ResponseId;
-
- if (responseId == SetupGuideResponseId)
- {
- UrlHelper.OpenUrl(GetSetupGuideUrl(_userError));
- }
-
- Dispose();
- }
-
- public static void CreateUserErrorDialog(UserError error)
- {
- new UserErrorDialog(error).Run();
- }
- }
-}
diff --git a/Ryujinx/Ui/GLRenderer.cs b/Ryujinx/Ui/GLRenderer.cs
index c20cc78b..6115c22b 100644
--- a/Ryujinx/Ui/GLRenderer.cs
+++ b/Ryujinx/Ui/GLRenderer.cs
@@ -11,7 +11,8 @@ using Ryujinx.Configuration;
using Ryujinx.Graphics.OpenGL;
using Ryujinx.HLE;
using Ryujinx.HLE.HOS.Services.Hid;
-using Ryujinx.Motion;
+using Ryujinx.Modules.Motion;
+using Ryujinx.Ui.Widgets;
using System;
using System.Collections.Generic;
using System.Threading;
@@ -73,9 +74,9 @@ namespace Ryujinx.Ui
_device = device;
- this.Initialized += GLRenderer_Initialized;
- this.Destroyed += GLRenderer_Destroyed;
- this.ShuttingDown += GLRenderer_ShuttingDown;
+ Initialized += GLRenderer_Initialized;
+ Destroyed += GLRenderer_Destroyed;
+ ShuttingDown += GLRenderer_ShuttingDown;
Initialize();
@@ -89,7 +90,7 @@ namespace Ryujinx.Ui
| EventMask.KeyPressMask
| EventMask.KeyReleaseMask));
- this.Shown += Renderer_Shown;
+ Shown += Renderer_Shown;
_dsuClient = new Client();
diff --git a/Ryujinx/Ui/UrlHelper.cs b/Ryujinx/Ui/Helper/OpenHelper.cs
index 79eacc67..6ccf4de3 100644
--- a/Ryujinx/Ui/UrlHelper.cs
+++ b/Ryujinx/Ui/Helper/OpenHelper.cs
@@ -2,10 +2,20 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.Helper
{
- static class UrlHelper
+ static class OpenHelper
{
+ public static void OpenFolder(string path)
+ {
+ Process.Start(new ProcessStartInfo
+ {
+ FileName = path,
+ UseShellExecute = true,
+ Verb = "open"
+ });
+ }
+
public static void OpenUrl(string url)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@@ -26,4 +36,4 @@ namespace Ryujinx.Ui
}
}
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/Diagnostic/SetupValidator.cs b/Ryujinx/Ui/Helper/SetupValidator.cs
index c52dc2ef..45315f8f 100644
--- a/Ryujinx/Ui/Diagnostic/SetupValidator.cs
+++ b/Ryujinx/Ui/Helper/SetupValidator.cs
@@ -1,9 +1,10 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem.Content;
+using Ryujinx.Ui.Widgets;
using System;
using System.IO;
-namespace Ryujinx.Ui.Diagnostic
+namespace Ryujinx.Ui.Helper
{
/// <summary>
/// Ensure installation validity
diff --git a/Ryujinx/Ui/Helper/SortHelper.cs b/Ryujinx/Ui/Helper/SortHelper.cs
new file mode 100644
index 00000000..78917fe7
--- /dev/null
+++ b/Ryujinx/Ui/Helper/SortHelper.cs
@@ -0,0 +1,116 @@
+using Gtk;
+using System;
+
+namespace Ryujinx.Ui.Helper
+{
+ static class SortHelper
+ {
+ public static int TimePlayedSort(ITreeModel model, TreeIter a, TreeIter b)
+ {
+ string aValue = model.GetValue(a, 5).ToString();
+ string bValue = model.GetValue(b, 5).ToString();
+
+ if (aValue.Length > 4 && aValue[^4..] == "mins")
+ {
+ aValue = (float.Parse(aValue[0..^5]) * 60).ToString();
+ }
+ else if (aValue.Length > 3 && aValue[^3..] == "hrs")
+ {
+ aValue = (float.Parse(aValue[0..^4]) * 3600).ToString();
+ }
+ else if (aValue.Length > 4 && aValue[^4..] == "days")
+ {
+ aValue = (float.Parse(aValue[0..^5]) * 86400).ToString();
+ }
+ else
+ {
+ aValue = aValue[0..^1];
+ }
+
+ if (bValue.Length > 4 && bValue[^4..] == "mins")
+ {
+ bValue = (float.Parse(bValue[0..^5]) * 60).ToString();
+ }
+ else if (bValue.Length > 3 && bValue[^3..] == "hrs")
+ {
+ bValue = (float.Parse(bValue[0..^4]) * 3600).ToString();
+ }
+ else if (bValue.Length > 4 && bValue[^4..] == "days")
+ {
+ bValue = (float.Parse(bValue[0..^5]) * 86400).ToString();
+ }
+ else
+ {
+ bValue = bValue[0..^1];
+ }
+
+ if (float.Parse(aValue) > float.Parse(bValue))
+ {
+ return -1;
+ }
+ else if (float.Parse(bValue) > float.Parse(aValue))
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ public static int LastPlayedSort(ITreeModel model, TreeIter a, TreeIter b)
+ {
+ string aValue = model.GetValue(a, 6).ToString();
+ string bValue = model.GetValue(b, 6).ToString();
+
+ if (aValue == "Never")
+ {
+ aValue = DateTime.UnixEpoch.ToString();
+ }
+
+ if (bValue == "Never")
+ {
+ bValue = DateTime.UnixEpoch.ToString();
+ }
+
+ return DateTime.Compare(DateTime.Parse(bValue), DateTime.Parse(aValue));
+ }
+
+ public static int FileSizeSort(ITreeModel model, TreeIter a, TreeIter b)
+ {
+ string aValue = model.GetValue(a, 8).ToString();
+ string bValue = model.GetValue(b, 8).ToString();
+
+ if (aValue[^2..] == "GB")
+ {
+ aValue = (float.Parse(aValue[0..^2]) * 1024).ToString();
+ }
+ else
+ {
+ aValue = aValue[0..^2];
+ }
+
+ if (bValue[^2..] == "GB")
+ {
+ bValue = (float.Parse(bValue[0..^2]) * 1024).ToString();
+ }
+ else
+ {
+ bValue = bValue[0..^2];
+ }
+
+ if (float.Parse(aValue) > float.Parse(bValue))
+ {
+ return -1;
+ }
+ else if (float.Parse(bValue) > float.Parse(aValue))
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/Helper/ThemeHelper.cs b/Ryujinx/Ui/Helper/ThemeHelper.cs
new file mode 100644
index 00000000..fca713e6
--- /dev/null
+++ b/Ryujinx/Ui/Helper/ThemeHelper.cs
@@ -0,0 +1,35 @@
+using Gtk;
+using Ryujinx.Common.Logging;
+using Ryujinx.Configuration;
+using System.IO;
+
+namespace Ryujinx.Ui.Helper
+{
+ static class ThemeHelper
+ {
+ public static void ApplyTheme()
+ {
+ if (!ConfigurationState.Instance.Ui.EnableCustomTheme)
+ {
+ return;
+ }
+
+ if (File.Exists(ConfigurationState.Instance.Ui.CustomThemePath) && (Path.GetExtension(ConfigurationState.Instance.Ui.CustomThemePath) == ".css"))
+ {
+ CssProvider cssProvider = new CssProvider();
+
+ cssProvider.LoadFromPath(ConfigurationState.Instance.Ui.CustomThemePath);
+
+ StyleContext.AddProviderForScreen(Gdk.Screen.Default, cssProvider, 800);
+ }
+ else
+ {
+ Logger.Warning?.Print(LogClass.Application, $"The \"custom_theme_path\" section in \"Config.json\" contains an invalid path: \"{ConfigurationState.Instance.Ui.CustomThemePath}\".");
+
+ ConfigurationState.Instance.Ui.CustomThemePath.Value = "";
+ ConfigurationState.Instance.Ui.EnableCustomTheme.Value = false;
+ ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/InputDialog.cs b/Ryujinx/Ui/InputDialog.cs
deleted file mode 100644
index a8dc80bf..00000000
--- a/Ryujinx/Ui/InputDialog.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using Gtk;
-using System;
-
-namespace Ryujinx.Ui
-{
- public class InputDialog : MessageDialog
- {
- private int _inputMin, _inputMax;
- private Predicate<int> _checkLength;
- private Label _validationInfo;
-
- public Entry InputEntry { get; }
- public Button OkButton { get; }
- public Button CancelButton { get; }
-
- public InputDialog(Window parent)
- : base(parent, DialogFlags.Modal | DialogFlags.DestroyWithParent, MessageType.Question, ButtonsType.None, null)
- {
- SetDefaultSize(300, 0);
-
- _validationInfo = new Label() { Visible = false };
-
- InputEntry = new Entry() { Visible = true };
- InputEntry.Activated += (object sender, EventArgs e) => { if (OkButton.IsSensitive) Respond(ResponseType.Ok); };
- InputEntry.Changed += OnInputChanged;
-
- OkButton = (Button)AddButton("OK", ResponseType.Ok);
- CancelButton = (Button)AddButton("Cancel", ResponseType.Cancel);
-
- ((Box)MessageArea).PackEnd(_validationInfo, true, true, 0);
- ((Box)MessageArea).PackEnd(InputEntry, true, true, 4);
-
- SetInputLengthValidation(0, int.MaxValue); // disable by default
- }
-
- public void SetInputLengthValidation(int min, int max)
- {
- _inputMin = Math.Min(min, max);
- _inputMax = Math.Max(min, max);
-
- _validationInfo.Visible = false;
-
- if (_inputMin <= 0 && _inputMax == int.MaxValue) // disable
- {
- _validationInfo.Visible = false;
- _checkLength = (length) => true;
- }
- else if (_inputMin > 0 && _inputMax == int.MaxValue)
- {
- _validationInfo.Visible = true;
- _validationInfo.Markup = $"<i>Must be at least {_inputMin} characters long</i>";
- _checkLength = (length) => _inputMin <= length;
- }
- else
- {
- _validationInfo.Visible = true;
- _validationInfo.Markup = $"<i>Must be {_inputMin}-{_inputMax} characters long</i>";
- _checkLength = (length) => _inputMin <= length && length <= _inputMax;
- }
-
- OnInputChanged(this, EventArgs.Empty);
- }
-
- private void OnInputChanged(object sender, EventArgs e)
- {
- OkButton.Sensitive = _checkLength(InputEntry.Text.Length);
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs
index f16158e2..58cd6401 100644
--- a/Ryujinx/Ui/MainWindow.cs
+++ b/Ryujinx/Ui/MainWindow.cs
@@ -13,11 +13,16 @@ using Ryujinx.Graphics.OpenGL;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS;
-using Ryujinx.Ui.Diagnostic;
+using Ryujinx.Modules;
+using Ryujinx.Ui.App;
+using Ryujinx.Ui.Applet;
+using Ryujinx.Ui.Helper;
+using Ryujinx.Ui.Widgets;
+using Ryujinx.Ui.Windows;
using System;
using System.Diagnostics;
using System.IO;
-using System.Reflection;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -27,26 +32,27 @@ namespace Ryujinx.Ui
{
public class MainWindow : Window
{
- private static VirtualFileSystem _virtualFileSystem;
- private static ContentManager _contentManager;
- private static UserChannelPersistence _userChannelPersistence;
+ private readonly VirtualFileSystem _virtualFileSystem;
+ private readonly ContentManager _contentManager;
- private static WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
- private static HLE.Switch _emulationContext;
+ private UserChannelPersistence _userChannelPersistence;
- private static GlRenderer _glWidget;
- private static GtkHostUiHandler _uiHandler;
+ private HLE.Switch _emulationContext;
- public static GlRenderer GlWidget => _glWidget;
+ private WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
- private static AutoResetEvent _deviceExitStatus = new AutoResetEvent(false);
+ private readonly ApplicationLibrary _applicationLibrary;
+ private readonly GtkHostUiHandler _uiHandler;
+ private readonly AutoResetEvent _deviceExitStatus;
+ private readonly ListStore _tableStore;
- private static ListStore _tableStore;
+ private bool _updatingGameTable;
+ private bool _gameLoaded;
+ private bool _ending;
- private static bool _updatingGameTable;
- private static bool _gameLoaded;
- private static string _gamePath;
- private static bool _ending;
+ private string _currentEmulatedGamePath = null;
+
+ public GlRenderer GlRendererWidget;
#pragma warning disable CS0169, CS0649, IDE0044
@@ -93,50 +99,41 @@ namespace Ryujinx.Ui
{
builder.Autoconnect(this);
+ // Apply custom theme if needed.
+ ThemeHelper.ApplyTheme();
+
+ // Sets overridden fields.
int monitorWidth = Display.PrimaryMonitor.Geometry.Width * Display.PrimaryMonitor.ScaleFactor;
int monitorHeight = Display.PrimaryMonitor.Geometry.Height * Display.PrimaryMonitor.ScaleFactor;
- this.DefaultWidth = monitorWidth < 1280 ? monitorWidth : 1280;
- this.DefaultHeight = monitorHeight < 760 ? monitorHeight : 760;
-
- this.WindowStateEvent += MainWindow_WindowStateEvent;
- this.DeleteEvent += Window_Close;
- _fullScreen.Activated += FullScreen_Toggled;
-
- this.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
- this.Title = $"Ryujinx {Program.Version}";
-
- ApplicationLibrary.ApplicationAdded += Application_Added;
- ApplicationLibrary.ApplicationCountUpdated += ApplicationCount_Updated;
- GlRenderer.StatusUpdatedEvent += Update_StatusBar;
+ DefaultWidth = monitorWidth < 1280 ? monitorWidth : 1280;
+ DefaultHeight = monitorHeight < 760 ? monitorHeight : 760;
- _gameTable.ButtonReleaseEvent += Row_Clicked;
+ Title = $"Ryujinx {Program.Version}";
- // First we check that a migration isn't needed. (because VirtualFileSystem will create the new directory otherwise)
- bool continueWithStartup = Migration.PromptIfMigrationNeededForStartup(this, out bool migrationNeeded);
- if (!continueWithStartup)
- {
- End(null);
- }
+ // Hide emulation context status bar.
+ _statusBar.Hide();
+ // Instanciate HLE objects.
_virtualFileSystem = VirtualFileSystem.CreateInstance();
- _userChannelPersistence = new UserChannelPersistence();
_contentManager = new ContentManager(_virtualFileSystem);
+ _userChannelPersistence = new UserChannelPersistence();
- if (migrationNeeded)
- {
- bool migrationSuccessful = Migration.DoMigrationForStartup(this, _virtualFileSystem);
+ // Instanciate GUI objects.
+ _applicationLibrary = new ApplicationLibrary(_virtualFileSystem);
+ _uiHandler = new GtkHostUiHandler(this);
+ _deviceExitStatus = new AutoResetEvent(false);
- if (!migrationSuccessful)
- {
- End(null);
- }
- }
+ WindowStateEvent += WindowStateEvent_Changed;
+ DeleteEvent += Window_Close;
- // Make sure that everything is loaded.
- _virtualFileSystem.Reload();
+ _applicationLibrary.ApplicationAdded += Application_Added;
+ _applicationLibrary.ApplicationCountUpdated += ApplicationCount_Updated;
+
+ _gameTable.ButtonReleaseEvent += Row_Clicked;
+ _fullScreen.Activated += FullScreen_Toggled;
- ApplyTheme();
+ GlRenderer.StatusUpdatedEvent += Update_StatusBar;
if (ConfigurationState.Instance.Ui.StartFullscreen)
{
@@ -169,9 +166,9 @@ namespace Ryujinx.Ui
typeof(string),
typeof(BlitStruct<ApplicationControlProperty>));
- _tableStore.SetSortFunc(5, TimePlayedSort);
- _tableStore.SetSortFunc(6, LastPlayedSort);
- _tableStore.SetSortFunc(8, FileSizeSort);
+ _tableStore.SetSortFunc(5, SortHelper.TimePlayedSort);
+ _tableStore.SetSortFunc(6, SortHelper.LastPlayedSort);
+ _tableStore.SetSortFunc(8, SortHelper.FileSizeSort);
int columnId = ConfigurationState.Instance.Ui.ColumnSort.SortColumnId;
bool ascending = ConfigurationState.Instance.Ui.ColumnSort.SortAscending;
@@ -193,39 +190,13 @@ namespace Ryujinx.Ui
};
Task.Run(RefreshFirmwareLabel);
-
- _statusBar.Hide();
-
- _uiHandler = new GtkHostUiHandler(this);
- _gamePath = null;
}
- private void MainWindow_WindowStateEvent(object o, WindowStateEventArgs args)
+ private void WindowStateEvent_Changed(object o, WindowStateEventArgs args)
{
_fullScreen.Label = args.Event.NewWindowState.HasFlag(Gdk.WindowState.Fullscreen) ? "Exit Fullscreen" : "Enter Fullscreen";
}
- internal static void ApplyTheme()
- {
- if (!ConfigurationState.Instance.Ui.EnableCustomTheme)
- {
- return;
- }
-
- if (File.Exists(ConfigurationState.Instance.Ui.CustomThemePath) && (System.IO.Path.GetExtension(ConfigurationState.Instance.Ui.CustomThemePath) == ".css"))
- {
- CssProvider cssProvider = new CssProvider();
-
- cssProvider.LoadFromPath(ConfigurationState.Instance.Ui.CustomThemePath);
-
- StyleContext.AddProviderForScreen(Gdk.Screen.Default, cssProvider, 800);
- }
- else
- {
- Logger.Warning?.Print(LogClass.Application, $"The \"custom_theme_path\" section in \"Config.json\" contains an invalid path: \"{ConfigurationState.Instance.Ui.CustomThemePath}\".");
- }
- }
-
private void UpdateColumns()
{
foreach (TreeViewColumn column in _gameTable.Columns)
@@ -291,21 +262,59 @@ namespace Ryujinx.Ui
}
}
- private HLE.Switch InitializeSwitchInstance()
+ private void InitializeSwitchInstance()
{
_virtualFileSystem.Reload();
- HLE.Switch instance = new HLE.Switch(_virtualFileSystem, _contentManager, _userChannelPersistence, InitializeRenderer(), InitializeAudioEngine())
+ IRenderer renderer = new Renderer();
+ IAalOutput audioEngine = new DummyAudioOut();
+
+ if (ConfigurationState.Instance.System.AudioBackend.Value == AudioBackend.SoundIo)
+ {
+ if (SoundIoAudioOut.IsSupported)
+ {
+ audioEngine = new SoundIoAudioOut();
+ }
+ else
+ {
+ Logger.Warning?.Print(LogClass.Audio, "SoundIO is not supported, falling back to dummy audio out.");
+ }
+ }
+ else if (ConfigurationState.Instance.System.AudioBackend.Value == AudioBackend.OpenAl)
+ {
+ if (OpenALAudioOut.IsSupported)
+ {
+ audioEngine = new OpenALAudioOut();
+ }
+ else
+ {
+ Logger.Warning?.Print(LogClass.Audio, "OpenAL is not supported, trying to fall back to SoundIO.");
+
+ if (SoundIoAudioOut.IsSupported)
+ {
+ Logger.Warning?.Print(LogClass.Audio, "Found SoundIO, changing configuration.");
+
+ ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.SoundIo;
+ SaveConfig();
+
+ audioEngine = new SoundIoAudioOut();
+ }
+ else
+ {
+ Logger.Warning?.Print(LogClass.Audio, "SoundIO is not supported, falling back to dummy audio out.");
+ }
+ }
+ }
+
+ _emulationContext = new HLE.Switch(_virtualFileSystem, _contentManager, _userChannelPersistence, renderer, audioEngine)
{
UiHandler = _uiHandler
};
- instance.Initialize();
-
- return instance;
+ _emulationContext.Initialize();
}
- internal static void UpdateGameTable()
+ public void UpdateGameTable()
{
if (_updatingGameTable || _gameLoaded)
{
@@ -318,64 +327,68 @@ namespace Ryujinx.Ui
Thread applicationLibraryThread = new Thread(() =>
{
- ApplicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs,
- _virtualFileSystem, ConfigurationState.Instance.System.Language);
+ _applicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs, ConfigurationState.Instance.System.Language);
_updatingGameTable = false;
});
- applicationLibraryThread.Name = "GUI.ApplicationLibraryThread";
+ applicationLibraryThread.Name = "GUI.ApplicationLibraryThread";
applicationLibraryThread.IsBackground = true;
applicationLibraryThread.Start();
}
- internal void LoadApplication(string path)
+ [Conditional("RELEASE")]
+ public void PerformanceCheck()
{
- if (_gameLoaded)
+ if (ConfigurationState.Instance.Logger.EnableDebug.Value)
{
- GtkDialog.CreateInfoDialog("Ryujinx", "A game has already been loaded", "Please close it first and try again.");
+ MessageDialog debugWarningDialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null)
+ {
+ Title = "Ryujinx - Warning",
+ Text = "You have debug logging enabled, which is designed to be used by developers only.",
+ SecondaryText = "For optimal performance, it's recommended to disable debug logging. Would you like to disable debug logging now?"
+ };
+
+ if (debugWarningDialog.Run() == (int)ResponseType.Yes)
+ {
+ ConfigurationState.Instance.Logger.EnableDebug.Value = false;
+ SaveConfig();
+ }
+
+ debugWarningDialog.Dispose();
}
- else
+
+ if (!string.IsNullOrWhiteSpace(ConfigurationState.Instance.Graphics.ShadersDumpPath.Value))
{
-#if !DEBUG
- if (ConfigurationState.Instance.Logger.EnableDebug.Value)
+ MessageDialog shadersDumpWarningDialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null)
{
- MessageDialog debugWarningDialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null)
- {
- Title = "Ryujinx - Warning",
- Text = "You have debug logging enabled, which is designed to be used by developers only.",
- SecondaryText = "For optimal performance, it's recommended to disable debug logging. Would you like to disable debug logging now?"
- };
-
- if (debugWarningDialog.Run() == (int)ResponseType.Yes)
- {
- ConfigurationState.Instance.Logger.EnableDebug.Value = false;
- SaveConfig();
- }
+ Title = "Ryujinx - Warning",
+ Text = "You have shader dumping enabled, which is designed to be used by developers only.",
+ SecondaryText = "For optimal performance, it's recommended to disable shader dumping. Would you like to disable shader dumping now?"
+ };
- debugWarningDialog.Dispose();
+ if (shadersDumpWarningDialog.Run() == (int)ResponseType.Yes)
+ {
+ ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = "";
+ SaveConfig();
}
- if (!string.IsNullOrWhiteSpace(ConfigurationState.Instance.Graphics.ShadersDumpPath.Value))
- {
- MessageDialog shadersDumpWarningDialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null)
- {
- Title = "Ryujinx - Warning",
- Text = "You have shader dumping enabled, which is designed to be used by developers only.",
- SecondaryText = "For optimal performance, it's recommended to disable shader dumping. Would you like to disable shader dumping now?"
- };
+ shadersDumpWarningDialog.Dispose();
+ }
+ }
- if (shadersDumpWarningDialog.Run() == (int)ResponseType.Yes)
- {
- ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = "";
- SaveConfig();
- }
+ public void LoadApplication(string path)
+ {
+ if (_gameLoaded)
+ {
+ GtkDialog.CreateInfoDialog("A game has already been loaded", "Please close it first and try again.");
+ }
+ else
+ {
+ PerformanceCheck();
- shadersDumpWarningDialog.Dispose();
- }
-#endif
Logger.RestartTime();
- HLE.Switch device = InitializeSwitchInstance();
+ InitializeSwitchInstance();
UpdateGraphicsConfig();
@@ -389,34 +402,25 @@ namespace Ryujinx.Ui
{
if (userError == UserError.NoFirmware)
{
- MessageDialog shouldInstallFirmwareDialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Info, ButtonsType.YesNo, null)
- {
- Title = "Ryujinx - Info",
- Text = "No Firmware Installed",
- SecondaryText = $"Would you like to install the firmware embedded in this game? (Firmware {firmwareVersion.VersionString})"
- };
+ string message = $"Would you like to install the firmware embedded in this game? (Firmware {firmwareVersion.VersionString})";
- if (shouldInstallFirmwareDialog.Run() != (int)ResponseType.Yes)
- {
- shouldInstallFirmwareDialog.Dispose();
+ ResponseType responseDialog = (ResponseType)GtkDialog.CreateConfirmationDialog("No Firmware Installed", message).Run();
+ if (responseDialog != ResponseType.Yes)
+ {
UserErrorDialog.CreateUserErrorDialog(userError);
- device.Dispose();
+ _emulationContext.Dispose();
return;
}
- else
- {
- shouldInstallFirmwareDialog.Dispose();
- }
}
if (!SetupValidator.TryFixStartApplication(_contentManager, path, userError, out _))
{
UserErrorDialog.CreateUserErrorDialog(userError);
- device.Dispose();
+ _emulationContext.Dispose();
return;
}
@@ -428,15 +432,16 @@ namespace Ryujinx.Ui
RefreshFirmwareLabel();
- GtkDialog.CreateInfoDialog("Ryujinx - Info", $"Firmware {firmwareVersion.VersionString} was installed",
- $"No installed firmware was found but Ryujinx was able to install firmware {firmwareVersion.VersionString} from the provided game.\nThe emulator will now start.");
+ string message = $"No installed firmware was found but Ryujinx was able to install firmware {firmwareVersion.VersionString} from the provided game.\nThe emulator will now start.";
+
+ GtkDialog.CreateInfoDialog($"Firmware {firmwareVersion.VersionString} was installed", message);
}
}
else
{
UserErrorDialog.CreateUserErrorDialog(userError);
- device.Dispose();
+ _emulationContext.Dispose();
return;
}
@@ -456,12 +461,12 @@ namespace Ryujinx.Ui
if (romFsFiles.Length > 0)
{
Logger.Info?.Print(LogClass.Application, "Loading as cart with RomFS.");
- device.LoadCart(path, romFsFiles[0]);
+ _emulationContext.LoadCart(path, romFsFiles[0]);
}
else
{
Logger.Info?.Print(LogClass.Application, "Loading as cart WITHOUT RomFS.");
- device.LoadCart(path);
+ _emulationContext.LoadCart(path);
}
}
else if (File.Exists(path))
@@ -470,22 +475,22 @@ namespace Ryujinx.Ui
{
case ".xci":
Logger.Info?.Print(LogClass.Application, "Loading as XCI.");
- device.LoadXci(path);
+ _emulationContext.LoadXci(path);
break;
case ".nca":
Logger.Info?.Print(LogClass.Application, "Loading as NCA.");
- device.LoadNca(path);
+ _emulationContext.LoadNca(path);
break;
case ".nsp":
case ".pfs0":
Logger.Info?.Print(LogClass.Application, "Loading as NSP.");
- device.LoadNsp(path);
+ _emulationContext.LoadNsp(path);
break;
default:
Logger.Info?.Print(LogClass.Application, "Loading as homebrew.");
try
{
- device.LoadProgram(path);
+ _emulationContext.LoadProgram(path);
}
catch (ArgumentOutOfRangeException)
{
@@ -497,23 +502,23 @@ namespace Ryujinx.Ui
else
{
Logger.Warning?.Print(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file.");
- device.Dispose();
+
+ _emulationContext.Dispose();
return;
}
- _emulationContext = device;
- _gamePath = path;
+ _currentEmulatedGamePath = path;
_deviceExitStatus.Reset();
Translator.IsReadyForTranslation.Reset();
#if MACOS_BUILD
- CreateGameWindow(device);
+ CreateGameWindow();
#else
Thread windowThread = new Thread(() =>
{
- CreateGameWindow(device);
+ CreateGameWindow();
})
{
Name = "GUI.WindowThread"
@@ -528,34 +533,34 @@ namespace Ryujinx.Ui
_firmwareInstallFile.Sensitive = false;
_firmwareInstallDirectory.Sensitive = false;
- DiscordIntegrationModule.SwitchToPlayingState(device.Application.TitleIdText, device.Application.TitleName);
+ DiscordIntegrationModule.SwitchToPlayingState(_emulationContext.Application.TitleIdText, _emulationContext.Application.TitleName);
- ApplicationLibrary.LoadAndSaveMetaData(device.Application.TitleIdText, appMetadata =>
+ _applicationLibrary.LoadAndSaveMetaData(_emulationContext.Application.TitleIdText, appMetadata =>
{
appMetadata.LastPlayed = DateTime.UtcNow.ToString();
});
}
}
- private void CreateGameWindow(HLE.Switch device)
+ private void CreateGameWindow()
{
- if (Environment.OSVersion.Platform == PlatformID.Win32NT)
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
_windowsMultimediaTimerResolution = new WindowsMultimediaTimerResolution(1);
}
- _glWidget = new GlRenderer(_emulationContext, ConfigurationState.Instance.Logger.GraphicsDebugLevel);
+ GlRendererWidget = new GlRenderer(_emulationContext, ConfigurationState.Instance.Logger.GraphicsDebugLevel);
Application.Invoke(delegate
{
_viewBox.Remove(_gameTableWindow);
- _glWidget.Expand = true;
- _viewBox.Child = _glWidget;
+ GlRendererWidget.Expand = true;
+ _viewBox.Child = GlRendererWidget;
- _glWidget.ShowAll();
- EditFooterForGameRender();
+ GlRendererWidget.ShowAll();
+ EditFooterForGameRenderer();
- if (this.Window.State.HasFlag(Gdk.WindowState.Fullscreen))
+ if (Window.State.HasFlag(Gdk.WindowState.Fullscreen))
{
ToggleExtraWidgets(false);
}
@@ -565,33 +570,34 @@ namespace Ryujinx.Ui
}
});
- _glWidget.WaitEvent.WaitOne();
+ GlRendererWidget.WaitEvent.WaitOne();
- _glWidget.Start();
+ GlRendererWidget.Start();
Ptc.Close();
PtcProfiler.Stop();
- device.Dispose();
+ _emulationContext.Dispose();
_deviceExitStatus.Set();
// NOTE: Everything that is here will not be executed when you close the UI.
Application.Invoke(delegate
{
- if (this.Window.State.HasFlag(Gdk.WindowState.Fullscreen))
+ if (Window.State.HasFlag(Gdk.WindowState.Fullscreen))
{
ToggleExtraWidgets(true);
}
- _viewBox.Remove(_glWidget);
- _glWidget.Exit();
+ _viewBox.Remove(GlRendererWidget);
+ GlRendererWidget.Exit();
- if(_glWidget.Window != this.Window && _glWidget.Window != null)
+ if(GlRendererWidget.Window != Window && GlRendererWidget.Window != null)
{
- _glWidget.Window.Dispose();
+ GlRendererWidget.Window.Dispose();
}
- _glWidget.Dispose();
+ GlRendererWidget.Dispose();
+
_windowsMultimediaTimerResolution?.Dispose();
_windowsMultimediaTimerResolution = null;
@@ -599,11 +605,11 @@ namespace Ryujinx.Ui
_gameTableWindow.Expand = true;
- this.Window.Title = $"Ryujinx {Program.Version}";
+ Window.Title = $"Ryujinx {Program.Version}";
_emulationContext = null;
_gameLoaded = false;
- _glWidget = null;
+ GlRendererWidget = null;
DiscordIntegrationModule.SwitchToMainMenu();
@@ -627,7 +633,7 @@ namespace Ryujinx.Ui
_statusBar.Hide();
}
- private void EditFooterForGameRender()
+ private void EditFooterForGameRenderer()
{
_listStatusBox.Hide();
_statusBar.Show();
@@ -635,7 +641,7 @@ namespace Ryujinx.Ui
public void ToggleExtraWidgets(bool show)
{
- if (_glWidget != null)
+ if (GlRendererWidget != null)
{
if (show)
{
@@ -651,11 +657,11 @@ namespace Ryujinx.Ui
}
}
- private static void UpdateGameMetadata(string titleId)
+ private void UpdateGameMetadata(string titleId)
{
if (_gameLoaded)
{
- ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
+ _applicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
{
DateTime lastPlayedDateTime = DateTime.Parse(appMetadata.LastPlayed);
double sessionTimePlayed = DateTime.UtcNow.Subtract(lastPlayedDateTime).TotalSeconds;
@@ -665,7 +671,7 @@ namespace Ryujinx.Ui
}
}
- public static void UpdateGraphicsConfig()
+ public void UpdateGraphicsConfig()
{
int resScale = ConfigurationState.Instance.Graphics.ResScale;
float resScaleCustom = ConfigurationState.Instance.Graphics.ResScaleCustom;
@@ -676,12 +682,12 @@ namespace Ryujinx.Ui
Graphics.Gpu.GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
}
- public static void SaveConfig()
+ public void SaveConfig()
{
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
}
- private void End(HLE.Switch device)
+ private void End()
{
if (_ending)
{
@@ -690,14 +696,14 @@ namespace Ryujinx.Ui
_ending = true;
- if (device != null)
+ if (_emulationContext != null)
{
- UpdateGameMetadata(device.Application.TitleIdText);
+ UpdateGameMetadata(_emulationContext.Application.TitleIdText);
- if (_glWidget != null)
+ if (GlRendererWidget != null)
{
- // We tell the widget that we are exiting
- _glWidget.Exit();
+ // We tell the widget that we are exiting.
+ GlRendererWidget.Exit();
// Wait for the other thread to dispose the HLE context before exiting.
_deviceExitStatus.WaitOne();
@@ -706,64 +712,13 @@ namespace Ryujinx.Ui
Dispose();
- DiscordIntegrationModule.Exit();
-
- Ptc.Dispose();
- PtcProfiler.Dispose();
-
- Logger.Shutdown();
-
+ Program.Exit();
Application.Quit();
}
- private static IRenderer InitializeRenderer()
- {
- return new Renderer();
- }
-
- private static IAalOutput InitializeAudioEngine()
- {
- if (ConfigurationState.Instance.System.AudioBackend.Value == AudioBackend.SoundIo)
- {
- if (SoundIoAudioOut.IsSupported)
- {
- return new SoundIoAudioOut();
- }
- else
- {
- Logger.Warning?.Print(LogClass.Audio, "SoundIO is not supported, falling back to dummy audio out.");
- }
- }
- else if (ConfigurationState.Instance.System.AudioBackend.Value == AudioBackend.OpenAl)
- {
- if (OpenALAudioOut.IsSupported)
- {
- return new OpenALAudioOut();
- }
- else
- {
- Logger.Warning?.Print(LogClass.Audio, "OpenAL is not supported, trying to fall back to SoundIO.");
-
- if (SoundIoAudioOut.IsSupported)
- {
- Logger.Warning?.Print(LogClass.Audio, "Found SoundIO, changing configuration.");
-
- ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.SoundIo;
- SaveConfig();
-
- return new SoundIoAudioOut();
- }
- else
- {
- Logger.Warning?.Print(LogClass.Audio, "SoundIO is not supported, falling back to dummy audio out.");
- }
- }
- }
-
- return new DummyAudioOut();
- }
-
- //Events
+ //
+ // Events
+ //
private void Application_Added(object sender, ApplicationAddedEventArgs args)
{
Application.Invoke(delegate
@@ -797,7 +752,8 @@ namespace Ryujinx.Ui
_progressBar.Value = barValue;
- if (args.NumAppsLoaded == args.NumAppsFound) // Reset the vertical scrollbar to the top when titles finish loading
+ // Reset the vertical scrollbar to the top when titles finish loading
+ if (args.NumAppsLoaded == args.NumAppsFound)
{
_gameTableWindow.Vadjustment.Value = 0;
}
@@ -831,13 +787,12 @@ namespace Ryujinx.Ui
{
_tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path));
- string titleId = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower();
-
- bool newToggleValue = !(bool)_tableStore.GetValue(treeIter, 0);
+ string titleId = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower();
+ bool newToggleValue = !(bool)_tableStore.GetValue(treeIter, 0);
_tableStore.SetValue(treeIter, 0, newToggleValue);
- ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
+ _applicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
{
appMetadata.Favorite = newToggleValue;
});
@@ -856,6 +811,7 @@ namespace Ryujinx.Ui
private void Row_Activated(object sender, RowActivatedArgs args)
{
_gameTableSelection.GetSelected(out TreeIter treeIter);
+
string path = (string)_tableStore.GetValue(treeIter, 9);
LoadApplication(path);
@@ -880,81 +836,76 @@ namespace Ryujinx.Ui
private void Row_Clicked(object sender, ButtonReleaseEventArgs args)
{
- if (args.Event.Button != 3) return;
+ if (args.Event.Button != 3 /* Right Click */)
+ {
+ return;
+ }
_gameTableSelection.GetSelected(out TreeIter treeIter);
- if (treeIter.UserData == IntPtr.Zero) return;
+ if (treeIter.UserData == IntPtr.Zero)
+ {
+ return;
+ }
+
+ string titleFilePath = _tableStore.GetValue(treeIter, 9).ToString();
+ string titleName = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[0];
+ string titleId = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower();
BlitStruct<ApplicationControlProperty> controlData = (BlitStruct<ApplicationControlProperty>)_tableStore.GetValue(treeIter, 10);
- GameTableContextMenu contextMenu = new GameTableContextMenu(_tableStore, controlData, treeIter, _virtualFileSystem);
- contextMenu.ShowAll();
- contextMenu.PopupAtPointer(null);
+ _ = new GameTableContextMenu(this, _virtualFileSystem, titleFilePath, titleName, titleId, controlData);
}
private void Load_Application_File(object sender, EventArgs args)
{
- FileChooserDialog fileChooser = new FileChooserDialog("Choose the file to open", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
-
- fileChooser.Filter = new FileFilter();
- fileChooser.Filter.AddPattern("*.nsp" );
- fileChooser.Filter.AddPattern("*.pfs0");
- fileChooser.Filter.AddPattern("*.xci" );
- fileChooser.Filter.AddPattern("*.nca" );
- fileChooser.Filter.AddPattern("*.nro" );
- fileChooser.Filter.AddPattern("*.nso" );
-
- if (fileChooser.Run() == (int)ResponseType.Accept)
+ using (FileChooserDialog fileChooser = new FileChooserDialog("Choose the file to open", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept))
{
- LoadApplication(fileChooser.Filename);
+ fileChooser.Filter = new FileFilter();
+ fileChooser.Filter.AddPattern("*.nsp");
+ fileChooser.Filter.AddPattern("*.pfs0");
+ fileChooser.Filter.AddPattern("*.xci");
+ fileChooser.Filter.AddPattern("*.nca");
+ fileChooser.Filter.AddPattern("*.nro");
+ fileChooser.Filter.AddPattern("*.nso");
+
+ if (fileChooser.Run() == (int)ResponseType.Accept)
+ {
+ LoadApplication(fileChooser.Filename);
+ }
}
-
- fileChooser.Dispose();
}
private void Load_Application_Folder(object sender, EventArgs args)
{
- FileChooserDialog fileChooser = new FileChooserDialog("Choose the folder to open", this, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
-
- if (fileChooser.Run() == (int)ResponseType.Accept)
+ using (FileChooserDialog fileChooser = new FileChooserDialog("Choose the folder to open", this, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept))
{
- LoadApplication(fileChooser.Filename);
+ if (fileChooser.Run() == (int)ResponseType.Accept)
+ {
+ LoadApplication(fileChooser.Filename);
+ }
}
-
- fileChooser.Dispose();
}
private void Open_Ryu_Folder(object sender, EventArgs args)
{
- Process.Start(new ProcessStartInfo
- {
- FileName = AppDataManager.BaseDirPath,
- UseShellExecute = true,
- Verb = "open"
- });
+ OpenHelper.OpenFolder(AppDataManager.BaseDirPath);
}
private void OpenLogsFolder_Pressed(object sender, EventArgs args)
{
string logPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
- DirectoryInfo directory = new DirectoryInfo(logPath);
- directory.Create();
+ new DirectoryInfo(logPath).Create();
- Process.Start(new ProcessStartInfo
- {
- FileName = logPath,
- UseShellExecute = true,
- Verb = "open"
- });
+ OpenHelper.OpenFolder(logPath);
}
private void Exit_Pressed(object sender, EventArgs args)
{
if (!_gameLoaded || GtkDialog.CreateExitDialog())
{
- End(_emulationContext);
+ End();
}
}
@@ -962,7 +913,7 @@ namespace Ryujinx.Ui
{
if (!_gameLoaded || GtkDialog.CreateExitDialog())
{
- End(_emulationContext);
+ End();
}
else
{
@@ -972,18 +923,12 @@ namespace Ryujinx.Ui
private void StopEmulation_Pressed(object sender, EventArgs args)
{
- _glWidget?.Exit();
+ GlRendererWidget?.Exit();
}
private void Installer_File_Pressed(object o, EventArgs args)
{
- FileChooserDialog fileChooser = new FileChooserDialog("Choose the firmware file to open",
- this,
- FileChooserAction.Open,
- "Cancel",
- ResponseType.Cancel,
- "Open",
- ResponseType.Accept);
+ FileChooserDialog fileChooser = new FileChooserDialog("Choose the firmware file to open", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
fileChooser.Filter = new FileFilter();
fileChooser.Filter.AddPattern("*.zip");
@@ -994,51 +939,15 @@ namespace Ryujinx.Ui
private void Installer_Directory_Pressed(object o, EventArgs args)
{
- FileChooserDialog directoryChooser = new FileChooserDialog("Choose the firmware directory to open",
- this,
- FileChooserAction.SelectFolder,
- "Cancel",
- ResponseType.Cancel,
- "Open",
- ResponseType.Accept);
+ FileChooserDialog directoryChooser = new FileChooserDialog("Choose the firmware directory to open", this, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
HandleInstallerDialog(directoryChooser);
}
- private void RefreshFirmwareLabel()
- {
- SystemVersion currentFirmware = _contentManager.GetCurrentFirmwareVersion();
-
- GLib.Idle.Add(new GLib.IdleHandler(() =>
- {
- _firmwareVersionLabel.Text = currentFirmware != null ? currentFirmware.VersionString : "0.0.0";
-
- return false;
- }));
- }
-
- private void HandleRelaunch()
- {
- if (_userChannelPersistence.PreviousIndex != -1 && _userChannelPersistence.ShouldRestart)
- {
- _userChannelPersistence.ShouldRestart = false;
-
- LoadApplication(_gamePath);
- }
- else
- {
- // otherwise, clear state.
- _userChannelPersistence = new UserChannelPersistence();
- _gamePath = null;
- }
- }
-
private void HandleInstallerDialog(FileChooserDialog fileChooser)
{
if (fileChooser.Run() == (int)ResponseType.Accept)
{
- MessageDialog dialog = null;
-
try
{
string filename = fileChooser.Filename;
@@ -1047,19 +956,11 @@ namespace Ryujinx.Ui
SystemVersion firmwareVersion = _contentManager.VerifyFirmwarePackage(filename);
+ string dialogTitle = $"Install Firmware {firmwareVersion.VersionString}";
+
if (firmwareVersion == null)
{
- dialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Info, ButtonsType.Ok, false, "");
-
- dialog.Text = "Firmware not found.";
-
- dialog.SecondaryText = $"A valid system firmware was not found in {filename}.";
-
- Logger.Error?.Print(LogClass.Application, $"A valid system firmware was not found in {filename}.");
-
- dialog.Run();
- dialog.Hide();
- dialog.Dispose();
+ GtkDialog.CreateErrorDialog($"A valid system firmware was not found in {filename}.");
return;
}
@@ -1070,80 +971,49 @@ namespace Ryujinx.Ui
if (currentVersion != null)
{
- dialogMessage += $"This will replace the current system version {currentVersion.VersionString}. ";
+ dialogMessage += $"\n\nThis will replace the current system version {currentVersion.VersionString}. ";
}
- dialogMessage += "Do you want to continue?";
-
- dialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Question, ButtonsType.YesNo, false, "");
-
- dialog.Text = $"Install Firmware {firmwareVersion.VersionString}";
- dialog.SecondaryText = dialogMessage;
-
- int response = dialog.Run();
+ dialogMessage += "\n\nDo you want to continue?";
- dialog.Dispose();
+ ResponseType responseInstallDialog = (ResponseType)GtkDialog.CreateConfirmationDialog(dialogTitle, dialogMessage).Run();
- dialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Info, ButtonsType.None, false, "");
+ MessageDialog waitingDialog = GtkDialog.CreateWaitingDialog(dialogTitle, "Installing firmware...");
- dialog.Text = $"Install Firmware {firmwareVersion.VersionString}";
-
- dialog.SecondaryText = "Installing firmware...";
-
- if (response == (int)ResponseType.Yes)
+ if (responseInstallDialog == ResponseType.Yes)
{
Logger.Info?.Print(LogClass.Application, $"Installing firmware {firmwareVersion.VersionString}");
Thread thread = new Thread(() =>
{
- GLib.Idle.Add(new GLib.IdleHandler(() =>
+ Application.Invoke(delegate
{
- dialog.Run();
- return false;
- }));
+ waitingDialog.Run();
+
+ });
try
{
_contentManager.InstallFirmware(filename);
- GLib.Idle.Add(new GLib.IdleHandler(() =>
+ Application.Invoke(delegate
{
- dialog.Dispose();
-
- dialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Info, ButtonsType.Ok, false, "");
-
- dialog.Text = $"Install Firmware {firmwareVersion.VersionString}";
+ waitingDialog.Dispose();
- dialog.SecondaryText = $"System version {firmwareVersion.VersionString} successfully installed.";
+ string message = $"System version {firmwareVersion.VersionString} successfully installed.";
- Logger.Info?.Print(LogClass.Application, $"System version {firmwareVersion.VersionString} successfully installed.");
-
- dialog.Run();
- dialog.Dispose();
-
- return false;
- }));
+ GtkDialog.CreateInfoDialog(dialogTitle, message);
+ Logger.Info?.Print(LogClass.Application, message);
+ });
}
catch (Exception ex)
{
- GLib.Idle.Add(new GLib.IdleHandler(() =>
+ Application.Invoke(delegate
{
- dialog.Dispose();
-
- dialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Info, ButtonsType.Ok, false, "");
-
- dialog.Text = $"Install Firmware {firmwareVersion.VersionString} Failed.";
-
- dialog.SecondaryText = $"An error occured while installing system version {firmwareVersion.VersionString}." +
- " Please check logs for more info.";
+ waitingDialog.Dispose();
- Logger.Error?.Print(LogClass.Application, ex.Message);
-
- dialog.Run();
- dialog.Dispose();
-
- return false;
- }));
+ GtkDialog.CreateErrorDialog(ex.Message);
+ });
}
finally
{
@@ -1154,41 +1024,47 @@ namespace Ryujinx.Ui
thread.Name = "GUI.FirmwareInstallerThread";
thread.Start();
}
- else
- {
- dialog.Dispose();
- }
}
catch (Exception ex)
{
- if (dialog != null)
- {
- dialog.Dispose();
- }
-
- dialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Info, ButtonsType.Ok, false, "");
+ GtkDialog.CreateErrorDialog(ex.Message);
+ }
+ }
+ else
+ {
+ fileChooser.Dispose();
+ }
+ }
- dialog.Text = "Parsing Firmware Failed.";
+ private void RefreshFirmwareLabel()
+ {
+ SystemVersion currentFirmware = _contentManager.GetCurrentFirmwareVersion();
- dialog.SecondaryText = "An error occured while parsing firmware. Please check the logs for more info.";
+ Application.Invoke(delegate
+ {
+ _firmwareVersionLabel.Text = currentFirmware != null ? currentFirmware.VersionString : "0.0.0";
+ });
+ }
- Logger.Error?.Print(LogClass.Application, ex.Message);
+ private void HandleRelaunch()
+ {
+ if (_userChannelPersistence.PreviousIndex != -1 && _userChannelPersistence.ShouldRestart)
+ {
+ _userChannelPersistence.ShouldRestart = false;
- dialog.Run();
- dialog.Dispose();
- }
+ LoadApplication(_currentEmulatedGamePath);
}
else
{
- fileChooser.Dispose();
+ // otherwise, clear state.
+ _userChannelPersistence = new UserChannelPersistence();
+ _currentEmulatedGamePath = null;
}
}
private void FullScreen_Toggled(object sender, EventArgs args)
{
- bool fullScreenToggled = this.Window.State.HasFlag(Gdk.WindowState.Fullscreen);
-
- if (!fullScreenToggled)
+ if (!Window.State.HasFlag(Gdk.WindowState.Fullscreen))
{
Fullscreen();
@@ -1211,13 +1087,15 @@ namespace Ryujinx.Ui
private void Settings_Pressed(object sender, EventArgs args)
{
- SettingsWindow settingsWin = new SettingsWindow(_virtualFileSystem, _contentManager);
- settingsWin.Show();
+ new SettingsWindow(this, _virtualFileSystem, _contentManager).Show();
}
private void Simulate_WakeUp_Message_Pressed(object sender, EventArgs args)
{
- _emulationContext.System.SimulateWakeUpMessage();
+ if (_emulationContext != null)
+ {
+ _emulationContext.System.SimulateWakeUpMessage();
+ }
}
private void Update_Pressed(object sender, EventArgs args)
@@ -1230,8 +1108,7 @@ namespace Ryujinx.Ui
private void About_Pressed(object sender, EventArgs args)
{
- AboutWindow aboutWin = new AboutWindow();
- aboutWin.Show();
+ new AboutWindow().Show();
}
private void Fav_Toggled(object sender, EventArgs args)
@@ -1318,113 +1195,5 @@ namespace Ryujinx.Ui
{
UpdateGameTable();
}
-
- private static int TimePlayedSort(ITreeModel model, TreeIter a, TreeIter b)
- {
- string aValue = model.GetValue(a, 5).ToString();
- string bValue = model.GetValue(b, 5).ToString();
-
- if (aValue.Length > 4 && aValue.Substring(aValue.Length - 4) == "mins")
- {
- aValue = (float.Parse(aValue.Substring(0, aValue.Length - 5)) * 60).ToString();
- }
- else if (aValue.Length > 3 && aValue.Substring(aValue.Length - 3) == "hrs")
- {
- aValue = (float.Parse(aValue.Substring(0, aValue.Length - 4)) * 3600).ToString();
- }
- else if (aValue.Length > 4 && aValue.Substring(aValue.Length - 4) == "days")
- {
- aValue = (float.Parse(aValue.Substring(0, aValue.Length - 5)) * 86400).ToString();
- }
- else
- {
- aValue = aValue.Substring(0, aValue.Length - 1);
- }
-
- if (bValue.Length > 4 && bValue.Substring(bValue.Length - 4) == "mins")
- {
- bValue = (float.Parse(bValue.Substring(0, bValue.Length - 5)) * 60).ToString();
- }
- else if (bValue.Length > 3 && bValue.Substring(bValue.Length - 3) == "hrs")
- {
- bValue = (float.Parse(bValue.Substring(0, bValue.Length - 4)) * 3600).ToString();
- }
- else if (bValue.Length > 4 && bValue.Substring(bValue.Length - 4) == "days")
- {
- bValue = (float.Parse(bValue.Substring(0, bValue.Length - 5)) * 86400).ToString();
- }
- else
- {
- bValue = bValue.Substring(0, bValue.Length - 1);
- }
-
- if (float.Parse(aValue) > float.Parse(bValue))
- {
- return -1;
- }
- else if (float.Parse(bValue) > float.Parse(aValue))
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
-
- private static int LastPlayedSort(ITreeModel model, TreeIter a, TreeIter b)
- {
- string aValue = model.GetValue(a, 6).ToString();
- string bValue = model.GetValue(b, 6).ToString();
-
- if (aValue == "Never")
- {
- aValue = DateTime.UnixEpoch.ToString();
- }
-
- if (bValue == "Never")
- {
- bValue = DateTime.UnixEpoch.ToString();
- }
-
- return DateTime.Compare(DateTime.Parse(bValue), DateTime.Parse(aValue));
- }
-
- private static int FileSizeSort(ITreeModel model, TreeIter a, TreeIter b)
- {
- string aValue = model.GetValue(a, 8).ToString();
- string bValue = model.GetValue(b, 8).ToString();
-
- if (aValue.Substring(aValue.Length - 2) == "GB")
- {
- aValue = (float.Parse(aValue[0..^2]) * 1024).ToString();
- }
- else
- {
- aValue = aValue[0..^2];
- }
-
- if (bValue.Substring(bValue.Length - 2) == "GB")
- {
- bValue = (float.Parse(bValue[0..^2]) * 1024).ToString();
- }
- else
- {
- bValue = bValue[0..^2];
- }
-
- if (float.Parse(aValue) > float.Parse(bValue))
- {
- return -1;
- }
- else if (float.Parse(bValue) > float.Parse(aValue))
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/Migration.cs b/Ryujinx/Ui/Migration.cs
deleted file mode 100644
index a7a49105..00000000
--- a/Ryujinx/Ui/Migration.cs
+++ /dev/null
@@ -1,189 +0,0 @@
-using Gtk;
-using LibHac;
-using Ryujinx.Common.Configuration;
-using Ryujinx.HLE.FileSystem;
-using System;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-
-namespace Ryujinx.Ui
-{
- internal class Migration
- {
- private VirtualFileSystem _virtualFileSystem;
-
- public Migration(VirtualFileSystem virtualFileSystem)
- {
- _virtualFileSystem = virtualFileSystem;
- }
-
- public static bool PromptIfMigrationNeededForStartup(Window parentWindow, out bool isMigrationNeeded)
- {
- if (!IsMigrationNeeded())
- {
- isMigrationNeeded = false;
-
- return true;
- }
-
- isMigrationNeeded = true;
-
- int dialogResponse;
-
- using (MessageDialog dialog = new MessageDialog(parentWindow, DialogFlags.Modal, MessageType.Question,
- ButtonsType.YesNo, "What's this?"))
- {
- dialog.Title = "Data Migration Needed";
- dialog.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
- dialog.Text =
- "The folder structure of Ryujinx's RyuFs folder has been updated and renamed to \"Ryujinx\". " +
- "Your RyuFs folder must be copied and migrated to the new \"Ryujinx\" structure. Would you like to do the migration now?\n\n" +
- "Select \"Yes\" to automatically perform the migration. Your old RyuFs folder will remain as it is.\n\n" +
- "Selecting \"No\" will exit Ryujinx without changing anything.";
-
- dialogResponse = dialog.Run();
- }
-
- return dialogResponse == (int)ResponseType.Yes;
- }
-
- public static bool DoMigrationForStartup(MainWindow parentWindow, VirtualFileSystem virtualFileSystem)
- {
- try
- {
- Migration migration = new Migration(virtualFileSystem);
- int saveCount = migration.Migrate();
-
- using MessageDialog dialogSuccess = new MessageDialog(parentWindow, DialogFlags.Modal, MessageType.Info, ButtonsType.Ok, null)
- {
- Title = "Migration Success",
- Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"),
- Text = $"Data migration was successful. {saveCount} saves were migrated.",
- };
-
- dialogSuccess.Run();
-
- return true;
- }
- catch (HorizonResultException ex)
- {
- GtkDialog.CreateErrorDialog(ex.Message);
-
- return false;
- }
- }
-
- // Returns the number of saves migrated
- public int Migrate()
- {
- // Make sure FsClient is initialized
- _virtualFileSystem.Reload();
-
- string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
-
- string oldBasePath = Path.Combine(appDataPath, "RyuFs");
- string newBasePath = Path.Combine(appDataPath, "Ryujinx");
-
- string oldSaveDir = Path.Combine(oldBasePath, "nand/user/save");
-
- CopyRyuFs(oldBasePath, newBasePath);
-
- SaveImporter importer = new SaveImporter(oldSaveDir, _virtualFileSystem.FsClient);
-
- return importer.Import();
- }
-
- private static void CopyRyuFs(string oldPath, string newPath)
- {
- Directory.CreateDirectory(newPath);
-
- CopyExcept(oldPath, newPath, "nand", "bis", "sdmc", "sdcard");
-
- string oldNandPath = Path.Combine(oldPath, "nand");
- string newNandPath = Path.Combine(newPath, "bis");
-
- CopyExcept(oldNandPath, newNandPath, "system", "user");
-
- string oldSdPath = Path.Combine(oldPath, "sdmc");
- string newSdPath = Path.Combine(newPath, "sdcard");
-
- CopyDirectory(oldSdPath, newSdPath);
-
- string oldSystemPath = Path.Combine(oldNandPath, "system");
- string newSystemPath = Path.Combine(newNandPath, "system");
-
- CopyExcept(oldSystemPath, newSystemPath, "save");
-
- string oldUserPath = Path.Combine(oldNandPath, "user");
- string newUserPath = Path.Combine(newNandPath, "user");
-
- CopyExcept(oldUserPath, newUserPath, "save");
- }
-
- private static void CopyExcept(string srcPath, string dstPath, params string[] exclude)
- {
- exclude = exclude.Select(x => x.ToLowerInvariant()).ToArray();
-
- DirectoryInfo srcDir = new DirectoryInfo(srcPath);
-
- if (!srcDir.Exists)
- {
- return;
- }
-
- Directory.CreateDirectory(dstPath);
-
- foreach (DirectoryInfo subDir in srcDir.EnumerateDirectories())
- {
- if (exclude.Contains(subDir.Name.ToLowerInvariant()))
- {
- continue;
- }
-
- CopyDirectory(subDir.FullName, Path.Combine(dstPath, subDir.Name));
- }
-
- foreach (FileInfo file in srcDir.EnumerateFiles())
- {
- file.CopyTo(Path.Combine(dstPath, file.Name));
- }
- }
-
- private static void CopyDirectory(string srcPath, string dstPath)
- {
- Directory.CreateDirectory(dstPath);
-
- DirectoryInfo srcDir = new DirectoryInfo(srcPath);
-
- if (!srcDir.Exists)
- {
- return;
- }
-
- Directory.CreateDirectory(dstPath);
-
- foreach (DirectoryInfo subDir in srcDir.EnumerateDirectories())
- {
- CopyDirectory(subDir.FullName, Path.Combine(dstPath, subDir.Name));
- }
-
- foreach (FileInfo file in srcDir.EnumerateFiles())
- {
- file.CopyTo(Path.Combine(dstPath, file.Name));
- }
- }
-
- public static bool IsMigrationNeeded()
- {
- if (AppDataManager.IsCustomBasePath) return false;
-
- string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
-
- string oldBasePath = Path.Combine(appDataPath, "RyuFs");
- string newBasePath = Path.Combine(appDataPath, "Ryujinx");
-
- return Directory.Exists(oldBasePath) && !Directory.Exists(newBasePath);
- }
- }
-}
diff --git a/Ryujinx/Ui/assets/JoyConLeft.svg b/Ryujinx/Ui/Resources/Controller_JoyConLeft.svg
index 40d06136..40d06136 100644
--- a/Ryujinx/Ui/assets/JoyConLeft.svg
+++ b/Ryujinx/Ui/Resources/Controller_JoyConLeft.svg
diff --git a/Ryujinx/Ui/assets/JoyConPair.svg b/Ryujinx/Ui/Resources/Controller_JoyConPair.svg
index fca94d18..fca94d18 100644
--- a/Ryujinx/Ui/assets/JoyConPair.svg
+++ b/Ryujinx/Ui/Resources/Controller_JoyConPair.svg
diff --git a/Ryujinx/Ui/assets/JoyConRight.svg b/Ryujinx/Ui/Resources/Controller_JoyConRight.svg
index 014c0ae3..014c0ae3 100644
--- a/Ryujinx/Ui/assets/JoyConRight.svg
+++ b/Ryujinx/Ui/Resources/Controller_JoyConRight.svg
diff --git a/Ryujinx/Ui/assets/ProCon.svg b/Ryujinx/Ui/Resources/Controller_ProCon.svg
index 8c2b879f..8c2b879f 100644
--- a/Ryujinx/Ui/assets/ProCon.svg
+++ b/Ryujinx/Ui/Resources/Controller_ProCon.svg
diff --git a/Ryujinx/Ui/assets/NCAIcon.png b/Ryujinx/Ui/Resources/Icon_NCA.png
index 6d73c8c7..6d73c8c7 100644
--- a/Ryujinx/Ui/assets/NCAIcon.png
+++ b/Ryujinx/Ui/Resources/Icon_NCA.png
Binary files differ
diff --git a/Ryujinx/Ui/assets/NROIcon.png b/Ryujinx/Ui/Resources/Icon_NRO.png
index bc6b65bf..bc6b65bf 100644
--- a/Ryujinx/Ui/assets/NROIcon.png
+++ b/Ryujinx/Ui/Resources/Icon_NRO.png
Binary files differ
diff --git a/Ryujinx/Ui/assets/NSOIcon.png b/Ryujinx/Ui/Resources/Icon_NSO.png
index 8782b3ea..8782b3ea 100644
--- a/Ryujinx/Ui/assets/NSOIcon.png
+++ b/Ryujinx/Ui/Resources/Icon_NSO.png
Binary files differ
diff --git a/Ryujinx/Ui/assets/NSPIcon.png b/Ryujinx/Ui/Resources/Icon_NSP.png
index d01dc482..d01dc482 100644
--- a/Ryujinx/Ui/assets/NSPIcon.png
+++ b/Ryujinx/Ui/Resources/Icon_NSP.png
Binary files differ
diff --git a/Ryujinx/Ui/assets/XCIIcon.png b/Ryujinx/Ui/Resources/Icon_XCI.png
index 08f783a8..08f783a8 100644
--- a/Ryujinx/Ui/assets/XCIIcon.png
+++ b/Ryujinx/Ui/Resources/Icon_XCI.png
Binary files differ
diff --git a/Ryujinx/Ui/assets/DiscordLogo.png b/Ryujinx/Ui/Resources/Logo_Discord.png
index f3486b99..f3486b99 100644
--- a/Ryujinx/Ui/assets/DiscordLogo.png
+++ b/Ryujinx/Ui/Resources/Logo_Discord.png
Binary files differ
diff --git a/Ryujinx/Ui/assets/GitHubLogo.png b/Ryujinx/Ui/Resources/Logo_GitHub.png
index 2e860709..2e860709 100644
--- a/Ryujinx/Ui/assets/GitHubLogo.png
+++ b/Ryujinx/Ui/Resources/Logo_GitHub.png
Binary files differ
diff --git a/Ryujinx/Ui/assets/PatreonLogo.png b/Ryujinx/Ui/Resources/Logo_Patreon.png
index 19c7ffbc..19c7ffbc 100644
--- a/Ryujinx/Ui/assets/PatreonLogo.png
+++ b/Ryujinx/Ui/Resources/Logo_Patreon.png
Binary files differ
diff --git a/Ryujinx/Ui/assets/Icon.png b/Ryujinx/Ui/Resources/Logo_Ryujinx.png
index 2fc7b017..2fc7b017 100644
--- a/Ryujinx/Ui/assets/Icon.png
+++ b/Ryujinx/Ui/Resources/Logo_Ryujinx.png
Binary files differ
diff --git a/Ryujinx/Ui/assets/TwitterLogo.png b/Ryujinx/Ui/Resources/Logo_Twitter.png
index 3d01efc0..3d01efc0 100644
--- a/Ryujinx/Ui/assets/TwitterLogo.png
+++ b/Ryujinx/Ui/Resources/Logo_Twitter.png
Binary files differ
diff --git a/Ryujinx/Ui/SaveImporter.cs b/Ryujinx/Ui/SaveImporter.cs
deleted file mode 100644
index 946b6cd3..00000000
--- a/Ryujinx/Ui/SaveImporter.cs
+++ /dev/null
@@ -1,219 +0,0 @@
-using LibHac;
-using LibHac.Common;
-using LibHac.Fs;
-using LibHac.Fs.Shim;
-using LibHac.FsSystem;
-using LibHac.Ncm;
-using Ryujinx.HLE.Utilities;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.CompilerServices;
-
-using ApplicationId = LibHac.Ncm.ApplicationId;
-
-namespace Ryujinx.Ui
-{
- internal class SaveImporter
- {
- private FileSystemClient FsClient { get; }
- private string ImportPath { get; }
-
- public SaveImporter(string importPath, FileSystemClient destFsClient)
- {
- ImportPath = importPath;
- FsClient = destFsClient;
- }
-
- // Returns the number of saves imported
- public int Import()
- {
- return ImportSaves(FsClient, ImportPath);
- }
-
- private static int ImportSaves(FileSystemClient fsClient, string rootSaveDir)
- {
- if (!Directory.Exists(rootSaveDir))
- {
- return 0;
- }
-
- SaveFinder finder = new SaveFinder();
- finder.FindSaves(rootSaveDir);
-
- foreach (SaveToImport save in finder.Saves)
- {
- Result importResult = ImportSave(fsClient, save);
-
- if (importResult.IsFailure())
- {
- throw new HorizonResultException(importResult, $"Error importing save {save.Path}");
- }
- }
-
- return finder.Saves.Count;
- }
-
- private static Result ImportSave(FileSystemClient fs, SaveToImport save)
- {
- SaveDataAttribute key = save.Attribute;
-
- Result result = fs.CreateSaveData(new ApplicationId(key.ProgramId.Value), key.UserId, key.ProgramId.Value, 0, 0, 0);
- if (result.IsFailure()) return result;
-
- bool isOldMounted = false;
- bool isNewMounted = false;
-
- try
- {
- result = fs.Register("OldSave".ToU8Span(), new LocalFileSystem(save.Path));
- if (result.IsFailure()) return result;
-
- isOldMounted = true;
-
- result = fs.MountSaveData("NewSave".ToU8Span(), new ApplicationId(key.ProgramId.Value), key.UserId);
- if (result.IsFailure()) return result;
-
- isNewMounted = true;
-
- result = fs.CopyDirectory("OldSave:/", "NewSave:/");
- if (result.IsFailure()) return result;
-
- result = fs.Commit("NewSave".ToU8Span());
- }
- finally
- {
- if (isOldMounted)
- {
- fs.Unmount("OldSave".ToU8Span());
- }
-
- if (isNewMounted)
- {
- fs.Unmount("NewSave".ToU8Span());
- }
- }
-
- return result;
- }
-
- private class SaveFinder
- {
- public List<SaveToImport> Saves { get; } = new List<SaveToImport>();
-
- public void FindSaves(string rootPath)
- {
- foreach (string subDir in Directory.EnumerateDirectories(rootPath))
- {
- if (TryGetUInt64(subDir, out ulong saveDataId))
- {
- SearchSaveId(subDir, saveDataId);
- }
- }
- }
-
- private void SearchSaveId(string path, ulong saveDataId)
- {
- foreach (string subDir in Directory.EnumerateDirectories(path))
- {
- if (TryGetUserId(subDir, out UserId userId))
- {
- SearchUser(subDir, saveDataId, userId);
- }
- }
- }
-
- private void SearchUser(string path, ulong saveDataId, UserId userId)
- {
- foreach (string subDir in Directory.EnumerateDirectories(path))
- {
- if (TryGetUInt64(subDir, out ulong titleId) && TryGetDataPath(subDir, out string dataPath))
- {
- SaveDataAttribute attribute = new SaveDataAttribute
- {
- Type = SaveDataType.Account,
- UserId = userId,
- ProgramId = new ProgramId(titleId)
- };
-
- SaveToImport save = new SaveToImport(dataPath, attribute);
-
- Saves.Add(save);
- }
- }
- }
-
- private static bool TryGetDataPath(string path, out string dataPath)
- {
- string committedPath = Path.Combine(path, "0");
- string workingPath = Path.Combine(path, "1");
-
- if (Directory.Exists(committedPath) && Directory.EnumerateFileSystemEntries(committedPath).Any())
- {
- dataPath = committedPath;
- return true;
- }
-
- if (Directory.Exists(workingPath) && Directory.EnumerateFileSystemEntries(workingPath).Any())
- {
- dataPath = workingPath;
- return true;
- }
-
- dataPath = default;
- return false;
- }
-
- private static bool TryGetUInt64(string path, out ulong converted)
- {
- string name = Path.GetFileName(path);
-
- if (name.Length == 16)
- {
- try
- {
- converted = Convert.ToUInt64(name, 16);
- return true;
- }
- catch { }
- }
-
- converted = default;
- return false;
- }
-
- private static bool TryGetUserId(string path, out UserId userId)
- {
- string name = Path.GetFileName(path);
-
- if (name.Length == 32)
- {
- try
- {
- UInt128 id = new UInt128(name);
-
- userId = Unsafe.As<UInt128, UserId>(ref id);
- return true;
- }
- catch { }
- }
-
- userId = default;
- return false;
- }
- }
-
- private class SaveToImport
- {
- public string Path { get; }
- public SaveDataAttribute Attribute { get; }
-
- public SaveToImport(string path, SaveDataAttribute attribute)
- {
- Path = path;
- Attribute = attribute;
- }
- }
- }
-}
diff --git a/Ryujinx/Ui/StatusUpdatedEventArgs.cs b/Ryujinx/Ui/StatusUpdatedEventArgs.cs
index a028c8f8..c9fba77b 100644
--- a/Ryujinx/Ui/StatusUpdatedEventArgs.cs
+++ b/Ryujinx/Ui/StatusUpdatedEventArgs.cs
@@ -21,4 +21,4 @@ namespace Ryujinx.Ui
GpuName = gpuName;
}
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/Widgets/GameTableContextMenu.Designer.cs b/Ryujinx/Ui/Widgets/GameTableContextMenu.Designer.cs
new file mode 100644
index 00000000..4b903d6c
--- /dev/null
+++ b/Ryujinx/Ui/Widgets/GameTableContextMenu.Designer.cs
@@ -0,0 +1,198 @@
+using Gtk;
+
+namespace Ryujinx.Ui.Widgets
+{
+ public partial class GameTableContextMenu : Menu
+ {
+ private MenuItem _openSaveUserDirMenuItem;
+ private MenuItem _openSaveDeviceDirMenuItem;
+ private MenuItem _openSaveBcatDirMenuItem;
+ private MenuItem _manageTitleUpdatesMenuItem;
+ private MenuItem _manageDlcMenuItem;
+ private MenuItem _openTitleModDirMenuItem;
+ private Menu _extractSubMenu;
+ private MenuItem _extractMenuItem;
+ private MenuItem _extractRomFsMenuItem;
+ private MenuItem _extractExeFsMenuItem;
+ private MenuItem _extractLogoMenuItem;
+ private Menu _manageSubMenu;
+ private MenuItem _manageCacheMenuItem;
+ private MenuItem _purgePtcCacheMenuItem;
+ private MenuItem _purgeShaderCacheMenuItem;
+ private MenuItem _openPtcDirMenuItem;
+ private MenuItem _openShaderCacheDirMenuItem;
+
+ private void InitializeComponent()
+ {
+ //
+ // _openSaveUserDirMenuItem
+ //
+ _openSaveUserDirMenuItem = new MenuItem("Open User Save Directory")
+ {
+ TooltipText = "Open the directory which contains Application's User Saves."
+ };
+ _openSaveUserDirMenuItem.Activated += OpenSaveUserDir_Clicked;
+
+ //
+ // _openSaveDeviceDirMenuItem
+ //
+ _openSaveDeviceDirMenuItem = new MenuItem("Open Device Save Directory")
+ {
+ TooltipText = "Open the directory which contains Application's Device Saves."
+ };
+ _openSaveDeviceDirMenuItem.Activated += OpenSaveDeviceDir_Clicked;
+
+ //
+ // _openSaveBcatDirMenuItem
+ //
+ _openSaveBcatDirMenuItem = new MenuItem("Open BCAT Save Directory")
+ {
+ TooltipText = "Open the directory which contains Application's BCAT Saves."
+ };
+ _openSaveBcatDirMenuItem.Activated += OpenSaveBcatDir_Clicked;
+
+ //
+ // _manageTitleUpdatesMenuItem
+ //
+ _manageTitleUpdatesMenuItem = new MenuItem("Manage Title Updates")
+ {
+ TooltipText = "Open the Title Update management window"
+ };
+ _manageTitleUpdatesMenuItem.Activated += ManageTitleUpdates_Clicked;
+
+ //
+ // _manageDlcMenuItem
+ //
+ _manageDlcMenuItem = new MenuItem("Manage DLC")
+ {
+ TooltipText = "Open the DLC management window"
+ };
+ _manageDlcMenuItem.Activated += ManageDlc_Clicked;
+
+ //
+ // _openTitleModDirMenuItem
+ //
+ _openTitleModDirMenuItem = new MenuItem("Open Mods Directory")
+ {
+ TooltipText = "Open the directory which contains Application's Mods."
+ };
+ _openTitleModDirMenuItem.Activated += OpenTitleModDir_Clicked;
+
+ //
+ // _extractSubMenu
+ //
+ _extractSubMenu = new Menu();
+
+ //
+ // _extractMenuItem
+ //
+ _extractMenuItem = new MenuItem("Extract Data")
+ {
+ Submenu = _extractSubMenu
+ };
+
+ //
+ // _extractRomFsMenuItem
+ //
+ _extractRomFsMenuItem = new MenuItem("RomFS")
+ {
+ TooltipText = "Extract the RomFS section from Application's current config (including updates)."
+ };
+ _extractRomFsMenuItem.Activated += ExtractRomFs_Clicked;
+
+ //
+ // _extractExeFsMenuItem
+ //
+ _extractExeFsMenuItem = new MenuItem("ExeFS")
+ {
+ TooltipText = "Extract the ExeFS section from Application's current config (including updates)."
+ };
+ _extractExeFsMenuItem.Activated += ExtractExeFs_Clicked;
+
+ //
+ // _extractLogoMenuItem
+ //
+ _extractLogoMenuItem = new MenuItem("Logo")
+ {
+ TooltipText = "Extract the Logo section from Application's current config (including updates)."
+ };
+ _extractLogoMenuItem.Activated += ExtractLogo_Clicked;
+
+ //
+ // _manageSubMenu
+ //
+ _manageSubMenu = new Menu();
+
+ //
+ // _manageCacheMenuItem
+ //
+ _manageCacheMenuItem = new MenuItem("Cache Management")
+ {
+ Submenu = _manageSubMenu
+ };
+
+ //
+ // _purgePtcCacheMenuItem
+ //
+ _purgePtcCacheMenuItem = new MenuItem("Purge PPTC Cache")
+ {
+ TooltipText = "Delete the Application's PPTC cache."
+ };
+ _purgePtcCacheMenuItem.Activated += PurgePtcCache_Clicked;
+
+ //
+ // _purgeShaderCacheMenuItem
+ //
+ _purgeShaderCacheMenuItem = new MenuItem("Purge Shader Cache")
+ {
+ TooltipText = "Delete the Application's shader cache."
+ };
+ _purgeShaderCacheMenuItem.Activated += PurgeShaderCache_Clicked;
+
+ //
+ // _openPtcDirMenuItem
+ //
+ _openPtcDirMenuItem = new MenuItem("Open PPTC Directory")
+ {
+ TooltipText = "Open the directory which contains the Application's PPTC cache."
+ };
+ _openPtcDirMenuItem.Activated += OpenPtcDir_Clicked;
+
+ //
+ // _openShaderCacheDirMenuItem
+ //
+ _openShaderCacheDirMenuItem = new MenuItem("Open Shader Cache Directory")
+ {
+ TooltipText = "Open the directory which contains the Application's shader cache."
+ };
+ _openShaderCacheDirMenuItem.Activated += OpenShaderCacheDir_Clicked;
+
+ ShowComponent();
+ }
+
+ private void ShowComponent()
+ {
+ _extractSubMenu.Append(_extractExeFsMenuItem);
+ _extractSubMenu.Append(_extractRomFsMenuItem);
+ _extractSubMenu.Append(_extractLogoMenuItem);
+
+ _manageSubMenu.Append(_purgePtcCacheMenuItem);
+ _manageSubMenu.Append(_purgeShaderCacheMenuItem);
+ _manageSubMenu.Append(_openPtcDirMenuItem);
+ _manageSubMenu.Append(_openShaderCacheDirMenuItem);
+
+ Add(_openSaveUserDirMenuItem);
+ Add(_openSaveDeviceDirMenuItem);
+ Add(_openSaveBcatDirMenuItem);
+ Add(new SeparatorMenuItem());
+ Add(_manageTitleUpdatesMenuItem);
+ Add(_manageDlcMenuItem);
+ Add(_openTitleModDirMenuItem);
+ Add(new SeparatorMenuItem());
+ Add(_manageCacheMenuItem);
+ Add(_extractMenuItem);
+
+ ShowAll();
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/GameTableContextMenu.cs b/Ryujinx/Ui/Widgets/GameTableContextMenu.cs
index 58c40791..5ee8baa3 100644
--- a/Ryujinx/Ui/GameTableContextMenu.cs
+++ b/Ryujinx/Ui/Widgets/GameTableContextMenu.cs
@@ -11,159 +11,66 @@ using LibHac.Ncm;
using LibHac.Ns;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
-using Ryujinx.Common.Utilities;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
+using Ryujinx.Ui.Helper;
+using Ryujinx.Ui.Windows;
using System;
using System.Buffers;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Globalization;
using System.IO;
-using System.Reflection;
using System.Threading;
using static LibHac.Fs.ApplicationSaveDataManagement;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.Widgets
{
- public class GameTableContextMenu : Menu
+ public partial class GameTableContextMenu : Menu
{
- private readonly ListStore _gameTableStore;
- private readonly TreeIter _rowIter;
- private readonly VirtualFileSystem _virtualFileSystem;
-
+ private readonly MainWindow _parent;
+ private readonly VirtualFileSystem _virtualFileSystem;
private readonly BlitStruct<ApplicationControlProperty> _controlData;
+ private readonly string _titleFilePath;
+ private readonly string _titleName;
+ private readonly string _titleIdText;
+ private readonly ulong _titleId;
+
private MessageDialog _dialog;
private bool _cancel;
- public GameTableContextMenu(ListStore gameTableStore, BlitStruct<ApplicationControlProperty> controlData, TreeIter rowIter, VirtualFileSystem virtualFileSystem)
+ public GameTableContextMenu(MainWindow parent, VirtualFileSystem virtualFileSystem, string titleFilePath, string titleName, string titleId, BlitStruct<ApplicationControlProperty> controlData)
{
- _gameTableStore = gameTableStore;
- _rowIter = rowIter;
- _virtualFileSystem = virtualFileSystem;
- _controlData = controlData;
-
- MenuItem openSaveUserDir = new MenuItem("Open User Save Directory")
- {
- Sensitive = !Utilities.IsEmpty(controlData.ByteSpan) && controlData.Value.UserAccountSaveDataSize > 0,
- TooltipText = "Open the directory which contains Application's User Saves."
- };
-
- MenuItem openSaveDeviceDir = new MenuItem("Open Device Save Directory")
- {
- Sensitive = !Utilities.IsEmpty(controlData.ByteSpan) && controlData.Value.DeviceSaveDataSize > 0,
- TooltipText = "Open the directory which contains Application's Device Saves."
- };
-
- MenuItem openSaveBcatDir = new MenuItem("Open BCAT Save Directory")
- {
- Sensitive = !Utilities.IsEmpty(controlData.ByteSpan) && controlData.Value.BcatDeliveryCacheStorageSize > 0,
- TooltipText = "Open the directory which contains Application's BCAT Saves."
- };
-
- MenuItem manageTitleUpdates = new MenuItem("Manage Title Updates")
- {
- TooltipText = "Open the Title Update management window"
- };
+ _parent = parent;
- MenuItem manageDlc = new MenuItem("Manage DLC")
- {
- TooltipText = "Open the DLC management window"
- };
-
- MenuItem openTitleModDir = new MenuItem("Open Mods Directory")
- {
- TooltipText = "Open the directory which contains Application's Mods."
- };
-
- string ext = System.IO.Path.GetExtension(_gameTableStore.GetValue(_rowIter, 9).ToString()).ToLower();
- bool hasNca = ext == ".nca" || ext == ".nsp" || ext == ".pfs0" || ext == ".xci";
-
- MenuItem extractMenu = new MenuItem("Extract Data");
-
- MenuItem extractRomFs = new MenuItem("RomFS")
- {
- Sensitive = hasNca,
- TooltipText = "Extract the RomFS section from Application's current config (including updates)."
- };
+ InitializeComponent();
- MenuItem extractExeFs = new MenuItem("ExeFS")
- {
- Sensitive = hasNca,
- TooltipText = "Extract the ExeFS section from Application's current config (including updates)."
- };
+ _virtualFileSystem = virtualFileSystem;
+ _titleFilePath = titleFilePath;
+ _titleName = titleName;
+ _titleIdText = titleId;
+ _controlData = controlData;
- MenuItem extractLogo = new MenuItem("Logo")
+ if (!ulong.TryParse(_titleIdText, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out _titleId))
{
- Sensitive = hasNca,
- TooltipText = "Extract the Logo section from Application's current config (including updates)."
- };
-
- Menu extractSubMenu = new Menu();
-
- extractSubMenu.Append(extractExeFs);
- extractSubMenu.Append(extractRomFs);
- extractSubMenu.Append(extractLogo);
+ GtkDialog.CreateErrorDialog("The selected game did not have a valid Title Id");
- extractMenu.Submenu = extractSubMenu;
-
- MenuItem managePtcMenu = new MenuItem("Cache Management");
-
- MenuItem purgePtcCache = new MenuItem("Purge PPTC Cache")
- {
- TooltipText = "Delete the Application's PPTC cache."
- };
+ return;
+ }
- MenuItem purgeShaderCache = new MenuItem("Purge Shader Cache")
- {
- TooltipText = "Delete the Application's shader cache."
- };
+ _openSaveUserDirMenuItem.Sensitive = !Utilities.IsEmpty(controlData.ByteSpan) && controlData.Value.UserAccountSaveDataSize > 0;
+ _openSaveDeviceDirMenuItem.Sensitive = !Utilities.IsEmpty(controlData.ByteSpan) && controlData.Value.DeviceSaveDataSize > 0;
+ _openSaveBcatDirMenuItem.Sensitive = !Utilities.IsEmpty(controlData.ByteSpan) && controlData.Value.BcatDeliveryCacheStorageSize > 0;
- MenuItem openPtcDir = new MenuItem("Open PPTC Directory")
- {
- TooltipText = "Open the directory which contains the Application's PPTC cache."
- };
+ string fileExt = System.IO.Path.GetExtension(_titleFilePath).ToLower();
+ bool hasNca = fileExt == ".nca" || fileExt == ".nsp" || fileExt == ".pfs0" || fileExt == ".xci";
- MenuItem openShaderCacheDir = new MenuItem("Open Shader Cache Directory")
- {
- TooltipText = "Open the directory which contains the Application's shader cache."
- };
+ _extractRomFsMenuItem.Sensitive = hasNca;
+ _extractExeFsMenuItem.Sensitive = hasNca;
+ _extractLogoMenuItem.Sensitive = hasNca;
- Menu manageSubMenu = new Menu();
-
- manageSubMenu.Append(purgePtcCache);
- manageSubMenu.Append(purgeShaderCache);
- manageSubMenu.Append(openPtcDir);
- manageSubMenu.Append(openShaderCacheDir);
-
- managePtcMenu.Submenu = manageSubMenu;
-
- openSaveUserDir.Activated += OpenSaveUserDir_Clicked;
- openSaveDeviceDir.Activated += OpenSaveDeviceDir_Clicked;
- openSaveBcatDir.Activated += OpenSaveBcatDir_Clicked;
- manageTitleUpdates.Activated += ManageTitleUpdates_Clicked;
- manageDlc.Activated += ManageDlc_Clicked;
- openTitleModDir.Activated += OpenTitleModDir_Clicked;
- extractRomFs.Activated += ExtractRomFs_Clicked;
- extractExeFs.Activated += ExtractExeFs_Clicked;
- extractLogo.Activated += ExtractLogo_Clicked;
- purgePtcCache.Activated += PurgePtcCache_Clicked;
- purgeShaderCache.Activated += PurgeShaderCache_Clicked;
- openPtcDir.Activated += OpenPtcDir_Clicked;
- openShaderCacheDir.Activated += OpenShaderCacheDir_Clicked;
-
- this.Add(openSaveUserDir);
- this.Add(openSaveDeviceDir);
- this.Add(openSaveBcatDir);
- this.Add(new SeparatorMenuItem());
- this.Add(manageTitleUpdates);
- this.Add(manageDlc);
- this.Add(openTitleModDir);
- this.Add(new SeparatorMenuItem());
- this.Add(managePtcMenu);
- this.Add(extractMenu);
+ PopupAtPointer(null);
}
private bool TryFindSaveData(string titleName, ulong titleId, BlitStruct<ApplicationControlProperty> controlHolder, SaveDataFilter filter, out ulong saveDataId)
@@ -178,7 +85,6 @@ namespace Ryujinx.Ui
using MessageDialog messageDialog = new MessageDialog(null, DialogFlags.Modal, MessageType.Question, ButtonsType.YesNo, null)
{
Title = "Ryujinx",
- Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"),
Text = $"There is no savedata for {titleName} [{titleId:x16}]",
SecondaryText = "Would you like to create savedata for this game?",
WindowPosition = WindowPosition.Center
@@ -191,7 +97,7 @@ namespace Ryujinx.Ui
ref ApplicationControlProperty control = ref controlHolder.Value;
- if (LibHac.Utilities.IsEmpty(controlHolder.ByteSpan))
+ if (Utilities.IsEmpty(controlHolder.ByteSpan))
{
// If the current application doesn't have a loaded control property, create a dummy one
// and set the savedata sizes so a user savedata will be created.
@@ -201,11 +107,10 @@ namespace Ryujinx.Ui
control.UserAccountSaveDataSize = 0x4000;
control.UserAccountSaveDataJournalSize = 0x4000;
- Logger.Warning?.Print(LogClass.Application,
- "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
+ Logger.Warning?.Print(LogClass.Application, "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
}
- Uid user = new Uid(1, 0);
+ Uid user = new Uid(1, 0); // TODO: Remove Hardcoded value.
result = EnsureApplicationSaveData(_virtualFileSystem.FsClient, out _, new LibHac.Ncm.ApplicationId(titleId), ref control, ref user);
@@ -232,8 +137,15 @@ namespace Ryujinx.Ui
return false;
}
- private string GetSaveDataDirectory(ulong saveDataId)
+ private void OpenSaveDir(SaveDataFilter saveDataFilter)
{
+ saveDataFilter.SetProgramId(new ProgramId(_titleId));
+
+ if (!TryFindSaveData(_titleName, _titleId, _controlData, saveDataFilter, out ulong saveDataId))
+ {
+ return;
+ }
+
string saveRootPath = System.IO.Path.Combine(_virtualFileSystem.GetNandPath(), $"user/save/{saveDataId:x16}");
if (!Directory.Exists(saveRootPath))
@@ -248,17 +160,19 @@ namespace Ryujinx.Ui
// If the committed directory exists, that path will be loaded the next time the savedata is mounted
if (Directory.Exists(committedPath))
{
- return committedPath;
+ OpenHelper.OpenFolder(committedPath);
}
-
- // If the working directory exists and the committed directory doesn't,
- // the working directory will be loaded the next time the savedata is mounted
- if (!Directory.Exists(workingPath))
+ else
{
- Directory.CreateDirectory(workingPath);
- }
+ // If the working directory exists and the committed directory doesn't,
+ // the working directory will be loaded the next time the savedata is mounted
+ if (!Directory.Exists(workingPath))
+ {
+ Directory.CreateDirectory(workingPath);
+ }
- return workingPath;
+ OpenHelper.OpenFolder(workingPath);
+ }
}
private void ExtractSection(NcaSectionType ncaSectionType, int programIndex = 0)
@@ -266,24 +180,21 @@ namespace Ryujinx.Ui
FileChooserDialog fileChooser = new FileChooserDialog("Choose the folder to extract into", null, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Extract", ResponseType.Accept);
fileChooser.SetPosition(WindowPosition.Center);
- int response = fileChooser.Run();
- string destination = fileChooser.Filename;
+ ResponseType response = (ResponseType)fileChooser.Run();
+ string destination = fileChooser.Filename;
fileChooser.Dispose();
- if (response == (int)ResponseType.Accept)
+ if (response == ResponseType.Accept)
{
Thread extractorThread = new Thread(() =>
{
- string sourceFile = _gameTableStore.GetValue(_rowIter, 9).ToString();
-
Gtk.Application.Invoke(delegate
{
_dialog = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Cancel, null)
{
Title = "Ryujinx - NCA Section Extractor",
- Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"),
- SecondaryText = $"Extracting {ncaSectionType} section from {System.IO.Path.GetFileName(sourceFile)}...",
+ SecondaryText = $"Extracting {ncaSectionType} section from {System.IO.Path.GetFileName(_titleFilePath)}...",
WindowPosition = WindowPosition.Center
};
@@ -295,18 +206,18 @@ namespace Ryujinx.Ui
}
});
- using (FileStream file = new FileStream(sourceFile, FileMode.Open, FileAccess.Read))
+ using (FileStream file = new FileStream(_titleFilePath, FileMode.Open, FileAccess.Read))
{
Nca mainNca = null;
Nca patchNca = null;
- if ((System.IO.Path.GetExtension(sourceFile).ToLower() == ".nsp") ||
- (System.IO.Path.GetExtension(sourceFile).ToLower() == ".pfs0") ||
- (System.IO.Path.GetExtension(sourceFile).ToLower() == ".xci"))
+ if ((System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".nsp") ||
+ (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".pfs0") ||
+ (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".xci"))
{
PartitionFileSystem pfs;
- if (System.IO.Path.GetExtension(sourceFile) == ".xci")
+ if (System.IO.Path.GetExtension(_titleFilePath) == ".xci")
{
Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage());
@@ -338,7 +249,7 @@ namespace Ryujinx.Ui
}
}
}
- else if (System.IO.Path.GetExtension(sourceFile).ToLower() == ".nca")
+ else if (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".nca")
{
mainNca = new Nca(_virtualFileSystem.KeySet, file.AsStorage());
}
@@ -355,7 +266,6 @@ namespace Ryujinx.Ui
return;
}
-
(Nca updatePatchNca, _) = ApplicationLoader.GetGameUpdateData(_virtualFileSystem, mainNca.Header.TitleId.ToString("x16"), programIndex, out _);
if (updatePatchNca != null)
@@ -370,8 +280,8 @@ namespace Ryujinx.Ui
FileSystemClient fsClient = _virtualFileSystem.FsClient;
- string source = DateTime.Now.ToFileTime().ToString().Substring(10);
- string output = DateTime.Now.ToFileTime().ToString().Substring(10);
+ string source = DateTime.Now.ToFileTime().ToString()[10..];
+ string output = DateTime.Now.ToFileTime().ToString()[10..];
fsClient.Register(source.ToU8Span(), ncaFileSystem);
fsClient.Register(output.ToU8Span(), new LocalFileSystem(destination));
@@ -400,7 +310,6 @@ namespace Ryujinx.Ui
MessageDialog dialog = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null)
{
Title = "Ryujinx - NCA Section Extractor",
- Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"),
SecondaryText = "Extraction has completed successfully.",
WindowPosition = WindowPosition.Center
};
@@ -510,111 +419,49 @@ namespace Ryujinx.Ui
return Result.Success;
}
+ //
// Events
+ //
private void OpenSaveUserDir_Clicked(object sender, EventArgs args)
{
- string titleName = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[0];
- string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
-
- if (!ulong.TryParse(titleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
- {
- GtkDialog.CreateErrorDialog("UI error: The selected game did not have a valid title ID");
-
- return;
- }
-
- SaveDataFilter filter = new SaveDataFilter();
- filter.SetUserId(new UserId(1, 0));
-
- OpenSaveDir(titleName, titleIdNumber, filter);
- }
-
- private void OpenSaveDir(string titleName, ulong titleId, SaveDataFilter filter)
- {
- filter.SetProgramId(new ProgramId(titleId));
-
- if (!TryFindSaveData(titleName, titleId, _controlData, filter, out ulong saveDataId))
- {
- return;
- }
-
- string saveDir = GetSaveDataDirectory(saveDataId);
+ SaveDataFilter saveDataFilter = new SaveDataFilter();
+ saveDataFilter.SetUserId(new UserId(1, 0)); // TODO: Remove Hardcoded value.
- Process.Start(new ProcessStartInfo
- {
- FileName = saveDir,
- UseShellExecute = true,
- Verb = "open"
- });
+ OpenSaveDir(saveDataFilter);
}
private void OpenSaveDeviceDir_Clicked(object sender, EventArgs args)
{
- string titleName = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[0];
- string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
-
- if (!ulong.TryParse(titleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
- {
- GtkDialog.CreateErrorDialog("UI error: The selected game did not have a valid title ID");
-
- return;
- }
-
- SaveDataFilter filter = new SaveDataFilter();
- filter.SetSaveDataType(SaveDataType.Device);
+ SaveDataFilter saveDataFilter = new SaveDataFilter();
+ saveDataFilter.SetSaveDataType(SaveDataType.Device);
- OpenSaveDir(titleName, titleIdNumber, filter);
+ OpenSaveDir(saveDataFilter);
}
private void OpenSaveBcatDir_Clicked(object sender, EventArgs args)
{
- string titleName = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[0];
- string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
+ SaveDataFilter saveDataFilter = new SaveDataFilter();
+ saveDataFilter.SetSaveDataType(SaveDataType.Bcat);
- if (!ulong.TryParse(titleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
- {
- GtkDialog.CreateErrorDialog("UI error: The selected game did not have a valid title ID");
-
- return;
- }
-
- SaveDataFilter filter = new SaveDataFilter();
- filter.SetSaveDataType(SaveDataType.Bcat);
-
- OpenSaveDir(titleName, titleIdNumber, filter);
+ OpenSaveDir(saveDataFilter);
}
private void ManageTitleUpdates_Clicked(object sender, EventArgs args)
{
- string titleName = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[0];
- string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
-
- TitleUpdateWindow titleUpdateWindow = new TitleUpdateWindow(titleId, titleName, _virtualFileSystem);
- titleUpdateWindow.Show();
+ new TitleUpdateWindow(_parent, _virtualFileSystem, _titleIdText, _titleName).Show();
}
private void ManageDlc_Clicked(object sender, EventArgs args)
{
- string titleName = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[0];
- string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
-
- DlcWindow dlcWindow = new DlcWindow(titleId, titleName, _virtualFileSystem);
- dlcWindow.Show();
+ new DlcWindow(_virtualFileSystem, _titleIdText, _titleName).Show();
}
private void OpenTitleModDir_Clicked(object sender, EventArgs args)
{
- string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
-
- var modsBasePath = _virtualFileSystem.ModLoader.GetModsBasePath();
- var titleModsPath = _virtualFileSystem.ModLoader.GetTitleDir(modsBasePath, titleId);
+ string modsBasePath = _virtualFileSystem.ModLoader.GetModsBasePath();
+ string titleModsPath = _virtualFileSystem.ModLoader.GetTitleDir(modsBasePath, _titleIdText);
- Process.Start(new ProcessStartInfo
- {
- FileName = titleModsPath,
- UseShellExecute = true,
- Verb = "open"
- });
+ OpenHelper.OpenFolder(titleModsPath);
}
private void ExtractRomFs_Clicked(object sender, EventArgs args)
@@ -634,8 +481,7 @@ namespace Ryujinx.Ui
private void OpenPtcDir_Clicked(object sender, EventArgs args)
{
- string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
- string ptcDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, titleId, "cache", "cpu");
+ string ptcDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu");
string mainPath = System.IO.Path.Combine(ptcDir, "0");
string backupPath = System.IO.Path.Combine(ptcDir, "1");
@@ -646,52 +492,40 @@ namespace Ryujinx.Ui
Directory.CreateDirectory(mainPath);
Directory.CreateDirectory(backupPath);
}
-
- Process.Start(new ProcessStartInfo
- {
- FileName = ptcDir,
- UseShellExecute = true,
- Verb = "open"
- });
+
+ OpenHelper.OpenFolder(ptcDir);
}
private void OpenShaderCacheDir_Clicked(object sender, EventArgs args)
{
- string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
- string shaderCacheDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, titleId, "cache", "shader");
+ string shaderCacheDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "shader");
if (!Directory.Exists(shaderCacheDir))
{
Directory.CreateDirectory(shaderCacheDir);
}
- Process.Start(new ProcessStartInfo
- {
- FileName = shaderCacheDir,
- UseShellExecute = true,
- Verb = "open"
- });
+ OpenHelper.OpenFolder(shaderCacheDir);
}
private void PurgePtcCache_Clicked(object sender, EventArgs args)
{
- string[] tableEntry = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n");
- string titleId = tableEntry[1].ToLower();
-
- DirectoryInfo mainDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, titleId, "cache", "cpu", "0"));
- DirectoryInfo backupDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, titleId, "cache", "cpu", "1"));
-
- MessageDialog warningDialog = new MessageDialog(null, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null)
- {
- Title = "Ryujinx - Warning",
- Text = $"You are about to delete the PPTC cache for '{tableEntry[0]}'. Are you sure you want to proceed?",
- WindowPosition = WindowPosition.Center
- };
+ DirectoryInfo mainDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu", "0"));
+ DirectoryInfo backupDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu", "1"));
+
+ MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to delete the PPTC cache for :\n\n<b>{_titleName}</b>\n\nAre you sure you want to proceed?");
List<FileInfo> cacheFiles = new List<FileInfo>();
- if (mainDir.Exists) { cacheFiles.AddRange(mainDir.EnumerateFiles("*.cache")); }
- if (backupDir.Exists) { cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache")); }
+ if (mainDir.Exists)
+ {
+ cacheFiles.AddRange(mainDir.EnumerateFiles("*.cache"));
+ }
+
+ if (backupDir.Exists)
+ {
+ cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
+ }
if (cacheFiles.Count > 0 && warningDialog.Run() == (int)ResponseType.Yes)
{
@@ -703,7 +537,7 @@ namespace Ryujinx.Ui
}
catch(Exception e)
{
- Logger.Error?.Print(LogClass.Application, $"Error purging PPTC cache {file.Name}: {e}");
+ GtkDialog.CreateErrorDialog($"Error purging PPTC cache {file.Name}: {e}");
}
}
}
@@ -713,21 +547,16 @@ namespace Ryujinx.Ui
private void PurgeShaderCache_Clicked(object sender, EventArgs args)
{
- string[] tableEntry = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n");
- string titleId = tableEntry[1].ToLower();
-
- DirectoryInfo shaderCacheDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, titleId, "cache", "shader"));
+ DirectoryInfo shaderCacheDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "shader"));
- MessageDialog warningDialog = new MessageDialog(null, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null)
- {
- Title = "Ryujinx - Warning",
- Text = $"You are about to delete the shader cache for '{tableEntry[0]}'. Are you sure you want to proceed?",
- WindowPosition = WindowPosition.Center
- };
+ MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to delete the shader cache for :\n\n<b>{_titleName}</b>\n\nAre you sure you want to proceed?");
List<DirectoryInfo> cacheDirectory = new List<DirectoryInfo>();
- if (shaderCacheDir.Exists) { cacheDirectory.AddRange(shaderCacheDir.EnumerateDirectories("*")); }
+ if (shaderCacheDir.Exists)
+ {
+ cacheDirectory.AddRange(shaderCacheDir.EnumerateDirectories("*"));
+ }
if (cacheDirectory.Count > 0 && warningDialog.Run() == (int)ResponseType.Yes)
{
@@ -739,7 +568,7 @@ namespace Ryujinx.Ui
}
catch (Exception e)
{
- Logger.Error?.Print(LogClass.Application, $"Error purging shader cache {directory.Name}: {e}");
+ GtkDialog.CreateErrorDialog($"Error purging shader cache {directory.Name}: {e}");
}
}
}
@@ -747,4 +576,4 @@ namespace Ryujinx.Ui
warningDialog.Dispose();
}
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/GtkDialog.cs b/Ryujinx/Ui/Widgets/GtkDialog.cs
index f86b7016..e603383a 100644
--- a/Ryujinx/Ui/GtkDialog.cs
+++ b/Ryujinx/Ui/Widgets/GtkDialog.cs
@@ -1,7 +1,7 @@
using Gtk;
-using System.Reflection;
+using Ryujinx.Common.Logging;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.Widgets
{
internal class GtkDialog : MessageDialog
{
@@ -10,14 +10,15 @@ namespace Ryujinx.Ui
private GtkDialog(string title, string mainText, string secondaryText, MessageType messageType = MessageType.Other, ButtonsType buttonsType = ButtonsType.Ok)
: base(null, DialogFlags.Modal, messageType, buttonsType, null)
{
- Title = title;
- Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
- Text = mainText;
- SecondaryText = secondaryText;
- WindowPosition = WindowPosition.Center;
- Response += GtkDialog_Response;
-
- SetSizeRequest(100, 20);
+ Title = title;
+ Text = mainText;
+ SecondaryText = secondaryText;
+ WindowPosition = WindowPosition.Center;
+ SecondaryUseMarkup = true;
+
+ Response += GtkDialog_Response;
+
+ SetSizeRequest(200, 20);
}
private void GtkDialog_Response(object sender, ResponseArgs args)
@@ -25,9 +26,19 @@ namespace Ryujinx.Ui
Dispose();
}
- internal static void CreateInfoDialog(string title, string mainText, string secondaryText)
+ internal static void CreateInfoDialog(string mainText, string secondaryText)
+ {
+ new GtkDialog("Ryujinx - Info", mainText, secondaryText, MessageType.Info).Run();
+ }
+
+ internal static void CreateUpdaterInfoDialog(string mainText, string secondaryText)
{
- new GtkDialog(title, mainText, secondaryText, MessageType.Info).Run();
+ new GtkDialog("Ryujinx - Updater", mainText, secondaryText, MessageType.Info).Run();
+ }
+
+ internal static MessageDialog CreateWaitingDialog(string mainText, string secondaryText)
+ {
+ return new GtkDialog("Ryujinx - Waiting", mainText, secondaryText, MessageType.Info, ButtonsType.None);
}
internal static void CreateWarningDialog(string mainText, string secondaryText)
@@ -37,6 +48,8 @@ namespace Ryujinx.Ui
internal static void CreateErrorDialog(string errorMessage)
{
+ Logger.Error?.Print(LogClass.Application, errorMessage);
+
new GtkDialog("Ryujinx - Error", "Ryujinx has encountered an error", errorMessage, MessageType.Error).Run();
}
@@ -48,10 +61,14 @@ namespace Ryujinx.Ui
internal static bool CreateChoiceDialog(string title, string mainText, string secondaryText)
{
if (_isChoiceDialogOpen)
+ {
return false;
+ }
_isChoiceDialogOpen = true;
+
ResponseType response = (ResponseType)new GtkDialog(title, mainText, secondaryText, MessageType.Question, ButtonsType.YesNo).Run();
+
_isChoiceDialogOpen = false;
return response == ResponseType.Yes;
diff --git a/Ryujinx/Ui/ProfileDialog.cs b/Ryujinx/Ui/Widgets/ProfileDialog.cs
index 2b26cbef..86667572 100644
--- a/Ryujinx/Ui/ProfileDialog.cs
+++ b/Ryujinx/Ui/Widgets/ProfileDialog.cs
@@ -1,10 +1,9 @@
using Gtk;
using System;
-using System.Reflection;
using GUI = Gtk.Builder.ObjectAttribute;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.Widgets
{
public class ProfileDialog : Dialog
{
@@ -15,18 +14,16 @@ namespace Ryujinx.Ui
[GUI] Label _errorMessage;
#pragma warning restore CS0649, IDE0044
- public ProfileDialog() : this(new Builder("Ryujinx.Ui.ProfileDialog.glade")) { }
+ public ProfileDialog() : this(new Builder("Ryujinx.Ui.Widgets.ProfileDialog.glade")) { }
private ProfileDialog(Builder builder) : base(builder.GetObject("_profileDialog").Handle)
{
builder.Autoconnect(this);
-
- Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
}
private void OkToggle_Activated(object sender, EventArgs args)
{
- ((ToggleButton)sender).SetStateFlags(0, true);
+ ((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
bool validFileName = true;
diff --git a/Ryujinx/Ui/ProfileDialog.glade b/Ryujinx/Ui/Widgets/ProfileDialog.glade
index adaf6608..adaf6608 100644
--- a/Ryujinx/Ui/ProfileDialog.glade
+++ b/Ryujinx/Ui/Widgets/ProfileDialog.glade
diff --git a/Ryujinx/Ui/Diagnostic/UserError.cs b/Ryujinx/Ui/Widgets/UserError.cs
index eaa1bc83..08695571 100644
--- a/Ryujinx/Ui/Diagnostic/UserError.cs
+++ b/Ryujinx/Ui/Widgets/UserError.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Ui.Diagnostic
+namespace Ryujinx.Ui.Widgets
{
/// <summary>
/// Represent a common error that could be reported to the user by the emulator.
@@ -36,4 +36,4 @@
/// </summary>
Unknown = 0xDEAD
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/Widgets/UserErrorDialog.cs b/Ryujinx/Ui/Widgets/UserErrorDialog.cs
new file mode 100644
index 00000000..095b88a3
--- /dev/null
+++ b/Ryujinx/Ui/Widgets/UserErrorDialog.cs
@@ -0,0 +1,122 @@
+using Gtk;
+using Ryujinx.Ui.Helper;
+
+namespace Ryujinx.Ui.Widgets
+{
+ internal class UserErrorDialog : MessageDialog
+ {
+ private const string SetupGuideUrl = "https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide";
+ private const int OkResponseId = 0;
+ private const int SetupGuideResponseId = 1;
+
+ private readonly UserError _userError;
+
+ private UserErrorDialog(UserError error) : base(null, DialogFlags.Modal, MessageType.Error, ButtonsType.None, null)
+ {
+ _userError = error;
+
+ WindowPosition = WindowPosition.Center;
+ SecondaryUseMarkup = true;
+
+ Response += UserErrorDialog_Response;
+
+ SetSizeRequest(120, 50);
+
+ AddButton("OK", OkResponseId);
+
+ bool isInSetupGuide = IsCoveredBySetupGuide(error);
+
+ if (isInSetupGuide)
+ {
+ AddButton("Open the Setup Guide", SetupGuideResponseId);
+ }
+
+ string errorCode = GetErrorCode(error);
+
+ SecondaryUseMarkup = true;
+
+ Title = $"Ryujinx error ({errorCode})";
+ Text = $"{errorCode}: {GetErrorTitle(error)}";
+ SecondaryText = GetErrorDescription(error);
+
+ if (isInSetupGuide)
+ {
+ SecondaryText += "\n<b>For more information on how to fix this error, follow our Setup Guide.</b>";
+ }
+ }
+
+ private string GetErrorCode(UserError error)
+ {
+ return $"RYU-{(uint)error:X4}";
+ }
+
+ private string GetErrorTitle(UserError error)
+ {
+ return error switch
+ {
+ UserError.NoKeys => "Keys not found",
+ UserError.NoFirmware => "Firmware not found",
+ UserError.FirmwareParsingFailed => "Firmware parsing error",
+ UserError.ApplicationNotFound => "Application not found",
+ UserError.Unknown => "Unknown error",
+ _ => "Undefined error",
+ };
+ }
+
+ private string GetErrorDescription(UserError error)
+ {
+ return error switch
+ {
+ UserError.NoKeys => "Ryujinx was unable to find your 'prod.keys' file",
+ UserError.NoFirmware => "Ryujinx was unable to find any firmwares installed",
+ UserError.FirmwareParsingFailed => "Ryujinx was unable to parse the provided firmware. This is usually caused by outdated keys.",
+ UserError.ApplicationNotFound => "Ryujinx couldn't find a valid application at the given path.",
+ UserError.Unknown => "An unknown error occured!",
+ _ => "An undefined error occured! This shouldn't happen, please contact a dev!",
+ };
+ }
+
+ private static bool IsCoveredBySetupGuide(UserError error)
+ {
+ return error switch
+ {
+ UserError.NoKeys or
+ UserError.NoFirmware or
+ UserError.FirmwareParsingFailed => true,
+ _ => false,
+ };
+ }
+
+ private static string GetSetupGuideUrl(UserError error)
+ {
+ if (!IsCoveredBySetupGuide(error))
+ {
+ return null;
+ }
+
+ return error switch
+ {
+ UserError.NoKeys => SetupGuideUrl + "#initial-setup---placement-of-prodkeys",
+ UserError.NoFirmware => SetupGuideUrl + "#initial-setup-continued---installation-of-firmware",
+ _ => SetupGuideUrl,
+ };
+ }
+
+ private void UserErrorDialog_Response(object sender, ResponseArgs args)
+ {
+ int responseId = (int)args.ResponseId;
+
+ if (responseId == SetupGuideResponseId)
+ {
+ OpenHelper.OpenUrl(GetSetupGuideUrl(_userError));
+ }
+
+ Dispose();
+ }
+
+ public static void CreateUserErrorDialog(UserError error)
+ {
+ new UserErrorDialog(error).Run();
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/Windows/AboutWindow.Designer.cs b/Ryujinx/Ui/Windows/AboutWindow.Designer.cs
new file mode 100644
index 00000000..99ce9333
--- /dev/null
+++ b/Ryujinx/Ui/Windows/AboutWindow.Designer.cs
@@ -0,0 +1,467 @@
+using Gtk;
+using Pango;
+using System.Reflection;
+
+namespace Ryujinx.Ui.Windows
+{
+ public partial class AboutWindow : Window
+ {
+ private Box _mainBox;
+ private Box _leftBox;
+ private Box _logoBox;
+ private Image _ryujinxLogo;
+ private Box _logoTextBox;
+ private Label _ryujinxLabel;
+ private Label _ryujinxPhoneticLabel;
+ private EventBox _ryujinxLink;
+ private Label _ryujinxLinkLabel;
+ private Label _versionLabel;
+ private Label _disclaimerLabel;
+ private Box _socialBox;
+ private EventBox _patreonEventBox;
+ private Box _patreonBox;
+ private Image _patreonLogo;
+ private Label _patreonLabel;
+ private EventBox _githubEventBox;
+ private Box _githubBox;
+ private Image _githubLogo;
+ private Label _githubLabel;
+ private Box _discordBox;
+ private EventBox _discordEventBox;
+ private Image _discordLogo;
+ private Label _discordLabel;
+ private EventBox _twitterEventBox;
+ private Box _twitterBox;
+ private Image _twitterLogo;
+ private Label _twitterLabel;
+ private Separator _separator;
+ private Box _rightBox;
+ private Label _aboutLabel;
+ private Label _aboutDescriptionLabel;
+ private Label _createdByLabel;
+ private TextView _createdByText;
+ private EventBox _contributorsEventBox;
+ private Label _contributorsLinkLabel;
+ private Label _patreonNamesLabel;
+ private ScrolledWindow _patreonNamesScrolled;
+ private TextView _patreonNamesText;
+
+ private void InitializeComponent()
+ {
+
+#pragma warning disable CS0612
+
+ //
+ // AboutWindow
+ //
+ CanFocus = false;
+ Resizable = false;
+ Modal = true;
+ WindowPosition = WindowPosition.Center;
+ DefaultWidth = 800;
+ DefaultHeight = 450;
+ TypeHint = Gdk.WindowTypeHint.Dialog;
+
+ //
+ // _mainBox
+ //
+ _mainBox = new Box(Orientation.Horizontal, 0);
+
+ //
+ // _leftBox
+ //
+ _leftBox = new Box(Orientation.Vertical, 0)
+ {
+ Margin = 15,
+ MarginLeft = 30,
+ MarginRight = 0
+ };
+
+ //
+ // _logoBox
+ //
+ _logoBox = new Box(Orientation.Horizontal, 0);
+
+ //
+ // _ryujinxLogo
+ //
+ _ryujinxLogo = new Image(new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_Ryujinx.png", 100, 100))
+ {
+ Margin = 10,
+ MarginLeft = 15
+ };
+
+ //
+ // _logoTextBox
+ //
+ _logoTextBox = new Box(Orientation.Vertical, 0);
+
+ //
+ // _ryujinxLabel
+ //
+ _ryujinxLabel = new Label("Ryujinx")
+ {
+ MarginTop = 15,
+ Justify = Justification.Center,
+ Attributes = new AttrList()
+ };
+ _ryujinxLabel.Attributes.Insert(new Pango.AttrScale(2.7f));
+
+ //
+ // _ryujinxPhoneticLabel
+ //
+ _ryujinxPhoneticLabel = new Label("(REE-YOU-JI-NX)")
+ {
+ Justify = Justification.Center
+ };
+
+ //
+ // _ryujinxLink
+ //
+ _ryujinxLink = new EventBox()
+ {
+ Margin = 5
+ };
+ _ryujinxLink.ButtonPressEvent += RyujinxButton_Pressed;
+
+ //
+ // _ryujinxLinkLabel
+ //
+ _ryujinxLinkLabel = new Label("www.ryujinx.org")
+ {
+ TooltipText = "Click to open the Ryujinx website in your default browser.",
+ Justify = Justification.Center,
+ Attributes = new AttrList()
+ };
+ _ryujinxLinkLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
+
+ //
+ // _versionLabel
+ //
+ _versionLabel = new Label(Program.Version)
+ {
+ Expand = true,
+ Justify = Justification.Center,
+ Margin = 5
+ };
+
+ //
+ // _disclaimerLabel
+ //
+ _disclaimerLabel = new Label("Ryujinx is not affiliated with Nintendo™,\nor any of its partners, in any way.")
+ {
+ Expand = true,
+ Justify = Justification.Center,
+ Margin = 5,
+ Attributes = new AttrList()
+ };
+ _disclaimerLabel.Attributes.Insert(new Pango.AttrScale(0.8f));
+
+ //
+ // _socialBox
+ //
+ _socialBox = new Box(Orientation.Horizontal, 0)
+ {
+ Margin = 25,
+ MarginBottom = 10
+ };
+
+ //
+ // _patreonEventBox
+ //
+ _patreonEventBox = new EventBox()
+ {
+ TooltipText = "Click to open the Ryujinx Patreon page in your default browser."
+ };
+ _patreonEventBox.ButtonPressEvent += PatreonButton_Pressed;
+
+ //
+ // _patreonBox
+ //
+ _patreonBox = new Box(Orientation.Vertical, 0);
+
+ //
+ // _patreonLogo
+ //
+ _patreonLogo = new Image(new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_Patreon.png", 30, 30))
+ {
+ Margin = 10
+ };
+
+ //
+ // _patreonLabel
+ //
+ _patreonLabel = new Label("Patreon")
+ {
+ Justify = Justification.Center
+ };
+
+ //
+ // _githubEventBox
+ //
+ _githubEventBox = new EventBox()
+ {
+ TooltipText = "Click to open the Ryujinx GitHub page in your default browser."
+ };
+ _githubEventBox.ButtonPressEvent += GitHubButton_Pressed;
+
+ //
+ // _githubBox
+ //
+ _githubBox = new Box(Orientation.Vertical, 0);
+
+ //
+ // _githubLogo
+ //
+ _githubLogo = new Image(new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_GitHub.png", 30, 30))
+ {
+ Margin = 10
+ };
+
+ //
+ // _githubLabel
+ //
+ _githubLabel = new Label("GitHub")
+ {
+ Justify = Justification.Center
+ };
+
+ //
+ // _discordBox
+ //
+ _discordBox = new Box(Orientation.Vertical, 0);
+
+ //
+ // _discordEventBox
+ //
+ _discordEventBox = new EventBox()
+ {
+ TooltipText = "Click to open an invite to the Ryujinx Discord server in your default browser."
+ };
+ _discordEventBox.ButtonPressEvent += DiscordButton_Pressed;
+
+ //
+ // _discordLogo
+ //
+ _discordLogo = new Image(new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_Discord.png", 30, 30))
+ {
+ Margin = 10
+ };
+
+ //
+ // _discordLabel
+ //
+ _discordLabel = new Label("Discord")
+ {
+ Justify = Justification.Center
+ };
+
+ //
+ // _twitterEventBox
+ //
+ _twitterEventBox = new EventBox()
+ {
+ TooltipText = "Click to open the Ryujinx Twitter page in your default browser."
+ };
+ _twitterEventBox.ButtonPressEvent += TwitterButton_Pressed;
+
+ //
+ // _twitterBox
+ //
+ _twitterBox = new Box(Orientation.Vertical, 0);
+
+ //
+ // _twitterLogo
+ //
+ _twitterLogo = new Image(new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_Twitter.png", 30, 30))
+ {
+ Margin = 10
+ };
+
+ //
+ // _twitterLabel
+ //
+ _twitterLabel = new Label("Twitter")
+ {
+ Justify = Justification.Center
+ };
+
+ //
+ // _separator
+ //
+ _separator = new Separator(Orientation.Vertical)
+ {
+ Margin = 15
+ };
+
+ //
+ // _rightBox
+ //
+ _rightBox = new Box(Orientation.Vertical, 0)
+ {
+ Margin = 15,
+ MarginTop = 40
+ };
+
+ //
+ // _aboutLabel
+ //
+ _aboutLabel = new Label("About :")
+ {
+ Halign = Align.Start,
+ Attributes = new AttrList()
+ };
+ _aboutLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
+ _aboutLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
+
+ //
+ // _aboutDescriptionLabel
+ //
+ _aboutDescriptionLabel = new Label("Ryujinx is an emulator for the Nintendo Switch™.\n" +
+ "Please support us on Patreon.\n" +
+ "Get all the latest news on our Twitter or Discord.\n" +
+ "Developers interested in contributing can find out more on our GitHub or Discord.")
+ {
+ Margin = 15,
+ Halign = Align.Start
+ };
+
+ //
+ // _createdByLabel
+ //
+ _createdByLabel = new Label("Maintained by :")
+ {
+ Halign = Align.Start,
+ Attributes = new AttrList()
+ };
+ _createdByLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
+ _createdByLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
+
+ //
+ // _createdByText
+ //
+ _createdByText = new TextView()
+ {
+ WrapMode = Gtk.WrapMode.Word,
+ Editable = false,
+ CursorVisible = false,
+ Margin = 15,
+ MarginRight = 30
+ };
+ _createdByText.Buffer.Text = "gdkchan, Ac_K, Thog, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, Xpl0itR, GoffyDude, »jD« and more...";
+
+ //
+ // _contributorsEventBox
+ //
+ _contributorsEventBox = new EventBox();
+ _contributorsEventBox.ButtonPressEvent += ContributorsButton_Pressed;
+
+ //
+ // _contributorsLinkLabel
+ //
+ _contributorsLinkLabel = new Label("See All Contributors...")
+ {
+ TooltipText = "Click to open the Contributors page in your default browser.",
+ MarginRight = 30,
+ Halign = Align.End,
+ Attributes = new AttrList()
+ };
+ _contributorsLinkLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
+
+ //
+ // _patreonNamesLabel
+ //
+ _patreonNamesLabel = new Label("Supported on Patreon by :")
+ {
+ Halign = Align.Start,
+ Attributes = new AttrList()
+ };
+ _patreonNamesLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
+ _patreonNamesLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
+
+ //
+ // _patreonNamesScrolled
+ //
+ _patreonNamesScrolled = new ScrolledWindow()
+ {
+ Margin = 15,
+ MarginRight = 30,
+ Expand = true,
+ ShadowType = ShadowType.In
+ };
+ _patreonNamesScrolled.SetPolicy(PolicyType.Never, PolicyType.Automatic);
+
+ //
+ // _patreonNamesText
+ //
+ _patreonNamesText = new TextView()
+ {
+ WrapMode = Gtk.WrapMode.Word
+ };
+ _patreonNamesText.Buffer.Text = "Loading...";
+ _patreonNamesText.SetProperty("editable", new GLib.Value(false));
+
+#pragma warning restore CS0612
+
+ ShowComponent();
+ }
+
+ private void ShowComponent()
+ {
+ _logoBox.Add(_ryujinxLogo);
+
+ _ryujinxLink.Add(_ryujinxLinkLabel);
+
+ _logoTextBox.Add(_ryujinxLabel);
+ _logoTextBox.Add(_ryujinxPhoneticLabel);
+ _logoTextBox.Add(_ryujinxLink);
+
+ _logoBox.Add(_logoTextBox);
+
+ _patreonBox.Add(_patreonLogo);
+ _patreonBox.Add(_patreonLabel);
+ _patreonEventBox.Add(_patreonBox);
+
+ _githubBox.Add(_githubLogo);
+ _githubBox.Add(_githubLabel);
+ _githubEventBox.Add(_githubBox);
+
+ _discordBox.Add(_discordLogo);
+ _discordBox.Add(_discordLabel);
+ _discordEventBox.Add(_discordBox);
+
+ _twitterBox.Add(_twitterLogo);
+ _twitterBox.Add(_twitterLabel);
+ _twitterEventBox.Add(_twitterBox);
+
+ _socialBox.Add(_patreonEventBox);
+ _socialBox.Add(_githubEventBox);
+ _socialBox.Add(_discordEventBox);
+ _socialBox.Add(_twitterEventBox);
+
+ _leftBox.Add(_logoBox);
+ _leftBox.Add(_versionLabel);
+ _leftBox.Add(_disclaimerLabel);
+ _leftBox.Add(_socialBox);
+
+ _contributorsEventBox.Add(_contributorsLinkLabel);
+ _patreonNamesScrolled.Add(_patreonNamesText);
+
+ _rightBox.Add(_aboutLabel);
+ _rightBox.Add(_aboutDescriptionLabel);
+ _rightBox.Add(_createdByLabel);
+ _rightBox.Add(_createdByText);
+ _rightBox.Add(_contributorsEventBox);
+ _rightBox.Add(_patreonNamesLabel);
+ _rightBox.Add(_patreonNamesScrolled);
+
+ _mainBox.Add(_leftBox);
+ _mainBox.Add(_separator);
+ _mainBox.Add(_rightBox);
+
+ Add(_mainBox);
+
+ ShowAll();
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/Windows/AboutWindow.cs b/Ryujinx/Ui/Windows/AboutWindow.cs
new file mode 100644
index 00000000..ab93e41d
--- /dev/null
+++ b/Ryujinx/Ui/Windows/AboutWindow.cs
@@ -0,0 +1,73 @@
+using Gtk;
+using Ryujinx.Common.Utilities;
+using Ryujinx.Ui.Helper;
+using System.Net.Http;
+using System.Net.NetworkInformation;
+using System.Threading.Tasks;
+
+namespace Ryujinx.Ui.Windows
+{
+ public partial class AboutWindow : Window
+ {
+ public AboutWindow() : base($"Ryujinx {Program.Version} - About")
+ {
+ InitializeComponent();
+
+ _ = DownloadPatronsJson();
+ }
+
+ private async Task DownloadPatronsJson()
+ {
+ if (!NetworkInterface.GetIsNetworkAvailable())
+ {
+ _patreonNamesText.Buffer.Text = "Connection Error.";
+ }
+
+ HttpClient httpClient = new HttpClient();
+
+ try
+ {
+ string patreonJsonString = await httpClient.GetStringAsync("https://patreon.ryujinx.org/");
+
+ _patreonNamesText.Buffer.Text = string.Join(", ", JsonHelper.Deserialize<string[]>(patreonJsonString));
+ }
+ catch
+ {
+ _patreonNamesText.Buffer.Text = "API Error.";
+ }
+ }
+
+ //
+ // Events
+ //
+ private void RyujinxButton_Pressed(object sender, ButtonPressEventArgs args)
+ {
+ OpenHelper.OpenUrl("https://ryujinx.org");
+ }
+
+ private void PatreonButton_Pressed(object sender, ButtonPressEventArgs args)
+ {
+ OpenHelper.OpenUrl("https://www.patreon.com/ryujinx");
+ }
+
+ private void GitHubButton_Pressed(object sender, ButtonPressEventArgs args)
+ {
+ OpenHelper.OpenUrl("https://github.com/Ryujinx/Ryujinx");
+ }
+
+ private void DiscordButton_Pressed(object sender, ButtonPressEventArgs args)
+ {
+ OpenHelper.OpenUrl("https://discordapp.com/invite/N2FmfVc");
+ }
+
+ private void TwitterButton_Pressed(object sender, ButtonPressEventArgs args)
+ {
+ OpenHelper.OpenUrl("https://twitter.com/RyujinxEmu");
+ }
+
+ private void ContributorsButton_Pressed(object sender, ButtonPressEventArgs args)
+ {
+ OpenHelper.OpenUrl("https://github.com/Ryujinx/Ryujinx/graphs/contributors?type=a");
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/ControllerWindow.cs b/Ryujinx/Ui/Windows/ControllerWindow.cs
index 77c8db0c..7b0f7cf8 100644
--- a/Ryujinx/Ui/ControllerWindow.cs
+++ b/Ryujinx/Ui/Windows/ControllerWindow.cs
@@ -4,7 +4,7 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Utilities;
using Ryujinx.Configuration;
-using Ryujinx.HLE.FileSystem;
+using Ryujinx.Ui.Widgets;
using System;
using System.Collections.Generic;
using System.IO;
@@ -15,14 +15,14 @@ using System.Threading;
using GUI = Gtk.Builder.ObjectAttribute;
using Key = Ryujinx.Configuration.Hid.Key;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.Windows
{
public class ControllerWindow : Window
{
- private PlayerIndex _playerIndex;
- private InputConfig _inputConfig;
- private bool _isWaitingForInput;
- private VirtualFileSystem _virtualFileSystem;
+ private readonly PlayerIndex _playerIndex;
+ private readonly InputConfig _inputConfig;
+
+ private bool _isWaitingForInput;
#pragma warning disable CS0649, IDE0044
[GUI] Adjustment _controllerDeadzoneLeft;
@@ -90,17 +90,14 @@ namespace Ryujinx.Ui
[GUI] Image _controllerImage;
#pragma warning restore CS0649, IDE0044
- public ControllerWindow(PlayerIndex controllerId, VirtualFileSystem virtualFileSystem) : this(new Builder("Ryujinx.Ui.ControllerWindow.glade"), controllerId, virtualFileSystem) { }
+ public ControllerWindow(PlayerIndex controllerId) : this(new Builder("Ryujinx.Ui.Windows.ControllerWindow.glade"), controllerId) { }
- private ControllerWindow(Builder builder, PlayerIndex controllerId, VirtualFileSystem virtualFileSystem) : base(builder.GetObject("_controllerWin").Handle)
+ private ControllerWindow(Builder builder, PlayerIndex controllerId) : base(builder.GetObject("_controllerWin").Handle)
{
builder.Autoconnect(this);
- this.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
-
- _playerIndex = controllerId;
- _virtualFileSystem = virtualFileSystem;
- _inputConfig = ConfigurationState.Instance.Hid.InputConfig.Value.Find(inputConfig => inputConfig.PlayerIndex == _playerIndex);
+ _playerIndex = controllerId;
+ _inputConfig = ConfigurationState.Instance.Hid.InputConfig.Value.Find(inputConfig => inputConfig.PlayerIndex == _playerIndex);
Title = $"Ryujinx - Controller Settings - {_playerIndex}";
@@ -119,7 +116,7 @@ namespace Ryujinx.Ui
_controllerType.Active = 0; // Set initial value to first in list.
- //Bind Events
+ // Bind Events.
_lStickX.Clicked += Button_Pressed;
_lStickY.Clicked += Button_Pressed;
_lStickUp.Clicked += Button_Pressed;
@@ -153,12 +150,15 @@ namespace Ryujinx.Ui
_rSl.Clicked += Button_Pressed;
_rSr.Clicked += Button_Pressed;
- // Setup current values
+ // Setup current values.
UpdateInputDeviceList();
SetAvailableOptions();
ClearValues();
- if (_inputDevice.ActiveId != null) SetCurrentValues();
+ if (_inputDevice.ActiveId != null)
+ {
+ SetCurrentValues();
+ }
}
private void UpdateInputDeviceList()
@@ -193,7 +193,7 @@ namespace Ryujinx.Ui
{
if (_inputDevice.ActiveId != null && _inputDevice.ActiveId.StartsWith("keyboard"))
{
- this.ShowAll();
+ ShowAll();
_leftStickController.Hide();
_rightStickController.Hide();
_deadZoneLeftBox.Hide();
@@ -202,7 +202,7 @@ namespace Ryujinx.Ui
}
else if (_inputDevice.ActiveId != null && _inputDevice.ActiveId.StartsWith("controller"))
{
- this.ShowAll();
+ ShowAll();
_leftStickKeyboard.Hide();
_rightStickKeyboard.Hide();
}
@@ -249,21 +249,13 @@ namespace Ryujinx.Ui
break;
}
- switch (_controllerType.ActiveId)
+ _controllerImage.Pixbuf = _controllerType.ActiveId switch
{
- case "ProController":
- _controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.ProCon.svg", 400, 400);
- break;
- case "JoyconLeft":
- _controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyConLeft.svg", 400, 400);
- break;
- case "JoyconRight":
- _controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyConRight.svg", 400, 400);
- break;
- default:
- _controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyConPair.svg", 400, 400);
- break;
- }
+ "ProController" => new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Controller_ProCon.svg", 400, 400),
+ "JoyconLeft" => new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Controller_JoyConLeft.svg", 400, 400),
+ "JoyconRight" => new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Controller_JoyConRight.svg", 400, 400),
+ _ => new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Controller_JoyConPair.svg", 400, 400),
+ };
}
private void ClearValues()
@@ -620,8 +612,7 @@ namespace Ryujinx.Ui
if (joystickState.IsButtonDown(i))
{
Enum.TryParse($"Button{i}", out pressedButton);
-
- return true;
+ return true;
}
}
@@ -674,7 +665,9 @@ namespace Ryujinx.Ui
return path;
}
- //Events
+ //
+ // Events
+ //
private void InputDevice_Changed(object sender, EventArgs args)
{
SetAvailableOptions();
@@ -692,7 +685,7 @@ namespace Ryujinx.Ui
{
UpdateInputDeviceList();
- _refreshInputDevicesButton.SetStateFlags(0, true);
+ _refreshInputDevicesButton.SetStateFlags(StateFlags.Normal, true);
}
private void Button_Pressed(object sender, EventArgs args)
@@ -719,7 +712,7 @@ namespace Ryujinx.Ui
{
Application.Invoke(delegate
{
- button.SetStateFlags(0, true);
+ button.SetStateFlags(StateFlags.Normal, true);
});
_isWaitingForInput = false;
@@ -731,7 +724,7 @@ namespace Ryujinx.Ui
Application.Invoke(delegate
{
button.Label = pressedKey.ToString();
- button.SetStateFlags(0, true);
+ button.SetStateFlags(StateFlags.Normal, true);
});
}
else if (_inputDevice.ActiveId.StartsWith("controller"))
@@ -745,7 +738,7 @@ namespace Ryujinx.Ui
{
Application.Invoke(delegate
{
- button.SetStateFlags(0, true);
+ button.SetStateFlags(StateFlags.Normal, true);
});
_isWaitingForInput = false;
@@ -757,7 +750,7 @@ namespace Ryujinx.Ui
Application.Invoke(delegate
{
button.Label = pressedButton.ToString();
- button.SetStateFlags(0, true);
+ button.SetStateFlags(StateFlags.Normal, true);
});
}
@@ -788,7 +781,7 @@ namespace Ryujinx.Ui
private void ProfileLoad_Activated(object sender, EventArgs args)
{
- ((ToggleButton)sender).SetStateFlags(0, true);
+ ((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
if (_inputDevice.ActiveId == "disabled" || _profile.ActiveId == null) return;
@@ -940,7 +933,7 @@ namespace Ryujinx.Ui
private void ProfileAdd_Activated(object sender, EventArgs args)
{
- ((ToggleButton)sender).SetStateFlags(0, true);
+ ((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
if (_inputDevice.ActiveId == "disabled") return;
@@ -973,7 +966,7 @@ namespace Ryujinx.Ui
private void ProfileRemove_Activated(object sender, EventArgs args)
{
- ((ToggleButton) sender).SetStateFlags(0, true);
+ ((ToggleButton) sender).SetStateFlags(StateFlags.Normal, true);
if (_inputDevice.ActiveId == "disabled" || _profile.ActiveId == "default" || _profile.ActiveId == null) return;
@@ -1021,7 +1014,7 @@ namespace Ryujinx.Ui
// NOTE: Do not modify InputConfig.Value directly as other code depends on the on-change event.
ConfigurationState.Instance.Hid.InputConfig.Value = newConfig;
- MainWindow.SaveConfig();
+ ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
Dispose();
}
diff --git a/Ryujinx/Ui/ControllerWindow.glade b/Ryujinx/Ui/Windows/ControllerWindow.glade
index 2143e9de..2143e9de 100644
--- a/Ryujinx/Ui/ControllerWindow.glade
+++ b/Ryujinx/Ui/Windows/ControllerWindow.glade
diff --git a/Ryujinx/Ui/DlcWindow.cs b/Ryujinx/Ui/Windows/DlcWindow.cs
index 29e96b07..13a63088 100644
--- a/Ryujinx/Ui/DlcWindow.cs
+++ b/Ryujinx/Ui/Windows/DlcWindow.cs
@@ -1,13 +1,12 @@
using Gtk;
-using LibHac;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
using Ryujinx.Common.Configuration;
-using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem;
+using Ryujinx.Ui.Widgets;
using System;
using System.Collections.Generic;
using System.IO;
@@ -16,7 +15,7 @@ using System.Text;
using GUI = Gtk.Builder.ObjectAttribute;
using JsonHelper = Ryujinx.Common.Utilities.JsonHelper;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.Windows
{
public class DlcWindow : Window
{
@@ -31,9 +30,9 @@ namespace Ryujinx.Ui
[GUI] TreeSelection _dlcTreeSelection;
#pragma warning restore CS0649, IDE0044
- public DlcWindow(string titleId, string titleName, VirtualFileSystem virtualFileSystem) : this(new Builder("Ryujinx.Ui.DlcWindow.glade"), titleId, titleName, virtualFileSystem) { }
+ public DlcWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName) : this(new Builder("Ryujinx.Ui.Windows.DlcWindow.glade"), virtualFileSystem, titleId, titleName) { }
- private DlcWindow(Builder builder, string titleId, string titleName, VirtualFileSystem virtualFileSystem) : base(builder.GetObject("_dlcWindow").Handle)
+ private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetObject("_dlcWindow").Handle)
{
builder.Autoconnect(this);
@@ -51,10 +50,7 @@ namespace Ryujinx.Ui
_dlcContainerList = new List<DlcContainer>();
}
- _dlcTreeView.Model = new TreeStore(
- typeof(bool),
- typeof(string),
- typeof(string));
+ _dlcTreeView.Model = new TreeStore(typeof(bool), typeof(string), typeof(string));
CellRendererToggle enableToggle = new CellRendererToggle();
enableToggle.Toggled += (sender, args) =>
@@ -104,17 +100,9 @@ namespace Ryujinx.Ui
{
return new Nca(_virtualFileSystem.KeySet, ncaStorage);
}
- catch (InvalidDataException exception)
+ catch (Exception exception)
{
- Logger.Error?.Print(LogClass.Application, $"{exception.Message}. Errored File: {containerPath}");
-
- GtkDialog.CreateInfoDialog("Ryujinx - Error", "Add DLC Failed!", "The NCA header content type check has failed. This is usually because the header key is incorrect or missing.");
- }
- catch (MissingKeyException exception)
- {
- Logger.Error?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}. Errored File: {containerPath}");
-
- GtkDialog.CreateInfoDialog("Ryujinx - Error", "Add DLC Failed!", $"Your key set is missing a key with the name: {exception.Name}");
+ GtkDialog.CreateErrorDialog($"{exception.Message}. Errored File: {containerPath}");
}
return null;
diff --git a/Ryujinx/Ui/DlcWindow.glade b/Ryujinx/Ui/Windows/DlcWindow.glade
index cd0d8674..cd0d8674 100644
--- a/Ryujinx/Ui/DlcWindow.glade
+++ b/Ryujinx/Ui/Windows/DlcWindow.glade
diff --git a/Ryujinx/Ui/SettingsWindow.cs b/Ryujinx/Ui/Windows/SettingsWindow.cs
index d17bce60..a44abfcc 100644
--- a/Ryujinx/Ui/SettingsWindow.cs
+++ b/Ryujinx/Ui/Windows/SettingsWindow.cs
@@ -6,20 +6,20 @@ using Ryujinx.Configuration;
using Ryujinx.Configuration.System;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
+using Ryujinx.Ui.Helper;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
-using System.Reflection;
using System.Threading.Tasks;
using GUI = Gtk.Builder.ObjectAttribute;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.Windows
{
public class SettingsWindow : Window
{
- private readonly VirtualFileSystem _virtualFileSystem;
+ private readonly MainWindow _parent;
private readonly ListStore _gameDirsBoxStore;
private readonly ListStore _audioBackendStore;
private readonly TimeZoneContentManager _timeZoneContentManager;
@@ -86,36 +86,34 @@ namespace Ryujinx.Ui
#pragma warning restore CS0649, IDE0044
- public SettingsWindow(VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : this(new Builder("Ryujinx.Ui.SettingsWindow.glade"), virtualFileSystem, contentManager) { }
+ public SettingsWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : this(parent, new Builder("Ryujinx.Ui.Windows.SettingsWindow.glade"), virtualFileSystem, contentManager) { }
- private SettingsWindow(Builder builder, VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : base(builder.GetObject("_settingsWin").Handle)
+ private SettingsWindow(MainWindow parent, Builder builder, VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : base(builder.GetObject("_settingsWin").Handle)
{
- builder.Autoconnect(this);
-
- this.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
+ _parent = parent;
- _virtualFileSystem = virtualFileSystem;
+ builder.Autoconnect(this);
_timeZoneContentManager = new TimeZoneContentManager();
_timeZoneContentManager.InitializeInstance(virtualFileSystem, contentManager, LibHac.FsSystem.IntegrityCheckLevel.None);
_validTzRegions = new HashSet<string>(_timeZoneContentManager.LocationNameCache.Length, StringComparer.Ordinal); // Zone regions are identifiers. Must match exactly.
- //Bind Events
- _configureController1.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player1);
- _configureController2.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player2);
- _configureController3.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player3);
- _configureController4.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player4);
- _configureController5.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player5);
- _configureController6.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player6);
- _configureController7.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player7);
- _configureController8.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player8);
- _configureControllerH.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Handheld);
+ // Bind Events.
+ _configureController1.Pressed += (sender, args) => ConfigureController_Pressed(sender, PlayerIndex.Player1);
+ _configureController2.Pressed += (sender, args) => ConfigureController_Pressed(sender, PlayerIndex.Player2);
+ _configureController3.Pressed += (sender, args) => ConfigureController_Pressed(sender, PlayerIndex.Player3);
+ _configureController4.Pressed += (sender, args) => ConfigureController_Pressed(sender, PlayerIndex.Player4);
+ _configureController5.Pressed += (sender, args) => ConfigureController_Pressed(sender, PlayerIndex.Player5);
+ _configureController6.Pressed += (sender, args) => ConfigureController_Pressed(sender, PlayerIndex.Player6);
+ _configureController7.Pressed += (sender, args) => ConfigureController_Pressed(sender, PlayerIndex.Player7);
+ _configureController8.Pressed += (sender, args) => ConfigureController_Pressed(sender, PlayerIndex.Player8);
+ _configureControllerH.Pressed += (sender, args) => ConfigureController_Pressed(sender, PlayerIndex.Handheld);
_systemTimeZoneEntry.FocusOutEvent += TimeZoneEntry_FocusOut;
_resScaleCombo.Changed += (sender, args) => _resScaleText.Visible = _resScaleCombo.ActiveId == "-1";
- //Setup Currents
+ // Setup Currents.
if (ConfigurationState.Instance.Logger.EnableFileLog)
{
_fileLogToggle.Click();
@@ -419,12 +417,14 @@ namespace Ryujinx.Ui
ConfigurationState.Instance.System.AudioBackend.Value = (AudioBackend)_audioBackendStore.GetValue(activeIter, 1);
}
- MainWindow.SaveConfig();
- MainWindow.UpdateGraphicsConfig();
- MainWindow.ApplyTheme();
+ ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
+ _parent.UpdateGraphicsConfig();
+ ThemeHelper.ApplyTheme();
}
- //Events
+ //
+ // Events
+ //
private void TimeZoneEntry_FocusOut(object sender, FocusOutEventArgs e)
{
if (!_validTzRegions.Contains(_systemTimeZoneEntry.Text))
@@ -439,7 +439,7 @@ namespace Ryujinx.Ui
return ((string)compl.Model.GetValue(iter, 1)).Contains(key, StringComparison.OrdinalIgnoreCase) || // region
((string)compl.Model.GetValue(iter, 2)).StartsWith(key, StringComparison.OrdinalIgnoreCase) || // abbr
- ((string)compl.Model.GetValue(iter, 0)).Substring(3).StartsWith(key); // offset
+ ((string)compl.Model.GetValue(iter, 0))[3..].StartsWith(key); // offset
}
private void SystemTimeSpin_ValueChanged(object sender, EventArgs e)
@@ -511,7 +511,7 @@ namespace Ryujinx.Ui
_addGameDirBox.Buffer.Text = "";
- ((ToggleButton)sender).SetStateFlags(0, true);
+ ((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
}
private void RemoveDir_Pressed(object sender, EventArgs args)
@@ -523,7 +523,7 @@ namespace Ryujinx.Ui
_gameDirsBoxStore.Remove(ref treeIter);
}
- ((ToggleButton)sender).SetStateFlags(0, true);
+ ((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
}
private void CustThemeToggle_Activated(object sender, EventArgs args)
@@ -535,27 +535,25 @@ namespace Ryujinx.Ui
private void BrowseThemeDir_Pressed(object sender, EventArgs args)
{
- FileChooserDialog fileChooser = new FileChooserDialog("Choose the theme to load", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Select", ResponseType.Accept);
-
- fileChooser.Filter = new FileFilter();
- fileChooser.Filter.AddPattern("*.css");
-
- if (fileChooser.Run() == (int)ResponseType.Accept)
+ using (FileChooserDialog fileChooser = new FileChooserDialog("Choose the theme to load", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Select", ResponseType.Accept))
{
- _custThemePath.Buffer.Text = fileChooser.Filename;
- }
+ fileChooser.Filter = new FileFilter();
+ fileChooser.Filter.AddPattern("*.css");
- fileChooser.Dispose();
+ if (fileChooser.Run() == (int)ResponseType.Accept)
+ {
+ _custThemePath.Buffer.Text = fileChooser.Filename;
+ }
+ }
- _browseThemePath.SetStateFlags(0, true);
+ _browseThemePath.SetStateFlags(StateFlags.Normal, true);
}
- private void ConfigureController_Pressed(object sender, EventArgs args, PlayerIndex playerIndex)
+ private void ConfigureController_Pressed(object sender, PlayerIndex playerIndex)
{
- ((ToggleButton)sender).SetStateFlags(0, true);
+ ((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
- ControllerWindow controllerWin = new ControllerWindow(playerIndex, _virtualFileSystem);
- controllerWin.Show();
+ new ControllerWindow(playerIndex).Show();
}
private void SaveToggle_Activated(object sender, EventArgs args)
@@ -574,4 +572,4 @@ namespace Ryujinx.Ui
Dispose();
}
}
-}
+} \ No newline at end of file
diff --git a/Ryujinx/Ui/SettingsWindow.glade b/Ryujinx/Ui/Windows/SettingsWindow.glade
index 936aa520..936aa520 100644
--- a/Ryujinx/Ui/SettingsWindow.glade
+++ b/Ryujinx/Ui/Windows/SettingsWindow.glade
diff --git a/Ryujinx/Ui/TitleUpdateWindow.cs b/Ryujinx/Ui/Windows/TitleUpdateWindow.cs
index 54b5b262..647dea19 100644
--- a/Ryujinx/Ui/TitleUpdateWindow.cs
+++ b/Ryujinx/Ui/Windows/TitleUpdateWindow.cs
@@ -1,5 +1,4 @@
using Gtk;
-using LibHac;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
@@ -7,9 +6,9 @@ using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
using LibHac.Ns;
using Ryujinx.Common.Configuration;
-using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
+using Ryujinx.Ui.Widgets;
using System;
using System.Collections.Generic;
using System.IO;
@@ -19,16 +18,18 @@ using System.Text;
using GUI = Gtk.Builder.ObjectAttribute;
using JsonHelper = Ryujinx.Common.Utilities.JsonHelper;
-namespace Ryujinx.Ui
+namespace Ryujinx.Ui.Windows
{
public class TitleUpdateWindow : Window
{
+ private readonly MainWindow _parent;
private readonly VirtualFileSystem _virtualFileSystem;
private readonly string _titleId;
private readonly string _updateJsonPath;
- private TitleUpdateMetadata _titleUpdateWindowData;
- private Dictionary<RadioButton, string> _radioButtonToPathDictionary;
+ private TitleUpdateMetadata _titleUpdateWindowData;
+
+ private readonly Dictionary<RadioButton, string> _radioButtonToPathDictionary;
#pragma warning disable CS0649, IDE0044
[GUI] Label _baseTitleInfoLabel;
@@ -36,10 +37,12 @@ namespace Ryujinx.Ui
[GUI] RadioButton _noUpdateRadioButton;
#pragma warning restore CS0649, IDE0044
- public TitleUpdateWindow(string titleId, string titleName, VirtualFileSystem virtualFileSystem) : this(new Builder("Ryujinx.Ui.TitleUpdateWindow.glade"), titleId, titleName, virtualFileSystem) { }
+ public TitleUpdateWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : this(new Builder("Ryujinx.Ui.Windows.TitleUpdateWindow.glade"), parent, virtualFileSystem, titleId, titleName) { }
- private TitleUpdateWindow(Builder builder, string titleId, string titleName, VirtualFileSystem virtualFileSystem) : base(builder.GetObject("_titleUpdateWindow").Handle)
+ private TitleUpdateWindow(Builder builder, MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetObject("_titleUpdateWindow").Handle)
{
+ _parent = parent;
+
builder.Autoconnect(this);
_titleId = titleId;
@@ -61,20 +64,26 @@ namespace Ryujinx.Ui
}
_baseTitleInfoLabel.Text = $"Updates Available for {titleName} [{titleId.ToUpper()}]";
- _noUpdateRadioButton.Active = true;
-
+
foreach (string path in _titleUpdateWindowData.Paths)
{
- AddUpdate(path, false);
+ AddUpdate(path);
}
- foreach ((RadioButton update, var _) in _radioButtonToPathDictionary.Where(keyValuePair => keyValuePair.Value == _titleUpdateWindowData.Selected))
+ if (_titleUpdateWindowData.Selected == "")
+ {
+ _noUpdateRadioButton.Active = true;
+ }
+ else
{
- update.Active = true;
+ foreach ((RadioButton update, var _) in _radioButtonToPathDictionary.Where(keyValuePair => keyValuePair.Value == _titleUpdateWindowData.Selected))
+ {
+ update.Active = true;
+ }
}
}
- private void AddUpdate(string path, bool showErrorDialog = true)
+ private void AddUpdate(string path)
{
if (File.Exists(path))
{
@@ -107,23 +116,9 @@ namespace Ryujinx.Ui
GtkDialog.CreateErrorDialog("The specified file does not contain an update for the selected title!");
}
}
- catch (InvalidDataException exception)
- {
- Logger.Error?.Print(LogClass.Application, $"{exception.Message}. Errored File: {path}");
-
- if (showErrorDialog)
- {
- GtkDialog.CreateInfoDialog("Ryujinx - Error", "Add Update Failed!", "The NCA header content type check has failed. This is usually because the header key is incorrect or missing.");
- }
- }
- catch (MissingKeyException exception)
+ catch (Exception exception)
{
- Logger.Error?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}. Errored File: {path}");
-
- if (showErrorDialog)
- {
- GtkDialog.CreateInfoDialog("Ryujinx - Error", "Add Update Failed!", $"Your key set is missing a key with the name: {exception.Name}");
- }
+ GtkDialog.CreateErrorDialog($"{exception.Message}. Errored File: {path}");
}
}
}
@@ -144,23 +139,21 @@ namespace Ryujinx.Ui
private void AddButton_Clicked(object sender, EventArgs args)
{
- FileChooserDialog fileChooser = new FileChooserDialog("Select update files", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Add", ResponseType.Accept)
+ using (FileChooserDialog fileChooser = new FileChooserDialog("Select update files", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Add", ResponseType.Accept))
{
- SelectMultiple = true,
- Filter = new FileFilter()
- };
- fileChooser.SetPosition(WindowPosition.Center);
- fileChooser.Filter.AddPattern("*.nsp");
+ fileChooser.SelectMultiple = true;
+ fileChooser.SetPosition(WindowPosition.Center);
+ fileChooser.Filter = new FileFilter();
+ fileChooser.Filter.AddPattern("*.nsp");
- if (fileChooser.Run() == (int)ResponseType.Accept)
- {
- foreach (string path in fileChooser.Filenames)
+ if (fileChooser.Run() == (int)ResponseType.Accept)
{
- AddUpdate(path);
+ foreach (string path in fileChooser.Filenames)
+ {
+ AddUpdate(path);
+ }
}
}
-
- fileChooser.Dispose();
}
private void RemoveButton_Clicked(object sender, EventArgs args)
@@ -196,7 +189,8 @@ namespace Ryujinx.Ui
dlcJsonStream.Write(Encoding.UTF8.GetBytes(JsonHelper.Serialize(_titleUpdateWindowData, true)));
}
- MainWindow.UpdateGameTable();
+ _parent.UpdateGameTable();
+
Dispose();
}
diff --git a/Ryujinx/Ui/TitleUpdateWindow.glade b/Ryujinx/Ui/Windows/TitleUpdateWindow.glade
index de557471..de557471 100644
--- a/Ryujinx/Ui/TitleUpdateWindow.glade
+++ b/Ryujinx/Ui/Windows/TitleUpdateWindow.glade