[Ryujinx] Address dotnet-format issues (#5395)
* dotnet format style --severity info Some changes were manually reverted. * dotnet format analyzers --serverity info Some changes have been minimally adapted. * Restore a few unused methods and variables * Address dotnet format CA1816 warnings * Address or silence dotnet format CA2208 warnings * Address or silence dotnet format CA1806 and a few CA1854 warnings * Address dotnet format CA1822 warnings * Make dotnet format succeed in style mode * Address dotnet format CA2208 warnings properly * Address most dotnet format whitespace warnings * Apply dotnet format whitespace formatting A few of them have been manually reverted and the corresponding warning was silenced * Format if-blocks correctly * Another rebase, another dotnet format run * Run dotnet format whitespace after rebase * Run dotnet format after rebase and remove unused usings - analyzers - style - whitespace * Add comments to disabled warnings * Simplify properties and array initialization, Use const when possible, Remove trailing commas * Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas" This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e. * dotnet format whitespace after rebase * First dotnet format pass * Fix build issues * Apply suggestions from code review Co-authored-by: Ac_K <Acoustik666@gmail.com> * Second dotnet format pass * Update src/Ryujinx/Modules/Updater/Updater.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Add trailing commas and improve formatting * Fix formatting and naming issues * Rename nvStutterWorkaround to nvidiaStutterWorkaround * Use using declarations and extend resource lifetimes * Fix GTK issues * Add formatting for generated files * Add trailing commas --------- Co-authored-by: Ac_K <Acoustik666@gmail.com>
This commit is contained in:
parent
02b5c7ea89
commit
0684b00b3c
39 changed files with 1891 additions and 1830 deletions
|
@ -25,7 +25,7 @@ namespace Ryujinx.Input.GTK3
|
||||||
|
|
||||||
private readonly GTK3KeyboardDriver _driver;
|
private readonly GTK3KeyboardDriver _driver;
|
||||||
private StandardKeyboardInputConfig _configuration;
|
private StandardKeyboardInputConfig _configuration;
|
||||||
private List<ButtonMappingEntry> _buttonsUserMapping;
|
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
|
||||||
|
|
||||||
public GTK3Keyboard(GTK3KeyboardDriver driver, string id, string name)
|
public GTK3Keyboard(GTK3KeyboardDriver driver, string id, string name)
|
||||||
{
|
{
|
||||||
|
@ -48,6 +48,7 @@ namespace Ryujinx.Input.GTK3
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
// No operations
|
// No operations
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyboardStateSnapshot GetKeyboardStateSnapshot()
|
public KeyboardStateSnapshot GetKeyboardStateSnapshot()
|
||||||
|
@ -87,7 +88,7 @@ namespace Ryujinx.Input.GTK3
|
||||||
stickX -= 1;
|
stickX -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenTK.Mathematics.Vector2 stick = new OpenTK.Mathematics.Vector2(stickX, stickY);
|
OpenTK.Mathematics.Vector2 stick = new(stickX, stickY);
|
||||||
|
|
||||||
stick.NormalizeFast();
|
stick.NormalizeFast();
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace Ryujinx.Input.GTK3
|
||||||
public class GTK3KeyboardDriver : IGamepadDriver
|
public class GTK3KeyboardDriver : IGamepadDriver
|
||||||
{
|
{
|
||||||
private readonly Widget _widget;
|
private readonly Widget _widget;
|
||||||
private HashSet<GtkKey> _pressedKeys;
|
private readonly HashSet<GtkKey> _pressedKeys;
|
||||||
|
|
||||||
public GTK3KeyboardDriver(Widget widget)
|
public GTK3KeyboardDriver(Widget widget)
|
||||||
{
|
{
|
||||||
|
@ -28,13 +28,13 @@ namespace Ryujinx.Input.GTK3
|
||||||
|
|
||||||
public event Action<string> OnGamepadConnected
|
public event Action<string> OnGamepadConnected
|
||||||
{
|
{
|
||||||
add { }
|
add { }
|
||||||
remove { }
|
remove { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public event Action<string> OnGamepadDisconnected
|
public event Action<string> OnGamepadDisconnected
|
||||||
{
|
{
|
||||||
add { }
|
add { }
|
||||||
remove { }
|
remove { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ namespace Ryujinx.Input.GTK3
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,7 @@ namespace Ryujinx.Input.GTK3
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
_driver = null;
|
_driver = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,16 +14,16 @@ namespace Ryujinx.Input.GTK3
|
||||||
public bool[] PressedButtons { get; }
|
public bool[] PressedButtons { get; }
|
||||||
|
|
||||||
public Vector2 CurrentPosition { get; private set; }
|
public Vector2 CurrentPosition { get; private set; }
|
||||||
public Vector2 Scroll{ get; private set; }
|
public Vector2 Scroll { get; private set; }
|
||||||
|
|
||||||
public GTK3MouseDriver(Widget parent)
|
public GTK3MouseDriver(Widget parent)
|
||||||
{
|
{
|
||||||
_widget = parent;
|
_widget = parent;
|
||||||
|
|
||||||
_widget.MotionNotifyEvent += Parent_MotionNotifyEvent;
|
_widget.MotionNotifyEvent += Parent_MotionNotifyEvent;
|
||||||
_widget.ButtonPressEvent += Parent_ButtonPressEvent;
|
_widget.ButtonPressEvent += Parent_ButtonPressEvent;
|
||||||
_widget.ButtonReleaseEvent += Parent_ButtonReleaseEvent;
|
_widget.ButtonReleaseEvent += Parent_ButtonReleaseEvent;
|
||||||
_widget.ScrollEvent += Parent_ScrollEvent;
|
_widget.ScrollEvent += Parent_ScrollEvent;
|
||||||
|
|
||||||
PressedButtons = new bool[(int)MouseButton.Count];
|
PressedButtons = new bool[(int)MouseButton.Count];
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ namespace Ryujinx.Input.GTK3
|
||||||
|
|
||||||
public bool IsButtonPressed(MouseButton button)
|
public bool IsButtonPressed(MouseButton button)
|
||||||
{
|
{
|
||||||
return PressedButtons[(int) button];
|
return PressedButtons[(int)button];
|
||||||
}
|
}
|
||||||
|
|
||||||
public Size GetClientSize()
|
public Size GetClientSize()
|
||||||
|
@ -70,17 +70,17 @@ namespace Ryujinx.Input.GTK3
|
||||||
|
|
||||||
public event Action<string> OnGamepadConnected
|
public event Action<string> OnGamepadConnected
|
||||||
{
|
{
|
||||||
add { }
|
add { }
|
||||||
remove { }
|
remove { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public event Action<string> OnGamepadDisconnected
|
public event Action<string> OnGamepadDisconnected
|
||||||
{
|
{
|
||||||
add { }
|
add { }
|
||||||
remove { }
|
remove { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlySpan<string> GamepadsIds => new[] {"0"};
|
public ReadOnlySpan<string> GamepadsIds => new[] { "0" };
|
||||||
|
|
||||||
public IGamepad GetGamepad(string id)
|
public IGamepad GetGamepad(string id)
|
||||||
{
|
{
|
||||||
|
@ -94,6 +94,8 @@ namespace Ryujinx.Input.GTK3
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
|
||||||
_isDisposed = true;
|
_isDisposed = true;
|
||||||
|
|
||||||
_widget.MotionNotifyEvent -= Parent_MotionNotifyEvent;
|
_widget.MotionNotifyEvent -= Parent_MotionNotifyEvent;
|
||||||
|
|
|
@ -12,17 +12,17 @@ namespace Ryujinx.Modules
|
||||||
{
|
{
|
||||||
public class UpdateDialog : Gtk.Window
|
public class UpdateDialog : Gtk.Window
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649, IDE0044
|
#pragma warning disable CS0649, IDE0044 // Field is never assigned to, Add readonly modifier
|
||||||
[Builder.Object] public Label MainText;
|
[Builder.Object] public Label MainText;
|
||||||
[Builder.Object] public Label SecondaryText;
|
[Builder.Object] public Label SecondaryText;
|
||||||
[Builder.Object] public LevelBar ProgressBar;
|
[Builder.Object] public LevelBar ProgressBar;
|
||||||
[Builder.Object] public Button YesButton;
|
[Builder.Object] public Button YesButton;
|
||||||
[Builder.Object] public Button NoButton;
|
[Builder.Object] public Button NoButton;
|
||||||
#pragma warning restore CS0649, IDE0044
|
#pragma warning restore CS0649, IDE0044
|
||||||
|
|
||||||
private readonly MainWindow _mainWindow;
|
private readonly MainWindow _mainWindow;
|
||||||
private readonly string _buildUrl;
|
private readonly string _buildUrl;
|
||||||
private bool _restartQuery;
|
private bool _restartQuery;
|
||||||
|
|
||||||
public UpdateDialog(MainWindow mainWindow, Version newVersion, string buildUrl) : this(new Builder("Ryujinx.Modules.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) { }
|
||||||
|
|
||||||
|
@ -31,16 +31,16 @@ namespace Ryujinx.Modules
|
||||||
builder.Autoconnect(this);
|
builder.Autoconnect(this);
|
||||||
|
|
||||||
_mainWindow = mainWindow;
|
_mainWindow = mainWindow;
|
||||||
_buildUrl = buildUrl;
|
_buildUrl = buildUrl;
|
||||||
|
|
||||||
Icon = new Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
Icon = new Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
||||||
MainText.Text = "Do you want to update Ryujinx to the latest version?";
|
MainText.Text = "Do you want to update Ryujinx to the latest version?";
|
||||||
SecondaryText.Text = $"{Program.Version} -> {newVersion}";
|
SecondaryText.Text = $"{Program.Version} -> {newVersion}";
|
||||||
|
|
||||||
ProgressBar.Hide();
|
ProgressBar.Hide();
|
||||||
|
|
||||||
YesButton.Clicked += YesButton_Clicked;
|
YesButton.Clicked += YesButton_Clicked;
|
||||||
NoButton.Clicked += NoButton_Clicked;
|
NoButton.Clicked += NoButton_Clicked;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void YesButton_Clicked(object sender, EventArgs args)
|
private void YesButton_Clicked(object sender, EventArgs args)
|
||||||
|
@ -52,7 +52,7 @@ namespace Ryujinx.Modules
|
||||||
ProcessStartInfo processStart = new(ryuName)
|
ProcessStartInfo processStart = new(ryuName)
|
||||||
{
|
{
|
||||||
UseShellExecute = true,
|
UseShellExecute = true,
|
||||||
WorkingDirectory = ReleaseInformation.GetBaseApplicationDirectory()
|
WorkingDirectory = ReleaseInformation.GetBaseApplicationDirectory(),
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (string argument in CommandLineState.Arguments)
|
foreach (string argument in CommandLineState.Arguments)
|
||||||
|
@ -74,7 +74,7 @@ namespace Ryujinx.Modules
|
||||||
ProgressBar.Show();
|
ProgressBar.Show();
|
||||||
|
|
||||||
SecondaryText.Text = "";
|
SecondaryText.Text = "";
|
||||||
_restartQuery = true;
|
_restartQuery = true;
|
||||||
|
|
||||||
Updater.UpdateRyujinx(this, _buildUrl);
|
Updater.UpdateRyujinx(this, _buildUrl);
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ namespace Ryujinx.Modules
|
||||||
Updater.Running = false;
|
Updater.Running = false;
|
||||||
_mainWindow.Window.Functions = WMFunction.All;
|
_mainWindow.Window.Functions = WMFunction.All;
|
||||||
|
|
||||||
_mainWindow.ExitMenuItem.Sensitive = true;
|
_mainWindow.ExitMenuItem.Sensitive = true;
|
||||||
_mainWindow.UpdateMenuItem.Sensitive = true;
|
_mainWindow.UpdateMenuItem.Sensitive = true;
|
||||||
|
|
||||||
Dispose();
|
Dispose();
|
||||||
|
|
|
@ -24,28 +24,28 @@ namespace Ryujinx.Modules
|
||||||
{
|
{
|
||||||
public static class Updater
|
public static class Updater
|
||||||
{
|
{
|
||||||
private const string GitHubApiURL = "https://api.github.com";
|
private const string GitHubApiUrl = "https://api.github.com";
|
||||||
private const int ConnectionCount = 4;
|
private const int ConnectionCount = 4;
|
||||||
|
|
||||||
internal static bool Running;
|
internal static bool Running;
|
||||||
|
|
||||||
private static readonly string HomeDir = AppDomain.CurrentDomain.BaseDirectory;
|
private static readonly string _homeDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||||
private static readonly string UpdateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update");
|
private static readonly string _updateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update");
|
||||||
private static readonly string UpdatePublishDir = Path.Combine(UpdateDir, "publish");
|
private static readonly string _updatePublishDir = Path.Combine(_updateDir, "publish");
|
||||||
|
|
||||||
private static string _buildVer;
|
private static string _buildVer;
|
||||||
private static string _platformExt;
|
private static string _platformExt;
|
||||||
private static string _buildUrl;
|
private static string _buildUrl;
|
||||||
private static long _buildSize;
|
private static long _buildSize;
|
||||||
|
|
||||||
private static readonly GithubReleasesJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly GithubReleasesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
// On Windows, GtkSharp.Dependencies adds these extra dirs that must be cleaned during updates.
|
// On Windows, GtkSharp.Dependencies adds these extra dirs that must be cleaned during updates.
|
||||||
private static readonly string[] WindowsDependencyDirs = new string[] { "bin", "etc", "lib", "share" };
|
private static readonly string[] _windowsDependencyDirs = { "bin", "etc", "lib", "share" };
|
||||||
|
|
||||||
private static HttpClient ConstructHttpClient()
|
private static HttpClient ConstructHttpClient()
|
||||||
{
|
{
|
||||||
HttpClient result = new HttpClient();
|
HttpClient result = new();
|
||||||
|
|
||||||
// Required by GitHub to interact with APIs.
|
// Required by GitHub to interact with APIs.
|
||||||
result.DefaultRequestHeaders.Add("User-Agent", "Ryujinx-Updater/1.0.0");
|
result.DefaultRequestHeaders.Add("User-Agent", "Ryujinx-Updater/1.0.0");
|
||||||
|
@ -55,7 +55,10 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
|
public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
|
||||||
{
|
{
|
||||||
if (Running) return;
|
if (Running)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Running = true;
|
Running = true;
|
||||||
mainWindow.UpdateMenuItem.Sensitive = false;
|
mainWindow.UpdateMenuItem.Sensitive = false;
|
||||||
|
@ -65,17 +68,17 @@ namespace Ryujinx.Modules
|
||||||
// Detect current platform
|
// Detect current platform
|
||||||
if (OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
_platformExt = "osx_x64.zip";
|
_platformExt = "osx_x64.zip";
|
||||||
artifactIndex = 1;
|
artifactIndex = 1;
|
||||||
}
|
}
|
||||||
else if (OperatingSystem.IsWindows())
|
else if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
_platformExt = "win_x64.zip";
|
_platformExt = "win_x64.zip";
|
||||||
artifactIndex = 2;
|
artifactIndex = 2;
|
||||||
}
|
}
|
||||||
else if (OperatingSystem.IsLinux())
|
else if (OperatingSystem.IsLinux())
|
||||||
{
|
{
|
||||||
_platformExt = "linux_x64.tar.gz";
|
_platformExt = "linux_x64.tar.gz";
|
||||||
artifactIndex = 0;
|
artifactIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,11 +108,11 @@ namespace Ryujinx.Modules
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using HttpClient jsonClient = ConstructHttpClient();
|
using HttpClient jsonClient = ConstructHttpClient();
|
||||||
string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest";
|
string buildInfoUrl = $"{GitHubApiUrl}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest";
|
||||||
|
|
||||||
// Fetch latest build information
|
// Fetch latest build information
|
||||||
string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL);
|
string fetchedJson = await jsonClient.GetStringAsync(buildInfoUrl);
|
||||||
var fetched = JsonHelper.Deserialize(fetchedJson, SerializerContext.GithubReleasesJsonResponse);
|
var fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse);
|
||||||
_buildVer = fetched.Name;
|
_buildVer = fetched.Name;
|
||||||
|
|
||||||
foreach (var asset in fetched.Assets)
|
foreach (var asset in fetched.Assets)
|
||||||
|
@ -176,45 +179,43 @@ namespace Ryujinx.Modules
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch build size information to learn chunk sizes.
|
// Fetch build size information to learn chunk sizes.
|
||||||
using (HttpClient buildSizeClient = ConstructHttpClient())
|
using HttpClient buildSizeClient = ConstructHttpClient();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
buildSizeClient.DefaultRequestHeaders.Add("Range", "bytes=0-0");
|
||||||
{
|
|
||||||
buildSizeClient.DefaultRequestHeaders.Add("Range", "bytes=0-0");
|
|
||||||
|
|
||||||
HttpResponseMessage message = await buildSizeClient.GetAsync(new Uri(_buildUrl), HttpCompletionOption.ResponseHeadersRead);
|
HttpResponseMessage message = await buildSizeClient.GetAsync(new Uri(_buildUrl), HttpCompletionOption.ResponseHeadersRead);
|
||||||
|
|
||||||
_buildSize = message.Content.Headers.ContentRange.Length.Value;
|
_buildSize = message.Content.Headers.ContentRange.Length.Value;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, ex.Message);
|
Logger.Warning?.Print(LogClass.Application, ex.Message);
|
||||||
Logger.Warning?.Print(LogClass.Application, "Couldn't determine build size for update, using single-threaded updater");
|
Logger.Warning?.Print(LogClass.Application, "Couldn't determine build size for update, using single-threaded updater");
|
||||||
|
|
||||||
_buildSize = -1;
|
_buildSize = -1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show a message asking the user if they want to update
|
// Show a message asking the user if they want to update
|
||||||
UpdateDialog updateDialog = new UpdateDialog(mainWindow, newVersion, _buildUrl);
|
UpdateDialog updateDialog = new(mainWindow, newVersion, _buildUrl);
|
||||||
updateDialog.Show();
|
updateDialog.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdateRyujinx(UpdateDialog updateDialog, string downloadUrl)
|
public static void UpdateRyujinx(UpdateDialog updateDialog, string downloadUrl)
|
||||||
{
|
{
|
||||||
// Empty update dir, although it shouldn't ever have anything inside it
|
// Empty update dir, although it shouldn't ever have anything inside it
|
||||||
if (Directory.Exists(UpdateDir))
|
if (Directory.Exists(_updateDir))
|
||||||
{
|
{
|
||||||
Directory.Delete(UpdateDir, true);
|
Directory.Delete(_updateDir, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(UpdateDir);
|
Directory.CreateDirectory(_updateDir);
|
||||||
|
|
||||||
string updateFile = Path.Combine(UpdateDir, "update.bin");
|
string updateFile = Path.Combine(_updateDir, "update.bin");
|
||||||
|
|
||||||
// Download the update .zip
|
// Download the update .zip
|
||||||
updateDialog.MainText.Text = "Downloading Update...";
|
updateDialog.MainText.Text = "Downloading Update...";
|
||||||
updateDialog.ProgressBar.Value = 0;
|
updateDialog.ProgressBar.Value = 0;
|
||||||
updateDialog.ProgressBar.MaxValue = 100;
|
updateDialog.ProgressBar.MaxValue = 100;
|
||||||
|
|
||||||
if (_buildSize >= 0)
|
if (_buildSize >= 0)
|
||||||
|
@ -237,8 +238,8 @@ namespace Ryujinx.Modules
|
||||||
int totalProgressPercentage = 0;
|
int totalProgressPercentage = 0;
|
||||||
int[] progressPercentage = new int[ConnectionCount];
|
int[] progressPercentage = new int[ConnectionCount];
|
||||||
|
|
||||||
List<byte[]> list = new List<byte[]>(ConnectionCount);
|
List<byte[]> list = new(ConnectionCount);
|
||||||
List<WebClient> webClients = new List<WebClient>(ConnectionCount);
|
List<WebClient> webClients = new(ConnectionCount);
|
||||||
|
|
||||||
for (int i = 0; i < ConnectionCount; i++)
|
for (int i = 0; i < ConnectionCount; i++)
|
||||||
{
|
{
|
||||||
|
@ -249,7 +250,7 @@ namespace Ryujinx.Modules
|
||||||
{
|
{
|
||||||
#pragma warning disable SYSLIB0014
|
#pragma warning disable SYSLIB0014
|
||||||
// TODO: WebClient is obsolete and need to be replaced with a more complex logic using HttpClient.
|
// TODO: WebClient is obsolete and need to be replaced with a more complex logic using HttpClient.
|
||||||
using WebClient client = new WebClient();
|
using WebClient client = new();
|
||||||
#pragma warning restore SYSLIB0014
|
#pragma warning restore SYSLIB0014
|
||||||
webClients.Add(client);
|
webClients.Add(client);
|
||||||
|
|
||||||
|
@ -337,35 +338,32 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
private static void DoUpdateWithSingleThreadWorker(UpdateDialog updateDialog, string downloadUrl, string updateFile)
|
private static void DoUpdateWithSingleThreadWorker(UpdateDialog updateDialog, string downloadUrl, string updateFile)
|
||||||
{
|
{
|
||||||
using HttpClient client = new HttpClient();
|
using HttpClient client = new();
|
||||||
// We do not want to timeout while downloading
|
// We do not want to timeout while downloading
|
||||||
client.Timeout = TimeSpan.FromDays(1);
|
client.Timeout = TimeSpan.FromDays(1);
|
||||||
|
|
||||||
using (HttpResponseMessage response = client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead).Result)
|
using HttpResponseMessage response = client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead).Result;
|
||||||
using (Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result)
|
using Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result;
|
||||||
|
using Stream updateFileStream = File.Open(updateFile, FileMode.Create);
|
||||||
|
|
||||||
|
long totalBytes = response.Content.Headers.ContentLength.Value;
|
||||||
|
long byteWritten = 0;
|
||||||
|
|
||||||
|
byte[] buffer = new byte[32 * 1024];
|
||||||
|
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
using (Stream updateFileStream = File.Open(updateFile, FileMode.Create))
|
int readSize = remoteFileStream.Read(buffer);
|
||||||
|
|
||||||
|
if (readSize == 0)
|
||||||
{
|
{
|
||||||
long totalBytes = response.Content.Headers.ContentLength.Value;
|
break;
|
||||||
long byteWritten = 0;
|
|
||||||
|
|
||||||
byte[] buffer = new byte[32 * 1024];
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
int readSize = remoteFileStream.Read(buffer);
|
|
||||||
|
|
||||||
if (readSize == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
byteWritten += readSize;
|
|
||||||
|
|
||||||
updateDialog.ProgressBar.Value = ((double)byteWritten / totalBytes) * 100;
|
|
||||||
updateFileStream.Write(buffer, 0, readSize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byteWritten += readSize;
|
||||||
|
|
||||||
|
updateDialog.ProgressBar.Value = ((double)byteWritten / totalBytes) * 100;
|
||||||
|
updateFileStream.Write(buffer, 0, readSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallUpdate(updateDialog, updateFile);
|
InstallUpdate(updateDialog, updateFile);
|
||||||
|
@ -373,9 +371,9 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
private static void DoUpdateWithSingleThread(UpdateDialog updateDialog, string downloadUrl, string updateFile)
|
private static void DoUpdateWithSingleThread(UpdateDialog updateDialog, string downloadUrl, string updateFile)
|
||||||
{
|
{
|
||||||
Thread worker = new Thread(() => DoUpdateWithSingleThreadWorker(updateDialog, downloadUrl, updateFile))
|
Thread worker = new(() => DoUpdateWithSingleThreadWorker(updateDialog, downloadUrl, updateFile))
|
||||||
{
|
{
|
||||||
Name = "Updater.SingleThreadWorker"
|
Name = "Updater.SingleThreadWorker",
|
||||||
};
|
};
|
||||||
worker.Start();
|
worker.Start();
|
||||||
}
|
}
|
||||||
|
@ -383,14 +381,14 @@ namespace Ryujinx.Modules
|
||||||
private static async void InstallUpdate(UpdateDialog updateDialog, string updateFile)
|
private static async void InstallUpdate(UpdateDialog updateDialog, string updateFile)
|
||||||
{
|
{
|
||||||
// Extract Update
|
// Extract Update
|
||||||
updateDialog.MainText.Text = "Extracting Update...";
|
updateDialog.MainText.Text = "Extracting Update...";
|
||||||
updateDialog.ProgressBar.Value = 0;
|
updateDialog.ProgressBar.Value = 0;
|
||||||
|
|
||||||
if (OperatingSystem.IsLinux())
|
if (OperatingSystem.IsLinux())
|
||||||
{
|
{
|
||||||
using Stream inStream = File.OpenRead(updateFile);
|
using Stream inStream = File.OpenRead(updateFile);
|
||||||
using Stream gzipStream = new GZipInputStream(inStream);
|
using Stream gzipStream = new GZipInputStream(inStream);
|
||||||
using TarInputStream tarStream = new TarInputStream(gzipStream, Encoding.ASCII);
|
using TarInputStream tarStream = new(gzipStream, Encoding.ASCII);
|
||||||
updateDialog.ProgressBar.MaxValue = inStream.Length;
|
updateDialog.ProgressBar.MaxValue = inStream.Length;
|
||||||
|
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
|
@ -401,16 +399,17 @@ namespace Ryujinx.Modules
|
||||||
{
|
{
|
||||||
while ((tarEntry = tarStream.GetNextEntry()) != null)
|
while ((tarEntry = tarStream.GetNextEntry()) != null)
|
||||||
{
|
{
|
||||||
if (tarEntry.IsDirectory) continue;
|
if (tarEntry.IsDirectory)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
string outPath = Path.Combine(UpdateDir, tarEntry.Name);
|
string outPath = Path.Combine(_updateDir, tarEntry.Name);
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
||||||
|
|
||||||
using (FileStream outStream = File.OpenWrite(outPath))
|
using FileStream outStream = File.OpenWrite(outPath);
|
||||||
{
|
tarStream.CopyEntryContents(outStream);
|
||||||
tarStream.CopyEntryContents(outStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
File.SetUnixFileMode(outPath, (UnixFileMode)tarEntry.TarHeader.Mode);
|
File.SetUnixFileMode(outPath, (UnixFileMode)tarEntry.TarHeader.Mode);
|
||||||
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc));
|
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc));
|
||||||
|
@ -429,25 +428,26 @@ namespace Ryujinx.Modules
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using Stream inStream = File.OpenRead(updateFile);
|
using Stream inStream = File.OpenRead(updateFile);
|
||||||
using ZipFile zipFile = new ZipFile(inStream);
|
using ZipFile zipFile = new(inStream);
|
||||||
updateDialog.ProgressBar.MaxValue = zipFile.Count;
|
updateDialog.ProgressBar.MaxValue = zipFile.Count;
|
||||||
|
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
{
|
{
|
||||||
foreach (ZipEntry zipEntry in zipFile)
|
foreach (ZipEntry zipEntry in zipFile)
|
||||||
{
|
{
|
||||||
if (zipEntry.IsDirectory) continue;
|
if (zipEntry.IsDirectory)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
string outPath = Path.Combine(UpdateDir, zipEntry.Name);
|
string outPath = Path.Combine(_updateDir, zipEntry.Name);
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
||||||
|
|
||||||
using (Stream zipStream = zipFile.GetInputStream(zipEntry))
|
using Stream zipStream = zipFile.GetInputStream(zipEntry);
|
||||||
using (FileStream outStream = File.OpenWrite(outPath))
|
using FileStream outStream = File.OpenWrite(outPath);
|
||||||
{
|
zipStream.CopyTo(outStream);
|
||||||
zipStream.CopyTo(outStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(zipEntry.DateTime, DateTimeKind.Utc));
|
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(zipEntry.DateTime, DateTimeKind.Utc));
|
||||||
|
|
||||||
|
@ -464,8 +464,8 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
List<string> allFiles = EnumerateFilesToDelete().ToList();
|
List<string> allFiles = EnumerateFilesToDelete().ToList();
|
||||||
|
|
||||||
updateDialog.MainText.Text = "Renaming Old Files...";
|
updateDialog.MainText.Text = "Renaming Old Files...";
|
||||||
updateDialog.ProgressBar.Value = 0;
|
updateDialog.ProgressBar.Value = 0;
|
||||||
updateDialog.ProgressBar.MaxValue = allFiles.Count;
|
updateDialog.ProgressBar.MaxValue = allFiles.Count;
|
||||||
|
|
||||||
// Replace old files
|
// Replace old files
|
||||||
|
@ -490,19 +490,19 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
Application.Invoke(delegate
|
Application.Invoke(delegate
|
||||||
{
|
{
|
||||||
updateDialog.MainText.Text = "Adding New Files...";
|
updateDialog.MainText.Text = "Adding New Files...";
|
||||||
updateDialog.ProgressBar.Value = 0;
|
updateDialog.ProgressBar.Value = 0;
|
||||||
updateDialog.ProgressBar.MaxValue = Directory.GetFiles(UpdatePublishDir, "*", SearchOption.AllDirectories).Length;
|
updateDialog.ProgressBar.MaxValue = Directory.GetFiles(_updatePublishDir, "*", SearchOption.AllDirectories).Length;
|
||||||
});
|
});
|
||||||
|
|
||||||
MoveAllFilesOver(UpdatePublishDir, HomeDir, updateDialog);
|
MoveAllFilesOver(_updatePublishDir, _homeDir, updateDialog);
|
||||||
});
|
});
|
||||||
|
|
||||||
Directory.Delete(UpdateDir, true);
|
Directory.Delete(_updateDir, true);
|
||||||
|
|
||||||
updateDialog.MainText.Text = "Update Complete!";
|
updateDialog.MainText.Text = "Update Complete!";
|
||||||
updateDialog.SecondaryText.Text = "Do you want to restart Ryujinx now?";
|
updateDialog.SecondaryText.Text = "Do you want to restart Ryujinx now?";
|
||||||
updateDialog.Modal = true;
|
updateDialog.Modal = true;
|
||||||
|
|
||||||
updateDialog.ProgressBar.Hide();
|
updateDialog.ProgressBar.Hide();
|
||||||
updateDialog.YesButton.Show();
|
updateDialog.YesButton.Show();
|
||||||
|
@ -563,15 +563,15 @@ namespace Ryujinx.Modules
|
||||||
// NOTE: This method should always reflect the latest build layout.
|
// NOTE: This method should always reflect the latest build layout.
|
||||||
private static IEnumerable<string> EnumerateFilesToDelete()
|
private static IEnumerable<string> EnumerateFilesToDelete()
|
||||||
{
|
{
|
||||||
var files = Directory.EnumerateFiles(HomeDir); // All files directly in base dir.
|
var files = Directory.EnumerateFiles(_homeDir); // All files directly in base dir.
|
||||||
|
|
||||||
// Determine and exclude user files only when the updater is running, not when cleaning old files
|
// Determine and exclude user files only when the updater is running, not when cleaning old files
|
||||||
if (Running)
|
if (Running)
|
||||||
{
|
{
|
||||||
// Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list.
|
// Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list.
|
||||||
var oldFiles = Directory.EnumerateFiles(HomeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
var oldFiles = Directory.EnumerateFiles(_homeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
||||||
var newFiles = Directory.EnumerateFiles(UpdatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
var newFiles = Directory.EnumerateFiles(_updatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
||||||
var userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(HomeDir, filename));
|
var userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(_homeDir, filename));
|
||||||
|
|
||||||
// Remove user files from the paths in files.
|
// Remove user files from the paths in files.
|
||||||
files = files.Except(userFiles);
|
files = files.Except(userFiles);
|
||||||
|
@ -579,9 +579,9 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
foreach (string dir in WindowsDependencyDirs)
|
foreach (string dir in _windowsDependencyDirs)
|
||||||
{
|
{
|
||||||
string dirPath = Path.Combine(HomeDir, dir);
|
string dirPath = Path.Combine(_homeDir, dir);
|
||||||
if (Directory.Exists(dirPath))
|
if (Directory.Exists(dirPath))
|
||||||
{
|
{
|
||||||
files = files.Concat(Directory.EnumerateFiles(dirPath, "*", SearchOption.AllDirectories));
|
files = files.Concat(Directory.EnumerateFiles(dirPath, "*", SearchOption.AllDirectories));
|
||||||
|
|
|
@ -43,10 +43,7 @@ namespace Ryujinx
|
||||||
[LibraryImport("libc", SetLastError = true)]
|
[LibraryImport("libc", SetLastError = true)]
|
||||||
private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite);
|
private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite);
|
||||||
|
|
||||||
[LibraryImport("libc")]
|
private const uint MbIconWarning = 0x30;
|
||||||
private static partial IntPtr getenv([MarshalAs(UnmanagedType.LPStr)] string name);
|
|
||||||
|
|
||||||
private const uint MB_ICONWARNING = 0x30;
|
|
||||||
|
|
||||||
static Program()
|
static Program()
|
||||||
{
|
{
|
||||||
|
@ -78,16 +75,16 @@ namespace Ryujinx
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
||||||
{
|
{
|
||||||
MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING);
|
MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MbIconWarning);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
CommandLineState.ParseArguments(args);
|
CommandLineState.ParseArguments(args);
|
||||||
|
|
||||||
// Hook unhandled exception and process exit events.
|
// Hook unhandled exception and process exit events.
|
||||||
GLib.ExceptionManager.UnhandledException += (GLib.UnhandledExceptionArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
|
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.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
|
||||||
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit();
|
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit();
|
||||||
|
|
||||||
// Make process DPI aware for proper window sizing on high-res screens.
|
// Make process DPI aware for proper window sizing on high-res screens.
|
||||||
ForceDpiAware.Windows();
|
ForceDpiAware.Windows();
|
||||||
|
@ -102,7 +99,11 @@ namespace Ryujinx
|
||||||
// This ends up causing race condition and abort of XCB when a context is created by SPB (even if SPB do call XInitThreads).
|
// This ends up causing race condition and abort of XCB when a context is created by SPB (even if SPB do call XInitThreads).
|
||||||
if (OperatingSystem.IsLinux())
|
if (OperatingSystem.IsLinux())
|
||||||
{
|
{
|
||||||
XInitThreads();
|
if (XInitThreads() == 0)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Failed to initialize multi-threading support.");
|
||||||
|
}
|
||||||
|
|
||||||
Environment.SetEnvironmentVariable("GDK_BACKEND", "x11");
|
Environment.SetEnvironmentVariable("GDK_BACKEND", "x11");
|
||||||
setenv("GDK_BACKEND", "x11", 1);
|
setenv("GDK_BACKEND", "x11", 1);
|
||||||
}
|
}
|
||||||
|
@ -121,7 +122,7 @@ namespace Ryujinx
|
||||||
resourcesDataDir = baseDirectory;
|
resourcesDataDir = baseDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetEnvironmentVariableNoCaching(string key, string value)
|
static void SetEnvironmentVariableNoCaching(string key, string value)
|
||||||
{
|
{
|
||||||
int res = setenv(key, value, 1);
|
int res = setenv(key, value, 1);
|
||||||
Debug.Assert(res != -1);
|
Debug.Assert(res != -1);
|
||||||
|
@ -163,11 +164,11 @@ namespace Ryujinx
|
||||||
// Sets ImageSharp Jpeg Encoder Quality.
|
// Sets ImageSharp Jpeg Encoder Quality.
|
||||||
SixLabors.ImageSharp.Configuration.Default.ImageFormatsManager.SetEncoder(JpegFormat.Instance, new JpegEncoder()
|
SixLabors.ImageSharp.Configuration.Default.ImageFormatsManager.SetEncoder(JpegFormat.Instance, new JpegEncoder()
|
||||||
{
|
{
|
||||||
Quality = 100
|
Quality = 100,
|
||||||
});
|
});
|
||||||
|
|
||||||
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json");
|
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
|
||||||
ConfigurationPath = File.Exists(localConfigurationPath)
|
ConfigurationPath = File.Exists(localConfigurationPath)
|
||||||
|
@ -232,7 +233,7 @@ namespace Ryujinx
|
||||||
"never" => HideCursorMode.Never,
|
"never" => HideCursorMode.Never,
|
||||||
"onidle" => HideCursorMode.OnIdle,
|
"onidle" => HideCursorMode.OnIdle,
|
||||||
"always" => HideCursorMode.Always,
|
"always" => HideCursorMode.Always,
|
||||||
_ => ConfigurationState.Instance.HideCursor.Value
|
_ => ConfigurationState.Instance.HideCursor.Value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +262,7 @@ namespace Ryujinx
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show the main window UI.
|
// Show the main window UI.
|
||||||
MainWindow mainWindow = new MainWindow();
|
MainWindow mainWindow = new();
|
||||||
mainWindow.Show();
|
mainWindow.Show();
|
||||||
|
|
||||||
if (OperatingSystem.IsLinux())
|
if (OperatingSystem.IsLinux())
|
||||||
|
@ -278,7 +279,7 @@ namespace Ryujinx
|
||||||
{
|
{
|
||||||
{ 0, "Yes, until the next restart" },
|
{ 0, "Yes, until the next restart" },
|
||||||
{ 1, "Yes, permanently" },
|
{ 1, "Yes, permanently" },
|
||||||
{ 2, "No" }
|
{ 2, "No" },
|
||||||
};
|
};
|
||||||
|
|
||||||
ResponseType response = GtkDialog.CreateCustomDialog(
|
ResponseType response = GtkDialog.CreateCustomDialog(
|
||||||
|
@ -347,7 +348,7 @@ namespace Ryujinx
|
||||||
var buttonTexts = new Dictionary<int, string>()
|
var buttonTexts = new Dictionary<int, string>()
|
||||||
{
|
{
|
||||||
{ 0, "Yes (Vulkan)" },
|
{ 0, "Yes (Vulkan)" },
|
||||||
{ 1, "No (OpenGL)" }
|
{ 1, "No (OpenGL)" },
|
||||||
};
|
};
|
||||||
|
|
||||||
ResponseType response = GtkDialog.CreateCustomDialog(
|
ResponseType response = GtkDialog.CreateCustomDialog(
|
||||||
|
|
|
@ -11,15 +11,15 @@ namespace Ryujinx.Ui.Applet
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class GtkDynamicTextInputHandler : IDynamicTextInputHandler
|
internal class GtkDynamicTextInputHandler : IDynamicTextInputHandler
|
||||||
{
|
{
|
||||||
private readonly Window _parent;
|
private readonly Window _parent;
|
||||||
private readonly OffscreenWindow _inputToTextWindow = new OffscreenWindow();
|
private readonly OffscreenWindow _inputToTextWindow = new();
|
||||||
private readonly RawInputToTextEntry _inputToTextEntry = new RawInputToTextEntry();
|
private readonly RawInputToTextEntry _inputToTextEntry = new();
|
||||||
|
|
||||||
private bool _canProcessInput;
|
private bool _canProcessInput;
|
||||||
|
|
||||||
public event DynamicTextChangedHandler TextChangedEvent;
|
public event DynamicTextChangedHandler TextChangedEvent;
|
||||||
public event KeyPressedHandler KeyPressedEvent;
|
public event KeyPressedHandler KeyPressedEvent;
|
||||||
public event KeyReleasedHandler KeyReleasedEvent;
|
public event KeyReleasedHandler KeyReleasedEvent;
|
||||||
|
|
||||||
public bool TextProcessingEnabled
|
public bool TextProcessingEnabled
|
||||||
{
|
{
|
||||||
|
@ -37,7 +37,7 @@ namespace Ryujinx.Ui.Applet
|
||||||
public GtkDynamicTextInputHandler(Window parent)
|
public GtkDynamicTextInputHandler(Window parent)
|
||||||
{
|
{
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
_parent.KeyPressEvent += HandleKeyPressEvent;
|
_parent.KeyPressEvent += HandleKeyPressEvent;
|
||||||
_parent.KeyReleaseEvent += HandleKeyReleaseEvent;
|
_parent.KeyReleaseEvent += HandleKeyReleaseEvent;
|
||||||
|
|
||||||
_inputToTextWindow.Add(_inputToTextEntry);
|
_inputToTextWindow.Add(_inputToTextEntry);
|
||||||
|
@ -101,7 +101,7 @@ namespace Ryujinx.Ui.Applet
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_parent.KeyPressEvent -= HandleKeyPressEvent;
|
_parent.KeyPressEvent -= HandleKeyPressEvent;
|
||||||
_parent.KeyReleaseEvent -= HandleKeyReleaseEvent;
|
_parent.KeyReleaseEvent -= HandleKeyReleaseEvent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ using Ryujinx.HLE.Ui;
|
||||||
using Ryujinx.Ui.Widgets;
|
using Ryujinx.Ui.Widgets;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Action = System.Action;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Applet
|
namespace Ryujinx.Ui.Applet
|
||||||
{
|
{
|
||||||
|
@ -37,7 +36,7 @@ namespace Ryujinx.Ui.Applet
|
||||||
|
|
||||||
public bool DisplayMessageDialog(string title, string message)
|
public bool DisplayMessageDialog(string title, string message)
|
||||||
{
|
{
|
||||||
ManualResetEvent dialogCloseEvent = new ManualResetEvent(false);
|
ManualResetEvent dialogCloseEvent = new(false);
|
||||||
|
|
||||||
bool okPressed = false;
|
bool okPressed = false;
|
||||||
|
|
||||||
|
@ -49,9 +48,9 @@ namespace Ryujinx.Ui.Applet
|
||||||
{
|
{
|
||||||
msgDialog = new MessageDialog(_parent, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null)
|
msgDialog = new MessageDialog(_parent, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null)
|
||||||
{
|
{
|
||||||
Title = title,
|
Title = title,
|
||||||
Text = message,
|
Text = message,
|
||||||
UseMarkup = true
|
UseMarkup = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
msgDialog.SetDefaultSize(400, 0);
|
msgDialog.SetDefaultSize(400, 0);
|
||||||
|
@ -84,10 +83,10 @@ namespace Ryujinx.Ui.Applet
|
||||||
|
|
||||||
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
|
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
|
||||||
{
|
{
|
||||||
ManualResetEvent dialogCloseEvent = new ManualResetEvent(false);
|
ManualResetEvent dialogCloseEvent = new(false);
|
||||||
|
|
||||||
bool okPressed = false;
|
bool okPressed = false;
|
||||||
bool error = false;
|
bool error = false;
|
||||||
string inputText = args.InitialText ?? "";
|
string inputText = args.InitialText ?? "";
|
||||||
|
|
||||||
Application.Invoke(delegate
|
Application.Invoke(delegate
|
||||||
|
@ -96,14 +95,14 @@ namespace Ryujinx.Ui.Applet
|
||||||
{
|
{
|
||||||
var swkbdDialog = new SwkbdAppletDialog(_parent)
|
var swkbdDialog = new SwkbdAppletDialog(_parent)
|
||||||
{
|
{
|
||||||
Title = "Software Keyboard",
|
Title = "Software Keyboard",
|
||||||
Text = args.HeaderText,
|
Text = args.HeaderText,
|
||||||
SecondaryText = args.SubtitleText
|
SecondaryText = args.SubtitleText,
|
||||||
};
|
};
|
||||||
|
|
||||||
swkbdDialog.InputEntry.Text = inputText;
|
swkbdDialog.InputEntry.Text = inputText;
|
||||||
swkbdDialog.InputEntry.PlaceholderText = args.GuideText;
|
swkbdDialog.InputEntry.PlaceholderText = args.GuideText;
|
||||||
swkbdDialog.OkButton.Label = args.SubmitText;
|
swkbdDialog.OkButton.Label = args.SubmitText;
|
||||||
|
|
||||||
swkbdDialog.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax);
|
swkbdDialog.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax);
|
||||||
swkbdDialog.SetInputValidation(args.KeyboardMode);
|
swkbdDialog.SetInputValidation(args.KeyboardMode);
|
||||||
|
@ -143,7 +142,7 @@ namespace Ryujinx.Ui.Applet
|
||||||
|
|
||||||
public bool DisplayErrorAppletDialog(string title, string message, string[] buttons)
|
public bool DisplayErrorAppletDialog(string title, string message, string[] buttons)
|
||||||
{
|
{
|
||||||
ManualResetEvent dialogCloseEvent = new ManualResetEvent(false);
|
ManualResetEvent dialogCloseEvent = new(false);
|
||||||
|
|
||||||
bool showDetails = false;
|
bool showDetails = false;
|
||||||
|
|
||||||
|
@ -151,12 +150,12 @@ namespace Ryujinx.Ui.Applet
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ErrorAppletDialog msgDialog = new ErrorAppletDialog(_parent, DialogFlags.DestroyWithParent, MessageType.Error, buttons)
|
ErrorAppletDialog msgDialog = new(_parent, DialogFlags.DestroyWithParent, MessageType.Error, buttons)
|
||||||
{
|
{
|
||||||
Title = title,
|
Title = title,
|
||||||
Text = message,
|
Text = message,
|
||||||
UseMarkup = true,
|
UseMarkup = true,
|
||||||
WindowPosition = WindowPosition.CenterAlways
|
WindowPosition = WindowPosition.CenterAlways,
|
||||||
};
|
};
|
||||||
|
|
||||||
msgDialog.SetDefaultSize(400, 0);
|
msgDialog.SetDefaultSize(400, 0);
|
||||||
|
@ -193,19 +192,6 @@ namespace Ryujinx.Ui.Applet
|
||||||
return showDetails;
|
return showDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SynchronousGtkInvoke(Action action)
|
|
||||||
{
|
|
||||||
var waitHandle = new ManualResetEventSlim();
|
|
||||||
|
|
||||||
Application.Invoke(delegate
|
|
||||||
{
|
|
||||||
action();
|
|
||||||
waitHandle.Set();
|
|
||||||
});
|
|
||||||
|
|
||||||
waitHandle.Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDynamicTextInputHandler CreateDynamicTextInputHandler()
|
public IDynamicTextInputHandler CreateDynamicTextInputHandler()
|
||||||
{
|
{
|
||||||
return new GtkDynamicTextInputHandler(_parent);
|
return new GtkDynamicTextInputHandler(_parent);
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace Ryujinx.Ui.Applet
|
||||||
{
|
{
|
||||||
internal class GtkHostUiTheme : IHostUiTheme
|
internal class GtkHostUiTheme : IHostUiTheme
|
||||||
{
|
{
|
||||||
private const int RenderSurfaceWidth = 32;
|
private const int RenderSurfaceWidth = 32;
|
||||||
private const int RenderSurfaceHeight = 32;
|
private const int RenderSurfaceHeight = 32;
|
||||||
|
|
||||||
public string FontFamily { get; private set; }
|
public string FontFamily { get; private set; }
|
||||||
|
@ -19,7 +19,7 @@ namespace Ryujinx.Ui.Applet
|
||||||
|
|
||||||
public GtkHostUiTheme(Window parent)
|
public GtkHostUiTheme(Window parent)
|
||||||
{
|
{
|
||||||
Entry entry = new Entry();
|
Entry entry = new();
|
||||||
entry.SetStateFlags(StateFlags.Selected, true);
|
entry.SetStateFlags(StateFlags.Selected, true);
|
||||||
|
|
||||||
// Get the font and some colors directly from GTK.
|
// Get the font and some colors directly from GTK.
|
||||||
|
@ -30,10 +30,10 @@ namespace Ryujinx.Ui.Applet
|
||||||
var defaultForegroundColor = entry.StyleContext.GetColor(StateFlags.Normal);
|
var defaultForegroundColor = entry.StyleContext.GetColor(StateFlags.Normal);
|
||||||
var selectedForegroundColor = entry.StyleContext.GetColor(StateFlags.Selected);
|
var selectedForegroundColor = entry.StyleContext.GetColor(StateFlags.Selected);
|
||||||
|
|
||||||
DefaultForegroundColor = new ThemeColor((float) defaultForegroundColor.Alpha, (float) defaultForegroundColor.Red, (float) defaultForegroundColor.Green, (float) defaultForegroundColor.Blue);
|
DefaultForegroundColor = new ThemeColor((float)defaultForegroundColor.Alpha, (float)defaultForegroundColor.Red, (float)defaultForegroundColor.Green, (float)defaultForegroundColor.Blue);
|
||||||
SelectionForegroundColor = new ThemeColor((float)selectedForegroundColor.Alpha, (float)selectedForegroundColor.Red, (float)selectedForegroundColor.Green, (float)selectedForegroundColor.Blue);
|
SelectionForegroundColor = new ThemeColor((float)selectedForegroundColor.Alpha, (float)selectedForegroundColor.Red, (float)selectedForegroundColor.Green, (float)selectedForegroundColor.Blue);
|
||||||
|
|
||||||
ListBoxRow row = new ListBoxRow();
|
ListBoxRow row = new();
|
||||||
row.SetStateFlags(StateFlags.Selected, true);
|
row.SetStateFlags(StateFlags.Selected, true);
|
||||||
|
|
||||||
// Request the main thread to render some UI elements to an image to get an approximation for the color.
|
// Request the main thread to render some UI elements to an image to get an approximation for the color.
|
||||||
|
@ -67,7 +67,7 @@ namespace Ryujinx.Ui.Applet
|
||||||
SelectionBackgroundColor = DefaultBorderColor;
|
SelectionBackgroundColor = DefaultBorderColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ThemeColor ToThemeColor(byte[] data)
|
private static ThemeColor ToThemeColor(byte[] data)
|
||||||
{
|
{
|
||||||
Debug.Assert(data.Length == 4 * RenderSurfaceWidth * RenderSurfaceHeight);
|
Debug.Assert(data.Length == 4 * RenderSurfaceWidth * RenderSurfaceHeight);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,9 @@ namespace Ryujinx.Ui.Applet
|
||||||
{
|
{
|
||||||
private int _inputMin;
|
private int _inputMin;
|
||||||
private int _inputMax;
|
private int _inputMax;
|
||||||
|
#pragma warning disable IDE0052 // Remove unread private member
|
||||||
private KeyboardMode _mode;
|
private KeyboardMode _mode;
|
||||||
|
#pragma warning restore IDE0052
|
||||||
|
|
||||||
private string _validationInfoText = "";
|
private string _validationInfoText = "";
|
||||||
|
|
||||||
|
@ -18,8 +20,8 @@ namespace Ryujinx.Ui.Applet
|
||||||
|
|
||||||
private readonly Label _validationInfo;
|
private readonly Label _validationInfo;
|
||||||
|
|
||||||
public Entry InputEntry { get; }
|
public Entry InputEntry { get; }
|
||||||
public Button OkButton { get; }
|
public Button OkButton { get; }
|
||||||
public Button CancelButton { get; }
|
public Button CancelButton { get; }
|
||||||
|
|
||||||
public SwkbdAppletDialog(Window parent) : base(parent, DialogFlags.Modal | DialogFlags.DestroyWithParent, MessageType.Question, ButtonsType.None, null)
|
public SwkbdAppletDialog(Window parent) : base(parent, DialogFlags.Modal | DialogFlags.DestroyWithParent, MessageType.Question, ButtonsType.None, null)
|
||||||
|
@ -28,22 +30,22 @@ namespace Ryujinx.Ui.Applet
|
||||||
|
|
||||||
_validationInfo = new Label()
|
_validationInfo = new Label()
|
||||||
{
|
{
|
||||||
Visible = false
|
Visible = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
InputEntry = new Entry()
|
InputEntry = new Entry()
|
||||||
{
|
{
|
||||||
Visible = true
|
Visible = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
InputEntry.Activated += OnInputActivated;
|
InputEntry.Activated += OnInputActivated;
|
||||||
InputEntry.Changed += OnInputChanged;
|
InputEntry.Changed += OnInputChanged;
|
||||||
|
|
||||||
OkButton = (Button)AddButton("OK", ResponseType.Ok);
|
OkButton = (Button)AddButton("OK", ResponseType.Ok);
|
||||||
CancelButton = (Button)AddButton("Cancel", ResponseType.Cancel);
|
CancelButton = (Button)AddButton("Cancel", ResponseType.Cancel);
|
||||||
|
|
||||||
((Box)MessageArea).PackEnd(_validationInfo, true, true, 0);
|
((Box)MessageArea).PackEnd(_validationInfo, true, true, 0);
|
||||||
((Box)MessageArea).PackEnd(InputEntry, true, true, 4);
|
((Box)MessageArea).PackEnd(InputEntry, true, true, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyValidationInfo()
|
private void ApplyValidationInfo()
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Ryujinx.Ui.Helper
|
||||||
{
|
{
|
||||||
private const string LibObjCImport = "/usr/lib/libobjc.A.dylib";
|
private const string LibObjCImport = "/usr/lib/libobjc.A.dylib";
|
||||||
|
|
||||||
private struct Selector
|
private readonly struct Selector
|
||||||
{
|
{
|
||||||
public readonly IntPtr NativePtr;
|
public readonly IntPtr NativePtr;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ namespace Ryujinx.Ui.Helper
|
||||||
NativePtr = sel_registerName(data);
|
NativePtr = sel_registerName(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static implicit operator Selector(string value) => new Selector(value);
|
public static implicit operator Selector(string value) => new(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe IntPtr GetClass(string value)
|
private static unsafe IntPtr GetClass(string value)
|
||||||
|
@ -45,27 +45,27 @@ namespace Ryujinx.Ui.Helper
|
||||||
return objc_getClass(data);
|
return objc_getClass(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct NSPoint
|
private struct NsPoint
|
||||||
{
|
{
|
||||||
public double X;
|
public double X;
|
||||||
public double Y;
|
public double Y;
|
||||||
|
|
||||||
public NSPoint(double x, double y)
|
public NsPoint(double x, double y)
|
||||||
{
|
{
|
||||||
X = x;
|
X = x;
|
||||||
Y = y;
|
Y = y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct NSRect
|
private struct NsRect
|
||||||
{
|
{
|
||||||
public NSPoint Pos;
|
public NsPoint Pos;
|
||||||
public NSPoint Size;
|
public NsPoint Size;
|
||||||
|
|
||||||
public NSRect(double x, double y, double width, double height)
|
public NsRect(double x, double y, double width, double height)
|
||||||
{
|
{
|
||||||
Pos = new NSPoint(x, y);
|
Pos = new NsPoint(x, y);
|
||||||
Size = new NSPoint(width, height);
|
Size = new NsPoint(width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ namespace Ryujinx.Ui.Helper
|
||||||
// Create a child NSView to render into.
|
// Create a child NSView to render into.
|
||||||
IntPtr nsViewClass = GetClass("NSView");
|
IntPtr nsViewClass = GetClass("NSView");
|
||||||
IntPtr child = IntPtr_objc_msgSend(nsViewClass, "alloc");
|
IntPtr child = IntPtr_objc_msgSend(nsViewClass, "alloc");
|
||||||
objc_msgSend(child, "init", new NSRect());
|
objc_msgSend(child, "init", new NsRect());
|
||||||
|
|
||||||
// Add it as a child.
|
// Add it as a child.
|
||||||
objc_msgSend(nsView, "addSubview:", child);
|
objc_msgSend(nsView, "addSubview:", child);
|
||||||
|
@ -92,11 +92,12 @@ namespace Ryujinx.Ui.Helper
|
||||||
objc_msgSend(metalLayer, "setContentsScale:", (double)display.GetMonitorAtWindow(window).ScaleFactor);
|
objc_msgSend(metalLayer, "setContentsScale:", (double)display.GetMonitorAtWindow(window).ScaleFactor);
|
||||||
|
|
||||||
// Set the frame position/location.
|
// Set the frame position/location.
|
||||||
updateBounds = (Window window) => {
|
updateBounds = (Window window) =>
|
||||||
|
{
|
||||||
window.GetPosition(out int x, out int y);
|
window.GetPosition(out int x, out int y);
|
||||||
int width = window.Width;
|
int width = window.Width;
|
||||||
int height = window.Height;
|
int height = window.Height;
|
||||||
objc_msgSend(child, "setFrame:", new NSRect(x, y, width, height));
|
objc_msgSend(child, "setFrame:", new NsRect(x, y, width, height));
|
||||||
};
|
};
|
||||||
|
|
||||||
updateBounds(window);
|
updateBounds(window);
|
||||||
|
@ -120,7 +121,7 @@ namespace Ryujinx.Ui.Helper
|
||||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value);
|
private static partial void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value);
|
||||||
|
|
||||||
[LibraryImport(LibObjCImport)]
|
[LibraryImport(LibObjCImport)]
|
||||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, NSRect point);
|
private static partial void objc_msgSend(IntPtr receiver, Selector selector, NsRect point);
|
||||||
|
|
||||||
[LibraryImport(LibObjCImport)]
|
[LibraryImport(LibObjCImport)]
|
||||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, double value);
|
private static partial void objc_msgSend(IntPtr receiver, Selector selector, double value);
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Ryujinx.Ui.Helper
|
||||||
|
|
||||||
if (File.Exists(ConfigurationState.Instance.Ui.CustomThemePath) && (Path.GetExtension(ConfigurationState.Instance.Ui.CustomThemePath) == ".css"))
|
if (File.Exists(ConfigurationState.Instance.Ui.CustomThemePath) && (Path.GetExtension(ConfigurationState.Instance.Ui.CustomThemePath) == ".css"))
|
||||||
{
|
{
|
||||||
CssProvider cssProvider = new CssProvider();
|
CssProvider cssProvider = new();
|
||||||
|
|
||||||
cssProvider.LoadFromPath(ConfigurationState.Instance.Ui.CustomThemePath);
|
cssProvider.LoadFromPath(ConfigurationState.Instance.Ui.CustomThemePath);
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ namespace Ryujinx.Ui.Helper
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, $"The \"custom_theme_path\" section in \"Config.json\" contains an invalid path: \"{ConfigurationState.Instance.Ui.CustomThemePath}\".");
|
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.CustomThemePath.Value = "";
|
||||||
ConfigurationState.Instance.Ui.EnableCustomTheme.Value = false;
|
ConfigurationState.Instance.Ui.EnableCustomTheme.Value = false;
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,6 @@ using Ryujinx.Common.SystemInterop;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.GAL.Multithreading;
|
using Ryujinx.Graphics.GAL.Multithreading;
|
||||||
using Ryujinx.Graphics.OpenGL;
|
|
||||||
using Ryujinx.Graphics.Vulkan;
|
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS;
|
using Ryujinx.HLE.HOS;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
|
@ -51,9 +49,9 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
public class MainWindow : Window
|
public class MainWindow : Window
|
||||||
{
|
{
|
||||||
private readonly VirtualFileSystem _virtualFileSystem;
|
private readonly VirtualFileSystem _virtualFileSystem;
|
||||||
private readonly ContentManager _contentManager;
|
private readonly ContentManager _contentManager;
|
||||||
private readonly AccountManager _accountManager;
|
private readonly AccountManager _accountManager;
|
||||||
private readonly LibHacHorizonManager _libHacHorizonManager;
|
private readonly LibHacHorizonManager _libHacHorizonManager;
|
||||||
|
|
||||||
private UserChannelPersistence _userChannelPersistence;
|
private UserChannelPersistence _userChannelPersistence;
|
||||||
|
@ -63,9 +61,9 @@ namespace Ryujinx.Ui
|
||||||
private WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
|
private WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
|
||||||
|
|
||||||
private readonly ApplicationLibrary _applicationLibrary;
|
private readonly ApplicationLibrary _applicationLibrary;
|
||||||
private readonly GtkHostUiHandler _uiHandler;
|
private readonly GtkHostUiHandler _uiHandler;
|
||||||
private readonly AutoResetEvent _deviceExitStatus;
|
private readonly AutoResetEvent _deviceExitStatus;
|
||||||
private readonly ListStore _tableStore;
|
private readonly ListStore _tableStore;
|
||||||
|
|
||||||
private bool _updatingGameTable;
|
private bool _updatingGameTable;
|
||||||
private bool _gameLoaded;
|
private bool _gameLoaded;
|
||||||
|
@ -74,76 +72,76 @@ namespace Ryujinx.Ui
|
||||||
private string _currentEmulatedGamePath = null;
|
private string _currentEmulatedGamePath = null;
|
||||||
|
|
||||||
private string _lastScannedAmiiboId = "";
|
private string _lastScannedAmiiboId = "";
|
||||||
private bool _lastScannedAmiiboShowAll = false;
|
private bool _lastScannedAmiiboShowAll = false;
|
||||||
|
|
||||||
public RendererWidgetBase RendererWidget;
|
public RendererWidgetBase RendererWidget;
|
||||||
public InputManager InputManager;
|
public InputManager InputManager;
|
||||||
|
|
||||||
public bool IsFocused;
|
public bool IsFocused;
|
||||||
|
|
||||||
#pragma warning disable CS0169, CS0649, IDE0044
|
#pragma warning disable CS0169, CS0649, IDE0044, IDE0051 // Field is never assigned to, Add readonly modifier, Remove unused private member
|
||||||
|
|
||||||
[GUI] public MenuItem ExitMenuItem;
|
[GUI] public MenuItem ExitMenuItem;
|
||||||
[GUI] public MenuItem UpdateMenuItem;
|
[GUI] public MenuItem UpdateMenuItem;
|
||||||
[GUI] MenuBar _menuBar;
|
[GUI] MenuBar _menuBar;
|
||||||
[GUI] Box _footerBox;
|
[GUI] Box _footerBox;
|
||||||
[GUI] Box _statusBar;
|
[GUI] Box _statusBar;
|
||||||
[GUI] MenuItem _optionMenu;
|
[GUI] MenuItem _optionMenu;
|
||||||
[GUI] MenuItem _manageUserProfiles;
|
[GUI] MenuItem _manageUserProfiles;
|
||||||
[GUI] MenuItem _fileMenu;
|
[GUI] MenuItem _fileMenu;
|
||||||
[GUI] MenuItem _loadApplicationFile;
|
[GUI] MenuItem _loadApplicationFile;
|
||||||
[GUI] MenuItem _loadApplicationFolder;
|
[GUI] MenuItem _loadApplicationFolder;
|
||||||
[GUI] MenuItem _appletMenu;
|
[GUI] MenuItem _appletMenu;
|
||||||
[GUI] MenuItem _actionMenu;
|
[GUI] MenuItem _actionMenu;
|
||||||
[GUI] MenuItem _pauseEmulation;
|
[GUI] MenuItem _pauseEmulation;
|
||||||
[GUI] MenuItem _resumeEmulation;
|
[GUI] MenuItem _resumeEmulation;
|
||||||
[GUI] MenuItem _stopEmulation;
|
[GUI] MenuItem _stopEmulation;
|
||||||
[GUI] MenuItem _simulateWakeUpMessage;
|
[GUI] MenuItem _simulateWakeUpMessage;
|
||||||
[GUI] MenuItem _scanAmiibo;
|
[GUI] MenuItem _scanAmiibo;
|
||||||
[GUI] MenuItem _takeScreenshot;
|
[GUI] MenuItem _takeScreenshot;
|
||||||
[GUI] MenuItem _hideUi;
|
[GUI] MenuItem _hideUi;
|
||||||
[GUI] MenuItem _fullScreen;
|
[GUI] MenuItem _fullScreen;
|
||||||
[GUI] CheckMenuItem _startFullScreen;
|
[GUI] CheckMenuItem _startFullScreen;
|
||||||
[GUI] CheckMenuItem _showConsole;
|
[GUI] CheckMenuItem _showConsole;
|
||||||
[GUI] CheckMenuItem _favToggle;
|
[GUI] CheckMenuItem _favToggle;
|
||||||
[GUI] MenuItem _firmwareInstallDirectory;
|
[GUI] MenuItem _firmwareInstallDirectory;
|
||||||
[GUI] MenuItem _firmwareInstallFile;
|
[GUI] MenuItem _firmwareInstallFile;
|
||||||
[GUI] MenuItem _fileTypesSubMenu;
|
[GUI] MenuItem _fileTypesSubMenu;
|
||||||
[GUI] Label _fifoStatus;
|
[GUI] Label _fifoStatus;
|
||||||
[GUI] CheckMenuItem _iconToggle;
|
[GUI] CheckMenuItem _iconToggle;
|
||||||
[GUI] CheckMenuItem _developerToggle;
|
[GUI] CheckMenuItem _developerToggle;
|
||||||
[GUI] CheckMenuItem _appToggle;
|
[GUI] CheckMenuItem _appToggle;
|
||||||
[GUI] CheckMenuItem _timePlayedToggle;
|
[GUI] CheckMenuItem _timePlayedToggle;
|
||||||
[GUI] CheckMenuItem _versionToggle;
|
[GUI] CheckMenuItem _versionToggle;
|
||||||
[GUI] CheckMenuItem _lastPlayedToggle;
|
[GUI] CheckMenuItem _lastPlayedToggle;
|
||||||
[GUI] CheckMenuItem _fileExtToggle;
|
[GUI] CheckMenuItem _fileExtToggle;
|
||||||
[GUI] CheckMenuItem _pathToggle;
|
[GUI] CheckMenuItem _pathToggle;
|
||||||
[GUI] CheckMenuItem _fileSizeToggle;
|
[GUI] CheckMenuItem _fileSizeToggle;
|
||||||
[GUI] CheckMenuItem _nspShown;
|
[GUI] CheckMenuItem _nspShown;
|
||||||
[GUI] CheckMenuItem _pfs0Shown;
|
[GUI] CheckMenuItem _pfs0Shown;
|
||||||
[GUI] CheckMenuItem _xciShown;
|
[GUI] CheckMenuItem _xciShown;
|
||||||
[GUI] CheckMenuItem _ncaShown;
|
[GUI] CheckMenuItem _ncaShown;
|
||||||
[GUI] CheckMenuItem _nroShown;
|
[GUI] CheckMenuItem _nroShown;
|
||||||
[GUI] CheckMenuItem _nsoShown;
|
[GUI] CheckMenuItem _nsoShown;
|
||||||
[GUI] Label _gpuBackend;
|
[GUI] Label _gpuBackend;
|
||||||
[GUI] Label _dockedMode;
|
[GUI] Label _dockedMode;
|
||||||
[GUI] Label _aspectRatio;
|
[GUI] Label _aspectRatio;
|
||||||
[GUI] Label _gameStatus;
|
[GUI] Label _gameStatus;
|
||||||
[GUI] TreeView _gameTable;
|
[GUI] TreeView _gameTable;
|
||||||
[GUI] TreeSelection _gameTableSelection;
|
[GUI] TreeSelection _gameTableSelection;
|
||||||
[GUI] ScrolledWindow _gameTableWindow;
|
[GUI] ScrolledWindow _gameTableWindow;
|
||||||
[GUI] Label _gpuName;
|
[GUI] Label _gpuName;
|
||||||
[GUI] Label _progressLabel;
|
[GUI] Label _progressLabel;
|
||||||
[GUI] Label _firmwareVersionLabel;
|
[GUI] Label _firmwareVersionLabel;
|
||||||
[GUI] Gtk.ProgressBar _progressBar;
|
[GUI] Gtk.ProgressBar _progressBar;
|
||||||
[GUI] Box _viewBox;
|
[GUI] Box _viewBox;
|
||||||
[GUI] Label _vSyncStatus;
|
[GUI] Label _vSyncStatus;
|
||||||
[GUI] Label _volumeStatus;
|
[GUI] Label _volumeStatus;
|
||||||
[GUI] Box _listStatusBox;
|
[GUI] Box _listStatusBox;
|
||||||
[GUI] Label _loadingStatusLabel;
|
[GUI] Label _loadingStatusLabel;
|
||||||
[GUI] Gtk.ProgressBar _loadingStatusBar;
|
[GUI] Gtk.ProgressBar _loadingStatusBar;
|
||||||
|
|
||||||
#pragma warning restore CS0649, IDE0044, CS0169
|
#pragma warning restore CS0649, IDE0044, CS0169, IDE0051
|
||||||
|
|
||||||
public MainWindow() : this(new Builder("Ryujinx.Ui.MainWindow.glade")) { }
|
public MainWindow() : this(new Builder("Ryujinx.Ui.MainWindow.glade")) { }
|
||||||
|
|
||||||
|
@ -156,14 +154,14 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
SetWindowSizePosition();
|
SetWindowSizePosition();
|
||||||
|
|
||||||
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
||||||
Title = $"Ryujinx {Program.Version}";
|
Title = $"Ryujinx {Program.Version}";
|
||||||
|
|
||||||
// Hide emulation context status bar.
|
// Hide emulation context status bar.
|
||||||
_statusBar.Hide();
|
_statusBar.Hide();
|
||||||
|
|
||||||
// Instantiate HLE objects.
|
// Instantiate HLE objects.
|
||||||
_virtualFileSystem = VirtualFileSystem.CreateInstance();
|
_virtualFileSystem = VirtualFileSystem.CreateInstance();
|
||||||
_libHacHorizonManager = new LibHacHorizonManager();
|
_libHacHorizonManager = new LibHacHorizonManager();
|
||||||
|
|
||||||
_libHacHorizonManager.InitializeFsServer(_virtualFileSystem);
|
_libHacHorizonManager.InitializeFsServer(_virtualFileSystem);
|
||||||
|
@ -178,36 +176,36 @@ namespace Ryujinx.Ui
|
||||||
// Consider removing this at some point in the future when we don't need to worry about old saves.
|
// Consider removing this at some point in the future when we don't need to worry about old saves.
|
||||||
VirtualFileSystem.FixExtraData(_libHacHorizonManager.RyujinxClient);
|
VirtualFileSystem.FixExtraData(_libHacHorizonManager.RyujinxClient);
|
||||||
|
|
||||||
_contentManager = new ContentManager(_virtualFileSystem);
|
_contentManager = new ContentManager(_virtualFileSystem);
|
||||||
_accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient, CommandLineState.Profile);
|
_accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient, CommandLineState.Profile);
|
||||||
_userChannelPersistence = new UserChannelPersistence();
|
_userChannelPersistence = new UserChannelPersistence();
|
||||||
|
|
||||||
// Instantiate GUI objects.
|
// Instantiate GUI objects.
|
||||||
_applicationLibrary = new ApplicationLibrary(_virtualFileSystem);
|
_applicationLibrary = new ApplicationLibrary(_virtualFileSystem);
|
||||||
_uiHandler = new GtkHostUiHandler(this);
|
_uiHandler = new GtkHostUiHandler(this);
|
||||||
_deviceExitStatus = new AutoResetEvent(false);
|
_deviceExitStatus = new AutoResetEvent(false);
|
||||||
|
|
||||||
WindowStateEvent += WindowStateEvent_Changed;
|
WindowStateEvent += WindowStateEvent_Changed;
|
||||||
DeleteEvent += Window_Close;
|
DeleteEvent += Window_Close;
|
||||||
FocusInEvent += MainWindow_FocusInEvent;
|
FocusInEvent += MainWindow_FocusInEvent;
|
||||||
FocusOutEvent += MainWindow_FocusOutEvent;
|
FocusOutEvent += MainWindow_FocusOutEvent;
|
||||||
|
|
||||||
_applicationLibrary.ApplicationAdded += Application_Added;
|
_applicationLibrary.ApplicationAdded += Application_Added;
|
||||||
_applicationLibrary.ApplicationCountUpdated += ApplicationCount_Updated;
|
_applicationLibrary.ApplicationCountUpdated += ApplicationCount_Updated;
|
||||||
|
|
||||||
_fileMenu.StateChanged += FileMenu_StateChanged;
|
_fileMenu.StateChanged += FileMenu_StateChanged;
|
||||||
_actionMenu.StateChanged += ActionMenu_StateChanged;
|
_actionMenu.StateChanged += ActionMenu_StateChanged;
|
||||||
_optionMenu.StateChanged += OptionMenu_StateChanged;
|
_optionMenu.StateChanged += OptionMenu_StateChanged;
|
||||||
|
|
||||||
_gameTable.ButtonReleaseEvent += Row_Clicked;
|
_gameTable.ButtonReleaseEvent += Row_Clicked;
|
||||||
_fullScreen.Activated += FullScreen_Toggled;
|
_fullScreen.Activated += FullScreen_Toggled;
|
||||||
|
|
||||||
RendererWidgetBase.StatusUpdatedEvent += Update_StatusBar;
|
RendererWidgetBase.StatusUpdatedEvent += Update_StatusBar;
|
||||||
|
|
||||||
ConfigurationState.Instance.System.IgnoreMissingServices.Event += UpdateIgnoreMissingServicesState;
|
ConfigurationState.Instance.System.IgnoreMissingServices.Event += UpdateIgnoreMissingServicesState;
|
||||||
ConfigurationState.Instance.Graphics.AspectRatio.Event += UpdateAspectRatioState;
|
ConfigurationState.Instance.Graphics.AspectRatio.Event += UpdateAspectRatioState;
|
||||||
ConfigurationState.Instance.System.EnableDockedMode.Event += UpdateDockedModeState;
|
ConfigurationState.Instance.System.EnableDockedMode.Event += UpdateDockedModeState;
|
||||||
ConfigurationState.Instance.System.AudioVolume.Event += UpdateAudioVolumeState;
|
ConfigurationState.Instance.System.AudioVolume.Event += UpdateAudioVolumeState;
|
||||||
|
|
||||||
if (ConfigurationState.Instance.Ui.StartFullscreen)
|
if (ConfigurationState.Instance.Ui.StartFullscreen)
|
||||||
{
|
{
|
||||||
|
@ -221,43 +219,73 @@ namespace Ryujinx.Ui
|
||||||
_pauseEmulation.Sensitive = false;
|
_pauseEmulation.Sensitive = false;
|
||||||
_resumeEmulation.Sensitive = false;
|
_resumeEmulation.Sensitive = false;
|
||||||
|
|
||||||
_nspShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value;
|
_nspShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value;
|
||||||
_pfs0Shown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value;
|
_pfs0Shown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value;
|
||||||
_xciShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value;
|
_xciShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value;
|
||||||
_ncaShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value;
|
_ncaShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value;
|
||||||
_nroShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value;
|
_nroShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value;
|
||||||
_nsoShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value;
|
_nsoShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value;
|
||||||
|
|
||||||
_nspShown.Toggled += NSP_Shown_Toggled;
|
_nspShown.Toggled += NSP_Shown_Toggled;
|
||||||
_pfs0Shown.Toggled += PFS0_Shown_Toggled;
|
_pfs0Shown.Toggled += PFS0_Shown_Toggled;
|
||||||
_xciShown.Toggled += XCI_Shown_Toggled;
|
_xciShown.Toggled += XCI_Shown_Toggled;
|
||||||
_ncaShown.Toggled += NCA_Shown_Toggled;
|
_ncaShown.Toggled += NCA_Shown_Toggled;
|
||||||
_nroShown.Toggled += NRO_Shown_Toggled;
|
_nroShown.Toggled += NRO_Shown_Toggled;
|
||||||
_nsoShown.Toggled += NSO_Shown_Toggled;
|
_nsoShown.Toggled += NSO_Shown_Toggled;
|
||||||
|
|
||||||
_fileTypesSubMenu.Visible = FileAssociationHelper.IsTypeAssociationSupported;
|
_fileTypesSubMenu.Visible = FileAssociationHelper.IsTypeAssociationSupported;
|
||||||
|
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn) _favToggle.Active = true;
|
if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn)
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.IconColumn) _iconToggle.Active = true;
|
{
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.AppColumn) _appToggle.Active = true;
|
_favToggle.Active = true;
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.DevColumn) _developerToggle.Active = true;
|
}
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.VersionColumn) _versionToggle.Active = true;
|
if (ConfigurationState.Instance.Ui.GuiColumns.IconColumn)
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn) _timePlayedToggle.Active = true;
|
{
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn) _lastPlayedToggle.Active = true;
|
_iconToggle.Active = true;
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn) _fileExtToggle.Active = true;
|
}
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn) _fileSizeToggle.Active = true;
|
if (ConfigurationState.Instance.Ui.GuiColumns.AppColumn)
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.PathColumn) _pathToggle.Active = true;
|
{
|
||||||
|
_appToggle.Active = true;
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.DevColumn)
|
||||||
|
{
|
||||||
|
_developerToggle.Active = true;
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.VersionColumn)
|
||||||
|
{
|
||||||
|
_versionToggle.Active = true;
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn)
|
||||||
|
{
|
||||||
|
_timePlayedToggle.Active = true;
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn)
|
||||||
|
{
|
||||||
|
_lastPlayedToggle.Active = true;
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn)
|
||||||
|
{
|
||||||
|
_fileExtToggle.Active = true;
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn)
|
||||||
|
{
|
||||||
|
_fileSizeToggle.Active = true;
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.PathColumn)
|
||||||
|
{
|
||||||
|
_pathToggle.Active = true;
|
||||||
|
}
|
||||||
|
|
||||||
_favToggle.Toggled += Fav_Toggled;
|
_favToggle.Toggled += Fav_Toggled;
|
||||||
_iconToggle.Toggled += Icon_Toggled;
|
_iconToggle.Toggled += Icon_Toggled;
|
||||||
_appToggle.Toggled += App_Toggled;
|
_appToggle.Toggled += App_Toggled;
|
||||||
_developerToggle.Toggled += Developer_Toggled;
|
_developerToggle.Toggled += Developer_Toggled;
|
||||||
_versionToggle.Toggled += Version_Toggled;
|
_versionToggle.Toggled += Version_Toggled;
|
||||||
_timePlayedToggle.Toggled += TimePlayed_Toggled;
|
_timePlayedToggle.Toggled += TimePlayed_Toggled;
|
||||||
_lastPlayedToggle.Toggled += LastPlayed_Toggled;
|
_lastPlayedToggle.Toggled += LastPlayed_Toggled;
|
||||||
_fileExtToggle.Toggled += FileExt_Toggled;
|
_fileExtToggle.Toggled += FileExt_Toggled;
|
||||||
_fileSizeToggle.Toggled += FileSize_Toggled;
|
_fileSizeToggle.Toggled += FileSize_Toggled;
|
||||||
_pathToggle.Toggled += Path_Toggled;
|
_pathToggle.Toggled += Path_Toggled;
|
||||||
|
|
||||||
_gameTable.Model = _tableStore = new ListStore(
|
_gameTable.Model = _tableStore = new ListStore(
|
||||||
typeof(bool),
|
typeof(bool),
|
||||||
|
@ -276,7 +304,7 @@ namespace Ryujinx.Ui
|
||||||
_tableStore.SetSortFunc(6, SortHelper.LastPlayedSort);
|
_tableStore.SetSortFunc(6, SortHelper.LastPlayedSort);
|
||||||
_tableStore.SetSortFunc(8, SortHelper.FileSizeSort);
|
_tableStore.SetSortFunc(8, SortHelper.FileSizeSort);
|
||||||
|
|
||||||
int columnId = ConfigurationState.Instance.Ui.ColumnSort.SortColumnId;
|
int columnId = ConfigurationState.Instance.Ui.ColumnSort.SortColumnId;
|
||||||
bool ascending = ConfigurationState.Instance.Ui.ColumnSort.SortAscending;
|
bool ascending = ConfigurationState.Instance.Ui.ColumnSort.SortAscending;
|
||||||
|
|
||||||
_tableStore.SetSortColumnId(columnId, ascending ? SortType.Ascending : SortType.Descending);
|
_tableStore.SetSortColumnId(columnId, ascending ? SortType.Ascending : SortType.Descending);
|
||||||
|
@ -321,10 +349,7 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
private void UpdateDockedModeState(object sender, ReactiveEventArgs<bool> e)
|
private void UpdateDockedModeState(object sender, ReactiveEventArgs<bool> e)
|
||||||
{
|
{
|
||||||
if (_emulationContext != null)
|
_emulationContext?.System.ChangeDockedModeState(e.NewValue);
|
||||||
{
|
|
||||||
_emulationContext.System.ChangeDockedModeState(e.NewValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateAudioVolumeState(object sender, ReactiveEventArgs<float> e)
|
private void UpdateAudioVolumeState(object sender, ReactiveEventArgs<float> e)
|
||||||
|
@ -354,19 +379,49 @@ namespace Ryujinx.Ui
|
||||||
_gameTable.RemoveColumn(column);
|
_gameTable.RemoveColumn(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
CellRendererToggle favToggle = new CellRendererToggle();
|
CellRendererToggle favToggle = new();
|
||||||
favToggle.Toggled += FavToggle_Toggled;
|
favToggle.Toggled += FavToggle_Toggled;
|
||||||
|
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn) _gameTable.AppendColumn("Fav", favToggle, "active", 0);
|
if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn)
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.IconColumn) _gameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 1);
|
{
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.AppColumn) _gameTable.AppendColumn("Application", new CellRendererText(), "text", 2);
|
_gameTable.AppendColumn("Fav", favToggle, "active", 0);
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.DevColumn) _gameTable.AppendColumn("Developer", new CellRendererText(), "text", 3);
|
}
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.VersionColumn) _gameTable.AppendColumn("Version", new CellRendererText(), "text", 4);
|
if (ConfigurationState.Instance.Ui.GuiColumns.IconColumn)
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn) _gameTable.AppendColumn("Time Played", new CellRendererText(), "text", 5);
|
{
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn) _gameTable.AppendColumn("Last Played", new CellRendererText(), "text", 6);
|
_gameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 1);
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn) _gameTable.AppendColumn("File Ext", new CellRendererText(), "text", 7);
|
}
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn) _gameTable.AppendColumn("File Size", new CellRendererText(), "text", 8);
|
if (ConfigurationState.Instance.Ui.GuiColumns.AppColumn)
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.PathColumn) _gameTable.AppendColumn("Path", new CellRendererText(), "text", 9);
|
{
|
||||||
|
_gameTable.AppendColumn("Application", new CellRendererText(), "text", 2);
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.DevColumn)
|
||||||
|
{
|
||||||
|
_gameTable.AppendColumn("Developer", new CellRendererText(), "text", 3);
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.VersionColumn)
|
||||||
|
{
|
||||||
|
_gameTable.AppendColumn("Version", new CellRendererText(), "text", 4);
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn)
|
||||||
|
{
|
||||||
|
_gameTable.AppendColumn("Time Played", new CellRendererText(), "text", 5);
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn)
|
||||||
|
{
|
||||||
|
_gameTable.AppendColumn("Last Played", new CellRendererText(), "text", 6);
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn)
|
||||||
|
{
|
||||||
|
_gameTable.AppendColumn("File Ext", new CellRendererText(), "text", 7);
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn)
|
||||||
|
{
|
||||||
|
_gameTable.AppendColumn("File Size", new CellRendererText(), "text", 8);
|
||||||
|
}
|
||||||
|
if (ConfigurationState.Instance.Ui.GuiColumns.PathColumn)
|
||||||
|
{
|
||||||
|
_gameTable.AppendColumn("Path", new CellRendererText(), "text", 9);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (TreeViewColumn column in _gameTable.Columns)
|
foreach (TreeViewColumn column in _gameTable.Columns)
|
||||||
{
|
{
|
||||||
|
@ -426,11 +481,11 @@ namespace Ryujinx.Ui
|
||||||
if (ConfigurationState.Instance.Graphics.GraphicsBackend == GraphicsBackend.Vulkan)
|
if (ConfigurationState.Instance.Graphics.GraphicsBackend == GraphicsBackend.Vulkan)
|
||||||
{
|
{
|
||||||
string preferredGpu = ConfigurationState.Instance.Graphics.PreferredGpu.Value;
|
string preferredGpu = ConfigurationState.Instance.Graphics.PreferredGpu.Value;
|
||||||
renderer = new VulkanRenderer(Vk.GetApi(), CreateVulkanSurface, VulkanHelper.GetRequiredInstanceExtensions, preferredGpu);
|
renderer = new Graphics.Vulkan.VulkanRenderer(Vk.GetApi(), CreateVulkanSurface, VulkanHelper.GetRequiredInstanceExtensions, preferredGpu);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
renderer = new OpenGLRenderer();
|
renderer = new Graphics.OpenGL.OpenGLRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
||||||
|
@ -570,38 +625,38 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None;
|
IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None;
|
||||||
|
|
||||||
HLE.HLEConfiguration configuration = new HLE.HLEConfiguration(_virtualFileSystem,
|
HLE.HLEConfiguration configuration = new(_virtualFileSystem,
|
||||||
_libHacHorizonManager,
|
_libHacHorizonManager,
|
||||||
_contentManager,
|
_contentManager,
|
||||||
_accountManager,
|
_accountManager,
|
||||||
_userChannelPersistence,
|
_userChannelPersistence,
|
||||||
renderer,
|
renderer,
|
||||||
deviceDriver,
|
deviceDriver,
|
||||||
memoryConfiguration,
|
memoryConfiguration,
|
||||||
_uiHandler,
|
_uiHandler,
|
||||||
(SystemLanguage)ConfigurationState.Instance.System.Language.Value,
|
(SystemLanguage)ConfigurationState.Instance.System.Language.Value,
|
||||||
(RegionCode)ConfigurationState.Instance.System.Region.Value,
|
(RegionCode)ConfigurationState.Instance.System.Region.Value,
|
||||||
ConfigurationState.Instance.Graphics.EnableVsync,
|
ConfigurationState.Instance.Graphics.EnableVsync,
|
||||||
ConfigurationState.Instance.System.EnableDockedMode,
|
ConfigurationState.Instance.System.EnableDockedMode,
|
||||||
ConfigurationState.Instance.System.EnablePtc,
|
ConfigurationState.Instance.System.EnablePtc,
|
||||||
ConfigurationState.Instance.System.EnableInternetAccess,
|
ConfigurationState.Instance.System.EnableInternetAccess,
|
||||||
fsIntegrityCheckLevel,
|
fsIntegrityCheckLevel,
|
||||||
ConfigurationState.Instance.System.FsGlobalAccessLogMode,
|
ConfigurationState.Instance.System.FsGlobalAccessLogMode,
|
||||||
ConfigurationState.Instance.System.SystemTimeOffset,
|
ConfigurationState.Instance.System.SystemTimeOffset,
|
||||||
ConfigurationState.Instance.System.TimeZone,
|
ConfigurationState.Instance.System.TimeZone,
|
||||||
ConfigurationState.Instance.System.MemoryManagerMode,
|
ConfigurationState.Instance.System.MemoryManagerMode,
|
||||||
ConfigurationState.Instance.System.IgnoreMissingServices,
|
ConfigurationState.Instance.System.IgnoreMissingServices,
|
||||||
ConfigurationState.Instance.Graphics.AspectRatio,
|
ConfigurationState.Instance.Graphics.AspectRatio,
|
||||||
ConfigurationState.Instance.System.AudioVolume,
|
ConfigurationState.Instance.System.AudioVolume,
|
||||||
ConfigurationState.Instance.System.UseHypervisor,
|
ConfigurationState.Instance.System.UseHypervisor,
|
||||||
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value);
|
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value);
|
||||||
|
|
||||||
_emulationContext = new HLE.Switch(configuration);
|
_emulationContext = new HLE.Switch(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SurfaceKHR CreateVulkanSurface(Instance instance, Vk vk)
|
private SurfaceKHR CreateVulkanSurface(Instance instance, Vk vk)
|
||||||
{
|
{
|
||||||
return new SurfaceKHR((ulong)((VKRenderer)RendererWidget).CreateWindowSurface(instance.Handle));
|
return new SurfaceKHR((ulong)((VulkanRenderer)RendererWidget).CreateWindowSurface(instance.Handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupProgressUiHandlers()
|
private void SetupProgressUiHandlers()
|
||||||
|
@ -655,14 +710,16 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
_tableStore.Clear();
|
_tableStore.Clear();
|
||||||
|
|
||||||
Thread applicationLibraryThread = new Thread(() =>
|
Thread applicationLibraryThread = new(() =>
|
||||||
{
|
{
|
||||||
_applicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs, ConfigurationState.Instance.System.Language);
|
_applicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs, ConfigurationState.Instance.System.Language);
|
||||||
|
|
||||||
_updatingGameTable = false;
|
_updatingGameTable = false;
|
||||||
});
|
})
|
||||||
applicationLibraryThread.Name = "GUI.ApplicationLibraryThread";
|
{
|
||||||
applicationLibraryThread.IsBackground = true;
|
Name = "GUI.ApplicationLibraryThread",
|
||||||
|
IsBackground = true,
|
||||||
|
};
|
||||||
applicationLibraryThread.Start();
|
applicationLibraryThread.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,11 +728,11 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
if (ConfigurationState.Instance.Logger.EnableTrace.Value)
|
if (ConfigurationState.Instance.Logger.EnableTrace.Value)
|
||||||
{
|
{
|
||||||
MessageDialog debugWarningDialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null)
|
MessageDialog debugWarningDialog = new(this, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null)
|
||||||
{
|
{
|
||||||
Title = "Ryujinx - Warning",
|
Title = "Ryujinx - Warning",
|
||||||
Text = "You have trace logging enabled, which is designed to be used by developers only.",
|
Text = "You have trace logging enabled, which is designed to be used by developers only.",
|
||||||
SecondaryText = "For optimal performance, it's recommended to disable trace logging. Would you like to disable trace logging now?"
|
SecondaryText = "For optimal performance, it's recommended to disable trace logging. Would you like to disable trace logging now?",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (debugWarningDialog.Run() == (int)ResponseType.Yes)
|
if (debugWarningDialog.Run() == (int)ResponseType.Yes)
|
||||||
|
@ -689,11 +746,11 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(ConfigurationState.Instance.Graphics.ShadersDumpPath.Value))
|
if (!string.IsNullOrWhiteSpace(ConfigurationState.Instance.Graphics.ShadersDumpPath.Value))
|
||||||
{
|
{
|
||||||
MessageDialog shadersDumpWarningDialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null)
|
MessageDialog shadersDumpWarningDialog = new(this, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null)
|
||||||
{
|
{
|
||||||
Title = "Ryujinx - Warning",
|
Title = "Ryujinx - Warning",
|
||||||
Text = "You have shader dumping enabled, which is designed to be used by developers only.",
|
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?"
|
SecondaryText = "For optimal performance, it's recommended to disable shader dumping. Would you like to disable shader dumping now?",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (shadersDumpWarningDialog.Run() == (int)ResponseType.Yes)
|
if (shadersDumpWarningDialog.Run() == (int)ResponseType.Yes)
|
||||||
|
@ -857,18 +914,18 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
Thread windowThread = new(CreateGameWindow)
|
Thread windowThread = new(CreateGameWindow)
|
||||||
{
|
{
|
||||||
Name = "GUI.WindowThread"
|
Name = "GUI.WindowThread",
|
||||||
};
|
};
|
||||||
|
|
||||||
windowThread.Start();
|
windowThread.Start();
|
||||||
|
|
||||||
_gameLoaded = true;
|
_gameLoaded = true;
|
||||||
_actionMenu.Sensitive = true;
|
_actionMenu.Sensitive = true;
|
||||||
UpdateMenuItem.Sensitive = false;
|
UpdateMenuItem.Sensitive = false;
|
||||||
|
|
||||||
_lastScannedAmiiboId = "";
|
_lastScannedAmiiboId = "";
|
||||||
|
|
||||||
_firmwareInstallFile.Sensitive = false;
|
_firmwareInstallFile.Sensitive = false;
|
||||||
_firmwareInstallDirectory.Sensitive = false;
|
_firmwareInstallDirectory.Sensitive = false;
|
||||||
|
|
||||||
DiscordIntegrationModule.SwitchToPlayingState(_emulationContext.Processes.ActiveApplication.ProgramIdText,
|
DiscordIntegrationModule.SwitchToPlayingState(_emulationContext.Processes.ActiveApplication.ProgramIdText,
|
||||||
|
@ -885,11 +942,11 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
if (ConfigurationState.Instance.Graphics.GraphicsBackend == GraphicsBackend.Vulkan)
|
if (ConfigurationState.Instance.Graphics.GraphicsBackend == GraphicsBackend.Vulkan)
|
||||||
{
|
{
|
||||||
return new VKRenderer(InputManager, ConfigurationState.Instance.Logger.GraphicsDebugLevel);
|
return new VulkanRenderer(InputManager, ConfigurationState.Instance.Logger.GraphicsDebugLevel);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new GlRenderer(InputManager, ConfigurationState.Instance.Logger.GraphicsDebugLevel);
|
return new OpenGLRenderer(InputManager, ConfigurationState.Instance.Logger.GraphicsDebugLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1030,20 +1087,20 @@ namespace Ryujinx.Ui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateGraphicsConfig()
|
public static void UpdateGraphicsConfig()
|
||||||
{
|
{
|
||||||
int resScale = ConfigurationState.Instance.Graphics.ResScale;
|
int resScale = ConfigurationState.Instance.Graphics.ResScale;
|
||||||
float resScaleCustom = ConfigurationState.Instance.Graphics.ResScaleCustom;
|
float resScaleCustom = ConfigurationState.Instance.Graphics.ResScaleCustom;
|
||||||
|
|
||||||
Graphics.Gpu.GraphicsConfig.ResScale = (resScale == -1) ? resScaleCustom : resScale;
|
Graphics.Gpu.GraphicsConfig.ResScale = (resScale == -1) ? resScaleCustom : resScale;
|
||||||
Graphics.Gpu.GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy;
|
Graphics.Gpu.GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy;
|
||||||
Graphics.Gpu.GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
|
Graphics.Gpu.GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
|
||||||
Graphics.Gpu.GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
|
Graphics.Gpu.GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
|
||||||
Graphics.Gpu.GraphicsConfig.EnableTextureRecompression = ConfigurationState.Instance.Graphics.EnableTextureRecompression;
|
Graphics.Gpu.GraphicsConfig.EnableTextureRecompression = ConfigurationState.Instance.Graphics.EnableTextureRecompression;
|
||||||
Graphics.Gpu.GraphicsConfig.EnableMacroHLE = ConfigurationState.Instance.Graphics.EnableMacroHLE;
|
Graphics.Gpu.GraphicsConfig.EnableMacroHLE = ConfigurationState.Instance.Graphics.EnableMacroHLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveConfig()
|
public static void SaveConfig()
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||||
}
|
}
|
||||||
|
@ -1105,7 +1162,7 @@ namespace Ryujinx.Ui
|
||||||
Application.Invoke(delegate
|
Application.Invoke(delegate
|
||||||
{
|
{
|
||||||
_progressLabel.Text = $"{args.NumAppsLoaded}/{args.NumAppsFound} Games Loaded";
|
_progressLabel.Text = $"{args.NumAppsLoaded}/{args.NumAppsFound} Games Loaded";
|
||||||
float barValue = 0;
|
float barValue = 0;
|
||||||
|
|
||||||
if (args.NumAppsFound != 0)
|
if (args.NumAppsFound != 0)
|
||||||
{
|
{
|
||||||
|
@ -1126,12 +1183,12 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
Application.Invoke(delegate
|
Application.Invoke(delegate
|
||||||
{
|
{
|
||||||
_gameStatus.Text = args.GameStatus;
|
_gameStatus.Text = args.GameStatus;
|
||||||
_fifoStatus.Text = args.FifoStatus;
|
_fifoStatus.Text = args.FifoStatus;
|
||||||
_gpuName.Text = args.GpuName;
|
_gpuName.Text = args.GpuName;
|
||||||
_dockedMode.Text = args.DockedMode;
|
_dockedMode.Text = args.DockedMode;
|
||||||
_aspectRatio.Text = args.AspectRatio;
|
_aspectRatio.Text = args.AspectRatio;
|
||||||
_gpuBackend.Text = args.GpuBackend;
|
_gpuBackend.Text = args.GpuBackend;
|
||||||
_volumeStatus.Text = GetVolumeLabelText(args.Volume);
|
_volumeStatus.Text = GetVolumeLabelText(args.Volume);
|
||||||
|
|
||||||
if (args.VSyncEnabled)
|
if (args.VSyncEnabled)
|
||||||
|
@ -1151,8 +1208,8 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
_tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path));
|
_tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path));
|
||||||
|
|
||||||
string titleId = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower();
|
string titleId = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower();
|
||||||
bool newToggleValue = !(bool)_tableStore.GetValue(treeIter, 0);
|
bool newToggleValue = !(bool)_tableStore.GetValue(treeIter, 0);
|
||||||
|
|
||||||
_tableStore.SetValue(treeIter, 0, newToggleValue);
|
_tableStore.SetValue(treeIter, 0, newToggleValue);
|
||||||
|
|
||||||
|
@ -1166,7 +1223,7 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
TreeViewColumn column = (TreeViewColumn)sender;
|
TreeViewColumn column = (TreeViewColumn)sender;
|
||||||
|
|
||||||
ConfigurationState.Instance.Ui.ColumnSort.SortColumnId.Value = column.SortColumnId;
|
ConfigurationState.Instance.Ui.ColumnSort.SortColumnId.Value = column.SortColumnId;
|
||||||
ConfigurationState.Instance.Ui.ColumnSort.SortAscending.Value = column.SortOrder == SortType.Ascending;
|
ConfigurationState.Instance.Ui.ColumnSort.SortAscending.Value = column.SortOrder == SortType.Ascending;
|
||||||
|
|
||||||
SaveConfig();
|
SaveConfig();
|
||||||
|
@ -1193,7 +1250,7 @@ namespace Ryujinx.Ui
|
||||||
ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value;
|
ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetVolumeLabelText(float volume)
|
private static string GetVolumeLabelText(float volume)
|
||||||
{
|
{
|
||||||
string icon = volume == 0 ? "🔇" : "🔊";
|
string icon = volume == 0 ? "🔇" : "🔊";
|
||||||
|
|
||||||
|
@ -1237,8 +1294,8 @@ namespace Ryujinx.Ui
|
||||||
}
|
}
|
||||||
|
|
||||||
string titleFilePath = _tableStore.GetValue(treeIter, 9).ToString();
|
string titleFilePath = _tableStore.GetValue(treeIter, 9).ToString();
|
||||||
string titleName = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[0];
|
string titleName = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[0];
|
||||||
string titleId = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower();
|
string titleId = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower();
|
||||||
|
|
||||||
BlitStruct<ApplicationControlProperty> controlData = (BlitStruct<ApplicationControlProperty>)_tableStore.GetValue(treeIter, 10);
|
BlitStruct<ApplicationControlProperty> controlData = (BlitStruct<ApplicationControlProperty>)_tableStore.GetValue(treeIter, 10);
|
||||||
|
|
||||||
|
@ -1247,43 +1304,41 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
private void Load_Application_File(object sender, EventArgs args)
|
private void Load_Application_File(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
using (FileChooserNative fileChooser = new FileChooserNative("Choose the file to open", this, FileChooserAction.Open, "Open", "Cancel"))
|
using FileChooserNative fileChooser = new("Choose the file to open", this, FileChooserAction.Open, "Open", "Cancel");
|
||||||
|
|
||||||
|
FileFilter filter = new()
|
||||||
{
|
{
|
||||||
FileFilter filter = new FileFilter()
|
Name = "Switch Executables",
|
||||||
{
|
};
|
||||||
Name = "Switch Executables"
|
filter.AddPattern("*.xci");
|
||||||
};
|
filter.AddPattern("*.nsp");
|
||||||
filter.AddPattern("*.xci");
|
filter.AddPattern("*.pfs0");
|
||||||
filter.AddPattern("*.nsp");
|
filter.AddPattern("*.nca");
|
||||||
filter.AddPattern("*.pfs0");
|
filter.AddPattern("*.nro");
|
||||||
filter.AddPattern("*.nca");
|
filter.AddPattern("*.nso");
|
||||||
filter.AddPattern("*.nro");
|
|
||||||
filter.AddPattern("*.nso");
|
|
||||||
|
|
||||||
fileChooser.AddFilter(filter);
|
fileChooser.AddFilter(filter);
|
||||||
|
|
||||||
if (fileChooser.Run() == (int)ResponseType.Accept)
|
if (fileChooser.Run() == (int)ResponseType.Accept)
|
||||||
{
|
{
|
||||||
RunApplication(fileChooser.Filename);
|
RunApplication(fileChooser.Filename);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Load_Application_Folder(object sender, EventArgs args)
|
private void Load_Application_Folder(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
using (FileChooserNative fileChooser = new FileChooserNative("Choose the folder to open", this, FileChooserAction.SelectFolder, "Open", "Cancel"))
|
using FileChooserNative fileChooser = new("Choose the folder to open", this, FileChooserAction.SelectFolder, "Open", "Cancel");
|
||||||
|
|
||||||
|
if (fileChooser.Run() == (int)ResponseType.Accept)
|
||||||
{
|
{
|
||||||
if (fileChooser.Run() == (int)ResponseType.Accept)
|
RunApplication(fileChooser.Filename);
|
||||||
{
|
|
||||||
RunApplication(fileChooser.Filename);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FileMenu_StateChanged(object o, StateChangedArgs args)
|
private void FileMenu_StateChanged(object o, StateChangedArgs args)
|
||||||
{
|
{
|
||||||
_appletMenu.Sensitive = _emulationContext == null && _contentManager.GetCurrentFirmwareVersion() != null && _contentManager.GetCurrentFirmwareVersion().Major > 3;
|
_appletMenu.Sensitive = _emulationContext == null && _contentManager.GetCurrentFirmwareVersion() != null && _contentManager.GetCurrentFirmwareVersion().Major > 3;
|
||||||
_loadApplicationFile.Sensitive = _emulationContext == null;
|
_loadApplicationFile.Sensitive = _emulationContext == null;
|
||||||
_loadApplicationFolder.Sensitive = _emulationContext == null;
|
_loadApplicationFolder.Sensitive = _emulationContext == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1332,7 +1387,7 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
private void SetWindowSizePosition()
|
private void SetWindowSizePosition()
|
||||||
{
|
{
|
||||||
DefaultWidth = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeWidth;
|
DefaultWidth = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeWidth;
|
||||||
DefaultHeight = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight;
|
DefaultHeight = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight;
|
||||||
|
|
||||||
Move(ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX, ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY);
|
Move(ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX, ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY);
|
||||||
|
@ -1399,11 +1454,11 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
private void Installer_File_Pressed(object o, EventArgs args)
|
private void Installer_File_Pressed(object o, EventArgs args)
|
||||||
{
|
{
|
||||||
FileChooserNative fileChooser = new FileChooserNative("Choose the firmware file to open", this, FileChooserAction.Open, "Open", "Cancel");
|
FileChooserNative fileChooser = new("Choose the firmware file to open", this, FileChooserAction.Open, "Open", "Cancel");
|
||||||
|
|
||||||
FileFilter filter = new FileFilter
|
FileFilter filter = new()
|
||||||
{
|
{
|
||||||
Name = "Switch Firmware Files"
|
Name = "Switch Firmware Files",
|
||||||
};
|
};
|
||||||
filter.AddPattern("*.zip");
|
filter.AddPattern("*.zip");
|
||||||
filter.AddPattern("*.xci");
|
filter.AddPattern("*.xci");
|
||||||
|
@ -1415,7 +1470,7 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
private void Installer_Directory_Pressed(object o, EventArgs args)
|
private void Installer_Directory_Pressed(object o, EventArgs args)
|
||||||
{
|
{
|
||||||
FileChooserNative directoryChooser = new FileChooserNative("Choose the firmware directory to open", this, FileChooserAction.SelectFolder, "Open", "Cancel");
|
FileChooserNative directoryChooser = new("Choose the firmware directory to open", this, FileChooserAction.SelectFolder, "Open", "Cancel");
|
||||||
|
|
||||||
HandleInstallerDialog(directoryChooser);
|
HandleInstallerDialog(directoryChooser);
|
||||||
}
|
}
|
||||||
|
@ -1460,7 +1515,7 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
Logger.Info?.Print(LogClass.Application, $"Installing firmware {firmwareVersion.VersionString}");
|
Logger.Info?.Print(LogClass.Application, $"Installing firmware {firmwareVersion.VersionString}");
|
||||||
|
|
||||||
Thread thread = new Thread(() =>
|
Thread thread = new(() =>
|
||||||
{
|
{
|
||||||
Application.Invoke(delegate
|
Application.Invoke(delegate
|
||||||
{
|
{
|
||||||
|
@ -1483,7 +1538,7 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
// Purge Applet Cache.
|
// Purge Applet Cache.
|
||||||
|
|
||||||
DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
|
DirectoryInfo miiEditorCacheFolder = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
|
||||||
|
|
||||||
if (miiEditorCacheFolder.Exists)
|
if (miiEditorCacheFolder.Exists)
|
||||||
{
|
{
|
||||||
|
@ -1504,9 +1559,10 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
RefreshFirmwareLabel();
|
RefreshFirmwareLabel();
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
{
|
||||||
thread.Name = "GUI.FirmwareInstallerThread";
|
Name = "GUI.FirmwareInstallerThread",
|
||||||
|
};
|
||||||
thread.Start();
|
thread.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1571,7 +1627,7 @@ namespace Ryujinx.Ui
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// otherwise, clear state.
|
// otherwise, clear state.
|
||||||
_userChannelPersistence = new UserChannelPersistence();
|
_userChannelPersistence = new UserChannelPersistence();
|
||||||
_currentEmulatedGamePath = null;
|
_currentEmulatedGamePath = null;
|
||||||
_actionMenu.Sensitive = false;
|
_actionMenu.Sensitive = false;
|
||||||
_firmwareInstallFile.Sensitive = true;
|
_firmwareInstallFile.Sensitive = true;
|
||||||
|
@ -1616,7 +1672,7 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
private void Settings_Pressed(object sender, EventArgs args)
|
private void Settings_Pressed(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
SettingsWindow settingsWindow = new SettingsWindow(this, _virtualFileSystem, _contentManager);
|
SettingsWindow settingsWindow = new(this, _virtualFileSystem, _contentManager);
|
||||||
|
|
||||||
settingsWindow.SetSizeRequest((int)(settingsWindow.DefaultWidth * Program.WindowScaleFactor), (int)(settingsWindow.DefaultHeight * Program.WindowScaleFactor));
|
settingsWindow.SetSizeRequest((int)(settingsWindow.DefaultWidth * Program.WindowScaleFactor), (int)(settingsWindow.DefaultHeight * Program.WindowScaleFactor));
|
||||||
settingsWindow.Show();
|
settingsWindow.Show();
|
||||||
|
@ -1648,7 +1704,7 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
private void ManageUserProfiles_Pressed(object sender, EventArgs args)
|
private void ManageUserProfiles_Pressed(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
UserProfilesManagerWindow userProfilesManagerWindow = new UserProfilesManagerWindow(_accountManager, _contentManager, _virtualFileSystem);
|
UserProfilesManagerWindow userProfilesManagerWindow = new(_accountManager, _contentManager, _virtualFileSystem);
|
||||||
|
|
||||||
userProfilesManagerWindow.SetSizeRequest((int)(userProfilesManagerWindow.DefaultWidth * Program.WindowScaleFactor), (int)(userProfilesManagerWindow.DefaultHeight * Program.WindowScaleFactor));
|
userProfilesManagerWindow.SetSizeRequest((int)(userProfilesManagerWindow.DefaultWidth * Program.WindowScaleFactor), (int)(userProfilesManagerWindow.DefaultHeight * Program.WindowScaleFactor));
|
||||||
userProfilesManagerWindow.Show();
|
userProfilesManagerWindow.Show();
|
||||||
|
@ -1656,15 +1712,12 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
private void Simulate_WakeUp_Message_Pressed(object sender, EventArgs args)
|
private void Simulate_WakeUp_Message_Pressed(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
if (_emulationContext != null)
|
_emulationContext?.System.SimulateWakeUpMessage();
|
||||||
{
|
|
||||||
_emulationContext.System.SimulateWakeUpMessage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ActionMenu_StateChanged(object o, StateChangedArgs args)
|
private void ActionMenu_StateChanged(object o, StateChangedArgs args)
|
||||||
{
|
{
|
||||||
_scanAmiibo.Sensitive = _emulationContext != null && _emulationContext.System.SearchingForAmiibo(out int _);
|
_scanAmiibo.Sensitive = _emulationContext != null && _emulationContext.System.SearchingForAmiibo(out int _);
|
||||||
_takeScreenshot.Sensitive = _emulationContext != null;
|
_takeScreenshot.Sensitive = _emulationContext != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1672,12 +1725,12 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
if (_emulationContext.System.SearchingForAmiibo(out int deviceId))
|
if (_emulationContext.System.SearchingForAmiibo(out int deviceId))
|
||||||
{
|
{
|
||||||
AmiiboWindow amiiboWindow = new AmiiboWindow
|
AmiiboWindow amiiboWindow = new()
|
||||||
{
|
{
|
||||||
LastScannedAmiiboShowAll = _lastScannedAmiiboShowAll,
|
LastScannedAmiiboShowAll = _lastScannedAmiiboShowAll,
|
||||||
LastScannedAmiiboId = _lastScannedAmiiboId,
|
LastScannedAmiiboId = _lastScannedAmiiboId,
|
||||||
DeviceId = deviceId,
|
DeviceId = deviceId,
|
||||||
TitleId = _emulationContext.Processes.ActiveApplication.ProgramIdText.ToUpper()
|
TitleId = _emulationContext.Processes.ActiveApplication.ProgramIdText.ToUpper(),
|
||||||
};
|
};
|
||||||
|
|
||||||
amiiboWindow.DeleteEvent += AmiiboWindow_DeleteEvent;
|
amiiboWindow.DeleteEvent += AmiiboWindow_DeleteEvent;
|
||||||
|
@ -1702,7 +1755,7 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
if (((AmiiboWindow)sender).AmiiboId != "" && ((AmiiboWindow)sender).Response == ResponseType.Ok)
|
if (((AmiiboWindow)sender).AmiiboId != "" && ((AmiiboWindow)sender).Response == ResponseType.Ok)
|
||||||
{
|
{
|
||||||
_lastScannedAmiiboId = ((AmiiboWindow)sender).AmiiboId;
|
_lastScannedAmiiboId = ((AmiiboWindow)sender).AmiiboId;
|
||||||
_lastScannedAmiiboShowAll = ((AmiiboWindow)sender).LastScannedAmiiboShowAll;
|
_lastScannedAmiiboShowAll = ((AmiiboWindow)sender).LastScannedAmiiboShowAll;
|
||||||
|
|
||||||
_emulationContext.System.ScanAmiibo(((AmiiboWindow)sender).DeviceId, ((AmiiboWindow)sender).AmiiboId, ((AmiiboWindow)sender).UseRandomUuid);
|
_emulationContext.System.ScanAmiibo(((AmiiboWindow)sender).DeviceId, ((AmiiboWindow)sender).AmiiboId, ((AmiiboWindow)sender).UseRandomUuid);
|
||||||
|
@ -1722,7 +1775,7 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
private void About_Pressed(object sender, EventArgs args)
|
private void About_Pressed(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
AboutWindow aboutWindow = new AboutWindow();
|
AboutWindow aboutWindow = new();
|
||||||
|
|
||||||
aboutWindow.SetSizeRequest((int)(aboutWindow.DefaultWidth * Program.WindowScaleFactor), (int)(aboutWindow.DefaultHeight * Program.WindowScaleFactor));
|
aboutWindow.SetSizeRequest((int)(aboutWindow.DefaultWidth * Program.WindowScaleFactor), (int)(aboutWindow.DefaultHeight * Program.WindowScaleFactor));
|
||||||
aboutWindow.Show();
|
aboutWindow.Show();
|
||||||
|
@ -1824,7 +1877,7 @@ namespace Ryujinx.Ui
|
||||||
UpdateGameTable();
|
UpdateGameTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void XCI_Shown_Toggled (object sender, EventArgs args)
|
private void XCI_Shown_Toggled(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value = _xciShown.Active;
|
ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value = _xciShown.Active;
|
||||||
|
|
||||||
|
@ -1832,7 +1885,7 @@ namespace Ryujinx.Ui
|
||||||
UpdateGameTable();
|
UpdateGameTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NCA_Shown_Toggled (object sender, EventArgs args)
|
private void NCA_Shown_Toggled(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value = _ncaShown.Active;
|
ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value = _ncaShown.Active;
|
||||||
|
|
||||||
|
@ -1840,7 +1893,7 @@ namespace Ryujinx.Ui
|
||||||
UpdateGameTable();
|
UpdateGameTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NRO_Shown_Toggled (object sender, EventArgs args)
|
private void NRO_Shown_Toggled(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value = _nroShown.Active;
|
ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value = _nroShown.Active;
|
||||||
|
|
||||||
|
@ -1848,7 +1901,7 @@ namespace Ryujinx.Ui
|
||||||
UpdateGameTable();
|
UpdateGameTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NSO_Shown_Toggled (object sender, EventArgs args)
|
private void NSO_Shown_Toggled(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value = _nsoShown.Active;
|
ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value = _nsoShown.Active;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.OpenGL;
|
|
||||||
using Ryujinx.Input.HLE;
|
using Ryujinx.Input.HLE;
|
||||||
using SPB.Graphics;
|
using SPB.Graphics;
|
||||||
using SPB.Graphics.Exceptions;
|
using SPB.Graphics.Exceptions;
|
||||||
|
@ -15,16 +14,16 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Ui
|
namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
public partial class GlRenderer : RendererWidgetBase
|
public partial class OpenGLRenderer : RendererWidgetBase
|
||||||
{
|
{
|
||||||
private GraphicsDebugLevel _glLogLevel;
|
private readonly GraphicsDebugLevel _glLogLevel;
|
||||||
|
|
||||||
private bool _initializedOpenGL;
|
private bool _initializedOpenGL;
|
||||||
|
|
||||||
private OpenGLContextBase _openGLContext;
|
private OpenGLContextBase _openGLContext;
|
||||||
private SwappableNativeWindowBase _nativeWindow;
|
private SwappableNativeWindowBase _nativeWindow;
|
||||||
|
|
||||||
public GlRenderer(InputManager inputManager, GraphicsDebugLevel glLogLevel) : base(inputManager, glLogLevel)
|
public OpenGLRenderer(InputManager inputManager, GraphicsDebugLevel glLogLevel) : base(inputManager, glLogLevel)
|
||||||
{
|
{
|
||||||
_glLogLevel = glLogLevel;
|
_glLogLevel = glLogLevel;
|
||||||
}
|
}
|
||||||
|
@ -93,7 +92,7 @@ namespace Ryujinx.Ui
|
||||||
public override void InitializeRenderer()
|
public override void InitializeRenderer()
|
||||||
{
|
{
|
||||||
// First take exclusivity on the OpenGL context.
|
// First take exclusivity on the OpenGL context.
|
||||||
((OpenGLRenderer)Renderer).InitializeBackgroundContext(SPBOpenGLContext.CreateBackgroundContext(_openGLContext));
|
((Graphics.OpenGL.OpenGLRenderer)Renderer).InitializeBackgroundContext(SPBOpenGLContext.CreateBackgroundContext(_openGLContext));
|
||||||
|
|
||||||
_openGLContext.MakeCurrent(_nativeWindow);
|
_openGLContext.MakeCurrent(_nativeWindow);
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
public class OpenToolkitBindingsContext : OpenTK.IBindingsContext
|
public class OpenToolkitBindingsContext : OpenTK.IBindingsContext
|
||||||
{
|
{
|
||||||
private IBindingsContext _bindingContext;
|
private readonly IBindingsContext _bindingContext;
|
||||||
|
|
||||||
public OpenToolkitBindingsContext(IBindingsContext bindingsContext)
|
public OpenToolkitBindingsContext(IBindingsContext bindingsContext)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,14 +21,13 @@ using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Image = SixLabors.ImageSharp.Image;
|
||||||
|
using Key = Ryujinx.Input.Key;
|
||||||
|
using ScalingFilter = Ryujinx.Graphics.GAL.ScalingFilter;
|
||||||
|
using Switch = Ryujinx.HLE.Switch;
|
||||||
|
|
||||||
namespace Ryujinx.Ui
|
namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
using Image = SixLabors.ImageSharp.Image;
|
|
||||||
using Key = Input.Key;
|
|
||||||
using ScalingFilter = Graphics.GAL.ScalingFilter;
|
|
||||||
using Switch = HLE.Switch;
|
|
||||||
|
|
||||||
public abstract class RendererWidgetBase : DrawingArea
|
public abstract class RendererWidgetBase : DrawingArea
|
||||||
{
|
{
|
||||||
private const int SwitchPanelWidth = 1280;
|
private const int SwitchPanelWidth = 1280;
|
||||||
|
@ -71,12 +70,12 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
// Hide Cursor
|
// Hide Cursor
|
||||||
const int CursorHideIdleTime = 5; // seconds
|
const int CursorHideIdleTime = 5; // seconds
|
||||||
private static readonly Cursor _invisibleCursor = new Cursor(Display.Default, CursorType.BlankCursor);
|
private static readonly Cursor _invisibleCursor = new(Display.Default, CursorType.BlankCursor);
|
||||||
private long _lastCursorMoveTime;
|
private long _lastCursorMoveTime;
|
||||||
private HideCursorMode _hideCursorMode;
|
private HideCursorMode _hideCursorMode;
|
||||||
private InputManager _inputManager;
|
private readonly InputManager _inputManager;
|
||||||
private IKeyboard _keyboardInterface;
|
private readonly IKeyboard _keyboardInterface;
|
||||||
private GraphicsDebugLevel _glLogLevel;
|
private readonly GraphicsDebugLevel _glLogLevel;
|
||||||
private string _gpuBackendName;
|
private string _gpuBackendName;
|
||||||
private string _gpuVendorName;
|
private string _gpuVendorName;
|
||||||
private bool _isMouseInClient;
|
private bool _isMouseInClient;
|
||||||
|
@ -165,7 +164,7 @@ namespace Ryujinx.Ui
|
||||||
Window.Cursor = _invisibleCursor;
|
Window.Cursor = _invisibleCursor;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException(nameof(state));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -379,12 +378,12 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
var currentTime = DateTime.Now;
|
var currentTime = DateTime.Now;
|
||||||
string filename = $"ryujinx_capture_{currentTime.Year}-{currentTime.Month:D2}-{currentTime.Day:D2}_{currentTime.Hour:D2}-{currentTime.Minute:D2}-{currentTime.Second:D2}.png";
|
string filename = $"ryujinx_capture_{currentTime.Year}-{currentTime.Month:D2}-{currentTime.Day:D2}_{currentTime.Hour:D2}-{currentTime.Minute:D2}-{currentTime.Second:D2}.png";
|
||||||
string directory = AppDataManager.Mode switch
|
string directory = AppDataManager.Mode switch
|
||||||
{
|
{
|
||||||
AppDataManager.LaunchMode.Portable or AppDataManager.LaunchMode.Custom => System.IO.Path.Combine(AppDataManager.BaseDirPath, "screenshots"),
|
AppDataManager.LaunchMode.Portable or AppDataManager.LaunchMode.Custom => System.IO.Path.Combine(AppDataManager.BaseDirPath, "screenshots"),
|
||||||
_ => System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx")
|
_ => System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx"),
|
||||||
};
|
};
|
||||||
|
|
||||||
string path = System.IO.Path.Combine(directory, filename);
|
string path = System.IO.Path.Combine(directory, filename);
|
||||||
|
@ -415,7 +414,7 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
image.SaveAsPng(path, new PngEncoder()
|
image.SaveAsPng(path, new PngEncoder()
|
||||||
{
|
{
|
||||||
ColorType = PngColorType.Rgb
|
ColorType = PngColorType.Rgb,
|
||||||
});
|
});
|
||||||
|
|
||||||
image.Dispose();
|
image.Dispose();
|
||||||
|
@ -524,30 +523,30 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
parent.Present();
|
parent.Present();
|
||||||
|
|
||||||
var activeProcess = Device.Processes.ActiveApplication;
|
var activeProcess = Device.Processes.ActiveApplication;
|
||||||
|
|
||||||
string titleNameSection = string.IsNullOrWhiteSpace(activeProcess.Name) ? string.Empty : $" {activeProcess.Name}";
|
string titleNameSection = string.IsNullOrWhiteSpace(activeProcess.Name) ? string.Empty : $" {activeProcess.Name}";
|
||||||
string titleVersionSection = string.IsNullOrWhiteSpace(activeProcess.DisplayVersion) ? string.Empty : $" v{activeProcess.DisplayVersion}";
|
string titleVersionSection = string.IsNullOrWhiteSpace(activeProcess.DisplayVersion) ? string.Empty : $" v{activeProcess.DisplayVersion}";
|
||||||
string titleIdSection = $" ({activeProcess.ProgramIdText.ToUpper()})";
|
string titleIdSection = $" ({activeProcess.ProgramIdText.ToUpper()})";
|
||||||
string titleArchSection = activeProcess.Is64Bit ? " (64-bit)" : " (32-bit)";
|
string titleArchSection = activeProcess.Is64Bit ? " (64-bit)" : " (32-bit)";
|
||||||
|
|
||||||
parent.Title = $"Ryujinx {Program.Version} -{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
|
parent.Title = $"Ryujinx {Program.Version} -{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
|
||||||
});
|
});
|
||||||
|
|
||||||
Thread renderLoopThread = new Thread(Render)
|
Thread renderLoopThread = new(Render)
|
||||||
{
|
{
|
||||||
Name = "GUI.RenderLoop"
|
Name = "GUI.RenderLoop",
|
||||||
};
|
};
|
||||||
renderLoopThread.Start();
|
renderLoopThread.Start();
|
||||||
|
|
||||||
Thread nvStutterWorkaround = null;
|
Thread nvidiaStutterWorkaround = null;
|
||||||
if (Renderer is Graphics.OpenGL.OpenGLRenderer)
|
if (Renderer is Graphics.OpenGL.OpenGLRenderer)
|
||||||
{
|
{
|
||||||
nvStutterWorkaround = new Thread(NVStutterWorkaround)
|
nvidiaStutterWorkaround = new Thread(NvidiaStutterWorkaround)
|
||||||
{
|
{
|
||||||
Name = "GUI.NVStutterWorkaround"
|
Name = "GUI.NvidiaStutterWorkaround",
|
||||||
};
|
};
|
||||||
nvStutterWorkaround.Start();
|
nvidiaStutterWorkaround.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
MainLoop();
|
MainLoop();
|
||||||
|
@ -556,7 +555,7 @@ namespace Ryujinx.Ui
|
||||||
// We only need to wait for all commands submitted during the main gpu loop to be processed.
|
// We only need to wait for all commands submitted during the main gpu loop to be processed.
|
||||||
_gpuDoneEvent.WaitOne();
|
_gpuDoneEvent.WaitOne();
|
||||||
_gpuDoneEvent.Dispose();
|
_gpuDoneEvent.Dispose();
|
||||||
nvStutterWorkaround?.Join();
|
nvidiaStutterWorkaround?.Join();
|
||||||
|
|
||||||
Exit();
|
Exit();
|
||||||
}
|
}
|
||||||
|
@ -584,7 +583,7 @@ namespace Ryujinx.Ui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NVStutterWorkaround()
|
private void NvidiaStutterWorkaround()
|
||||||
{
|
{
|
||||||
while (_isActive)
|
while (_isActive)
|
||||||
{
|
{
|
||||||
|
@ -752,7 +751,7 @@ namespace Ryujinx.Ui
|
||||||
ResScaleUp = 1 << 5,
|
ResScaleUp = 1 << 5,
|
||||||
ResScaleDown = 1 << 6,
|
ResScaleDown = 1 << 6,
|
||||||
VolumeUp = 1 << 7,
|
VolumeUp = 1 << 7,
|
||||||
VolumeDown = 1 << 8
|
VolumeDown = 1 << 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeyboardHotkeyState GetHotkeyState()
|
private KeyboardHotkeyState GetHotkeyState()
|
||||||
|
|
|
@ -9,8 +9,8 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
class SPBOpenGLContext : IOpenGLContext
|
class SPBOpenGLContext : IOpenGLContext
|
||||||
{
|
{
|
||||||
private OpenGLContextBase _context;
|
private readonly OpenGLContextBase _context;
|
||||||
private NativeWindowBase _window;
|
private readonly NativeWindowBase _window;
|
||||||
|
|
||||||
private SPBOpenGLContext(OpenGLContextBase context, NativeWindowBase window)
|
private SPBOpenGLContext(OpenGLContextBase context, NativeWindowBase window)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,8 +4,8 @@ namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
public class StatusUpdatedEventArgs : EventArgs
|
public class StatusUpdatedEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public bool VSyncEnabled;
|
public bool VSyncEnabled;
|
||||||
public float Volume;
|
public float Volume;
|
||||||
public string DockedMode;
|
public string DockedMode;
|
||||||
public string AspectRatio;
|
public string AspectRatio;
|
||||||
public string GameStatus;
|
public string GameStatus;
|
||||||
|
@ -16,13 +16,13 @@ namespace Ryujinx.Ui
|
||||||
public StatusUpdatedEventArgs(bool vSyncEnabled, float volume, string gpuBackend, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus, string gpuName)
|
public StatusUpdatedEventArgs(bool vSyncEnabled, float volume, string gpuBackend, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus, string gpuName)
|
||||||
{
|
{
|
||||||
VSyncEnabled = vSyncEnabled;
|
VSyncEnabled = vSyncEnabled;
|
||||||
Volume = volume;
|
Volume = volume;
|
||||||
GpuBackend = gpuBackend;
|
GpuBackend = gpuBackend;
|
||||||
DockedMode = dockedMode;
|
DockedMode = dockedMode;
|
||||||
AspectRatio = aspectRatio;
|
AspectRatio = aspectRatio;
|
||||||
GameStatus = gameStatus;
|
GameStatus = gameStatus;
|
||||||
FifoStatus = fifoStatus;
|
FifoStatus = fifoStatus;
|
||||||
GpuName = gpuName;
|
GpuName = gpuName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,12 +12,12 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Ui
|
namespace Ryujinx.Ui
|
||||||
{
|
{
|
||||||
public partial class VKRenderer : RendererWidgetBase
|
public partial class VulkanRenderer : RendererWidgetBase
|
||||||
{
|
{
|
||||||
public NativeWindowBase NativeWindow { get; private set; }
|
public NativeWindowBase NativeWindow { get; private set; }
|
||||||
private UpdateBoundsCallbackDelegate _updateBoundsCallback;
|
private UpdateBoundsCallbackDelegate _updateBoundsCallback;
|
||||||
|
|
||||||
public VKRenderer(InputManager inputManager, GraphicsDebugLevel glLogLevel) : base(inputManager, glLogLevel) { }
|
public VulkanRenderer(InputManager inputManager, GraphicsDebugLevel glLogLevel) : base(inputManager, glLogLevel) { }
|
||||||
|
|
||||||
private NativeWindowBase RetrieveNativeWindow()
|
private NativeWindowBase RetrieveNativeWindow()
|
||||||
{
|
{
|
|
@ -12,12 +12,12 @@ namespace Ryujinx.Ui.Widgets
|
||||||
private MenuItem _manageCheatMenuItem;
|
private MenuItem _manageCheatMenuItem;
|
||||||
private MenuItem _openTitleModDirMenuItem;
|
private MenuItem _openTitleModDirMenuItem;
|
||||||
private MenuItem _openTitleSdModDirMenuItem;
|
private MenuItem _openTitleSdModDirMenuItem;
|
||||||
private Menu _extractSubMenu;
|
private Menu _extractSubMenu;
|
||||||
private MenuItem _extractMenuItem;
|
private MenuItem _extractMenuItem;
|
||||||
private MenuItem _extractRomFsMenuItem;
|
private MenuItem _extractRomFsMenuItem;
|
||||||
private MenuItem _extractExeFsMenuItem;
|
private MenuItem _extractExeFsMenuItem;
|
||||||
private MenuItem _extractLogoMenuItem;
|
private MenuItem _extractLogoMenuItem;
|
||||||
private Menu _manageSubMenu;
|
private Menu _manageSubMenu;
|
||||||
private MenuItem _manageCacheMenuItem;
|
private MenuItem _manageCacheMenuItem;
|
||||||
private MenuItem _purgePtcCacheMenuItem;
|
private MenuItem _purgePtcCacheMenuItem;
|
||||||
private MenuItem _purgeShaderCacheMenuItem;
|
private MenuItem _purgeShaderCacheMenuItem;
|
||||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_openSaveUserDirMenuItem = new MenuItem("Open User Save Directory")
|
_openSaveUserDirMenuItem = new MenuItem("Open User Save Directory")
|
||||||
{
|
{
|
||||||
TooltipText = "Open the directory which contains Application's User Saves."
|
TooltipText = "Open the directory which contains Application's User Saves.",
|
||||||
};
|
};
|
||||||
_openSaveUserDirMenuItem.Activated += OpenSaveUserDir_Clicked;
|
_openSaveUserDirMenuItem.Activated += OpenSaveUserDir_Clicked;
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_openSaveDeviceDirMenuItem = new MenuItem("Open Device Save Directory")
|
_openSaveDeviceDirMenuItem = new MenuItem("Open Device Save Directory")
|
||||||
{
|
{
|
||||||
TooltipText = "Open the directory which contains Application's Device Saves."
|
TooltipText = "Open the directory which contains Application's Device Saves.",
|
||||||
};
|
};
|
||||||
_openSaveDeviceDirMenuItem.Activated += OpenSaveDeviceDir_Clicked;
|
_openSaveDeviceDirMenuItem.Activated += OpenSaveDeviceDir_Clicked;
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_openSaveBcatDirMenuItem = new MenuItem("Open BCAT Save Directory")
|
_openSaveBcatDirMenuItem = new MenuItem("Open BCAT Save Directory")
|
||||||
{
|
{
|
||||||
TooltipText = "Open the directory which contains Application's BCAT Saves."
|
TooltipText = "Open the directory which contains Application's BCAT Saves.",
|
||||||
};
|
};
|
||||||
_openSaveBcatDirMenuItem.Activated += OpenSaveBcatDir_Clicked;
|
_openSaveBcatDirMenuItem.Activated += OpenSaveBcatDir_Clicked;
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_manageTitleUpdatesMenuItem = new MenuItem("Manage Title Updates")
|
_manageTitleUpdatesMenuItem = new MenuItem("Manage Title Updates")
|
||||||
{
|
{
|
||||||
TooltipText = "Open the Title Update management window"
|
TooltipText = "Open the Title Update management window",
|
||||||
};
|
};
|
||||||
_manageTitleUpdatesMenuItem.Activated += ManageTitleUpdates_Clicked;
|
_manageTitleUpdatesMenuItem.Activated += ManageTitleUpdates_Clicked;
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_manageDlcMenuItem = new MenuItem("Manage DLC")
|
_manageDlcMenuItem = new MenuItem("Manage DLC")
|
||||||
{
|
{
|
||||||
TooltipText = "Open the DLC management window"
|
TooltipText = "Open the DLC management window",
|
||||||
};
|
};
|
||||||
_manageDlcMenuItem.Activated += ManageDlc_Clicked;
|
_manageDlcMenuItem.Activated += ManageDlc_Clicked;
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_manageCheatMenuItem = new MenuItem("Manage Cheats")
|
_manageCheatMenuItem = new MenuItem("Manage Cheats")
|
||||||
{
|
{
|
||||||
TooltipText = "Open the Cheat management window"
|
TooltipText = "Open the Cheat management window",
|
||||||
};
|
};
|
||||||
_manageCheatMenuItem.Activated += ManageCheats_Clicked;
|
_manageCheatMenuItem.Activated += ManageCheats_Clicked;
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_openTitleModDirMenuItem = new MenuItem("Open Mods Directory")
|
_openTitleModDirMenuItem = new MenuItem("Open Mods Directory")
|
||||||
{
|
{
|
||||||
TooltipText = "Open the directory which contains Application's Mods."
|
TooltipText = "Open the directory which contains Application's Mods.",
|
||||||
};
|
};
|
||||||
_openTitleModDirMenuItem.Activated += OpenTitleModDir_Clicked;
|
_openTitleModDirMenuItem.Activated += OpenTitleModDir_Clicked;
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_openTitleSdModDirMenuItem = new MenuItem("Open Atmosphere Mods Directory")
|
_openTitleSdModDirMenuItem = new MenuItem("Open Atmosphere Mods Directory")
|
||||||
{
|
{
|
||||||
TooltipText = "Open the alternative SD card atmosphere directory which contains the Application's Mods."
|
TooltipText = "Open the alternative SD card atmosphere directory which contains the Application's Mods.",
|
||||||
};
|
};
|
||||||
_openTitleSdModDirMenuItem.Activated += OpenTitleSdModDir_Clicked;
|
_openTitleSdModDirMenuItem.Activated += OpenTitleSdModDir_Clicked;
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_extractRomFsMenuItem = new MenuItem("RomFS")
|
_extractRomFsMenuItem = new MenuItem("RomFS")
|
||||||
{
|
{
|
||||||
TooltipText = "Extract the RomFS section from Application's current config (including updates)."
|
TooltipText = "Extract the RomFS section from Application's current config (including updates).",
|
||||||
};
|
};
|
||||||
_extractRomFsMenuItem.Activated += ExtractRomFs_Clicked;
|
_extractRomFsMenuItem.Activated += ExtractRomFs_Clicked;
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_extractExeFsMenuItem = new MenuItem("ExeFS")
|
_extractExeFsMenuItem = new MenuItem("ExeFS")
|
||||||
{
|
{
|
||||||
TooltipText = "Extract the ExeFS section from Application's current config (including updates)."
|
TooltipText = "Extract the ExeFS section from Application's current config (including updates).",
|
||||||
};
|
};
|
||||||
_extractExeFsMenuItem.Activated += ExtractExeFs_Clicked;
|
_extractExeFsMenuItem.Activated += ExtractExeFs_Clicked;
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_extractLogoMenuItem = new MenuItem("Logo")
|
_extractLogoMenuItem = new MenuItem("Logo")
|
||||||
{
|
{
|
||||||
TooltipText = "Extract the Logo section from Application's current config (including updates)."
|
TooltipText = "Extract the Logo section from Application's current config (including updates).",
|
||||||
};
|
};
|
||||||
_extractLogoMenuItem.Activated += ExtractLogo_Clicked;
|
_extractLogoMenuItem.Activated += ExtractLogo_Clicked;
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_manageCacheMenuItem = new MenuItem("Cache Management")
|
_manageCacheMenuItem = new MenuItem("Cache Management")
|
||||||
{
|
{
|
||||||
Submenu = _manageSubMenu
|
Submenu = _manageSubMenu,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -156,7 +156,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_purgePtcCacheMenuItem = new MenuItem("Queue PPTC Rebuild")
|
_purgePtcCacheMenuItem = new MenuItem("Queue PPTC Rebuild")
|
||||||
{
|
{
|
||||||
TooltipText = "Trigger PPTC to rebuild at boot time on the next game launch."
|
TooltipText = "Trigger PPTC to rebuild at boot time on the next game launch.",
|
||||||
};
|
};
|
||||||
_purgePtcCacheMenuItem.Activated += PurgePtcCache_Clicked;
|
_purgePtcCacheMenuItem.Activated += PurgePtcCache_Clicked;
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_purgeShaderCacheMenuItem = new MenuItem("Purge Shader Cache")
|
_purgeShaderCacheMenuItem = new MenuItem("Purge Shader Cache")
|
||||||
{
|
{
|
||||||
TooltipText = "Delete the Application's shader cache."
|
TooltipText = "Delete the Application's shader cache.",
|
||||||
};
|
};
|
||||||
_purgeShaderCacheMenuItem.Activated += PurgeShaderCache_Clicked;
|
_purgeShaderCacheMenuItem.Activated += PurgeShaderCache_Clicked;
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_openPtcDirMenuItem = new MenuItem("Open PPTC Directory")
|
_openPtcDirMenuItem = new MenuItem("Open PPTC Directory")
|
||||||
{
|
{
|
||||||
TooltipText = "Open the directory which contains the Application's PPTC cache."
|
TooltipText = "Open the directory which contains the Application's PPTC cache.",
|
||||||
};
|
};
|
||||||
_openPtcDirMenuItem.Activated += OpenPtcDir_Clicked;
|
_openPtcDirMenuItem.Activated += OpenPtcDir_Clicked;
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
//
|
//
|
||||||
_openShaderCacheDirMenuItem = new MenuItem("Open Shader Cache Directory")
|
_openShaderCacheDirMenuItem = new MenuItem("Open Shader Cache Directory")
|
||||||
{
|
{
|
||||||
TooltipText = "Open the directory which contains the Application's shader cache."
|
TooltipText = "Open the directory which contains the Application's shader cache.",
|
||||||
};
|
};
|
||||||
_openShaderCacheDirMenuItem.Activated += OpenShaderCacheDir_Clicked;
|
_openShaderCacheDirMenuItem.Activated += OpenShaderCacheDir_Clicked;
|
||||||
|
|
||||||
|
|
|
@ -31,19 +31,19 @@ namespace Ryujinx.Ui.Widgets
|
||||||
{
|
{
|
||||||
public partial class GameTableContextMenu : Menu
|
public partial class GameTableContextMenu : Menu
|
||||||
{
|
{
|
||||||
private readonly MainWindow _parent;
|
private readonly MainWindow _parent;
|
||||||
private readonly VirtualFileSystem _virtualFileSystem;
|
private readonly VirtualFileSystem _virtualFileSystem;
|
||||||
private readonly AccountManager _accountManager;
|
private readonly AccountManager _accountManager;
|
||||||
private readonly HorizonClient _horizonClient;
|
private readonly HorizonClient _horizonClient;
|
||||||
private readonly BlitStruct<ApplicationControlProperty> _controlData;
|
private readonly BlitStruct<ApplicationControlProperty> _controlData;
|
||||||
|
|
||||||
private readonly string _titleFilePath;
|
private readonly string _titleFilePath;
|
||||||
private readonly string _titleName;
|
private readonly string _titleName;
|
||||||
private readonly string _titleIdText;
|
private readonly string _titleIdText;
|
||||||
private readonly ulong _titleId;
|
private readonly ulong _titleId;
|
||||||
|
|
||||||
private MessageDialog _dialog;
|
private MessageDialog _dialog;
|
||||||
private bool _cancel;
|
private bool _cancel;
|
||||||
|
|
||||||
public GameTableContextMenu(MainWindow parent, VirtualFileSystem virtualFileSystem, AccountManager accountManager, HorizonClient horizonClient, string titleFilePath, string titleName, string titleId, BlitStruct<ApplicationControlProperty> controlData)
|
public GameTableContextMenu(MainWindow parent, VirtualFileSystem virtualFileSystem, AccountManager accountManager, HorizonClient horizonClient, string titleFilePath, string titleName, string titleId, BlitStruct<ApplicationControlProperty> controlData)
|
||||||
{
|
{
|
||||||
|
@ -52,12 +52,12 @@ namespace Ryujinx.Ui.Widgets
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_virtualFileSystem = virtualFileSystem;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
_accountManager = accountManager;
|
_accountManager = accountManager;
|
||||||
_horizonClient = horizonClient;
|
_horizonClient = horizonClient;
|
||||||
_titleFilePath = titleFilePath;
|
_titleFilePath = titleFilePath;
|
||||||
_titleName = titleName;
|
_titleName = titleName;
|
||||||
_titleIdText = titleId;
|
_titleIdText = titleId;
|
||||||
_controlData = controlData;
|
_controlData = controlData;
|
||||||
|
|
||||||
if (!ulong.TryParse(_titleIdText, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out _titleId))
|
if (!ulong.TryParse(_titleIdText, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out _titleId))
|
||||||
{
|
{
|
||||||
|
@ -66,16 +66,16 @@ namespace Ryujinx.Ui.Widgets
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_openSaveUserDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.UserAccountSaveDataSize > 0;
|
_openSaveUserDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.UserAccountSaveDataSize > 0;
|
||||||
_openSaveDeviceDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.DeviceSaveDataSize > 0;
|
_openSaveDeviceDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.DeviceSaveDataSize > 0;
|
||||||
_openSaveBcatDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.BcatDeliveryCacheStorageSize > 0;
|
_openSaveBcatDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.BcatDeliveryCacheStorageSize > 0;
|
||||||
|
|
||||||
string fileExt = System.IO.Path.GetExtension(_titleFilePath).ToLower();
|
string fileExt = System.IO.Path.GetExtension(_titleFilePath).ToLower();
|
||||||
bool hasNca = fileExt == ".nca" || fileExt == ".nsp" || fileExt == ".pfs0" || fileExt == ".xci";
|
bool hasNca = fileExt == ".nca" || fileExt == ".nsp" || fileExt == ".pfs0" || fileExt == ".xci";
|
||||||
|
|
||||||
_extractRomFsMenuItem.Sensitive = hasNca;
|
_extractRomFsMenuItem.Sensitive = hasNca;
|
||||||
_extractExeFsMenuItem.Sensitive = hasNca;
|
_extractExeFsMenuItem.Sensitive = hasNca;
|
||||||
_extractLogoMenuItem.Sensitive = hasNca;
|
_extractLogoMenuItem.Sensitive = hasNca;
|
||||||
|
|
||||||
PopupAtPointer(null);
|
PopupAtPointer(null);
|
||||||
}
|
}
|
||||||
|
@ -99,13 +99,13 @@ namespace Ryujinx.Ui.Widgets
|
||||||
control = ref new BlitStruct<ApplicationControlProperty>(1).Value;
|
control = ref new BlitStruct<ApplicationControlProperty>(1).Value;
|
||||||
|
|
||||||
// The set sizes don't actually matter as long as they're non-zero because we use directory savedata.
|
// The set sizes don't actually matter as long as they're non-zero because we use directory savedata.
|
||||||
control.UserAccountSaveDataSize = 0x4000;
|
control.UserAccountSaveDataSize = 0x4000;
|
||||||
control.UserAccountSaveDataJournalSize = 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((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low);
|
Uid user = new((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low);
|
||||||
|
|
||||||
result = _horizonClient.Fs.EnsureApplicationSaveData(out _, new LibHac.Ncm.ApplicationId(titleId), in control, in user);
|
result = _horizonClient.Fs.EnsureApplicationSaveData(out _, new LibHac.Ncm.ApplicationId(titleId), in control, in user);
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
}
|
}
|
||||||
|
|
||||||
string committedPath = System.IO.Path.Combine(saveRootPath, "0");
|
string committedPath = System.IO.Path.Combine(saveRootPath, "0");
|
||||||
string workingPath = System.IO.Path.Combine(saveRootPath, "1");
|
string workingPath = System.IO.Path.Combine(saveRootPath, "1");
|
||||||
|
|
||||||
// If the committed directory exists, that path will be loaded the next time the savedata is mounted
|
// If the committed directory exists, that path will be loaded the next time the savedata is mounted
|
||||||
if (Directory.Exists(committedPath))
|
if (Directory.Exists(committedPath))
|
||||||
|
@ -170,25 +170,25 @@ namespace Ryujinx.Ui.Widgets
|
||||||
|
|
||||||
private void ExtractSection(NcaSectionType ncaSectionType, int programIndex = 0)
|
private void ExtractSection(NcaSectionType ncaSectionType, int programIndex = 0)
|
||||||
{
|
{
|
||||||
FileChooserNative fileChooser = new FileChooserNative("Choose the folder to extract into", _parent, FileChooserAction.SelectFolder, "Extract", "Cancel");
|
FileChooserNative fileChooser = new("Choose the folder to extract into", _parent, FileChooserAction.SelectFolder, "Extract", "Cancel");
|
||||||
|
|
||||||
ResponseType response = (ResponseType)fileChooser.Run();
|
ResponseType response = (ResponseType)fileChooser.Run();
|
||||||
string destination = fileChooser.Filename;
|
string destination = fileChooser.Filename;
|
||||||
|
|
||||||
fileChooser.Dispose();
|
fileChooser.Dispose();
|
||||||
|
|
||||||
if (response == ResponseType.Accept)
|
if (response == ResponseType.Accept)
|
||||||
{
|
{
|
||||||
Thread extractorThread = new Thread(() =>
|
Thread extractorThread = new(() =>
|
||||||
{
|
{
|
||||||
Gtk.Application.Invoke(delegate
|
Gtk.Application.Invoke(delegate
|
||||||
{
|
{
|
||||||
_dialog = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Cancel, null)
|
_dialog = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Cancel, null)
|
||||||
{
|
{
|
||||||
Title = "Ryujinx - NCA Section Extractor",
|
Title = "Ryujinx - NCA Section Extractor",
|
||||||
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"),
|
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"),
|
||||||
SecondaryText = $"Extracting {ncaSectionType} section from {System.IO.Path.GetFileName(_titleFilePath)}...",
|
SecondaryText = $"Extracting {ncaSectionType} section from {System.IO.Path.GetFileName(_titleFilePath)}...",
|
||||||
WindowPosition = WindowPosition.Center
|
WindowPosition = WindowPosition.Center,
|
||||||
};
|
};
|
||||||
|
|
||||||
int dialogResponse = _dialog.Run();
|
int dialogResponse = _dialog.Run();
|
||||||
|
@ -199,139 +199,140 @@ namespace Ryujinx.Ui.Widgets
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
using (FileStream file = new FileStream(_titleFilePath, FileMode.Open, FileAccess.Read))
|
using FileStream file = new(_titleFilePath, FileMode.Open, FileAccess.Read);
|
||||||
|
|
||||||
|
Nca mainNca = null;
|
||||||
|
Nca patchNca = null;
|
||||||
|
|
||||||
|
if ((System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".nsp") ||
|
||||||
|
(System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".pfs0") ||
|
||||||
|
(System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".xci"))
|
||||||
{
|
{
|
||||||
Nca mainNca = null;
|
PartitionFileSystem pfs;
|
||||||
Nca patchNca = null;
|
|
||||||
|
|
||||||
if ((System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".nsp") ||
|
if (System.IO.Path.GetExtension(_titleFilePath) == ".xci")
|
||||||
(System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".pfs0") ||
|
|
||||||
(System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".xci"))
|
|
||||||
{
|
{
|
||||||
PartitionFileSystem pfs;
|
Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage());
|
||||||
|
|
||||||
if (System.IO.Path.GetExtension(_titleFilePath) == ".xci")
|
pfs = xci.OpenPartition(XciPartitionType.Secure);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pfs = new PartitionFileSystem(file.AsStorage());
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
||||||
|
{
|
||||||
|
using var ncaFile = new UniqueRef<IFile>();
|
||||||
|
|
||||||
|
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
|
Nca nca = new(_virtualFileSystem.KeySet, ncaFile.Release().AsStorage());
|
||||||
|
|
||||||
|
if (nca.Header.ContentType == NcaContentType.Program)
|
||||||
{
|
{
|
||||||
Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage());
|
int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
|
||||||
|
|
||||||
pfs = xci.OpenPartition(XciPartitionType.Secure);
|
if (nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection())
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pfs = new PartitionFileSystem(file.AsStorage());
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
|
||||||
{
|
|
||||||
using var ncaFile = new UniqueRef<IFile>();
|
|
||||||
|
|
||||||
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
|
||||||
|
|
||||||
Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.Release().AsStorage());
|
|
||||||
|
|
||||||
if (nca.Header.ContentType == NcaContentType.Program)
|
|
||||||
{
|
{
|
||||||
int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
|
patchNca = nca;
|
||||||
|
}
|
||||||
if (nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection())
|
else
|
||||||
{
|
{
|
||||||
patchNca = nca;
|
mainNca = nca;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mainNca = nca;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".nca")
|
}
|
||||||
{
|
else if (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".nca")
|
||||||
mainNca = new Nca(_virtualFileSystem.KeySet, file.AsStorage());
|
{
|
||||||
}
|
mainNca = new Nca(_virtualFileSystem.KeySet, file.AsStorage());
|
||||||
|
}
|
||||||
|
|
||||||
if (mainNca == null)
|
if (mainNca == null)
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Application, "Extraction failure. The main NCA is not present in the selected file.");
|
Logger.Error?.Print(LogClass.Application, "Extraction failure. The main NCA is not present in the selected file.");
|
||||||
|
|
||||||
Gtk.Application.Invoke(delegate
|
Gtk.Application.Invoke(delegate
|
||||||
{
|
{
|
||||||
GtkDialog.CreateErrorDialog("Extraction failure. The main NCA is not present in the selected file.");
|
GtkDialog.CreateErrorDialog("Extraction failure. The main NCA is not present in the selected file.");
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
(Nca updatePatchNca, _) = ApplicationLibrary.GetGameUpdateData(_virtualFileSystem, mainNca.Header.TitleId.ToString("x16"), programIndex, out _);
|
(Nca updatePatchNca, _) = ApplicationLibrary.GetGameUpdateData(_virtualFileSystem, mainNca.Header.TitleId.ToString("x16"), programIndex, out _);
|
||||||
|
|
||||||
if (updatePatchNca != null)
|
if (updatePatchNca != null)
|
||||||
{
|
{
|
||||||
patchNca = updatePatchNca;
|
patchNca = updatePatchNca;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = Nca.GetSectionIndexFromType(ncaSectionType, mainNca.Header.ContentType);
|
int index = Nca.GetSectionIndexFromType(ncaSectionType, mainNca.Header.ContentType);
|
||||||
|
|
||||||
bool sectionExistsInPatch = false;
|
bool sectionExistsInPatch = false;
|
||||||
if (patchNca != null)
|
|
||||||
{
|
|
||||||
sectionExistsInPatch = patchNca.CanOpenSection(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
IFileSystem ncaFileSystem = sectionExistsInPatch ? mainNca.OpenFileSystemWithPatch(patchNca, index, IntegrityCheckLevel.ErrorOnInvalid)
|
if (patchNca != null)
|
||||||
|
{
|
||||||
|
sectionExistsInPatch = patchNca.CanOpenSection(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
IFileSystem ncaFileSystem = sectionExistsInPatch ? mainNca.OpenFileSystemWithPatch(patchNca, index, IntegrityCheckLevel.ErrorOnInvalid)
|
||||||
: mainNca.OpenFileSystem(index, IntegrityCheckLevel.ErrorOnInvalid);
|
: mainNca.OpenFileSystem(index, IntegrityCheckLevel.ErrorOnInvalid);
|
||||||
|
|
||||||
FileSystemClient fsClient = _horizonClient.Fs;
|
FileSystemClient fsClient = _horizonClient.Fs;
|
||||||
|
|
||||||
string source = DateTime.Now.ToFileTime().ToString()[10..];
|
string source = DateTime.Now.ToFileTime().ToString()[10..];
|
||||||
string output = DateTime.Now.ToFileTime().ToString()[10..];
|
string output = DateTime.Now.ToFileTime().ToString()[10..];
|
||||||
|
|
||||||
using var uniqueSourceFs = new UniqueRef<IFileSystem>(ncaFileSystem);
|
using var uniqueSourceFs = new UniqueRef<IFileSystem>(ncaFileSystem);
|
||||||
using var uniqueOutputFs = new UniqueRef<IFileSystem>(new LocalFileSystem(destination));
|
using var uniqueOutputFs = new UniqueRef<IFileSystem>(new LocalFileSystem(destination));
|
||||||
|
|
||||||
fsClient.Register(source.ToU8Span(), ref uniqueSourceFs.Ref);
|
fsClient.Register(source.ToU8Span(), ref uniqueSourceFs.Ref);
|
||||||
fsClient.Register(output.ToU8Span(), ref uniqueOutputFs.Ref);
|
fsClient.Register(output.ToU8Span(), ref uniqueOutputFs.Ref);
|
||||||
|
|
||||||
(Result? resultCode, bool canceled) = CopyDirectory(fsClient, $"{source}:/", $"{output}:/");
|
(Result? resultCode, bool canceled) = CopyDirectory(fsClient, $"{source}:/", $"{output}:/");
|
||||||
|
|
||||||
if (!canceled)
|
if (!canceled)
|
||||||
|
{
|
||||||
|
if (resultCode.Value.IsFailure())
|
||||||
{
|
{
|
||||||
if (resultCode.Value.IsFailure())
|
Logger.Error?.Print(LogClass.Application, $"LibHac returned error code: {resultCode.Value.ErrorCode}");
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.Application, $"LibHac returned error code: {resultCode.Value.ErrorCode}");
|
|
||||||
|
|
||||||
Gtk.Application.Invoke(delegate
|
Gtk.Application.Invoke(delegate
|
||||||
{
|
{
|
||||||
_dialog?.Dispose();
|
_dialog?.Dispose();
|
||||||
|
|
||||||
GtkDialog.CreateErrorDialog("Extraction failed. Read the log file for further information.");
|
GtkDialog.CreateErrorDialog("Extraction failed. Read the log file for further information.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (resultCode.Value.IsSuccess())
|
else if (resultCode.Value.IsSuccess())
|
||||||
{
|
{
|
||||||
Gtk.Application.Invoke(delegate
|
Gtk.Application.Invoke(delegate
|
||||||
{
|
{
|
||||||
_dialog?.Dispose();
|
_dialog?.Dispose();
|
||||||
|
|
||||||
MessageDialog dialog = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null)
|
MessageDialog dialog = new(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null)
|
||||||
{
|
{
|
||||||
Title = "Ryujinx - NCA Section Extractor",
|
Title = "Ryujinx - NCA Section Extractor",
|
||||||
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"),
|
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"),
|
||||||
SecondaryText = "Extraction completed successfully.",
|
SecondaryText = "Extraction completed successfully.",
|
||||||
WindowPosition = WindowPosition.Center
|
WindowPosition = WindowPosition.Center,
|
||||||
};
|
};
|
||||||
|
|
||||||
dialog.Run();
|
dialog.Run();
|
||||||
dialog.Dispose();
|
dialog.Dispose();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fsClient.Unmount(source.ToU8Span());
|
|
||||||
fsClient.Unmount(output.ToU8Span());
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
extractorThread.Name = "GUI.NcaSectionExtractorThread";
|
fsClient.Unmount(source.ToU8Span());
|
||||||
extractorThread.IsBackground = true;
|
fsClient.Unmount(output.ToU8Span());
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Name = "GUI.NcaSectionExtractorThread",
|
||||||
|
IsBackground = true,
|
||||||
|
};
|
||||||
extractorThread.Start();
|
extractorThread.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,7 +340,10 @@ namespace Ryujinx.Ui.Widgets
|
||||||
private (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath)
|
private (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath)
|
||||||
{
|
{
|
||||||
Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath.ToU8Span(), OpenDirectoryMode.All);
|
Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath.ToU8Span(), OpenDirectoryMode.All);
|
||||||
if (rc.IsFailure()) return (rc, false);
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return (rc, false);
|
||||||
|
}
|
||||||
|
|
||||||
using (sourceHandle)
|
using (sourceHandle)
|
||||||
{
|
{
|
||||||
|
@ -369,7 +373,10 @@ namespace Ryujinx.Ui.Widgets
|
||||||
fs.CreateOrOverwriteFile(subDstPath, entry.Size);
|
fs.CreateOrOverwriteFile(subDstPath, entry.Size);
|
||||||
|
|
||||||
rc = CopyFile(fs, subSrcPath, subDstPath);
|
rc = CopyFile(fs, subSrcPath, subDstPath);
|
||||||
if (rc.IsFailure()) return (rc, false);
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return (rc, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,22 +384,31 @@ namespace Ryujinx.Ui.Widgets
|
||||||
return (Result.Success, false);
|
return (Result.Success, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result CopyFile(FileSystemClient fs, string sourcePath, string destPath)
|
public static Result CopyFile(FileSystemClient fs, string sourcePath, string destPath)
|
||||||
{
|
{
|
||||||
Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath.ToU8Span(), OpenMode.Read);
|
Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath.ToU8Span(), OpenMode.Read);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
using (sourceHandle)
|
using (sourceHandle)
|
||||||
{
|
{
|
||||||
rc = fs.OpenFile(out FileHandle destHandle, destPath.ToU8Span(), OpenMode.Write | OpenMode.AllowAppend);
|
rc = fs.OpenFile(out FileHandle destHandle, destPath.ToU8Span(), OpenMode.Write | OpenMode.AllowAppend);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
using (destHandle)
|
using (destHandle)
|
||||||
{
|
{
|
||||||
const int MaxBufferSize = 1024 * 1024;
|
const int MaxBufferSize = 1024 * 1024;
|
||||||
|
|
||||||
rc = fs.GetFileSize(out long fileSize, sourceHandle);
|
rc = fs.GetFileSize(out long fileSize, sourceHandle);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
int bufferSize = (int)Math.Min(MaxBufferSize, fileSize);
|
int bufferSize = (int)Math.Min(MaxBufferSize, fileSize);
|
||||||
|
|
||||||
|
@ -405,10 +421,16 @@ namespace Ryujinx.Ui.Widgets
|
||||||
Span<byte> buf = buffer.AsSpan(0, toRead);
|
Span<byte> buf = buffer.AsSpan(0, toRead);
|
||||||
|
|
||||||
rc = fs.ReadFile(out long _, sourceHandle, offset, buf);
|
rc = fs.ReadFile(out long _, sourceHandle, offset, buf);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
rc = fs.WriteFile(destHandle, offset, buf, WriteOption.None);
|
rc = fs.WriteFile(destHandle, offset, buf, WriteOption.None);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
@ -417,7 +439,10 @@ namespace Ryujinx.Ui.Widgets
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = fs.FlushFile(destHandle);
|
rc = fs.FlushFile(destHandle);
|
||||||
if (rc.IsFailure()) return rc;
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,7 +491,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
|
|
||||||
private void OpenTitleModDir_Clicked(object sender, EventArgs args)
|
private void OpenTitleModDir_Clicked(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
string modsBasePath = ModLoader.GetModsBasePath();
|
string modsBasePath = ModLoader.GetModsBasePath();
|
||||||
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, _titleIdText);
|
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, _titleIdText);
|
||||||
|
|
||||||
OpenHelper.OpenFolder(titleModsPath);
|
OpenHelper.OpenFolder(titleModsPath);
|
||||||
|
@ -474,8 +499,8 @@ namespace Ryujinx.Ui.Widgets
|
||||||
|
|
||||||
private void OpenTitleSdModDir_Clicked(object sender, EventArgs args)
|
private void OpenTitleSdModDir_Clicked(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
string sdModsBasePath = ModLoader.GetSdModsBasePath();
|
string sdModsBasePath = ModLoader.GetSdModsBasePath();
|
||||||
string titleModsPath = ModLoader.GetTitleDir(sdModsBasePath, _titleIdText);
|
string titleModsPath = ModLoader.GetTitleDir(sdModsBasePath, _titleIdText);
|
||||||
|
|
||||||
OpenHelper.OpenFolder(titleModsPath);
|
OpenHelper.OpenFolder(titleModsPath);
|
||||||
}
|
}
|
||||||
|
@ -497,9 +522,9 @@ namespace Ryujinx.Ui.Widgets
|
||||||
|
|
||||||
private void OpenPtcDir_Clicked(object sender, EventArgs args)
|
private void OpenPtcDir_Clicked(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
string ptcDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu");
|
string ptcDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu");
|
||||||
|
|
||||||
string mainPath = System.IO.Path.Combine(ptcDir, "0");
|
string mainPath = System.IO.Path.Combine(ptcDir, "0");
|
||||||
string backupPath = System.IO.Path.Combine(ptcDir, "1");
|
string backupPath = System.IO.Path.Combine(ptcDir, "1");
|
||||||
|
|
||||||
if (!Directory.Exists(ptcDir))
|
if (!Directory.Exists(ptcDir))
|
||||||
|
@ -526,12 +551,12 @@ namespace Ryujinx.Ui.Widgets
|
||||||
|
|
||||||
private void PurgePtcCache_Clicked(object sender, EventArgs args)
|
private void PurgePtcCache_Clicked(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
DirectoryInfo mainDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu", "0"));
|
DirectoryInfo mainDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu", "0"));
|
||||||
DirectoryInfo backupDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu", "1"));
|
DirectoryInfo backupDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu", "1"));
|
||||||
|
|
||||||
MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to queue a PPTC rebuild on the next boot of:\n\n<b>{_titleName}</b>\n\nAre you sure you want to proceed?");
|
MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to queue a PPTC rebuild on the next boot of:\n\n<b>{_titleName}</b>\n\nAre you sure you want to proceed?");
|
||||||
|
|
||||||
List<FileInfo> cacheFiles = new List<FileInfo>();
|
List<FileInfo> cacheFiles = new();
|
||||||
|
|
||||||
if (mainDir.Exists)
|
if (mainDir.Exists)
|
||||||
{
|
{
|
||||||
|
@ -551,7 +576,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
{
|
{
|
||||||
file.Delete();
|
file.Delete();
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
GtkDialog.CreateErrorDialog($"Error purging PPTC cache {file.Name}: {e}");
|
GtkDialog.CreateErrorDialog($"Error purging PPTC cache {file.Name}: {e}");
|
||||||
}
|
}
|
||||||
|
@ -563,12 +588,12 @@ namespace Ryujinx.Ui.Widgets
|
||||||
|
|
||||||
private void PurgeShaderCache_Clicked(object sender, EventArgs args)
|
private void PurgeShaderCache_Clicked(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
DirectoryInfo shaderCacheDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "shader"));
|
DirectoryInfo shaderCacheDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "shader"));
|
||||||
|
|
||||||
using 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?");
|
using 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> oldCacheDirectories = new List<DirectoryInfo>();
|
List<DirectoryInfo> oldCacheDirectories = new();
|
||||||
List<FileInfo> newCacheFiles = new List<FileInfo>();
|
List<FileInfo> newCacheFiles = new();
|
||||||
|
|
||||||
if (shaderCacheDir.Exists)
|
if (shaderCacheDir.Exists)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,11 +13,11 @@ namespace Ryujinx.Ui.Widgets
|
||||||
private GtkDialog(string title, string mainText, string secondaryText, MessageType messageType = MessageType.Other, ButtonsType buttonsType = ButtonsType.Ok)
|
private GtkDialog(string title, string mainText, string secondaryText, MessageType messageType = MessageType.Other, ButtonsType buttonsType = ButtonsType.Ok)
|
||||||
: base(null, DialogFlags.Modal, messageType, buttonsType, null)
|
: base(null, DialogFlags.Modal, messageType, buttonsType, null)
|
||||||
{
|
{
|
||||||
Title = title;
|
Title = title;
|
||||||
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
||||||
Text = mainText;
|
Text = mainText;
|
||||||
SecondaryText = secondaryText;
|
SecondaryText = secondaryText;
|
||||||
WindowPosition = WindowPosition.Center;
|
WindowPosition = WindowPosition.Center;
|
||||||
SecondaryUseMarkup = true;
|
SecondaryUseMarkup = true;
|
||||||
|
|
||||||
Response += GtkDialog_Response;
|
Response += GtkDialog_Response;
|
||||||
|
@ -80,7 +80,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
|
|
||||||
internal static ResponseType CreateCustomDialog(string title, string mainText, string secondaryText, Dictionary<int, string> buttons, MessageType messageType = MessageType.Other)
|
internal static ResponseType CreateCustomDialog(string title, string mainText, string secondaryText, Dictionary<int, string> buttons, MessageType messageType = MessageType.Other)
|
||||||
{
|
{
|
||||||
GtkDialog gtkDialog = new GtkDialog(title, mainText, secondaryText, messageType, ButtonsType.None);
|
GtkDialog gtkDialog = new(title, mainText, secondaryText, messageType, ButtonsType.None);
|
||||||
|
|
||||||
foreach (var button in buttons)
|
foreach (var button in buttons)
|
||||||
{
|
{
|
||||||
|
@ -92,9 +92,9 @@ namespace Ryujinx.Ui.Widgets
|
||||||
|
|
||||||
internal static string CreateInputDialog(Window parent, string title, string mainText, uint inputMax)
|
internal static string CreateInputDialog(Window parent, string title, string mainText, uint inputMax)
|
||||||
{
|
{
|
||||||
GtkInputDialog gtkDialog = new GtkInputDialog(parent, title, mainText, inputMax);
|
GtkInputDialog gtkDialog = new(parent, title, mainText, inputMax);
|
||||||
ResponseType response = (ResponseType)gtkDialog.Run();
|
ResponseType response = (ResponseType)gtkDialog.Run();
|
||||||
string responseText = gtkDialog.InputEntry.Text.TrimEnd();
|
string responseText = gtkDialog.InputEntry.Text.TrimEnd();
|
||||||
|
|
||||||
gtkDialog.Dispose();
|
gtkDialog.Dispose();
|
||||||
|
|
||||||
|
|
|
@ -12,23 +12,23 @@ namespace Ryujinx.Ui.Widgets
|
||||||
|
|
||||||
Title = title;
|
Title = title;
|
||||||
|
|
||||||
Label mainTextLabel = new Label
|
Label mainTextLabel = new()
|
||||||
{
|
{
|
||||||
Text = mainText
|
Text = mainText,
|
||||||
};
|
};
|
||||||
|
|
||||||
InputEntry = new Entry
|
InputEntry = new Entry
|
||||||
{
|
{
|
||||||
MaxLength = (int)inputMax
|
MaxLength = (int)inputMax,
|
||||||
};
|
};
|
||||||
|
|
||||||
Label inputMaxTextLabel = new Label
|
Label inputMaxTextLabel = new()
|
||||||
{
|
{
|
||||||
Text = $"(Max length: {inputMax})"
|
Text = $"(Max length: {inputMax})",
|
||||||
};
|
};
|
||||||
|
|
||||||
((Box)MessageArea).PackStart(mainTextLabel, true, true, 0);
|
((Box)MessageArea).PackStart(mainTextLabel, true, true, 0);
|
||||||
((Box)MessageArea).PackStart(InputEntry, true, true, 5);
|
((Box)MessageArea).PackStart(InputEntry, true, true, 5);
|
||||||
((Box)MessageArea).PackStart(inputMaxTextLabel, true, true, 0);
|
((Box)MessageArea).PackStart(inputMaxTextLabel, true, true, 0);
|
||||||
|
|
||||||
ShowAll();
|
ShowAll();
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
{
|
{
|
||||||
public string FileName { get; private set; }
|
public string FileName { get; private set; }
|
||||||
|
|
||||||
#pragma warning disable CS0649, IDE0044
|
#pragma warning disable CS0649, IDE0044 // Field is never assigned to, Add readonly modifier
|
||||||
[GUI] Entry _profileEntry;
|
[GUI] Entry _profileEntry;
|
||||||
[GUI] Label _errorMessage;
|
[GUI] Label _errorMessage;
|
||||||
#pragma warning restore CS0649, IDE0044
|
#pragma warning restore CS0649, IDE0044
|
||||||
|
|
|
@ -6,9 +6,9 @@ namespace Ryujinx.Ui.Widgets
|
||||||
{
|
{
|
||||||
internal class UserErrorDialog : MessageDialog
|
internal class UserErrorDialog : MessageDialog
|
||||||
{
|
{
|
||||||
private const string SetupGuideUrl = "https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide";
|
private const string SetupGuideUrl = "https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide";
|
||||||
private const int OkResponseId = 0;
|
private const int OkResponseId = 0;
|
||||||
private const int SetupGuideResponseId = 1;
|
private const int SetupGuideResponseId = 1;
|
||||||
|
|
||||||
private readonly UserError _userError;
|
private readonly UserError _userError;
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
{
|
{
|
||||||
_userError = error;
|
_userError = error;
|
||||||
|
|
||||||
WindowPosition = WindowPosition.Center;
|
WindowPosition = WindowPosition.Center;
|
||||||
SecondaryUseMarkup = true;
|
SecondaryUseMarkup = true;
|
||||||
|
|
||||||
Response += UserErrorDialog_Response;
|
Response += UserErrorDialog_Response;
|
||||||
|
@ -36,8 +36,8 @@ namespace Ryujinx.Ui.Widgets
|
||||||
|
|
||||||
SecondaryUseMarkup = true;
|
SecondaryUseMarkup = true;
|
||||||
|
|
||||||
Title = $"Ryujinx error ({errorCode})";
|
Title = $"Ryujinx error ({errorCode})";
|
||||||
Text = $"{errorCode}: {GetErrorTitle(error)}";
|
Text = $"{errorCode}: {GetErrorTitle(error)}";
|
||||||
SecondaryText = GetErrorDescription(error);
|
SecondaryText = GetErrorDescription(error);
|
||||||
|
|
||||||
if (isInSetupGuide)
|
if (isInSetupGuide)
|
||||||
|
@ -46,34 +46,34 @@ namespace Ryujinx.Ui.Widgets
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetErrorCode(UserError error)
|
private static string GetErrorCode(UserError error)
|
||||||
{
|
{
|
||||||
return $"RYU-{(uint)error:X4}";
|
return $"RYU-{(uint)error:X4}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetErrorTitle(UserError error)
|
private static string GetErrorTitle(UserError error)
|
||||||
{
|
{
|
||||||
return error switch
|
return error switch
|
||||||
{
|
{
|
||||||
UserError.NoKeys => "Keys not found",
|
UserError.NoKeys => "Keys not found",
|
||||||
UserError.NoFirmware => "Firmware not found",
|
UserError.NoFirmware => "Firmware not found",
|
||||||
UserError.FirmwareParsingFailed => "Firmware parsing error",
|
UserError.FirmwareParsingFailed => "Firmware parsing error",
|
||||||
UserError.ApplicationNotFound => "Application not found",
|
UserError.ApplicationNotFound => "Application not found",
|
||||||
UserError.Unknown => "Unknown error",
|
UserError.Unknown => "Unknown error",
|
||||||
_ => "Undefined error",
|
_ => "Undefined error",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetErrorDescription(UserError error)
|
private static string GetErrorDescription(UserError error)
|
||||||
{
|
{
|
||||||
return error switch
|
return error switch
|
||||||
{
|
{
|
||||||
UserError.NoKeys => "Ryujinx was unable to find your 'prod.keys' file",
|
UserError.NoKeys => "Ryujinx was unable to find your 'prod.keys' file",
|
||||||
UserError.NoFirmware => "Ryujinx was unable to find any firmwares installed",
|
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.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.ApplicationNotFound => "Ryujinx couldn't find a valid application at the given path.",
|
||||||
UserError.Unknown => "An unknown error occured!",
|
UserError.Unknown => "An unknown error occured!",
|
||||||
_ => "An undefined error occured! This shouldn't happen, please contact a dev!",
|
_ => "An undefined error occured! This shouldn't happen, please contact a dev!",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ namespace Ryujinx.Ui.Widgets
|
||||||
UserError.NoKeys or
|
UserError.NoKeys or
|
||||||
UserError.NoFirmware or
|
UserError.NoFirmware or
|
||||||
UserError.FirmwareParsingFailed => true,
|
UserError.FirmwareParsingFailed => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,9 +97,9 @@ namespace Ryujinx.Ui.Widgets
|
||||||
|
|
||||||
return error switch
|
return error switch
|
||||||
{
|
{
|
||||||
UserError.NoKeys => SetupGuideUrl + "#initial-setup---placement-of-prodkeys",
|
UserError.NoKeys => SetupGuideUrl + "#initial-setup---placement-of-prodkeys",
|
||||||
UserError.NoFirmware => SetupGuideUrl + "#initial-setup-continued---installation-of-firmware",
|
UserError.NoFirmware => SetupGuideUrl + "#initial-setup-continued---installation-of-firmware",
|
||||||
_ => SetupGuideUrl,
|
_ => SetupGuideUrl,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
214
src/Ryujinx/Ui/Windows/AboutWindow.Designer.cs
generated
214
src/Ryujinx/Ui/Windows/AboutWindow.Designer.cs
generated
|
@ -7,65 +7,63 @@ namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
public partial class AboutWindow : Window
|
public partial class AboutWindow : Window
|
||||||
{
|
{
|
||||||
private Box _mainBox;
|
private Box _mainBox;
|
||||||
private Box _leftBox;
|
private Box _leftBox;
|
||||||
private Box _logoBox;
|
private Box _logoBox;
|
||||||
private Image _ryujinxLogo;
|
private Image _ryujinxLogo;
|
||||||
private Box _logoTextBox;
|
private Box _logoTextBox;
|
||||||
private Label _ryujinxLabel;
|
private Label _ryujinxLabel;
|
||||||
private Label _ryujinxPhoneticLabel;
|
private Label _ryujinxPhoneticLabel;
|
||||||
private EventBox _ryujinxLink;
|
private EventBox _ryujinxLink;
|
||||||
private Label _ryujinxLinkLabel;
|
private Label _ryujinxLinkLabel;
|
||||||
private Label _versionLabel;
|
private Label _versionLabel;
|
||||||
private Label _disclaimerLabel;
|
private Label _disclaimerLabel;
|
||||||
private EventBox _amiiboApiLink;
|
private EventBox _amiiboApiLink;
|
||||||
private Label _amiiboApiLinkLabel;
|
private Label _amiiboApiLinkLabel;
|
||||||
private Box _socialBox;
|
private Box _socialBox;
|
||||||
private EventBox _patreonEventBox;
|
private EventBox _patreonEventBox;
|
||||||
private Box _patreonBox;
|
private Box _patreonBox;
|
||||||
private Image _patreonLogo;
|
private Image _patreonLogo;
|
||||||
private Label _patreonLabel;
|
private Label _patreonLabel;
|
||||||
private EventBox _githubEventBox;
|
private EventBox _githubEventBox;
|
||||||
private Box _githubBox;
|
private Box _githubBox;
|
||||||
private Image _githubLogo;
|
private Image _githubLogo;
|
||||||
private Label _githubLabel;
|
private Label _githubLabel;
|
||||||
private Box _discordBox;
|
private Box _discordBox;
|
||||||
private EventBox _discordEventBox;
|
private EventBox _discordEventBox;
|
||||||
private Image _discordLogo;
|
private Image _discordLogo;
|
||||||
private Label _discordLabel;
|
private Label _discordLabel;
|
||||||
private EventBox _twitterEventBox;
|
private EventBox _twitterEventBox;
|
||||||
private Box _twitterBox;
|
private Box _twitterBox;
|
||||||
private Image _twitterLogo;
|
private Image _twitterLogo;
|
||||||
private Label _twitterLabel;
|
private Label _twitterLabel;
|
||||||
private Separator _separator;
|
private Separator _separator;
|
||||||
private Box _rightBox;
|
private Box _rightBox;
|
||||||
private Label _aboutLabel;
|
private Label _aboutLabel;
|
||||||
private Label _aboutDescriptionLabel;
|
private Label _aboutDescriptionLabel;
|
||||||
private Label _createdByLabel;
|
private Label _createdByLabel;
|
||||||
private TextView _createdByText;
|
private TextView _createdByText;
|
||||||
private EventBox _contributorsEventBox;
|
private EventBox _contributorsEventBox;
|
||||||
private Label _contributorsLinkLabel;
|
private Label _contributorsLinkLabel;
|
||||||
private Label _patreonNamesLabel;
|
private Label _patreonNamesLabel;
|
||||||
private ScrolledWindow _patreonNamesScrolled;
|
private ScrolledWindow _patreonNamesScrolled;
|
||||||
private TextView _patreonNamesText;
|
private TextView _patreonNamesText;
|
||||||
private EventBox _changelogEventBox;
|
private EventBox _changelogEventBox;
|
||||||
private Label _changelogLinkLabel;
|
private Label _changelogLinkLabel;
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
|
|
||||||
#pragma warning disable CS0612
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// AboutWindow
|
// AboutWindow
|
||||||
//
|
//
|
||||||
CanFocus = false;
|
CanFocus = false;
|
||||||
Resizable = false;
|
Resizable = false;
|
||||||
Modal = true;
|
Modal = true;
|
||||||
WindowPosition = WindowPosition.Center;
|
WindowPosition = WindowPosition.Center;
|
||||||
DefaultWidth = 800;
|
DefaultWidth = 800;
|
||||||
DefaultHeight = 450;
|
DefaultHeight = 450;
|
||||||
TypeHint = Gdk.WindowTypeHint.Dialog;
|
TypeHint = Gdk.WindowTypeHint.Dialog;
|
||||||
|
|
||||||
//
|
//
|
||||||
// _mainBox
|
// _mainBox
|
||||||
|
@ -77,9 +75,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_leftBox = new Box(Orientation.Vertical, 0)
|
_leftBox = new Box(Orientation.Vertical, 0)
|
||||||
{
|
{
|
||||||
Margin = 15,
|
Margin = 15,
|
||||||
MarginLeft = 30,
|
MarginStart = 30,
|
||||||
MarginRight = 0
|
MarginEnd = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -92,8 +90,8 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_ryujinxLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png", 100, 100))
|
_ryujinxLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png", 100, 100))
|
||||||
{
|
{
|
||||||
Margin = 10,
|
Margin = 10,
|
||||||
MarginLeft = 15
|
MarginStart = 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -106,9 +104,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_ryujinxLabel = new Label("Ryujinx")
|
_ryujinxLabel = new Label("Ryujinx")
|
||||||
{
|
{
|
||||||
MarginTop = 15,
|
MarginTop = 15,
|
||||||
Justify = Justification.Center,
|
Justify = Justification.Center,
|
||||||
Attributes = new AttrList()
|
Attributes = new AttrList(),
|
||||||
};
|
};
|
||||||
_ryujinxLabel.Attributes.Insert(new Pango.AttrScale(2.7f));
|
_ryujinxLabel.Attributes.Insert(new Pango.AttrScale(2.7f));
|
||||||
|
|
||||||
|
@ -117,7 +115,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_ryujinxPhoneticLabel = new Label("(REE-YOU-JINX)")
|
_ryujinxPhoneticLabel = new Label("(REE-YOU-JINX)")
|
||||||
{
|
{
|
||||||
Justify = Justification.Center
|
Justify = Justification.Center,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -135,8 +133,8 @@ namespace Ryujinx.Ui.Windows
|
||||||
_ryujinxLinkLabel = new Label("www.ryujinx.org")
|
_ryujinxLinkLabel = new Label("www.ryujinx.org")
|
||||||
{
|
{
|
||||||
TooltipText = "Click to open the Ryujinx website in your default browser.",
|
TooltipText = "Click to open the Ryujinx website in your default browser.",
|
||||||
Justify = Justification.Center,
|
Justify = Justification.Center,
|
||||||
Attributes = new AttrList()
|
Attributes = new AttrList(),
|
||||||
};
|
};
|
||||||
_ryujinxLinkLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
|
_ryujinxLinkLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
|
||||||
|
|
||||||
|
@ -145,9 +143,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_versionLabel = new Label(Program.Version)
|
_versionLabel = new Label(Program.Version)
|
||||||
{
|
{
|
||||||
Expand = true,
|
Expand = true,
|
||||||
Justify = Justification.Center,
|
Justify = Justification.Center,
|
||||||
Margin = 5
|
Margin = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -163,7 +161,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
TooltipText = "Click to open the changelog for this version in your default browser.",
|
TooltipText = "Click to open the changelog for this version in your default browser.",
|
||||||
Justify = Justification.Center,
|
Justify = Justification.Center,
|
||||||
Attributes = new AttrList()
|
Attributes = new AttrList(),
|
||||||
};
|
};
|
||||||
_changelogLinkLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
|
_changelogLinkLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
|
||||||
|
|
||||||
|
@ -172,10 +170,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_disclaimerLabel = new Label("Ryujinx is not affiliated with Nintendo™,\nor any of its partners, in any way.")
|
_disclaimerLabel = new Label("Ryujinx is not affiliated with Nintendo™,\nor any of its partners, in any way.")
|
||||||
{
|
{
|
||||||
Expand = true,
|
Expand = true,
|
||||||
Justify = Justification.Center,
|
Justify = Justification.Center,
|
||||||
Margin = 5,
|
Margin = 5,
|
||||||
Attributes = new AttrList()
|
Attributes = new AttrList(),
|
||||||
};
|
};
|
||||||
_disclaimerLabel.Attributes.Insert(new Pango.AttrScale(0.8f));
|
_disclaimerLabel.Attributes.Insert(new Pango.AttrScale(0.8f));
|
||||||
|
|
||||||
|
@ -184,7 +182,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_amiiboApiLink = new EventBox()
|
_amiiboApiLink = new EventBox()
|
||||||
{
|
{
|
||||||
Margin = 5
|
Margin = 5,
|
||||||
};
|
};
|
||||||
_amiiboApiLink.ButtonPressEvent += AmiiboApiButton_Pressed;
|
_amiiboApiLink.ButtonPressEvent += AmiiboApiButton_Pressed;
|
||||||
|
|
||||||
|
@ -194,8 +192,8 @@ namespace Ryujinx.Ui.Windows
|
||||||
_amiiboApiLinkLabel = new Label("AmiiboAPI (www.amiiboapi.com) is used\nin our Amiibo emulation.")
|
_amiiboApiLinkLabel = new Label("AmiiboAPI (www.amiiboapi.com) is used\nin our Amiibo emulation.")
|
||||||
{
|
{
|
||||||
TooltipText = "Click to open the AmiiboAPI website in your default browser.",
|
TooltipText = "Click to open the AmiiboAPI website in your default browser.",
|
||||||
Justify = Justification.Center,
|
Justify = Justification.Center,
|
||||||
Attributes = new AttrList()
|
Attributes = new AttrList(),
|
||||||
};
|
};
|
||||||
_amiiboApiLinkLabel.Attributes.Insert(new Pango.AttrScale(0.9f));
|
_amiiboApiLinkLabel.Attributes.Insert(new Pango.AttrScale(0.9f));
|
||||||
|
|
||||||
|
@ -204,8 +202,8 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_socialBox = new Box(Orientation.Horizontal, 0)
|
_socialBox = new Box(Orientation.Horizontal, 0)
|
||||||
{
|
{
|
||||||
Margin = 25,
|
Margin = 25,
|
||||||
MarginBottom = 10
|
MarginBottom = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -213,7 +211,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_patreonEventBox = new EventBox()
|
_patreonEventBox = new EventBox()
|
||||||
{
|
{
|
||||||
TooltipText = "Click to open the Ryujinx Patreon page in your default browser."
|
TooltipText = "Click to open the Ryujinx Patreon page in your default browser.",
|
||||||
};
|
};
|
||||||
_patreonEventBox.ButtonPressEvent += PatreonButton_Pressed;
|
_patreonEventBox.ButtonPressEvent += PatreonButton_Pressed;
|
||||||
|
|
||||||
|
@ -227,7 +225,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_patreonLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Patreon_Light.png", 30, 30))
|
_patreonLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Patreon_Light.png", 30, 30))
|
||||||
{
|
{
|
||||||
Margin = 10
|
Margin = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -235,7 +233,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_patreonLabel = new Label("Patreon")
|
_patreonLabel = new Label("Patreon")
|
||||||
{
|
{
|
||||||
Justify = Justification.Center
|
Justify = Justification.Center,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -243,7 +241,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_githubEventBox = new EventBox()
|
_githubEventBox = new EventBox()
|
||||||
{
|
{
|
||||||
TooltipText = "Click to open the Ryujinx GitHub page in your default browser."
|
TooltipText = "Click to open the Ryujinx GitHub page in your default browser.",
|
||||||
};
|
};
|
||||||
_githubEventBox.ButtonPressEvent += GitHubButton_Pressed;
|
_githubEventBox.ButtonPressEvent += GitHubButton_Pressed;
|
||||||
|
|
||||||
|
@ -257,7 +255,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_githubLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_GitHub_Light.png", 30, 30))
|
_githubLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_GitHub_Light.png", 30, 30))
|
||||||
{
|
{
|
||||||
Margin = 10
|
Margin = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -265,7 +263,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_githubLabel = new Label("GitHub")
|
_githubLabel = new Label("GitHub")
|
||||||
{
|
{
|
||||||
Justify = Justification.Center
|
Justify = Justification.Center,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -278,7 +276,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_discordEventBox = new EventBox()
|
_discordEventBox = new EventBox()
|
||||||
{
|
{
|
||||||
TooltipText = "Click to open an invite to the Ryujinx Discord server in your default browser."
|
TooltipText = "Click to open an invite to the Ryujinx Discord server in your default browser.",
|
||||||
};
|
};
|
||||||
_discordEventBox.ButtonPressEvent += DiscordButton_Pressed;
|
_discordEventBox.ButtonPressEvent += DiscordButton_Pressed;
|
||||||
|
|
||||||
|
@ -287,7 +285,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_discordLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Discord_Light.png", 30, 30))
|
_discordLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Discord_Light.png", 30, 30))
|
||||||
{
|
{
|
||||||
Margin = 10
|
Margin = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -295,7 +293,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_discordLabel = new Label("Discord")
|
_discordLabel = new Label("Discord")
|
||||||
{
|
{
|
||||||
Justify = Justification.Center
|
Justify = Justification.Center,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -303,7 +301,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_twitterEventBox = new EventBox()
|
_twitterEventBox = new EventBox()
|
||||||
{
|
{
|
||||||
TooltipText = "Click to open the Ryujinx Twitter page in your default browser."
|
TooltipText = "Click to open the Ryujinx Twitter page in your default browser.",
|
||||||
};
|
};
|
||||||
_twitterEventBox.ButtonPressEvent += TwitterButton_Pressed;
|
_twitterEventBox.ButtonPressEvent += TwitterButton_Pressed;
|
||||||
|
|
||||||
|
@ -317,7 +315,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_twitterLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Twitter_Light.png", 30, 30))
|
_twitterLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Twitter_Light.png", 30, 30))
|
||||||
{
|
{
|
||||||
Margin = 10
|
Margin = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -325,7 +323,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_twitterLabel = new Label("Twitter")
|
_twitterLabel = new Label("Twitter")
|
||||||
{
|
{
|
||||||
Justify = Justification.Center
|
Justify = Justification.Center,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -333,7 +331,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_separator = new Separator(Orientation.Vertical)
|
_separator = new Separator(Orientation.Vertical)
|
||||||
{
|
{
|
||||||
Margin = 15
|
Margin = 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -341,8 +339,8 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_rightBox = new Box(Orientation.Vertical, 0)
|
_rightBox = new Box(Orientation.Vertical, 0)
|
||||||
{
|
{
|
||||||
Margin = 15,
|
Margin = 15,
|
||||||
MarginTop = 40
|
MarginTop = 40,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -350,8 +348,8 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_aboutLabel = new Label("About :")
|
_aboutLabel = new Label("About :")
|
||||||
{
|
{
|
||||||
Halign = Align.Start,
|
Halign = Align.Start,
|
||||||
Attributes = new AttrList()
|
Attributes = new AttrList(),
|
||||||
};
|
};
|
||||||
_aboutLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
|
_aboutLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
|
||||||
_aboutLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
|
_aboutLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
|
||||||
|
@ -365,7 +363,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
"Developers interested in contributing can find out more on our GitHub or Discord.")
|
"Developers interested in contributing can find out more on our GitHub or Discord.")
|
||||||
{
|
{
|
||||||
Margin = 15,
|
Margin = 15,
|
||||||
Halign = Align.Start
|
Halign = Align.Start,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -373,8 +371,8 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_createdByLabel = new Label("Maintained by :")
|
_createdByLabel = new Label("Maintained by :")
|
||||||
{
|
{
|
||||||
Halign = Align.Start,
|
Halign = Align.Start,
|
||||||
Attributes = new AttrList()
|
Attributes = new AttrList(),
|
||||||
};
|
};
|
||||||
_createdByLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
|
_createdByLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
|
||||||
_createdByLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
|
_createdByLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
|
||||||
|
@ -384,11 +382,11 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_createdByText = new TextView()
|
_createdByText = new TextView()
|
||||||
{
|
{
|
||||||
WrapMode = Gtk.WrapMode.Word,
|
WrapMode = Gtk.WrapMode.Word,
|
||||||
Editable = false,
|
Editable = false,
|
||||||
CursorVisible = false,
|
CursorVisible = false,
|
||||||
Margin = 15,
|
Margin = 15,
|
||||||
MarginRight = 30
|
MarginEnd = 30,
|
||||||
};
|
};
|
||||||
_createdByText.Buffer.Text = "gdkchan, Ac_K, Thog, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, Xpl0itR, GoffyDude, »jD« and more...";
|
_createdByText.Buffer.Text = "gdkchan, Ac_K, Thog, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, Xpl0itR, GoffyDude, »jD« and more...";
|
||||||
|
|
||||||
|
@ -404,9 +402,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
_contributorsLinkLabel = new Label("See All Contributors...")
|
_contributorsLinkLabel = new Label("See All Contributors...")
|
||||||
{
|
{
|
||||||
TooltipText = "Click to open the Contributors page in your default browser.",
|
TooltipText = "Click to open the Contributors page in your default browser.",
|
||||||
MarginRight = 30,
|
MarginEnd = 30,
|
||||||
Halign = Align.End,
|
Halign = Align.End,
|
||||||
Attributes = new AttrList()
|
Attributes = new AttrList(),
|
||||||
};
|
};
|
||||||
_contributorsLinkLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
|
_contributorsLinkLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
|
||||||
|
|
||||||
|
@ -415,8 +413,8 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_patreonNamesLabel = new Label("Supported on Patreon by :")
|
_patreonNamesLabel = new Label("Supported on Patreon by :")
|
||||||
{
|
{
|
||||||
Halign = Align.Start,
|
Halign = Align.Start,
|
||||||
Attributes = new AttrList()
|
Attributes = new AttrList(),
|
||||||
};
|
};
|
||||||
_patreonNamesLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
|
_patreonNamesLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
|
||||||
_patreonNamesLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
|
_patreonNamesLabel.Attributes.Insert(new Pango.AttrUnderline(Underline.Single));
|
||||||
|
@ -426,10 +424,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_patreonNamesScrolled = new ScrolledWindow()
|
_patreonNamesScrolled = new ScrolledWindow()
|
||||||
{
|
{
|
||||||
Margin = 15,
|
Margin = 15,
|
||||||
MarginRight = 30,
|
MarginEnd = 30,
|
||||||
Expand = true,
|
Expand = true,
|
||||||
ShadowType = ShadowType.In
|
ShadowType = ShadowType.In,
|
||||||
};
|
};
|
||||||
_patreonNamesScrolled.SetPolicy(PolicyType.Never, PolicyType.Automatic);
|
_patreonNamesScrolled.SetPolicy(PolicyType.Never, PolicyType.Automatic);
|
||||||
|
|
||||||
|
@ -438,13 +436,11 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_patreonNamesText = new TextView()
|
_patreonNamesText = new TextView()
|
||||||
{
|
{
|
||||||
WrapMode = Gtk.WrapMode.Word
|
WrapMode = Gtk.WrapMode.Word,
|
||||||
};
|
};
|
||||||
_patreonNamesText.Buffer.Text = "Loading...";
|
_patreonNamesText.Buffer.Text = "Loading...";
|
||||||
_patreonNamesText.SetProperty("editable", new GLib.Value(false));
|
_patreonNamesText.SetProperty("editable", new GLib.Value(false));
|
||||||
|
|
||||||
#pragma warning restore CS0612
|
|
||||||
|
|
||||||
ShowComponent();
|
ShowComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
_patreonNamesText.Buffer.Text = "Connection Error.";
|
_patreonNamesText.Buffer.Text = "Connection Error.";
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpClient httpClient = new HttpClient();
|
HttpClient httpClient = new();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
76
src/Ryujinx/Ui/Windows/AmiiboWindow.Designer.cs
generated
76
src/Ryujinx/Ui/Windows/AmiiboWindow.Designer.cs
generated
|
@ -4,37 +4,35 @@ namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
public partial class AmiiboWindow : Window
|
public partial class AmiiboWindow : Window
|
||||||
{
|
{
|
||||||
private Box _mainBox;
|
private Box _mainBox;
|
||||||
private ButtonBox _buttonBox;
|
private ButtonBox _buttonBox;
|
||||||
private Button _scanButton;
|
private Button _scanButton;
|
||||||
private Button _cancelButton;
|
private Button _cancelButton;
|
||||||
private CheckButton _randomUuidCheckBox;
|
private CheckButton _randomUuidCheckBox;
|
||||||
private Box _amiiboBox;
|
private Box _amiiboBox;
|
||||||
private Box _amiiboHeadBox;
|
private Box _amiiboHeadBox;
|
||||||
private Box _amiiboSeriesBox;
|
private Box _amiiboSeriesBox;
|
||||||
private Label _amiiboSeriesLabel;
|
private Label _amiiboSeriesLabel;
|
||||||
private ComboBoxText _amiiboSeriesComboBox;
|
private ComboBoxText _amiiboSeriesComboBox;
|
||||||
private Box _amiiboCharsBox;
|
private Box _amiiboCharsBox;
|
||||||
private Label _amiiboCharsLabel;
|
private Label _amiiboCharsLabel;
|
||||||
private ComboBoxText _amiiboCharsComboBox;
|
private ComboBoxText _amiiboCharsComboBox;
|
||||||
private CheckButton _showAllCheckBox;
|
private CheckButton _showAllCheckBox;
|
||||||
private Image _amiiboImage;
|
private Image _amiiboImage;
|
||||||
private Label _gameUsageLabel;
|
private Label _gameUsageLabel;
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0612
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// AmiiboWindow
|
// AmiiboWindow
|
||||||
//
|
//
|
||||||
CanFocus = false;
|
CanFocus = false;
|
||||||
Resizable = false;
|
Resizable = false;
|
||||||
Modal = true;
|
Modal = true;
|
||||||
WindowPosition = WindowPosition.Center;
|
WindowPosition = WindowPosition.Center;
|
||||||
DefaultWidth = 600;
|
DefaultWidth = 600;
|
||||||
DefaultHeight = 470;
|
DefaultHeight = 470;
|
||||||
TypeHint = Gdk.WindowTypeHint.Dialog;
|
TypeHint = Gdk.WindowTypeHint.Dialog;
|
||||||
|
|
||||||
//
|
//
|
||||||
// _mainBox
|
// _mainBox
|
||||||
|
@ -46,8 +44,8 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_buttonBox = new ButtonBox(Orientation.Horizontal)
|
_buttonBox = new ButtonBox(Orientation.Horizontal)
|
||||||
{
|
{
|
||||||
Margin = 20,
|
Margin = 20,
|
||||||
LayoutStyle = ButtonBoxStyle.End
|
LayoutStyle = ButtonBoxStyle.End,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -55,10 +53,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_scanButton = new Button()
|
_scanButton = new Button()
|
||||||
{
|
{
|
||||||
Label = "Scan It!",
|
Label = "Scan It!",
|
||||||
CanFocus = true,
|
CanFocus = true,
|
||||||
ReceivesDefault = true,
|
ReceivesDefault = true,
|
||||||
MarginLeft = 10
|
MarginStart = 10,
|
||||||
};
|
};
|
||||||
_scanButton.Clicked += ScanButton_Pressed;
|
_scanButton.Clicked += ScanButton_Pressed;
|
||||||
|
|
||||||
|
@ -67,8 +65,8 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_randomUuidCheckBox = new CheckButton()
|
_randomUuidCheckBox = new CheckButton()
|
||||||
{
|
{
|
||||||
Label = "Hack: Use Random Tag Uuid",
|
Label = "Hack: Use Random Tag Uuid",
|
||||||
TooltipText = "This allows multiple scans of a single Amiibo.\n(used in The Legend of Zelda: Breath of the Wild)"
|
TooltipText = "This allows multiple scans of a single Amiibo.\n(used in The Legend of Zelda: Breath of the Wild)",
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -76,10 +74,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_cancelButton = new Button()
|
_cancelButton = new Button()
|
||||||
{
|
{
|
||||||
Label = "Cancel",
|
Label = "Cancel",
|
||||||
CanFocus = true,
|
CanFocus = true,
|
||||||
ReceivesDefault = true,
|
ReceivesDefault = true,
|
||||||
MarginLeft = 10
|
MarginStart = 10,
|
||||||
};
|
};
|
||||||
_cancelButton.Clicked += CancelButton_Pressed;
|
_cancelButton.Clicked += CancelButton_Pressed;
|
||||||
|
|
||||||
|
@ -94,7 +92,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
_amiiboHeadBox = new Box(Orientation.Horizontal, 0)
|
_amiiboHeadBox = new Box(Orientation.Horizontal, 0)
|
||||||
{
|
{
|
||||||
Margin = 20,
|
Margin = 20,
|
||||||
Hexpand = true
|
Hexpand = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -102,7 +100,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_amiiboSeriesBox = new Box(Orientation.Horizontal, 0)
|
_amiiboSeriesBox = new Box(Orientation.Horizontal, 0)
|
||||||
{
|
{
|
||||||
Hexpand = true
|
Hexpand = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -120,7 +118,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_amiiboCharsBox = new Box(Orientation.Horizontal, 0)
|
_amiiboCharsBox = new Box(Orientation.Horizontal, 0)
|
||||||
{
|
{
|
||||||
Hexpand = true
|
Hexpand = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -138,7 +136,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_showAllCheckBox = new CheckButton()
|
_showAllCheckBox = new CheckButton()
|
||||||
{
|
{
|
||||||
Label = "Show All Amiibo"
|
Label = "Show All Amiibo",
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -147,7 +145,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
_amiiboImage = new Image()
|
_amiiboImage = new Image()
|
||||||
{
|
{
|
||||||
HeightRequest = 350,
|
HeightRequest = 350,
|
||||||
WidthRequest = 350
|
WidthRequest = 350,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -155,11 +153,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_gameUsageLabel = new Label("")
|
_gameUsageLabel = new Label("")
|
||||||
{
|
{
|
||||||
MarginTop = 20
|
MarginTop = 20,
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma warning restore CS0612
|
|
||||||
|
|
||||||
ShowComponent();
|
ShowComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,21 +14,19 @@ using System.Net.Http;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AmiiboApi = Ryujinx.Ui.Common.Models.Amiibo.AmiiboApi;
|
|
||||||
using AmiiboJsonSerializerContext = Ryujinx.Ui.Common.Models.Amiibo.AmiiboJsonSerializerContext;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Windows
|
namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
public partial class AmiiboWindow : Window
|
public partial class AmiiboWindow : Window
|
||||||
{
|
{
|
||||||
private const string DEFAULT_JSON = "{ \"amiibo\": [] }";
|
private const string DefaultJson = "{ \"amiibo\": [] }";
|
||||||
|
|
||||||
public string AmiiboId { get; private set; }
|
public string AmiiboId { get; private set; }
|
||||||
|
|
||||||
public int DeviceId { get; set; }
|
public int DeviceId { get; set; }
|
||||||
public string TitleId { get; set; }
|
public string TitleId { get; set; }
|
||||||
public string LastScannedAmiiboId { get; set; }
|
public string LastScannedAmiiboId { get; set; }
|
||||||
public bool LastScannedAmiiboShowAll { get; set; }
|
public bool LastScannedAmiiboShowAll { get; set; }
|
||||||
|
|
||||||
public ResponseType Response { get; private set; }
|
public ResponseType Response { get; private set; }
|
||||||
|
|
||||||
|
@ -41,13 +39,13 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly HttpClient _httpClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly string _amiiboJsonPath;
|
private readonly string _amiiboJsonPath;
|
||||||
|
|
||||||
private readonly byte[] _amiiboLogoBytes;
|
private readonly byte[] _amiiboLogoBytes;
|
||||||
|
|
||||||
private List<AmiiboApi> _amiiboList;
|
private List<AmiiboApi> _amiiboList;
|
||||||
|
|
||||||
private static readonly AmiiboJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly AmiiboJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
public AmiiboWindow() : base($"Ryujinx {Program.Version} - Amiibo")
|
public AmiiboWindow() : base($"Ryujinx {Program.Version} - Amiibo")
|
||||||
{
|
{
|
||||||
|
@ -57,18 +55,18 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
_httpClient = new HttpClient()
|
_httpClient = new HttpClient()
|
||||||
{
|
{
|
||||||
Timeout = TimeSpan.FromSeconds(30)
|
Timeout = TimeSpan.FromSeconds(30),
|
||||||
};
|
};
|
||||||
|
|
||||||
Directory.CreateDirectory(System.IO.Path.Join(AppDataManager.BaseDirPath, "system", "amiibo"));
|
Directory.CreateDirectory(System.IO.Path.Join(AppDataManager.BaseDirPath, "system", "amiibo"));
|
||||||
|
|
||||||
_amiiboJsonPath = System.IO.Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", "Amiibo.json");
|
_amiiboJsonPath = System.IO.Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", "Amiibo.json");
|
||||||
_amiiboList = new List<AmiiboApi>();
|
_amiiboList = new List<AmiiboApi>();
|
||||||
|
|
||||||
_amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.Ui.Common/Resources/Logo_Amiibo.png");
|
_amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.Ui.Common/Resources/Logo_Amiibo.png");
|
||||||
_amiiboImage.Pixbuf = new Gdk.Pixbuf(_amiiboLogoBytes);
|
_amiiboImage.Pixbuf = new Gdk.Pixbuf(_amiiboLogoBytes);
|
||||||
|
|
||||||
_scanButton.Sensitive = false;
|
_scanButton.Sensitive = false;
|
||||||
_randomUuidCheckBox.Sensitive = false;
|
_randomUuidCheckBox.Sensitive = false;
|
||||||
|
|
||||||
_ = LoadContentAsync();
|
_ = LoadContentAsync();
|
||||||
|
@ -76,13 +74,13 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private async Task LoadContentAsync()
|
private async Task LoadContentAsync()
|
||||||
{
|
{
|
||||||
string amiiboJsonString = DEFAULT_JSON;
|
string amiiboJsonString = DefaultJson;
|
||||||
|
|
||||||
if (File.Exists(_amiiboJsonPath))
|
if (File.Exists(_amiiboJsonPath))
|
||||||
{
|
{
|
||||||
amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
|
amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
|
||||||
|
|
||||||
if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).LastUpdated))
|
if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).LastUpdated))
|
||||||
{
|
{
|
||||||
amiiboJsonString = await DownloadAmiiboJson();
|
amiiboJsonString = await DownloadAmiiboJson();
|
||||||
}
|
}
|
||||||
|
@ -103,7 +101,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_amiiboList = JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).Amiibo;
|
_amiiboList = JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).Amiibo;
|
||||||
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
||||||
|
|
||||||
if (LastScannedAmiiboShowAll)
|
if (LastScannedAmiiboShowAll)
|
||||||
|
@ -118,7 +116,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private void ParseAmiiboData()
|
private void ParseAmiiboData()
|
||||||
{
|
{
|
||||||
List<string> comboxItemList = new List<string>();
|
List<string> comboxItemList = new();
|
||||||
|
|
||||||
for (int i = 0; i < _amiiboList.Count; i++)
|
for (int i = 0; i < _amiiboList.Count; i++)
|
||||||
{
|
{
|
||||||
|
@ -149,7 +147,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
|
|
||||||
_amiiboSeriesComboBox.Changed += SeriesComboBox_Changed;
|
_amiiboSeriesComboBox.Changed += SeriesComboBox_Changed;
|
||||||
_amiiboCharsComboBox.Changed += CharacterComboBox_Changed;
|
_amiiboCharsComboBox.Changed += CharacterComboBox_Changed;
|
||||||
|
|
||||||
if (LastScannedAmiiboId != "")
|
if (LastScannedAmiiboId != "")
|
||||||
{
|
{
|
||||||
|
@ -219,7 +217,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return DEFAULT_JSON;
|
return DefaultJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateAmiiboPreview(string imageUrl)
|
private async Task UpdateAmiiboPreview(string imageUrl)
|
||||||
|
@ -228,14 +226,14 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync();
|
byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync();
|
||||||
Gdk.Pixbuf amiiboPreview = new Gdk.Pixbuf(amiiboPreviewBytes);
|
Gdk.Pixbuf amiiboPreview = new(amiiboPreviewBytes);
|
||||||
|
|
||||||
float ratio = Math.Min((float)_amiiboImage.AllocatedWidth / amiiboPreview.Width,
|
float ratio = Math.Min((float)_amiiboImage.AllocatedWidth / amiiboPreview.Width,
|
||||||
(float)_amiiboImage.AllocatedHeight / amiiboPreview.Height);
|
(float)_amiiboImage.AllocatedHeight / amiiboPreview.Height);
|
||||||
|
|
||||||
int resizeHeight = (int)(amiiboPreview.Height * ratio);
|
int resizeHeight = (int)(amiiboPreview.Height * ratio);
|
||||||
int resizeWidth = (int)(amiiboPreview.Width * ratio);
|
int resizeWidth = (int)(amiiboPreview.Width * ratio);
|
||||||
|
|
||||||
_amiiboImage.Pixbuf = amiiboPreview.ScaleSimple(resizeWidth, resizeHeight, Gdk.InterpType.Bilinear);
|
_amiiboImage.Pixbuf = amiiboPreview.ScaleSimple(resizeWidth, resizeHeight, Gdk.InterpType.Bilinear);
|
||||||
}
|
}
|
||||||
|
@ -245,7 +243,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowInfoDialog()
|
private static void ShowInfoDialog()
|
||||||
{
|
{
|
||||||
GtkDialog.CreateInfoDialog($"Amiibo API", "Unable to connect to Amiibo API server. The service may be down or you may need to verify your internet connection is online.");
|
GtkDialog.CreateInfoDialog($"Amiibo API", "Unable to connect to Amiibo API server. The service may be down or you may need to verify your internet connection is online.");
|
||||||
}
|
}
|
||||||
|
@ -261,7 +259,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
List<AmiiboApi> amiiboSortedList = _amiiboList.Where(amiibo => amiibo.AmiiboSeries == _amiiboSeriesComboBox.ActiveId).OrderBy(amiibo => amiibo.Name).ToList();
|
List<AmiiboApi> amiiboSortedList = _amiiboList.Where(amiibo => amiibo.AmiiboSeries == _amiiboSeriesComboBox.ActiveId).OrderBy(amiibo => amiibo.Name).ToList();
|
||||||
|
|
||||||
List<string> comboxItemList = new List<string>();
|
List<string> comboxItemList = new();
|
||||||
|
|
||||||
for (int i = 0; i < amiiboSortedList.Count; i++)
|
for (int i = 0; i < amiiboSortedList.Count; i++)
|
||||||
{
|
{
|
||||||
|
@ -295,7 +293,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
_amiiboCharsComboBox.Active = 0;
|
_amiiboCharsComboBox.Active = 0;
|
||||||
|
|
||||||
_scanButton.Sensitive = true;
|
_scanButton.Sensitive = true;
|
||||||
_randomUuidCheckBox.Sensitive = true;
|
_randomUuidCheckBox.Sensitive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,12 +344,12 @@ namespace Ryujinx.Ui.Windows
|
||||||
_amiiboImage.Pixbuf = new Gdk.Pixbuf(_amiiboLogoBytes);
|
_amiiboImage.Pixbuf = new Gdk.Pixbuf(_amiiboLogoBytes);
|
||||||
|
|
||||||
_amiiboSeriesComboBox.Changed -= SeriesComboBox_Changed;
|
_amiiboSeriesComboBox.Changed -= SeriesComboBox_Changed;
|
||||||
_amiiboCharsComboBox.Changed -= CharacterComboBox_Changed;
|
_amiiboCharsComboBox.Changed -= CharacterComboBox_Changed;
|
||||||
|
|
||||||
_amiiboSeriesComboBox.RemoveAll();
|
_amiiboSeriesComboBox.RemoveAll();
|
||||||
_amiiboCharsComboBox.RemoveAll();
|
_amiiboCharsComboBox.RemoveAll();
|
||||||
|
|
||||||
_scanButton.Sensitive = false;
|
_scanButton.Sensitive = false;
|
||||||
_randomUuidCheckBox.Sensitive = false;
|
_randomUuidCheckBox.Sensitive = false;
|
||||||
|
|
||||||
new Task(() => ParseAmiiboData()).Start();
|
new Task(() => ParseAmiiboData()).Start();
|
||||||
|
@ -368,8 +366,8 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private void CancelButton_Pressed(object sender, EventArgs args)
|
private void CancelButton_Pressed(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
AmiiboId = "";
|
AmiiboId = "";
|
||||||
LastScannedAmiiboId = "";
|
LastScannedAmiiboId = "";
|
||||||
LastScannedAmiiboShowAll = false;
|
LastScannedAmiiboShowAll = false;
|
||||||
|
|
||||||
Response = ResponseType.Cancel;
|
Response = ResponseType.Cancel;
|
||||||
|
|
|
@ -18,7 +18,6 @@ using System.Buffers.Binary;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
using Image = SixLabors.ImageSharp.Image;
|
using Image = SixLabors.ImageSharp.Image;
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Windows
|
namespace Ryujinx.Ui.Windows
|
||||||
|
@ -26,23 +25,23 @@ namespace Ryujinx.Ui.Windows
|
||||||
public class AvatarWindow : Window
|
public class AvatarWindow : Window
|
||||||
{
|
{
|
||||||
public byte[] SelectedProfileImage;
|
public byte[] SelectedProfileImage;
|
||||||
public bool NewUser;
|
public bool NewUser;
|
||||||
|
|
||||||
private static Dictionary<string, byte[]> _avatarDict = new Dictionary<string, byte[]>();
|
private static readonly Dictionary<string, byte[]> _avatarDict = new();
|
||||||
|
|
||||||
private ListStore _listStore;
|
private readonly ListStore _listStore;
|
||||||
private IconView _iconView;
|
private readonly IconView _iconView;
|
||||||
private Button _setBackgroungColorButton;
|
private readonly Button _setBackgroungColorButton;
|
||||||
private Gdk.RGBA _backgroundColor;
|
private Gdk.RGBA _backgroundColor;
|
||||||
|
|
||||||
public AvatarWindow() : base($"Ryujinx {Program.Version} - Manage Accounts - Avatar")
|
public AvatarWindow() : base($"Ryujinx {Program.Version} - Manage Accounts - Avatar")
|
||||||
{
|
{
|
||||||
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
||||||
|
|
||||||
CanFocus = false;
|
CanFocus = false;
|
||||||
Resizable = false;
|
Resizable = false;
|
||||||
Modal = true;
|
Modal = true;
|
||||||
TypeHint = Gdk.WindowTypeHint.Dialog;
|
TypeHint = Gdk.WindowTypeHint.Dialog;
|
||||||
|
|
||||||
SetDefaultSize(740, 400);
|
SetDefaultSize(740, 400);
|
||||||
SetPosition(WindowPosition.Center);
|
SetPosition(WindowPosition.Center);
|
||||||
|
@ -50,54 +49,56 @@ namespace Ryujinx.Ui.Windows
|
||||||
Box vbox = new(Orientation.Vertical, 0);
|
Box vbox = new(Orientation.Vertical, 0);
|
||||||
Add(vbox);
|
Add(vbox);
|
||||||
|
|
||||||
ScrolledWindow scrolledWindow = new ScrolledWindow
|
ScrolledWindow scrolledWindow = new()
|
||||||
{
|
{
|
||||||
ShadowType = ShadowType.EtchedIn
|
ShadowType = ShadowType.EtchedIn,
|
||||||
};
|
};
|
||||||
scrolledWindow.SetPolicy(PolicyType.Automatic, PolicyType.Automatic);
|
scrolledWindow.SetPolicy(PolicyType.Automatic, PolicyType.Automatic);
|
||||||
|
|
||||||
Box hbox = new(Orientation.Horizontal, 0);
|
Box hbox = new(Orientation.Horizontal, 0);
|
||||||
|
|
||||||
Button chooseButton = new Button()
|
Button chooseButton = new()
|
||||||
{
|
{
|
||||||
Label = "Choose",
|
Label = "Choose",
|
||||||
CanFocus = true,
|
CanFocus = true,
|
||||||
ReceivesDefault = true
|
ReceivesDefault = true,
|
||||||
};
|
};
|
||||||
chooseButton.Clicked += ChooseButton_Pressed;
|
chooseButton.Clicked += ChooseButton_Pressed;
|
||||||
|
|
||||||
_setBackgroungColorButton = new Button()
|
_setBackgroungColorButton = new Button()
|
||||||
{
|
{
|
||||||
Label = "Set Background Color",
|
Label = "Set Background Color",
|
||||||
CanFocus = true
|
CanFocus = true,
|
||||||
};
|
};
|
||||||
_setBackgroungColorButton.Clicked += SetBackgroungColorButton_Pressed;
|
_setBackgroungColorButton.Clicked += SetBackgroungColorButton_Pressed;
|
||||||
|
|
||||||
_backgroundColor.Red = 1;
|
_backgroundColor.Red = 1;
|
||||||
_backgroundColor.Green = 1;
|
_backgroundColor.Green = 1;
|
||||||
_backgroundColor.Blue = 1;
|
_backgroundColor.Blue = 1;
|
||||||
_backgroundColor.Alpha = 1;
|
_backgroundColor.Alpha = 1;
|
||||||
|
|
||||||
Button closeButton = new Button()
|
Button closeButton = new()
|
||||||
{
|
{
|
||||||
Label = "Close",
|
Label = "Close",
|
||||||
CanFocus = true
|
CanFocus = true,
|
||||||
};
|
};
|
||||||
closeButton.Clicked += CloseButton_Pressed;
|
closeButton.Clicked += CloseButton_Pressed;
|
||||||
|
|
||||||
vbox.PackStart(scrolledWindow, true, true, 0);
|
vbox.PackStart(scrolledWindow, true, true, 0);
|
||||||
hbox.PackStart(chooseButton, true, true, 0);
|
hbox.PackStart(chooseButton, true, true, 0);
|
||||||
hbox.PackStart(_setBackgroungColorButton, true, true, 0);
|
hbox.PackStart(_setBackgroungColorButton, true, true, 0);
|
||||||
hbox.PackStart(closeButton, true, true, 0);
|
hbox.PackStart(closeButton, true, true, 0);
|
||||||
vbox.PackStart(hbox, false, false, 0);
|
vbox.PackStart(hbox, false, false, 0);
|
||||||
|
|
||||||
_listStore = new ListStore(typeof(string), typeof(Gdk.Pixbuf));
|
_listStore = new ListStore(typeof(string), typeof(Gdk.Pixbuf));
|
||||||
_listStore.SetSortColumnId(0, SortType.Ascending);
|
_listStore.SetSortColumnId(0, SortType.Ascending);
|
||||||
|
|
||||||
_iconView = new IconView(_listStore);
|
_iconView = new IconView(_listStore)
|
||||||
_iconView.ItemWidth = 64;
|
{
|
||||||
_iconView.ItemPadding = 10;
|
ItemWidth = 64,
|
||||||
_iconView.PixbufColumn = 1;
|
ItemPadding = 10,
|
||||||
|
PixbufColumn = 1,
|
||||||
|
};
|
||||||
|
|
||||||
_iconView.SelectionChanged += IconView_SelectionChanged;
|
_iconView.SelectionChanged += IconView_SelectionChanged;
|
||||||
|
|
||||||
|
@ -118,39 +119,36 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
|
|
||||||
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data);
|
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data);
|
||||||
string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath);
|
string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath);
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(avatarPath))
|
if (!string.IsNullOrWhiteSpace(avatarPath))
|
||||||
{
|
{
|
||||||
using (IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open))
|
using IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open);
|
||||||
|
|
||||||
|
Nca nca = new(virtualFileSystem.KeySet, ncaFileStream);
|
||||||
|
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||||
|
|
||||||
|
foreach (var item in romfs.EnumerateEntries())
|
||||||
{
|
{
|
||||||
Nca nca = new Nca(virtualFileSystem.KeySet, ncaFileStream);
|
// TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy.
|
||||||
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
|
||||||
|
|
||||||
foreach (var item in romfs.EnumerateEntries())
|
if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") && item.FullPath.Contains("szs"))
|
||||||
{
|
{
|
||||||
// TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy.
|
using var file = new UniqueRef<IFile>();
|
||||||
|
|
||||||
if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") && item.FullPath.Contains("szs"))
|
romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
{
|
|
||||||
using var file = new UniqueRef<IFile>();
|
|
||||||
|
|
||||||
romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||||
|
using MemoryStream streamPng = MemoryStreamManager.Shared.GetStream();
|
||||||
|
file.Get.AsStream().CopyTo(stream);
|
||||||
|
|
||||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
stream.Position = 0;
|
||||||
using (MemoryStream streamPng = MemoryStreamManager.Shared.GetStream())
|
|
||||||
{
|
|
||||||
file.Get.AsStream().CopyTo(stream);
|
|
||||||
|
|
||||||
stream.Position = 0;
|
Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256);
|
||||||
|
|
||||||
Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256);
|
avatarImage.SaveAsPng(streamPng);
|
||||||
|
|
||||||
avatarImage.SaveAsPng(streamPng);
|
_avatarDict.Add(item.FullPath, streamPng.ToArray());
|
||||||
|
|
||||||
_avatarDict.Add(item.FullPath, streamPng.ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,23 +163,24 @@ namespace Ryujinx.Ui.Windows
|
||||||
_listStore.AppendValues(avatar.Key, new Gdk.Pixbuf(ProcessImage(avatar.Value), 96, 96));
|
_listStore.AppendValues(avatar.Key, new Gdk.Pixbuf(ProcessImage(avatar.Value), 96, 96));
|
||||||
}
|
}
|
||||||
|
|
||||||
_iconView.SelectPath(new TreePath(new int[] { 0 }));
|
_iconView.SelectPath(new TreePath(new[] { 0 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] ProcessImage(byte[] data)
|
private byte[] ProcessImage(byte[] data)
|
||||||
{
|
{
|
||||||
using (MemoryStream streamJpg = MemoryStreamManager.Shared.GetStream())
|
using MemoryStream streamJpg = MemoryStreamManager.Shared.GetStream();
|
||||||
{
|
|
||||||
Image avatarImage = Image.Load(data, new PngDecoder());
|
|
||||||
|
|
||||||
avatarImage.Mutate(x => x.BackgroundColor(new Rgba32((byte)(_backgroundColor.Red * 255),
|
Image avatarImage = Image.Load(data, new PngDecoder());
|
||||||
(byte)(_backgroundColor.Green * 255),
|
|
||||||
(byte)(_backgroundColor.Blue * 255),
|
|
||||||
(byte)(_backgroundColor.Alpha * 255))));
|
|
||||||
avatarImage.SaveAsJpeg(streamJpg);
|
|
||||||
|
|
||||||
return streamJpg.ToArray();
|
avatarImage.Mutate(x => x.BackgroundColor(new Rgba32(
|
||||||
}
|
(byte)(_backgroundColor.Red * 255),
|
||||||
|
(byte)(_backgroundColor.Green * 255),
|
||||||
|
(byte)(_backgroundColor.Blue * 255),
|
||||||
|
(byte)(_backgroundColor.Alpha * 255)
|
||||||
|
)));
|
||||||
|
avatarImage.SaveAsJpeg(streamJpg);
|
||||||
|
|
||||||
|
return streamJpg.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CloseButton_Pressed(object sender, EventArgs e)
|
private void CloseButton_Pressed(object sender, EventArgs e)
|
||||||
|
@ -203,20 +202,19 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private void SetBackgroungColorButton_Pressed(object sender, EventArgs e)
|
private void SetBackgroungColorButton_Pressed(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
using (ColorChooserDialog colorChooserDialog = new ColorChooserDialog("Set Background Color", this))
|
using ColorChooserDialog colorChooserDialog = new("Set Background Color", this);
|
||||||
|
|
||||||
|
colorChooserDialog.UseAlpha = false;
|
||||||
|
colorChooserDialog.Rgba = _backgroundColor;
|
||||||
|
|
||||||
|
if (colorChooserDialog.Run() == (int)ResponseType.Ok)
|
||||||
{
|
{
|
||||||
colorChooserDialog.UseAlpha = false;
|
_backgroundColor = colorChooserDialog.Rgba;
|
||||||
colorChooserDialog.Rgba = _backgroundColor;
|
|
||||||
|
|
||||||
if (colorChooserDialog.Run() == (int)ResponseType.Ok)
|
ProcessAvatars();
|
||||||
{
|
|
||||||
_backgroundColor = colorChooserDialog.Rgba;
|
|
||||||
|
|
||||||
ProcessAvatars();
|
|
||||||
}
|
|
||||||
|
|
||||||
colorChooserDialog.Hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
colorChooserDialog.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChooseButton_Pressed(object sender, EventArgs e)
|
private void ChooseButton_Pressed(object sender, EventArgs e)
|
||||||
|
@ -226,69 +224,68 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private static byte[] DecompressYaz0(Stream stream)
|
private static byte[] DecompressYaz0(Stream stream)
|
||||||
{
|
{
|
||||||
using (BinaryReader reader = new BinaryReader(stream))
|
using BinaryReader reader = new(stream);
|
||||||
|
|
||||||
|
reader.ReadInt32(); // Magic
|
||||||
|
|
||||||
|
uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32());
|
||||||
|
|
||||||
|
reader.ReadInt64(); // Padding
|
||||||
|
|
||||||
|
byte[] input = new byte[stream.Length - stream.Position];
|
||||||
|
stream.Read(input, 0, input.Length);
|
||||||
|
|
||||||
|
long inputOffset = 0;
|
||||||
|
|
||||||
|
byte[] output = new byte[decodedLength];
|
||||||
|
long outputOffset = 0;
|
||||||
|
|
||||||
|
ushort mask = 0;
|
||||||
|
byte header = 0;
|
||||||
|
|
||||||
|
while (outputOffset < decodedLength)
|
||||||
{
|
{
|
||||||
reader.ReadInt32(); // Magic
|
if ((mask >>= 1) == 0)
|
||||||
|
|
||||||
uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32());
|
|
||||||
|
|
||||||
reader.ReadInt64(); // Padding
|
|
||||||
|
|
||||||
byte[] input = new byte[stream.Length - stream.Position];
|
|
||||||
stream.Read(input, 0, input.Length);
|
|
||||||
|
|
||||||
long inputOffset = 0;
|
|
||||||
|
|
||||||
byte[] output = new byte[decodedLength];
|
|
||||||
long outputOffset = 0;
|
|
||||||
|
|
||||||
ushort mask = 0;
|
|
||||||
byte header = 0;
|
|
||||||
|
|
||||||
while (outputOffset < decodedLength)
|
|
||||||
{
|
{
|
||||||
if ((mask >>= 1) == 0)
|
header = input[inputOffset++];
|
||||||
|
mask = 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((header & mask) > 0)
|
||||||
|
{
|
||||||
|
if (outputOffset == output.Length)
|
||||||
{
|
{
|
||||||
header = input[inputOffset++];
|
break;
|
||||||
mask = 0x80;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((header & mask) > 0)
|
output[outputOffset++] = input[inputOffset++];
|
||||||
{
|
}
|
||||||
if (outputOffset == output.Length)
|
else
|
||||||
{
|
{
|
||||||
break;
|
byte byte1 = input[inputOffset++];
|
||||||
}
|
byte byte2 = input[inputOffset++];
|
||||||
|
|
||||||
output[outputOffset++] = input[inputOffset++];
|
int dist = ((byte1 & 0xF) << 8) | byte2;
|
||||||
|
int position = (int)outputOffset - (dist + 1);
|
||||||
|
|
||||||
|
int length = byte1 >> 4;
|
||||||
|
if (length == 0)
|
||||||
|
{
|
||||||
|
length = input[inputOffset++] + 0x12;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
byte byte1 = input[inputOffset++];
|
length += 2;
|
||||||
byte byte2 = input[inputOffset++];
|
}
|
||||||
|
|
||||||
int dist = ((byte1 & 0xF) << 8) | byte2;
|
while (length-- > 0)
|
||||||
int position = (int)outputOffset - (dist + 1);
|
{
|
||||||
|
output[outputOffset++] = output[position++];
|
||||||
int length = byte1 >> 4;
|
|
||||||
if (length == 0)
|
|
||||||
{
|
|
||||||
length = input[inputOffset++] + 0x12;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
length += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (length-- > 0)
|
|
||||||
{
|
|
||||||
output[outputOffset++] = output[position++];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,7 +6,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using GUI = Gtk.Builder.ObjectAttribute;
|
using GUI = Gtk.Builder.ObjectAttribute;
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Windows
|
namespace Ryujinx.Ui.Windows
|
||||||
|
@ -16,11 +15,11 @@ namespace Ryujinx.Ui.Windows
|
||||||
private readonly string _enabledCheatsPath;
|
private readonly string _enabledCheatsPath;
|
||||||
private readonly bool _noCheatsFound;
|
private readonly bool _noCheatsFound;
|
||||||
|
|
||||||
#pragma warning disable CS0649, IDE0044
|
#pragma warning disable CS0649, IDE0044 // Field is never assigned to, Add readonly modifier
|
||||||
[GUI] Label _baseTitleInfoLabel;
|
[GUI] Label _baseTitleInfoLabel;
|
||||||
[GUI] TextView _buildIdTextView;
|
[GUI] TextView _buildIdTextView;
|
||||||
[GUI] TreeView _cheatTreeView;
|
[GUI] TreeView _cheatTreeView;
|
||||||
[GUI] Button _saveButton;
|
[GUI] Button _saveButton;
|
||||||
#pragma warning restore CS0649, IDE0044
|
#pragma warning restore CS0649, IDE0044
|
||||||
|
|
||||||
public CheatWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName, string titlePath) : this(new Builder("Ryujinx.Ui.Windows.CheatWindow.glade"), virtualFileSystem, titleId, titleName, titlePath) { }
|
public CheatWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName, string titlePath) : this(new Builder("Ryujinx.Ui.Windows.CheatWindow.glade"), virtualFileSystem, titleId, titleName, titlePath) { }
|
||||||
|
@ -31,14 +30,14 @@ namespace Ryujinx.Ui.Windows
|
||||||
_baseTitleInfoLabel.Text = $"Cheats Available for {titleName} [{titleId:X16}]";
|
_baseTitleInfoLabel.Text = $"Cheats Available for {titleName} [{titleId:X16}]";
|
||||||
_buildIdTextView.Buffer.Text = $"BuildId: {ApplicationData.GetApplicationBuildId(virtualFileSystem, titlePath)}";
|
_buildIdTextView.Buffer.Text = $"BuildId: {ApplicationData.GetApplicationBuildId(virtualFileSystem, titlePath)}";
|
||||||
|
|
||||||
string modsBasePath = ModLoader.GetModsBasePath();
|
string modsBasePath = ModLoader.GetModsBasePath();
|
||||||
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId.ToString("X16"));
|
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId.ToString("X16"));
|
||||||
|
|
||||||
_enabledCheatsPath = System.IO.Path.Combine(titleModsPath, "cheats", "enabled.txt");
|
_enabledCheatsPath = System.IO.Path.Combine(titleModsPath, "cheats", "enabled.txt");
|
||||||
|
|
||||||
_cheatTreeView.Model = new TreeStore(typeof(bool), typeof(string), typeof(string), typeof(string));
|
_cheatTreeView.Model = new TreeStore(typeof(bool), typeof(string), typeof(string), typeof(string));
|
||||||
|
|
||||||
CellRendererToggle enableToggle = new CellRendererToggle();
|
CellRendererToggle enableToggle = new();
|
||||||
enableToggle.Toggled += (sender, args) =>
|
enableToggle.Toggled += (sender, args) =>
|
||||||
{
|
{
|
||||||
_cheatTreeView.Model.GetIter(out TreeIter treeIter, new TreePath(args.Path));
|
_cheatTreeView.Model.GetIter(out TreeIter treeIter, new TreePath(args.Path));
|
||||||
|
@ -62,7 +61,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
var buildIdColumn = _cheatTreeView.AppendColumn("Build Id", new CellRendererText(), "text", 3);
|
var buildIdColumn = _cheatTreeView.AppendColumn("Build Id", new CellRendererText(), "text", 3);
|
||||||
buildIdColumn.Visible = false;
|
buildIdColumn.Visible = false;
|
||||||
|
|
||||||
string[] enabled = { };
|
string[] enabled = Array.Empty<string>();
|
||||||
|
|
||||||
if (File.Exists(_enabledCheatsPath))
|
if (File.Exists(_enabledCheatsPath))
|
||||||
{
|
{
|
||||||
|
@ -90,7 +89,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
parentIter = ((TreeStore)_cheatTreeView.Model).AppendValues(false, buildId, parentPath, "");
|
parentIter = ((TreeStore)_cheatTreeView.Model).AppendValues(false, buildId, parentPath, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
string cleanName = cheat.Name.Substring(1, cheat.Name.Length - 8);
|
string cleanName = cheat.Name[1..^7];
|
||||||
((TreeStore)_cheatTreeView.Model).AppendValues(parentIter, enabled.Contains($"{buildId}-{cheat.Name}"), cleanName, "", buildId);
|
((TreeStore)_cheatTreeView.Model).AppendValues(parentIter, enabled.Contains($"{buildId}-{cheat.Name}"), cleanName, "", buildId);
|
||||||
|
|
||||||
cheatAdded++;
|
cheatAdded++;
|
||||||
|
@ -116,7 +115,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<string> enabledCheats = new List<string>();
|
List<string> enabledCheats = new();
|
||||||
|
|
||||||
if (_cheatTreeView.Model.GetIterFirst(out TreeIter parentIter))
|
if (_cheatTreeView.Model.GetIterFirst(out TreeIter parentIter))
|
||||||
{
|
{
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -19,16 +19,16 @@ namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
public class DlcWindow : Window
|
public class DlcWindow : Window
|
||||||
{
|
{
|
||||||
private readonly VirtualFileSystem _virtualFileSystem;
|
private readonly VirtualFileSystem _virtualFileSystem;
|
||||||
private readonly string _titleId;
|
private readonly string _titleId;
|
||||||
private readonly string _dlcJsonPath;
|
private readonly string _dlcJsonPath;
|
||||||
private readonly List<DownloadableContentContainer> _dlcContainerList;
|
private readonly List<DownloadableContentContainer> _dlcContainerList;
|
||||||
|
|
||||||
private static readonly DownloadableContentJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly DownloadableContentJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
#pragma warning disable CS0649, IDE0044
|
#pragma warning disable CS0649, IDE0044 // Field is never assigned to, Add readonly modifier
|
||||||
[GUI] Label _baseTitleInfoLabel;
|
[GUI] Label _baseTitleInfoLabel;
|
||||||
[GUI] TreeView _dlcTreeView;
|
[GUI] TreeView _dlcTreeView;
|
||||||
[GUI] TreeSelection _dlcTreeSelection;
|
[GUI] TreeSelection _dlcTreeSelection;
|
||||||
#pragma warning restore CS0649, IDE0044
|
#pragma warning restore CS0649, IDE0044
|
||||||
|
|
||||||
|
@ -38,14 +38,14 @@ namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
builder.Autoconnect(this);
|
builder.Autoconnect(this);
|
||||||
|
|
||||||
_titleId = titleId;
|
_titleId = titleId;
|
||||||
_virtualFileSystem = virtualFileSystem;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
_dlcJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "dlc.json");
|
_dlcJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "dlc.json");
|
||||||
_baseTitleInfoLabel.Text = $"DLC Available for {titleName} [{titleId.ToUpper()}]";
|
_baseTitleInfoLabel.Text = $"DLC Available for {titleName} [{titleId.ToUpper()}]";
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_dlcContainerList = JsonHelper.DeserializeFromFile(_dlcJsonPath, SerializerContext.ListDownloadableContentContainer);
|
_dlcContainerList = JsonHelper.DeserializeFromFile(_dlcJsonPath, _serializerContext.ListDownloadableContentContainer);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -54,7 +54,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
_dlcTreeView.Model = new TreeStore(typeof(bool), typeof(string), typeof(string));
|
_dlcTreeView.Model = new TreeStore(typeof(bool), typeof(string), typeof(string));
|
||||||
|
|
||||||
CellRendererToggle enableToggle = new CellRendererToggle();
|
CellRendererToggle enableToggle = new();
|
||||||
enableToggle.Toggled += (sender, args) =>
|
enableToggle.Toggled += (sender, args) =>
|
||||||
{
|
{
|
||||||
_dlcTreeView.Model.GetIter(out TreeIter treeIter, new TreePath(args.Path));
|
_dlcTreeView.Model.GetIter(out TreeIter treeIter, new TreePath(args.Path));
|
||||||
|
@ -71,9 +71,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_dlcTreeView.AppendColumn("Enabled", enableToggle, "active", 0);
|
_dlcTreeView.AppendColumn("Enabled", enableToggle, "active", 0);
|
||||||
_dlcTreeView.AppendColumn("TitleId", new CellRendererText(), "text", 1);
|
_dlcTreeView.AppendColumn("TitleId", new CellRendererText(), "text", 1);
|
||||||
_dlcTreeView.AppendColumn("Path", new CellRendererText(), "text", 2);
|
_dlcTreeView.AppendColumn("Path", new CellRendererText(), "text", 2);
|
||||||
|
|
||||||
foreach (DownloadableContentContainer dlcContainer in _dlcContainerList)
|
foreach (DownloadableContentContainer dlcContainer in _dlcContainerList)
|
||||||
{
|
{
|
||||||
|
@ -85,8 +85,11 @@ namespace Ryujinx.Ui.Windows
|
||||||
// "enabled" box if all child NCAs are enabled. Usually fine since each nsp has only one nca.
|
// "enabled" box if all child NCAs are enabled. Usually fine since each nsp has only one nca.
|
||||||
bool areAllContentPacksEnabled = dlcContainer.DownloadableContentNcaList.TrueForAll((nca) => nca.Enabled);
|
bool areAllContentPacksEnabled = dlcContainer.DownloadableContentNcaList.TrueForAll((nca) => nca.Enabled);
|
||||||
TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(areAllContentPacksEnabled, "", dlcContainer.ContainerPath);
|
TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(areAllContentPacksEnabled, "", dlcContainer.ContainerPath);
|
||||||
|
|
||||||
using FileStream containerFile = File.OpenRead(dlcContainer.ContainerPath);
|
using FileStream containerFile = File.OpenRead(dlcContainer.ContainerPath);
|
||||||
PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
|
|
||||||
|
PartitionFileSystem pfs = new(containerFile.AsStorage());
|
||||||
|
|
||||||
_virtualFileSystem.ImportTickets(pfs);
|
_virtualFileSystem.ImportTickets(pfs);
|
||||||
|
|
||||||
foreach (DownloadableContentNca dlcNca in dlcContainer.DownloadableContentNcaList)
|
foreach (DownloadableContentNca dlcNca in dlcContainer.DownloadableContentNcaList)
|
||||||
|
@ -126,14 +129,14 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private void AddButton_Clicked(object sender, EventArgs args)
|
private void AddButton_Clicked(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
FileChooserNative fileChooser = new FileChooserNative("Select DLC files", this, FileChooserAction.Open, "Add", "Cancel")
|
FileChooserNative fileChooser = new("Select DLC files", this, FileChooserAction.Open, "Add", "Cancel")
|
||||||
{
|
{
|
||||||
SelectMultiple = true
|
SelectMultiple = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
FileFilter filter = new FileFilter()
|
FileFilter filter = new()
|
||||||
{
|
{
|
||||||
Name = "Switch Game DLCs"
|
Name = "Switch Game DLCs",
|
||||||
};
|
};
|
||||||
filter.AddPattern("*.nsp");
|
filter.AddPattern("*.nsp");
|
||||||
|
|
||||||
|
@ -148,44 +151,46 @@ namespace Ryujinx.Ui.Windows
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (FileStream containerFile = File.OpenRead(containerPath))
|
using FileStream containerFile = File.OpenRead(containerPath);
|
||||||
|
|
||||||
|
PartitionFileSystem pfs = new(containerFile.AsStorage());
|
||||||
|
bool containsDlc = false;
|
||||||
|
|
||||||
|
_virtualFileSystem.ImportTickets(pfs);
|
||||||
|
|
||||||
|
TreeIter? parentIter = null;
|
||||||
|
|
||||||
|
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
||||||
{
|
{
|
||||||
PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
|
using var ncaFile = new UniqueRef<IFile>();
|
||||||
bool containsDlc = false;
|
|
||||||
|
|
||||||
_virtualFileSystem.ImportTickets(pfs);
|
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
TreeIter? parentIter = null;
|
Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), containerPath);
|
||||||
|
|
||||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
if (nca == null)
|
||||||
{
|
{
|
||||||
using var ncaFile = new UniqueRef<IFile>();
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
if (nca.Header.ContentType == NcaContentType.PublicData)
|
||||||
|
{
|
||||||
Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), containerPath);
|
if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000).ToString("x16") != _titleId)
|
||||||
|
|
||||||
if (nca == null) continue;
|
|
||||||
|
|
||||||
if (nca.Header.ContentType == NcaContentType.PublicData)
|
|
||||||
{
|
{
|
||||||
if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000).ToString("x16") != _titleId)
|
break;
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
parentIter ??= ((TreeStore)_dlcTreeView.Model).AppendValues(true, "", containerPath);
|
|
||||||
|
|
||||||
((TreeStore)_dlcTreeView.Model).AppendValues(parentIter.Value, true, nca.Header.TitleId.ToString("X16"), fileEntry.FullPath);
|
|
||||||
containsDlc = true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!containsDlc)
|
parentIter ??= ((TreeStore)_dlcTreeView.Model).AppendValues(true, "", containerPath);
|
||||||
{
|
|
||||||
GtkDialog.CreateErrorDialog("The specified file does not contain DLC for the selected title!");
|
((TreeStore)_dlcTreeView.Model).AppendValues(parentIter.Value, true, nca.Header.TitleId.ToString("X16"), fileEntry.FullPath);
|
||||||
|
containsDlc = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!containsDlc)
|
||||||
|
{
|
||||||
|
GtkDialog.CreateErrorDialog("The specified file does not contain DLC for the selected title!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +214,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private void RemoveAllButton_Clicked(object sender, EventArgs args)
|
private void RemoveAllButton_Clicked(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
List<TreeIter> toRemove = new List<TreeIter>();
|
List<TreeIter> toRemove = new();
|
||||||
|
|
||||||
if (_dlcTreeView.Model.GetIterFirst(out TreeIter iter))
|
if (_dlcTreeView.Model.GetIterFirst(out TreeIter iter))
|
||||||
{
|
{
|
||||||
|
@ -237,19 +242,19 @@ namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
if (_dlcTreeView.Model.IterChildren(out TreeIter childIter, parentIter))
|
if (_dlcTreeView.Model.IterChildren(out TreeIter childIter, parentIter))
|
||||||
{
|
{
|
||||||
DownloadableContentContainer dlcContainer = new DownloadableContentContainer
|
DownloadableContentContainer dlcContainer = new()
|
||||||
{
|
{
|
||||||
ContainerPath = (string)_dlcTreeView.Model.GetValue(parentIter, 2),
|
ContainerPath = (string)_dlcTreeView.Model.GetValue(parentIter, 2),
|
||||||
DownloadableContentNcaList = new List<DownloadableContentNca>()
|
DownloadableContentNcaList = new List<DownloadableContentNca>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
dlcContainer.DownloadableContentNcaList.Add(new DownloadableContentNca
|
dlcContainer.DownloadableContentNcaList.Add(new DownloadableContentNca
|
||||||
{
|
{
|
||||||
Enabled = (bool)_dlcTreeView.Model.GetValue(childIter, 0),
|
Enabled = (bool)_dlcTreeView.Model.GetValue(childIter, 0),
|
||||||
TitleId = Convert.ToUInt64(_dlcTreeView.Model.GetValue(childIter, 1).ToString(), 16),
|
TitleId = Convert.ToUInt64(_dlcTreeView.Model.GetValue(childIter, 1).ToString(), 16),
|
||||||
FullPath = (string)_dlcTreeView.Model.GetValue(childIter, 2)
|
FullPath = (string)_dlcTreeView.Model.GetValue(childIter, 2),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
while (_dlcTreeView.Model.IterNext(ref childIter));
|
while (_dlcTreeView.Model.IterNext(ref childIter));
|
||||||
|
@ -260,7 +265,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
while (_dlcTreeView.Model.IterNext(ref parentIter));
|
while (_dlcTreeView.Model.IterNext(ref parentIter));
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonHelper.SerializeToFile(_dlcJsonPath, _dlcContainerList, SerializerContext.ListDownloadableContentContainer);
|
JsonHelper.SerializeToFile(_dlcJsonPath, _dlcContainerList, _serializerContext.ListDownloadableContentContainer);
|
||||||
|
|
||||||
Dispose();
|
Dispose();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,12 @@ using Ryujinx.Audio.Backends.SoundIo;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Common.GraphicsDriver;
|
using Ryujinx.Common.GraphicsDriver;
|
||||||
using Ryujinx.Graphics.Vulkan;
|
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using Ryujinx.Ui.Common.Configuration.System;
|
using Ryujinx.Ui.Common.Configuration.System;
|
||||||
using Ryujinx.Ui.Helper;
|
using Ryujinx.Ui.Helper;
|
||||||
using Ryujinx.Ui.Widgets;
|
using Ryujinx.Ui.Widgets;
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
@ -27,95 +25,95 @@ namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
public class SettingsWindow : Window
|
public class SettingsWindow : Window
|
||||||
{
|
{
|
||||||
private readonly MainWindow _parent;
|
private readonly MainWindow _parent;
|
||||||
private readonly ListStore _gameDirsBoxStore;
|
private readonly ListStore _gameDirsBoxStore;
|
||||||
private readonly ListStore _audioBackendStore;
|
private readonly ListStore _audioBackendStore;
|
||||||
private readonly TimeZoneContentManager _timeZoneContentManager;
|
private readonly TimeZoneContentManager _timeZoneContentManager;
|
||||||
private readonly HashSet<string> _validTzRegions;
|
private readonly HashSet<string> _validTzRegions;
|
||||||
|
|
||||||
private long _systemTimeOffset;
|
private long _systemTimeOffset;
|
||||||
private float _previousVolumeLevel;
|
private float _previousVolumeLevel;
|
||||||
private bool _directoryChanged = false;
|
private bool _directoryChanged = false;
|
||||||
|
|
||||||
#pragma warning disable CS0649, IDE0044
|
#pragma warning disable CS0649, IDE0044 // Field is never assigned to, Add readonly modifier
|
||||||
[GUI] CheckButton _traceLogToggle;
|
[GUI] CheckButton _traceLogToggle;
|
||||||
[GUI] CheckButton _errorLogToggle;
|
[GUI] CheckButton _errorLogToggle;
|
||||||
[GUI] CheckButton _warningLogToggle;
|
[GUI] CheckButton _warningLogToggle;
|
||||||
[GUI] CheckButton _infoLogToggle;
|
[GUI] CheckButton _infoLogToggle;
|
||||||
[GUI] CheckButton _stubLogToggle;
|
[GUI] CheckButton _stubLogToggle;
|
||||||
[GUI] CheckButton _debugLogToggle;
|
[GUI] CheckButton _debugLogToggle;
|
||||||
[GUI] CheckButton _fileLogToggle;
|
[GUI] CheckButton _fileLogToggle;
|
||||||
[GUI] CheckButton _guestLogToggle;
|
[GUI] CheckButton _guestLogToggle;
|
||||||
[GUI] CheckButton _fsAccessLogToggle;
|
[GUI] CheckButton _fsAccessLogToggle;
|
||||||
[GUI] Adjustment _fsLogSpinAdjustment;
|
[GUI] Adjustment _fsLogSpinAdjustment;
|
||||||
[GUI] ComboBoxText _graphicsDebugLevel;
|
[GUI] ComboBoxText _graphicsDebugLevel;
|
||||||
[GUI] CheckButton _dockedModeToggle;
|
[GUI] CheckButton _dockedModeToggle;
|
||||||
[GUI] CheckButton _discordToggle;
|
[GUI] CheckButton _discordToggle;
|
||||||
[GUI] CheckButton _checkUpdatesToggle;
|
[GUI] CheckButton _checkUpdatesToggle;
|
||||||
[GUI] CheckButton _showConfirmExitToggle;
|
[GUI] CheckButton _showConfirmExitToggle;
|
||||||
[GUI] RadioButton _hideCursorNever;
|
[GUI] RadioButton _hideCursorNever;
|
||||||
[GUI] RadioButton _hideCursorOnIdle;
|
[GUI] RadioButton _hideCursorOnIdle;
|
||||||
[GUI] RadioButton _hideCursorAlways;
|
[GUI] RadioButton _hideCursorAlways;
|
||||||
[GUI] CheckButton _vSyncToggle;
|
[GUI] CheckButton _vSyncToggle;
|
||||||
[GUI] CheckButton _shaderCacheToggle;
|
[GUI] CheckButton _shaderCacheToggle;
|
||||||
[GUI] CheckButton _textureRecompressionToggle;
|
[GUI] CheckButton _textureRecompressionToggle;
|
||||||
[GUI] CheckButton _macroHLEToggle;
|
[GUI] CheckButton _macroHLEToggle;
|
||||||
[GUI] CheckButton _ptcToggle;
|
[GUI] CheckButton _ptcToggle;
|
||||||
[GUI] CheckButton _internetToggle;
|
[GUI] CheckButton _internetToggle;
|
||||||
[GUI] CheckButton _fsicToggle;
|
[GUI] CheckButton _fsicToggle;
|
||||||
[GUI] RadioButton _mmSoftware;
|
[GUI] RadioButton _mmSoftware;
|
||||||
[GUI] RadioButton _mmHost;
|
[GUI] RadioButton _mmHost;
|
||||||
[GUI] RadioButton _mmHostUnsafe;
|
[GUI] RadioButton _mmHostUnsafe;
|
||||||
[GUI] CheckButton _expandRamToggle;
|
[GUI] CheckButton _expandRamToggle;
|
||||||
[GUI] CheckButton _ignoreToggle;
|
[GUI] CheckButton _ignoreToggle;
|
||||||
[GUI] CheckButton _directKeyboardAccess;
|
[GUI] CheckButton _directKeyboardAccess;
|
||||||
[GUI] CheckButton _directMouseAccess;
|
[GUI] CheckButton _directMouseAccess;
|
||||||
[GUI] ComboBoxText _systemLanguageSelect;
|
[GUI] ComboBoxText _systemLanguageSelect;
|
||||||
[GUI] ComboBoxText _systemRegionSelect;
|
[GUI] ComboBoxText _systemRegionSelect;
|
||||||
[GUI] Entry _systemTimeZoneEntry;
|
[GUI] Entry _systemTimeZoneEntry;
|
||||||
[GUI] EntryCompletion _systemTimeZoneCompletion;
|
[GUI] EntryCompletion _systemTimeZoneCompletion;
|
||||||
[GUI] Box _audioBackendBox;
|
[GUI] Box _audioBackendBox;
|
||||||
[GUI] ComboBox _audioBackendSelect;
|
[GUI] ComboBox _audioBackendSelect;
|
||||||
[GUI] Label _audioVolumeLabel;
|
[GUI] Label _audioVolumeLabel;
|
||||||
[GUI] Scale _audioVolumeSlider;
|
[GUI] Scale _audioVolumeSlider;
|
||||||
[GUI] SpinButton _systemTimeYearSpin;
|
[GUI] SpinButton _systemTimeYearSpin;
|
||||||
[GUI] SpinButton _systemTimeMonthSpin;
|
[GUI] SpinButton _systemTimeMonthSpin;
|
||||||
[GUI] SpinButton _systemTimeDaySpin;
|
[GUI] SpinButton _systemTimeDaySpin;
|
||||||
[GUI] SpinButton _systemTimeHourSpin;
|
[GUI] SpinButton _systemTimeHourSpin;
|
||||||
[GUI] SpinButton _systemTimeMinuteSpin;
|
[GUI] SpinButton _systemTimeMinuteSpin;
|
||||||
[GUI] Adjustment _systemTimeYearSpinAdjustment;
|
[GUI] Adjustment _systemTimeYearSpinAdjustment;
|
||||||
[GUI] Adjustment _systemTimeMonthSpinAdjustment;
|
[GUI] Adjustment _systemTimeMonthSpinAdjustment;
|
||||||
[GUI] Adjustment _systemTimeDaySpinAdjustment;
|
[GUI] Adjustment _systemTimeDaySpinAdjustment;
|
||||||
[GUI] Adjustment _systemTimeHourSpinAdjustment;
|
[GUI] Adjustment _systemTimeHourSpinAdjustment;
|
||||||
[GUI] Adjustment _systemTimeMinuteSpinAdjustment;
|
[GUI] Adjustment _systemTimeMinuteSpinAdjustment;
|
||||||
[GUI] ComboBoxText _multiLanSelect;
|
[GUI] ComboBoxText _multiLanSelect;
|
||||||
[GUI] CheckButton _custThemeToggle;
|
[GUI] CheckButton _custThemeToggle;
|
||||||
[GUI] Entry _custThemePath;
|
[GUI] Entry _custThemePath;
|
||||||
[GUI] ToggleButton _browseThemePath;
|
[GUI] ToggleButton _browseThemePath;
|
||||||
[GUI] Label _custThemePathLabel;
|
[GUI] Label _custThemePathLabel;
|
||||||
[GUI] TreeView _gameDirsBox;
|
[GUI] TreeView _gameDirsBox;
|
||||||
[GUI] Entry _addGameDirBox;
|
[GUI] Entry _addGameDirBox;
|
||||||
[GUI] ComboBoxText _galThreading;
|
[GUI] ComboBoxText _galThreading;
|
||||||
[GUI] Entry _graphicsShadersDumpPath;
|
[GUI] Entry _graphicsShadersDumpPath;
|
||||||
[GUI] ComboBoxText _anisotropy;
|
[GUI] ComboBoxText _anisotropy;
|
||||||
[GUI] ComboBoxText _aspectRatio;
|
[GUI] ComboBoxText _aspectRatio;
|
||||||
[GUI] ComboBoxText _antiAliasing;
|
[GUI] ComboBoxText _antiAliasing;
|
||||||
[GUI] ComboBoxText _scalingFilter;
|
[GUI] ComboBoxText _scalingFilter;
|
||||||
[GUI] ComboBoxText _graphicsBackend;
|
[GUI] ComboBoxText _graphicsBackend;
|
||||||
[GUI] ComboBoxText _preferredGpu;
|
[GUI] ComboBoxText _preferredGpu;
|
||||||
[GUI] ComboBoxText _resScaleCombo;
|
[GUI] ComboBoxText _resScaleCombo;
|
||||||
[GUI] Entry _resScaleText;
|
[GUI] Entry _resScaleText;
|
||||||
[GUI] Adjustment _scalingFilterLevel;
|
[GUI] Adjustment _scalingFilterLevel;
|
||||||
[GUI] Scale _scalingFilterSlider;
|
[GUI] Scale _scalingFilterSlider;
|
||||||
[GUI] ToggleButton _configureController1;
|
[GUI] ToggleButton _configureController1;
|
||||||
[GUI] ToggleButton _configureController2;
|
[GUI] ToggleButton _configureController2;
|
||||||
[GUI] ToggleButton _configureController3;
|
[GUI] ToggleButton _configureController3;
|
||||||
[GUI] ToggleButton _configureController4;
|
[GUI] ToggleButton _configureController4;
|
||||||
[GUI] ToggleButton _configureController5;
|
[GUI] ToggleButton _configureController5;
|
||||||
[GUI] ToggleButton _configureController6;
|
[GUI] ToggleButton _configureController6;
|
||||||
[GUI] ToggleButton _configureController7;
|
[GUI] ToggleButton _configureController7;
|
||||||
[GUI] ToggleButton _configureController8;
|
[GUI] ToggleButton _configureController8;
|
||||||
[GUI] ToggleButton _configureControllerH;
|
[GUI] ToggleButton _configureControllerH;
|
||||||
|
|
||||||
#pragma warning restore CS0649, IDE0044
|
#pragma warning restore CS0649, IDE0044
|
||||||
|
|
||||||
|
@ -316,11 +314,11 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom EntryCompletion Columns. If added to glade, need to override more signals
|
// Custom EntryCompletion Columns. If added to glade, need to override more signals
|
||||||
ListStore tzList = new ListStore(typeof(string), typeof(string), typeof(string));
|
ListStore tzList = new(typeof(string), typeof(string), typeof(string));
|
||||||
_systemTimeZoneCompletion.Model = tzList;
|
_systemTimeZoneCompletion.Model = tzList;
|
||||||
|
|
||||||
CellRendererText offsetCol = new CellRendererText();
|
CellRendererText offsetCol = new();
|
||||||
CellRendererText abbrevCol = new CellRendererText();
|
CellRendererText abbrevCol = new();
|
||||||
|
|
||||||
_systemTimeZoneCompletion.PackStart(offsetCol, false);
|
_systemTimeZoneCompletion.PackStart(offsetCol, false);
|
||||||
_systemTimeZoneCompletion.AddAttribute(offsetCol, "text", 0);
|
_systemTimeZoneCompletion.AddAttribute(offsetCol, "text", 0);
|
||||||
|
@ -364,17 +362,17 @@ namespace Ryujinx.Ui.Windows
|
||||||
PopulateNetworkInterfaces();
|
PopulateNetworkInterfaces();
|
||||||
_multiLanSelect.SetActiveId(ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value);
|
_multiLanSelect.SetActiveId(ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value);
|
||||||
|
|
||||||
_custThemePath.Buffer.Text = ConfigurationState.Instance.Ui.CustomThemePath;
|
_custThemePath.Buffer.Text = ConfigurationState.Instance.Ui.CustomThemePath;
|
||||||
_resScaleText.Buffer.Text = ConfigurationState.Instance.Graphics.ResScaleCustom.Value.ToString();
|
_resScaleText.Buffer.Text = ConfigurationState.Instance.Graphics.ResScaleCustom.Value.ToString();
|
||||||
_scalingFilterLevel.Value = ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value;
|
_scalingFilterLevel.Value = ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value;
|
||||||
_resScaleText.Visible = _resScaleCombo.ActiveId == "-1";
|
_resScaleText.Visible = _resScaleCombo.ActiveId == "-1";
|
||||||
_scalingFilterSlider.Visible = _scalingFilter.ActiveId == "2";
|
_scalingFilterSlider.Visible = _scalingFilter.ActiveId == "2";
|
||||||
_graphicsShadersDumpPath.Buffer.Text = ConfigurationState.Instance.Graphics.ShadersDumpPath;
|
_graphicsShadersDumpPath.Buffer.Text = ConfigurationState.Instance.Graphics.ShadersDumpPath;
|
||||||
_fsLogSpinAdjustment.Value = ConfigurationState.Instance.System.FsGlobalAccessLogMode;
|
_fsLogSpinAdjustment.Value = ConfigurationState.Instance.System.FsGlobalAccessLogMode;
|
||||||
_systemTimeOffset = ConfigurationState.Instance.System.SystemTimeOffset;
|
_systemTimeOffset = ConfigurationState.Instance.System.SystemTimeOffset;
|
||||||
|
|
||||||
_gameDirsBox.AppendColumn("", new CellRendererText(), "text", 0);
|
_gameDirsBox.AppendColumn("", new CellRendererText(), "text", 0);
|
||||||
_gameDirsBoxStore = new ListStore(typeof(string));
|
_gameDirsBoxStore = new ListStore(typeof(string));
|
||||||
_gameDirsBox.Model = _gameDirsBoxStore;
|
_gameDirsBox.Model = _gameDirsBoxStore;
|
||||||
|
|
||||||
foreach (string gameDir in ConfigurationState.Instance.Ui.GameDirs.Value)
|
foreach (string gameDir in ConfigurationState.Instance.Ui.GameDirs.Value)
|
||||||
|
@ -384,9 +382,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
if (_custThemeToggle.Active == false)
|
if (_custThemeToggle.Active == false)
|
||||||
{
|
{
|
||||||
_custThemePath.Sensitive = false;
|
_custThemePath.Sensitive = false;
|
||||||
_custThemePathLabel.Sensitive = false;
|
_custThemePathLabel.Sensitive = false;
|
||||||
_browseThemePath.Sensitive = false;
|
_browseThemePath.Sensitive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup system time spinners
|
// Setup system time spinners
|
||||||
|
@ -394,10 +392,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
_audioBackendStore = new ListStore(typeof(string), typeof(AudioBackend));
|
_audioBackendStore = new ListStore(typeof(string), typeof(AudioBackend));
|
||||||
|
|
||||||
TreeIter openAlIter = _audioBackendStore.AppendValues("OpenAL", AudioBackend.OpenAl);
|
TreeIter openAlIter = _audioBackendStore.AppendValues("OpenAL", AudioBackend.OpenAl);
|
||||||
TreeIter soundIoIter = _audioBackendStore.AppendValues("SoundIO", AudioBackend.SoundIo);
|
TreeIter soundIoIter = _audioBackendStore.AppendValues("SoundIO", AudioBackend.SoundIo);
|
||||||
TreeIter sdl2Iter = _audioBackendStore.AppendValues("SDL2", AudioBackend.SDL2);
|
TreeIter sdl2Iter = _audioBackendStore.AppendValues("SDL2", AudioBackend.SDL2);
|
||||||
TreeIter dummyIter = _audioBackendStore.AppendValues("Dummy", AudioBackend.Dummy);
|
TreeIter dummyIter = _audioBackendStore.AppendValues("Dummy", AudioBackend.Dummy);
|
||||||
|
|
||||||
_audioBackendSelect = ComboBox.NewWithModelAndEntry(_audioBackendStore);
|
_audioBackendSelect = ComboBox.NewWithModelAndEntry(_audioBackendStore);
|
||||||
_audioBackendSelect.EntryTextColumn = 0;
|
_audioBackendSelect.EntryTextColumn = 0;
|
||||||
|
@ -418,35 +416,35 @@ namespace Ryujinx.Ui.Windows
|
||||||
_audioBackendSelect.SetActiveIter(dummyIter);
|
_audioBackendSelect.SetActiveIter(dummyIter);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new InvalidOperationException($"{nameof(ConfigurationState.Instance.System.AudioBackend)} contains an invalid value: {ConfigurationState.Instance.System.AudioBackend.Value}");
|
||||||
}
|
}
|
||||||
|
|
||||||
_audioBackendBox.Add(_audioBackendSelect);
|
_audioBackendBox.Add(_audioBackendSelect);
|
||||||
_audioBackendSelect.Show();
|
_audioBackendSelect.Show();
|
||||||
|
|
||||||
_previousVolumeLevel = ConfigurationState.Instance.System.AudioVolume;
|
_previousVolumeLevel = ConfigurationState.Instance.System.AudioVolume;
|
||||||
_audioVolumeLabel = new Label("Volume: ");
|
_audioVolumeLabel = new Label("Volume: ");
|
||||||
_audioVolumeSlider = new Scale(Orientation.Horizontal, 0, 100, 1);
|
_audioVolumeSlider = new Scale(Orientation.Horizontal, 0, 100, 1);
|
||||||
_audioVolumeLabel.MarginStart = 10;
|
_audioVolumeLabel.MarginStart = 10;
|
||||||
_audioVolumeSlider.ValuePos = PositionType.Right;
|
_audioVolumeSlider.ValuePos = PositionType.Right;
|
||||||
_audioVolumeSlider.WidthRequest = 200;
|
_audioVolumeSlider.WidthRequest = 200;
|
||||||
|
|
||||||
_audioVolumeSlider.Value = _previousVolumeLevel * 100;
|
_audioVolumeSlider.Value = _previousVolumeLevel * 100;
|
||||||
_audioVolumeSlider.ValueChanged += VolumeSlider_OnChange;
|
_audioVolumeSlider.ValueChanged += VolumeSlider_OnChange;
|
||||||
_audioBackendBox.Add(_audioVolumeLabel);
|
_audioBackendBox.Add(_audioVolumeLabel);
|
||||||
_audioBackendBox.Add(_audioVolumeSlider);
|
_audioBackendBox.Add(_audioVolumeSlider);
|
||||||
_audioVolumeLabel.Show();
|
_audioVolumeLabel.Show();
|
||||||
_audioVolumeSlider.Show();
|
_audioVolumeSlider.Show();
|
||||||
|
|
||||||
bool openAlIsSupported = false;
|
bool openAlIsSupported = false;
|
||||||
bool soundIoIsSupported = false;
|
bool soundIoIsSupported = false;
|
||||||
bool sdl2IsSupported = false;
|
bool sdl2IsSupported = false;
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
openAlIsSupported = OpenALHardwareDeviceDriver.IsSupported;
|
openAlIsSupported = OpenALHardwareDeviceDriver.IsSupported;
|
||||||
soundIoIsSupported = !OperatingSystem.IsMacOS() && SoundIoHardwareDeviceDriver.IsSupported;
|
soundIoIsSupported = !OperatingSystem.IsMacOS() && SoundIoHardwareDeviceDriver.IsSupported;
|
||||||
sdl2IsSupported = SDL2HardwareDeviceDriver.IsSupported;
|
sdl2IsSupported = SDL2HardwareDeviceDriver.IsSupported;
|
||||||
});
|
});
|
||||||
|
|
||||||
// This function runs whenever the dropdown is opened
|
// This function runs whenever the dropdown is opened
|
||||||
|
@ -454,18 +452,18 @@ namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
cell.Sensitive = ((AudioBackend)_audioBackendStore.GetValue(iter, 1)) switch
|
cell.Sensitive = ((AudioBackend)_audioBackendStore.GetValue(iter, 1)) switch
|
||||||
{
|
{
|
||||||
AudioBackend.OpenAl => openAlIsSupported,
|
AudioBackend.OpenAl => openAlIsSupported,
|
||||||
AudioBackend.SoundIo => soundIoIsSupported,
|
AudioBackend.SoundIo => soundIoIsSupported,
|
||||||
AudioBackend.SDL2 => sdl2IsSupported,
|
AudioBackend.SDL2 => sdl2IsSupported,
|
||||||
AudioBackend.Dummy => true,
|
AudioBackend.Dummy => true,
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
_ => throw new InvalidOperationException($"{nameof(_audioBackendStore)} contains an invalid value for iteration {iter}: {_audioBackendStore.GetValue(iter, 1)}"),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
if (OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
var store = (_graphicsBackend.Model as ListStore);
|
var store = (_graphicsBackend.Model as ListStore);
|
||||||
store.GetIter(out TreeIter openglIter, new TreePath(new int[] {1}));
|
store.GetIter(out TreeIter openglIter, new TreePath(new[] { 1 }));
|
||||||
store.Remove(ref openglIter);
|
store.Remove(ref openglIter);
|
||||||
|
|
||||||
_graphicsBackend.Model = store;
|
_graphicsBackend.Model = store;
|
||||||
|
@ -478,15 +476,15 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
if (Enum.Parse<GraphicsBackend>(_graphicsBackend.ActiveId) == GraphicsBackend.Vulkan)
|
if (Enum.Parse<GraphicsBackend>(_graphicsBackend.ActiveId) == GraphicsBackend.Vulkan)
|
||||||
{
|
{
|
||||||
var devices = VulkanRenderer.GetPhysicalDevices();
|
var devices = Graphics.Vulkan.VulkanRenderer.GetPhysicalDevices();
|
||||||
string preferredGpuIdFromConfig = ConfigurationState.Instance.Graphics.PreferredGpu.Value;
|
string preferredGpuIdFromConfig = ConfigurationState.Instance.Graphics.PreferredGpu.Value;
|
||||||
string preferredGpuId = preferredGpuIdFromConfig;
|
string preferredGpuId = preferredGpuIdFromConfig;
|
||||||
bool noGpuId = string.IsNullOrEmpty(preferredGpuIdFromConfig);
|
bool noGpuId = string.IsNullOrEmpty(preferredGpuIdFromConfig);
|
||||||
|
|
||||||
foreach (var device in devices)
|
foreach (var device in devices)
|
||||||
{
|
{
|
||||||
string dGPU = device.IsDiscrete ? " (dGPU)" : "";
|
string dGpu = device.IsDiscrete ? " (dGPU)" : "";
|
||||||
_preferredGpu.Append(device.Id, $"{device.Name}{dGPU}");
|
_preferredGpu.Append(device.Id, $"{device.Name}{dGpu}");
|
||||||
|
|
||||||
// If there's no GPU selected yet, we just pick the first GPU.
|
// If there's no GPU selected yet, we just pick the first GPU.
|
||||||
// If there's a discrete GPU available, we always prefer that over the previous selection,
|
// If there's a discrete GPU available, we always prefer that over the previous selection,
|
||||||
|
@ -521,33 +519,33 @@ namespace Ryujinx.Ui.Windows
|
||||||
private void UpdateSystemTimeSpinners()
|
private void UpdateSystemTimeSpinners()
|
||||||
{
|
{
|
||||||
//Bind system time events
|
//Bind system time events
|
||||||
_systemTimeYearSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
|
_systemTimeYearSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
|
||||||
_systemTimeMonthSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
|
_systemTimeMonthSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
|
||||||
_systemTimeDaySpin.ValueChanged -= SystemTimeSpin_ValueChanged;
|
_systemTimeDaySpin.ValueChanged -= SystemTimeSpin_ValueChanged;
|
||||||
_systemTimeHourSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
|
_systemTimeHourSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
|
||||||
_systemTimeMinuteSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
|
_systemTimeMinuteSpin.ValueChanged -= SystemTimeSpin_ValueChanged;
|
||||||
|
|
||||||
//Apply actual system time + SystemTimeOffset to system time spin buttons
|
//Apply actual system time + SystemTimeOffset to system time spin buttons
|
||||||
DateTime systemTime = DateTime.Now.AddSeconds(_systemTimeOffset);
|
DateTime systemTime = DateTime.Now.AddSeconds(_systemTimeOffset);
|
||||||
|
|
||||||
_systemTimeYearSpinAdjustment.Value = systemTime.Year;
|
_systemTimeYearSpinAdjustment.Value = systemTime.Year;
|
||||||
_systemTimeMonthSpinAdjustment.Value = systemTime.Month;
|
_systemTimeMonthSpinAdjustment.Value = systemTime.Month;
|
||||||
_systemTimeDaySpinAdjustment.Value = systemTime.Day;
|
_systemTimeDaySpinAdjustment.Value = systemTime.Day;
|
||||||
_systemTimeHourSpinAdjustment.Value = systemTime.Hour;
|
_systemTimeHourSpinAdjustment.Value = systemTime.Hour;
|
||||||
_systemTimeMinuteSpinAdjustment.Value = systemTime.Minute;
|
_systemTimeMinuteSpinAdjustment.Value = systemTime.Minute;
|
||||||
|
|
||||||
//Format spin buttons text to include leading zeros
|
//Format spin buttons text to include leading zeros
|
||||||
_systemTimeYearSpin.Text = systemTime.Year.ToString("0000");
|
_systemTimeYearSpin.Text = systemTime.Year.ToString("0000");
|
||||||
_systemTimeMonthSpin.Text = systemTime.Month.ToString("00");
|
_systemTimeMonthSpin.Text = systemTime.Month.ToString("00");
|
||||||
_systemTimeDaySpin.Text = systemTime.Day.ToString("00");
|
_systemTimeDaySpin.Text = systemTime.Day.ToString("00");
|
||||||
_systemTimeHourSpin.Text = systemTime.Hour.ToString("00");
|
_systemTimeHourSpin.Text = systemTime.Hour.ToString("00");
|
||||||
_systemTimeMinuteSpin.Text = systemTime.Minute.ToString("00");
|
_systemTimeMinuteSpin.Text = systemTime.Minute.ToString("00");
|
||||||
|
|
||||||
//Bind system time events
|
//Bind system time events
|
||||||
_systemTimeYearSpin.ValueChanged += SystemTimeSpin_ValueChanged;
|
_systemTimeYearSpin.ValueChanged += SystemTimeSpin_ValueChanged;
|
||||||
_systemTimeMonthSpin.ValueChanged += SystemTimeSpin_ValueChanged;
|
_systemTimeMonthSpin.ValueChanged += SystemTimeSpin_ValueChanged;
|
||||||
_systemTimeDaySpin.ValueChanged += SystemTimeSpin_ValueChanged;
|
_systemTimeDaySpin.ValueChanged += SystemTimeSpin_ValueChanged;
|
||||||
_systemTimeHourSpin.ValueChanged += SystemTimeSpin_ValueChanged;
|
_systemTimeHourSpin.ValueChanged += SystemTimeSpin_ValueChanged;
|
||||||
_systemTimeMinuteSpin.ValueChanged += SystemTimeSpin_ValueChanged;
|
_systemTimeMinuteSpin.ValueChanged += SystemTimeSpin_ValueChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,7 +553,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
if (_directoryChanged)
|
if (_directoryChanged)
|
||||||
{
|
{
|
||||||
List<string> gameDirs = new List<string>();
|
List<string> gameDirs = new();
|
||||||
|
|
||||||
_gameDirsBoxStore.GetIterFirst(out TreeIter treeIter);
|
_gameDirsBoxStore.GetIterFirst(out TreeIter treeIter);
|
||||||
|
|
||||||
|
@ -611,52 +609,52 @@ namespace Ryujinx.Ui.Windows
|
||||||
DriverUtilities.ToggleOGLThreading(backendThreading == BackendThreading.Off);
|
DriverUtilities.ToggleOGLThreading(backendThreading == BackendThreading.Off);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationState.Instance.Logger.EnableError.Value = _errorLogToggle.Active;
|
ConfigurationState.Instance.Logger.EnableError.Value = _errorLogToggle.Active;
|
||||||
ConfigurationState.Instance.Logger.EnableTrace.Value = _traceLogToggle.Active;
|
ConfigurationState.Instance.Logger.EnableTrace.Value = _traceLogToggle.Active;
|
||||||
ConfigurationState.Instance.Logger.EnableWarn.Value = _warningLogToggle.Active;
|
ConfigurationState.Instance.Logger.EnableWarn.Value = _warningLogToggle.Active;
|
||||||
ConfigurationState.Instance.Logger.EnableInfo.Value = _infoLogToggle.Active;
|
ConfigurationState.Instance.Logger.EnableInfo.Value = _infoLogToggle.Active;
|
||||||
ConfigurationState.Instance.Logger.EnableStub.Value = _stubLogToggle.Active;
|
ConfigurationState.Instance.Logger.EnableStub.Value = _stubLogToggle.Active;
|
||||||
ConfigurationState.Instance.Logger.EnableDebug.Value = _debugLogToggle.Active;
|
ConfigurationState.Instance.Logger.EnableDebug.Value = _debugLogToggle.Active;
|
||||||
ConfigurationState.Instance.Logger.EnableGuest.Value = _guestLogToggle.Active;
|
ConfigurationState.Instance.Logger.EnableGuest.Value = _guestLogToggle.Active;
|
||||||
ConfigurationState.Instance.Logger.EnableFsAccessLog.Value = _fsAccessLogToggle.Active;
|
ConfigurationState.Instance.Logger.EnableFsAccessLog.Value = _fsAccessLogToggle.Active;
|
||||||
ConfigurationState.Instance.Logger.EnableFileLog.Value = _fileLogToggle.Active;
|
ConfigurationState.Instance.Logger.EnableFileLog.Value = _fileLogToggle.Active;
|
||||||
ConfigurationState.Instance.Logger.GraphicsDebugLevel.Value = Enum.Parse<GraphicsDebugLevel>(_graphicsDebugLevel.ActiveId);
|
ConfigurationState.Instance.Logger.GraphicsDebugLevel.Value = Enum.Parse<GraphicsDebugLevel>(_graphicsDebugLevel.ActiveId);
|
||||||
ConfigurationState.Instance.System.EnableDockedMode.Value = _dockedModeToggle.Active;
|
ConfigurationState.Instance.System.EnableDockedMode.Value = _dockedModeToggle.Active;
|
||||||
ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active;
|
ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active;
|
||||||
ConfigurationState.Instance.CheckUpdatesOnStart.Value = _checkUpdatesToggle.Active;
|
ConfigurationState.Instance.CheckUpdatesOnStart.Value = _checkUpdatesToggle.Active;
|
||||||
ConfigurationState.Instance.ShowConfirmExit.Value = _showConfirmExitToggle.Active;
|
ConfigurationState.Instance.ShowConfirmExit.Value = _showConfirmExitToggle.Active;
|
||||||
ConfigurationState.Instance.HideCursor.Value = hideCursor;
|
ConfigurationState.Instance.HideCursor.Value = hideCursor;
|
||||||
ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active;
|
ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active;
|
||||||
ConfigurationState.Instance.Graphics.EnableShaderCache.Value = _shaderCacheToggle.Active;
|
ConfigurationState.Instance.Graphics.EnableShaderCache.Value = _shaderCacheToggle.Active;
|
||||||
ConfigurationState.Instance.Graphics.EnableTextureRecompression.Value = _textureRecompressionToggle.Active;
|
ConfigurationState.Instance.Graphics.EnableTextureRecompression.Value = _textureRecompressionToggle.Active;
|
||||||
ConfigurationState.Instance.Graphics.EnableMacroHLE.Value = _macroHLEToggle.Active;
|
ConfigurationState.Instance.Graphics.EnableMacroHLE.Value = _macroHLEToggle.Active;
|
||||||
ConfigurationState.Instance.System.EnablePtc.Value = _ptcToggle.Active;
|
ConfigurationState.Instance.System.EnablePtc.Value = _ptcToggle.Active;
|
||||||
ConfigurationState.Instance.System.EnableInternetAccess.Value = _internetToggle.Active;
|
ConfigurationState.Instance.System.EnableInternetAccess.Value = _internetToggle.Active;
|
||||||
ConfigurationState.Instance.System.EnableFsIntegrityChecks.Value = _fsicToggle.Active;
|
ConfigurationState.Instance.System.EnableFsIntegrityChecks.Value = _fsicToggle.Active;
|
||||||
ConfigurationState.Instance.System.MemoryManagerMode.Value = memoryMode;
|
ConfigurationState.Instance.System.MemoryManagerMode.Value = memoryMode;
|
||||||
ConfigurationState.Instance.System.ExpandRam.Value = _expandRamToggle.Active;
|
ConfigurationState.Instance.System.ExpandRam.Value = _expandRamToggle.Active;
|
||||||
ConfigurationState.Instance.System.IgnoreMissingServices.Value = _ignoreToggle.Active;
|
ConfigurationState.Instance.System.IgnoreMissingServices.Value = _ignoreToggle.Active;
|
||||||
ConfigurationState.Instance.Hid.EnableKeyboard.Value = _directKeyboardAccess.Active;
|
ConfigurationState.Instance.Hid.EnableKeyboard.Value = _directKeyboardAccess.Active;
|
||||||
ConfigurationState.Instance.Hid.EnableMouse.Value = _directMouseAccess.Active;
|
ConfigurationState.Instance.Hid.EnableMouse.Value = _directMouseAccess.Active;
|
||||||
ConfigurationState.Instance.Ui.EnableCustomTheme.Value = _custThemeToggle.Active;
|
ConfigurationState.Instance.Ui.EnableCustomTheme.Value = _custThemeToggle.Active;
|
||||||
ConfigurationState.Instance.System.Language.Value = Enum.Parse<Language>(_systemLanguageSelect.ActiveId);
|
ConfigurationState.Instance.System.Language.Value = Enum.Parse<Language>(_systemLanguageSelect.ActiveId);
|
||||||
ConfigurationState.Instance.System.Region.Value = Enum.Parse<Common.Configuration.System.Region>(_systemRegionSelect.ActiveId);
|
ConfigurationState.Instance.System.Region.Value = Enum.Parse<Common.Configuration.System.Region>(_systemRegionSelect.ActiveId);
|
||||||
ConfigurationState.Instance.System.SystemTimeOffset.Value = _systemTimeOffset;
|
ConfigurationState.Instance.System.SystemTimeOffset.Value = _systemTimeOffset;
|
||||||
ConfigurationState.Instance.Ui.CustomThemePath.Value = _custThemePath.Buffer.Text;
|
ConfigurationState.Instance.Ui.CustomThemePath.Value = _custThemePath.Buffer.Text;
|
||||||
ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = _graphicsShadersDumpPath.Buffer.Text;
|
ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = _graphicsShadersDumpPath.Buffer.Text;
|
||||||
ConfigurationState.Instance.System.FsGlobalAccessLogMode.Value = (int)_fsLogSpinAdjustment.Value;
|
ConfigurationState.Instance.System.FsGlobalAccessLogMode.Value = (int)_fsLogSpinAdjustment.Value;
|
||||||
ConfigurationState.Instance.Graphics.MaxAnisotropy.Value = float.Parse(_anisotropy.ActiveId, CultureInfo.InvariantCulture);
|
ConfigurationState.Instance.Graphics.MaxAnisotropy.Value = float.Parse(_anisotropy.ActiveId, CultureInfo.InvariantCulture);
|
||||||
ConfigurationState.Instance.Graphics.AspectRatio.Value = Enum.Parse<AspectRatio>(_aspectRatio.ActiveId);
|
ConfigurationState.Instance.Graphics.AspectRatio.Value = Enum.Parse<AspectRatio>(_aspectRatio.ActiveId);
|
||||||
ConfigurationState.Instance.Graphics.BackendThreading.Value = backendThreading;
|
ConfigurationState.Instance.Graphics.BackendThreading.Value = backendThreading;
|
||||||
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = Enum.Parse<GraphicsBackend>(_graphicsBackend.ActiveId);
|
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = Enum.Parse<GraphicsBackend>(_graphicsBackend.ActiveId);
|
||||||
ConfigurationState.Instance.Graphics.PreferredGpu.Value = _preferredGpu.ActiveId;
|
ConfigurationState.Instance.Graphics.PreferredGpu.Value = _preferredGpu.ActiveId;
|
||||||
ConfigurationState.Instance.Graphics.ResScale.Value = int.Parse(_resScaleCombo.ActiveId);
|
ConfigurationState.Instance.Graphics.ResScale.Value = int.Parse(_resScaleCombo.ActiveId);
|
||||||
ConfigurationState.Instance.Graphics.ResScaleCustom.Value = resScaleCustom;
|
ConfigurationState.Instance.Graphics.ResScaleCustom.Value = resScaleCustom;
|
||||||
ConfigurationState.Instance.System.AudioVolume.Value = (float)_audioVolumeSlider.Value / 100.0f;
|
ConfigurationState.Instance.System.AudioVolume.Value = (float)_audioVolumeSlider.Value / 100.0f;
|
||||||
ConfigurationState.Instance.Graphics.AntiAliasing.Value = Enum.Parse<AntiAliasing>(_antiAliasing.ActiveId);
|
ConfigurationState.Instance.Graphics.AntiAliasing.Value = Enum.Parse<AntiAliasing>(_antiAliasing.ActiveId);
|
||||||
ConfigurationState.Instance.Graphics.ScalingFilter.Value = Enum.Parse<ScalingFilter>(_scalingFilter.ActiveId);
|
ConfigurationState.Instance.Graphics.ScalingFilter.Value = Enum.Parse<ScalingFilter>(_scalingFilter.ActiveId);
|
||||||
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value = (int)_scalingFilterLevel.Value;
|
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value = (int)_scalingFilterLevel.Value;
|
||||||
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value = _multiLanSelect.ActiveId;
|
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value = _multiLanSelect.ActiveId;
|
||||||
|
|
||||||
_previousVolumeLevel = ConfigurationState.Instance.System.AudioVolume.Value;
|
_previousVolumeLevel = ConfigurationState.Instance.System.AudioVolume.Value;
|
||||||
|
|
||||||
|
@ -666,7 +664,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||||
_parent.UpdateGraphicsConfig();
|
MainWindow.UpdateGraphicsConfig();
|
||||||
ThemeHelper.ApplyTheme();
|
ThemeHelper.ApplyTheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -692,10 +690,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private void SystemTimeSpin_ValueChanged(object sender, EventArgs e)
|
private void SystemTimeSpin_ValueChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
int year = _systemTimeYearSpin.ValueAsInt;
|
int year = _systemTimeYearSpin.ValueAsInt;
|
||||||
int month = _systemTimeMonthSpin.ValueAsInt;
|
int month = _systemTimeMonthSpin.ValueAsInt;
|
||||||
int day = _systemTimeDaySpin.ValueAsInt;
|
int day = _systemTimeDaySpin.ValueAsInt;
|
||||||
int hour = _systemTimeHourSpin.ValueAsInt;
|
int hour = _systemTimeHourSpin.ValueAsInt;
|
||||||
int minute = _systemTimeMinuteSpin.ValueAsInt;
|
int minute = _systemTimeMinuteSpin.ValueAsInt;
|
||||||
|
|
||||||
if (!DateTime.TryParse(year + "-" + month + "-" + day + " " + hour + ":" + minute, out DateTime newTime))
|
if (!DateTime.TryParse(year + "-" + month + "-" + day + " " + hour + ":" + minute, out DateTime newTime))
|
||||||
|
@ -725,9 +723,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FileChooserNative fileChooser = new FileChooserNative("Choose the game directory to add to the list", this, FileChooserAction.SelectFolder, "Add", "Cancel")
|
FileChooserNative fileChooser = new("Choose the game directory to add to the list", this, FileChooserAction.SelectFolder, "Add", "Cancel")
|
||||||
{
|
{
|
||||||
SelectMultiple = true
|
SelectMultiple = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (fileChooser.Run() == (int)ResponseType.Accept)
|
if (fileChooser.Run() == (int)ResponseType.Accept)
|
||||||
|
@ -779,18 +777,18 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private void CustThemeToggle_Activated(object sender, EventArgs args)
|
private void CustThemeToggle_Activated(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
_custThemePath.Sensitive = _custThemeToggle.Active;
|
_custThemePath.Sensitive = _custThemeToggle.Active;
|
||||||
_custThemePathLabel.Sensitive = _custThemeToggle.Active;
|
_custThemePathLabel.Sensitive = _custThemeToggle.Active;
|
||||||
_browseThemePath.Sensitive = _custThemeToggle.Active;
|
_browseThemePath.Sensitive = _custThemeToggle.Active;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BrowseThemeDir_Pressed(object sender, EventArgs args)
|
private void BrowseThemeDir_Pressed(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
using (FileChooserNative fileChooser = new FileChooserNative("Choose the theme to load", this, FileChooserAction.Open, "Select", "Cancel"))
|
using (FileChooserNative fileChooser = new("Choose the theme to load", this, FileChooserAction.Open, "Select", "Cancel"))
|
||||||
{
|
{
|
||||||
FileFilter filter = new FileFilter()
|
FileFilter filter = new()
|
||||||
{
|
{
|
||||||
Name = "Theme Files"
|
Name = "Theme Files",
|
||||||
};
|
};
|
||||||
filter.AddPattern("*.css");
|
filter.AddPattern("*.css");
|
||||||
|
|
||||||
|
@ -809,7 +807,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
|
((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
|
||||||
|
|
||||||
ControllerWindow controllerWindow = new ControllerWindow(_parent, playerIndex);
|
ControllerWindow controllerWindow = new(_parent, playerIndex);
|
||||||
|
|
||||||
controllerWindow.SetSizeRequest((int)(controllerWindow.DefaultWidth * Program.WindowScaleFactor), (int)(controllerWindow.DefaultHeight * Program.WindowScaleFactor));
|
controllerWindow.SetSizeRequest((int)(controllerWindow.DefaultWidth * Program.WindowScaleFactor), (int)(controllerWindow.DefaultHeight * Program.WindowScaleFactor));
|
||||||
controllerWindow.Show();
|
controllerWindow.Show();
|
||||||
|
|
|
@ -9,33 +9,32 @@ using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS;
|
|
||||||
using Ryujinx.Ui.App.Common;
|
using Ryujinx.Ui.App.Common;
|
||||||
using Ryujinx.Ui.Widgets;
|
using Ryujinx.Ui.Widgets;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GUI = Gtk.Builder.ObjectAttribute;
|
using GUI = Gtk.Builder.ObjectAttribute;
|
||||||
using SpanHelpers = LibHac.Common.SpanHelpers;
|
using SpanHelpers = LibHac.Common.SpanHelpers;
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Windows
|
namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
public class TitleUpdateWindow : Window
|
public class TitleUpdateWindow : Window
|
||||||
{
|
{
|
||||||
private readonly MainWindow _parent;
|
private readonly MainWindow _parent;
|
||||||
private readonly VirtualFileSystem _virtualFileSystem;
|
private readonly VirtualFileSystem _virtualFileSystem;
|
||||||
private readonly string _titleId;
|
private readonly string _titleId;
|
||||||
private readonly string _updateJsonPath;
|
private readonly string _updateJsonPath;
|
||||||
|
|
||||||
private TitleUpdateMetadata _titleUpdateWindowData;
|
private TitleUpdateMetadata _titleUpdateWindowData;
|
||||||
|
|
||||||
private readonly Dictionary<RadioButton, string> _radioButtonToPathDictionary;
|
private readonly Dictionary<RadioButton, string> _radioButtonToPathDictionary;
|
||||||
private static readonly TitleUpdateMetadataJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly TitleUpdateMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
#pragma warning disable CS0649, IDE0044
|
#pragma warning disable CS0649, IDE0044 // Field is never assigned to, Add readonly modifier
|
||||||
[GUI] Label _baseTitleInfoLabel;
|
[GUI] Label _baseTitleInfoLabel;
|
||||||
[GUI] Box _availableUpdatesBox;
|
[GUI] Box _availableUpdatesBox;
|
||||||
[GUI] RadioButton _noUpdateRadioButton;
|
[GUI] RadioButton _noUpdateRadioButton;
|
||||||
#pragma warning restore CS0649, IDE0044
|
#pragma warning restore CS0649, IDE0044
|
||||||
|
|
||||||
|
@ -47,21 +46,21 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
builder.Autoconnect(this);
|
builder.Autoconnect(this);
|
||||||
|
|
||||||
_titleId = titleId;
|
_titleId = titleId;
|
||||||
_virtualFileSystem = virtualFileSystem;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
_updateJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "updates.json");
|
_updateJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "updates.json");
|
||||||
_radioButtonToPathDictionary = new Dictionary<RadioButton, string>();
|
_radioButtonToPathDictionary = new Dictionary<RadioButton, string>();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_titleUpdateWindowData = JsonHelper.DeserializeFromFile(_updateJsonPath, SerializerContext.TitleUpdateMetadata);
|
_titleUpdateWindowData = JsonHelper.DeserializeFromFile(_updateJsonPath, _serializerContext.TitleUpdateMetadata);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
_titleUpdateWindowData = new TitleUpdateMetadata
|
_titleUpdateWindowData = new TitleUpdateMetadata
|
||||||
{
|
{
|
||||||
Selected = "",
|
Selected = "",
|
||||||
Paths = new List<string>()
|
Paths = new List<string>(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,42 +88,41 @@ namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read))
|
using FileStream file = new(path, FileMode.Open, FileAccess.Read);
|
||||||
|
|
||||||
|
PartitionFileSystem nsp = new(file.AsStorage());
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage());
|
(Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(_virtualFileSystem, nsp, _titleId, 0);
|
||||||
|
|
||||||
try
|
if (controlNca != null && patchNca != null)
|
||||||
{
|
{
|
||||||
(Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(_virtualFileSystem, nsp, _titleId, 0);
|
ApplicationControlProperty controlData = new();
|
||||||
|
|
||||||
if (controlNca != null && patchNca != null)
|
using var nacpFile = new UniqueRef<IFile>();
|
||||||
{
|
|
||||||
ApplicationControlProperty controlData = new ApplicationControlProperty();
|
|
||||||
|
|
||||||
using var nacpFile = new UniqueRef<IFile>();
|
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
||||||
|
|
||||||
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
RadioButton radioButton = new($"Version {controlData.DisplayVersionString.ToString()} - {path}");
|
||||||
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
radioButton.JoinGroup(_noUpdateRadioButton);
|
||||||
|
|
||||||
RadioButton radioButton = new RadioButton($"Version {controlData.DisplayVersionString.ToString()} - {path}");
|
_availableUpdatesBox.Add(radioButton);
|
||||||
radioButton.JoinGroup(_noUpdateRadioButton);
|
_radioButtonToPathDictionary.Add(radioButton, path);
|
||||||
|
|
||||||
_availableUpdatesBox.Add(radioButton);
|
radioButton.Show();
|
||||||
_radioButtonToPathDictionary.Add(radioButton, path);
|
radioButton.Active = true;
|
||||||
|
|
||||||
radioButton.Show();
|
|
||||||
radioButton.Active = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GtkDialog.CreateErrorDialog("The specified file does not contain an update for the selected title!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
else
|
||||||
{
|
{
|
||||||
GtkDialog.CreateErrorDialog($"{exception.Message}. Errored File: {path}");
|
GtkDialog.CreateErrorDialog("The specified file does not contain an update for the selected title!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
GtkDialog.CreateErrorDialog($"{exception.Message}. Errored File: {path}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,24 +141,23 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private void AddButton_Clicked(object sender, EventArgs args)
|
private void AddButton_Clicked(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
using (FileChooserNative fileChooser = new FileChooserNative("Select update files", this, FileChooserAction.Open, "Add", "Cancel"))
|
using FileChooserNative fileChooser = new("Select update files", this, FileChooserAction.Open, "Add", "Cancel");
|
||||||
|
|
||||||
|
fileChooser.SelectMultiple = true;
|
||||||
|
|
||||||
|
FileFilter filter = new()
|
||||||
{
|
{
|
||||||
fileChooser.SelectMultiple = true;
|
Name = "Switch Game Updates",
|
||||||
|
};
|
||||||
|
filter.AddPattern("*.nsp");
|
||||||
|
|
||||||
FileFilter filter = new FileFilter()
|
fileChooser.AddFilter(filter);
|
||||||
|
|
||||||
|
if (fileChooser.Run() == (int)ResponseType.Accept)
|
||||||
|
{
|
||||||
|
foreach (string path in fileChooser.Filenames)
|
||||||
{
|
{
|
||||||
Name = "Switch Game Updates"
|
AddUpdate(path);
|
||||||
};
|
|
||||||
filter.AddPattern("*.nsp");
|
|
||||||
|
|
||||||
fileChooser.AddFilter(filter);
|
|
||||||
|
|
||||||
if (fileChooser.Run() == (int)ResponseType.Accept)
|
|
||||||
{
|
|
||||||
foreach (string path in fileChooser.Filenames)
|
|
||||||
{
|
|
||||||
AddUpdate(path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,7 +190,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonHelper.SerializeToFile(_updateJsonPath, _titleUpdateWindowData, SerializerContext.TitleUpdateMetadata);
|
JsonHelper.SerializeToFile(_updateJsonPath, _titleUpdateWindowData, _serializerContext.TitleUpdateMetadata);
|
||||||
|
|
||||||
_parent.UpdateGameTable();
|
_parent.UpdateGameTable();
|
||||||
|
|
||||||
|
|
|
@ -1,45 +1,43 @@
|
||||||
using Gtk;
|
using Gtk;
|
||||||
using Pango;
|
using Pango;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Windows
|
namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
public partial class UserProfilesManagerWindow : Window
|
public partial class UserProfilesManagerWindow : Window
|
||||||
{
|
{
|
||||||
private Box _mainBox;
|
private Box _mainBox;
|
||||||
private Label _selectedLabel;
|
private Label _selectedLabel;
|
||||||
private Box _selectedUserBox;
|
private Box _selectedUserBox;
|
||||||
private Image _selectedUserImage;
|
private Image _selectedUserImage;
|
||||||
private VBox _selectedUserInfoBox;
|
private Box _selectedUserInfoBox;
|
||||||
private Entry _selectedUserNameEntry;
|
private Entry _selectedUserNameEntry;
|
||||||
private Label _selectedUserIdLabel;
|
private Label _selectedUserIdLabel;
|
||||||
private VBox _selectedUserButtonsBox;
|
private Box _selectedUserButtonsBox;
|
||||||
private Button _saveProfileNameButton;
|
private Button _saveProfileNameButton;
|
||||||
private Button _changeProfileImageButton;
|
private Button _changeProfileImageButton;
|
||||||
private Box _usersTreeViewBox;
|
private Box _usersTreeViewBox;
|
||||||
private Label _availableUsersLabel;
|
private Label _availableUsersLabel;
|
||||||
private ScrolledWindow _usersTreeViewWindow;
|
private ScrolledWindow _usersTreeViewWindow;
|
||||||
private ListStore _tableStore;
|
private ListStore _tableStore;
|
||||||
private TreeView _usersTreeView;
|
private TreeView _usersTreeView;
|
||||||
private Box _bottomBox;
|
private Box _bottomBox;
|
||||||
private Button _addButton;
|
private Button _addButton;
|
||||||
private Button _deleteButton;
|
private Button _deleteButton;
|
||||||
private Button _closeButton;
|
private Button _closeButton;
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
|
|
||||||
#pragma warning disable CS0612
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// UserProfilesManagerWindow
|
// UserProfilesManagerWindow
|
||||||
//
|
//
|
||||||
CanFocus = false;
|
CanFocus = false;
|
||||||
Resizable = false;
|
Resizable = false;
|
||||||
Modal = true;
|
Modal = true;
|
||||||
WindowPosition = WindowPosition.Center;
|
WindowPosition = WindowPosition.Center;
|
||||||
DefaultWidth = 620;
|
DefaultWidth = 620;
|
||||||
DefaultHeight = 548;
|
DefaultHeight = 548;
|
||||||
TypeHint = Gdk.WindowTypeHint.Dialog;
|
TypeHint = Gdk.WindowTypeHint.Dialog;
|
||||||
|
|
||||||
//
|
//
|
||||||
// _mainBox
|
// _mainBox
|
||||||
|
@ -51,9 +49,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_selectedLabel = new Label("Selected User Profile:")
|
_selectedLabel = new Label("Selected User Profile:")
|
||||||
{
|
{
|
||||||
Margin = 15,
|
Margin = 15,
|
||||||
Attributes = new AttrList(),
|
Attributes = new AttrList(),
|
||||||
Halign = Align.Start
|
Halign = Align.Start,
|
||||||
};
|
};
|
||||||
_selectedLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
|
_selectedLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
|
||||||
|
|
||||||
|
@ -67,7 +65,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_selectedUserBox = new Box(Orientation.Horizontal, 0)
|
_selectedUserBox = new Box(Orientation.Horizontal, 0)
|
||||||
{
|
{
|
||||||
MarginLeft = 30
|
MarginStart = 30,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -78,15 +76,18 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
// _selectedUserInfoBox
|
// _selectedUserInfoBox
|
||||||
//
|
//
|
||||||
_selectedUserInfoBox = new VBox(true, 0);
|
_selectedUserInfoBox = new Box(Orientation.Vertical, 0)
|
||||||
|
{
|
||||||
|
Homogeneous = true,
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// _selectedUserNameEntry
|
// _selectedUserNameEntry
|
||||||
//
|
//
|
||||||
_selectedUserNameEntry = new Entry("")
|
_selectedUserNameEntry = new Entry("")
|
||||||
{
|
{
|
||||||
MarginLeft = 15,
|
MarginStart = 15,
|
||||||
MaxLength = (int)MaxProfileNameLength
|
MaxLength = (int)MaxProfileNameLength,
|
||||||
};
|
};
|
||||||
_selectedUserNameEntry.KeyReleaseEvent += SelectedUserNameEntry_KeyReleaseEvent;
|
_selectedUserNameEntry.KeyReleaseEvent += SelectedUserNameEntry_KeyReleaseEvent;
|
||||||
|
|
||||||
|
@ -95,16 +96,16 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_selectedUserIdLabel = new Label("")
|
_selectedUserIdLabel = new Label("")
|
||||||
{
|
{
|
||||||
MarginTop = 15,
|
MarginTop = 15,
|
||||||
MarginLeft = 15
|
MarginStart = 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// _selectedUserButtonsBox
|
// _selectedUserButtonsBox
|
||||||
//
|
//
|
||||||
_selectedUserButtonsBox = new VBox()
|
_selectedUserButtonsBox = new Box(Orientation.Vertical, 0)
|
||||||
{
|
{
|
||||||
MarginRight = 30
|
MarginEnd = 30,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -112,10 +113,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_saveProfileNameButton = new Button()
|
_saveProfileNameButton = new Button()
|
||||||
{
|
{
|
||||||
Label = "Save Profile Name",
|
Label = "Save Profile Name",
|
||||||
CanFocus = true,
|
CanFocus = true,
|
||||||
ReceivesDefault = true,
|
ReceivesDefault = true,
|
||||||
Sensitive = false
|
Sensitive = false,
|
||||||
};
|
};
|
||||||
_saveProfileNameButton.Clicked += EditProfileNameButton_Pressed;
|
_saveProfileNameButton.Clicked += EditProfileNameButton_Pressed;
|
||||||
|
|
||||||
|
@ -124,10 +125,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_changeProfileImageButton = new Button()
|
_changeProfileImageButton = new Button()
|
||||||
{
|
{
|
||||||
Label = "Change Profile Image",
|
Label = "Change Profile Image",
|
||||||
CanFocus = true,
|
CanFocus = true,
|
||||||
ReceivesDefault = true,
|
ReceivesDefault = true,
|
||||||
MarginTop = 10
|
MarginTop = 10,
|
||||||
};
|
};
|
||||||
_changeProfileImageButton.Clicked += ChangeProfileImageButton_Pressed;
|
_changeProfileImageButton.Clicked += ChangeProfileImageButton_Pressed;
|
||||||
|
|
||||||
|
@ -136,9 +137,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_availableUsersLabel = new Label("Available User Profiles:")
|
_availableUsersLabel = new Label("Available User Profiles:")
|
||||||
{
|
{
|
||||||
Margin = 15,
|
Margin = 15,
|
||||||
Attributes = new AttrList(),
|
Attributes = new AttrList(),
|
||||||
Halign = Align.Start
|
Halign = Align.Start,
|
||||||
};
|
};
|
||||||
_availableUsersLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
|
_availableUsersLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
|
||||||
|
|
||||||
|
@ -147,12 +148,12 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_usersTreeViewWindow = new ScrolledWindow()
|
_usersTreeViewWindow = new ScrolledWindow()
|
||||||
{
|
{
|
||||||
ShadowType = ShadowType.In,
|
ShadowType = ShadowType.In,
|
||||||
CanFocus = true,
|
CanFocus = true,
|
||||||
Expand = true,
|
Expand = true,
|
||||||
MarginLeft = 30,
|
MarginStart = 30,
|
||||||
MarginRight = 30,
|
MarginEnd = 30,
|
||||||
MarginBottom = 15
|
MarginBottom = 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -175,9 +176,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_bottomBox = new Box(Orientation.Horizontal, 0)
|
_bottomBox = new Box(Orientation.Horizontal, 0)
|
||||||
{
|
{
|
||||||
MarginLeft = 30,
|
MarginStart = 30,
|
||||||
MarginRight = 30,
|
MarginEnd = 30,
|
||||||
MarginBottom = 15
|
MarginBottom = 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -185,10 +186,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_addButton = new Button()
|
_addButton = new Button()
|
||||||
{
|
{
|
||||||
Label = "Add New Profile",
|
Label = "Add New Profile",
|
||||||
CanFocus = true,
|
CanFocus = true,
|
||||||
ReceivesDefault = true,
|
ReceivesDefault = true,
|
||||||
HeightRequest = 35
|
HeightRequest = 35,
|
||||||
};
|
};
|
||||||
_addButton.Clicked += AddButton_Pressed;
|
_addButton.Clicked += AddButton_Pressed;
|
||||||
|
|
||||||
|
@ -197,11 +198,11 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_deleteButton = new Button()
|
_deleteButton = new Button()
|
||||||
{
|
{
|
||||||
Label = "Delete Selected Profile",
|
Label = "Delete Selected Profile",
|
||||||
CanFocus = true,
|
CanFocus = true,
|
||||||
ReceivesDefault = true,
|
ReceivesDefault = true,
|
||||||
HeightRequest = 35,
|
HeightRequest = 35,
|
||||||
MarginLeft = 10
|
MarginStart = 10,
|
||||||
};
|
};
|
||||||
_deleteButton.Clicked += DeleteButton_Pressed;
|
_deleteButton.Clicked += DeleteButton_Pressed;
|
||||||
|
|
||||||
|
@ -210,16 +211,14 @@ namespace Ryujinx.Ui.Windows
|
||||||
//
|
//
|
||||||
_closeButton = new Button()
|
_closeButton = new Button()
|
||||||
{
|
{
|
||||||
Label = "Close",
|
Label = "Close",
|
||||||
CanFocus = true,
|
CanFocus = true,
|
||||||
ReceivesDefault = true,
|
ReceivesDefault = true,
|
||||||
HeightRequest = 35,
|
HeightRequest = 35,
|
||||||
WidthRequest = 80
|
WidthRequest = 80,
|
||||||
};
|
};
|
||||||
_closeButton.Clicked += CloseButton_Pressed;
|
_closeButton.Clicked += CloseButton_Pressed;
|
||||||
|
|
||||||
#pragma warning restore CS0612
|
|
||||||
|
|
||||||
ShowComponent();
|
ShowComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Image = SixLabors.ImageSharp.Image;
|
using Image = SixLabors.ImageSharp.Image;
|
||||||
using UserId = Ryujinx.HLE.HOS.Services.Account.Acc.UserId;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Windows
|
namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
|
@ -29,7 +28,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private Gdk.RGBA _selectedColor;
|
private Gdk.RGBA _selectedColor;
|
||||||
|
|
||||||
private ManualResetEvent _avatarsPreloadingEvent = new ManualResetEvent(false);
|
private readonly ManualResetEvent _avatarsPreloadingEvent = new(false);
|
||||||
|
|
||||||
public UserProfilesManagerWindow(AccountManager accountManager, ContentManager contentManager, VirtualFileSystem virtualFileSystem) : base($"Ryujinx {Program.Version} - Manage User Profiles")
|
public UserProfilesManagerWindow(AccountManager accountManager, ContentManager contentManager, VirtualFileSystem virtualFileSystem) : base($"Ryujinx {Program.Version} - Manage User Profiles")
|
||||||
{
|
{
|
||||||
|
@ -37,21 +36,21 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_selectedColor.Red = 0.212;
|
_selectedColor.Red = 0.212;
|
||||||
_selectedColor.Green = 0.843;
|
_selectedColor.Green = 0.843;
|
||||||
_selectedColor.Blue = 0.718;
|
_selectedColor.Blue = 0.718;
|
||||||
_selectedColor.Alpha = 1;
|
_selectedColor.Alpha = 1;
|
||||||
|
|
||||||
_accountManager = accountManager;
|
_accountManager = accountManager;
|
||||||
_contentManager = contentManager;
|
_contentManager = contentManager;
|
||||||
|
|
||||||
CellRendererToggle userSelectedToggle = new CellRendererToggle();
|
CellRendererToggle userSelectedToggle = new();
|
||||||
userSelectedToggle.Toggled += UserSelectedToggle_Toggled;
|
userSelectedToggle.Toggled += UserSelectedToggle_Toggled;
|
||||||
|
|
||||||
// NOTE: Uncomment following line when multiple selection of user profiles is supported.
|
// NOTE: Uncomment following line when multiple selection of user profiles is supported.
|
||||||
//_usersTreeView.AppendColumn("Selected", userSelectedToggle, "active", 0);
|
//_usersTreeView.AppendColumn("Selected", userSelectedToggle, "active", 0);
|
||||||
_usersTreeView.AppendColumn("User Icon", new CellRendererPixbuf(), "pixbuf", 1);
|
_usersTreeView.AppendColumn("User Icon", new CellRendererPixbuf(), "pixbuf", 1);
|
||||||
_usersTreeView.AppendColumn("User Info", new CellRendererText(), "text", 2, "background-rgba", 3);
|
_usersTreeView.AppendColumn("User Info", new CellRendererText(), "text", 2, "background-rgba", 3);
|
||||||
|
|
||||||
_tableStore.SetSortColumnId(0, SortType.Descending);
|
_tableStore.SetSortColumnId(0, SortType.Descending);
|
||||||
|
|
||||||
|
@ -77,8 +76,8 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
if (userProfile.AccountState == AccountState.Open)
|
if (userProfile.AccountState == AccountState.Open)
|
||||||
{
|
{
|
||||||
_selectedUserImage.Pixbuf = new Gdk.Pixbuf(userProfile.Image, 96, 96);
|
_selectedUserImage.Pixbuf = new Gdk.Pixbuf(userProfile.Image, 96, 96);
|
||||||
_selectedUserIdLabel.Text = userProfile.UserId.ToString();
|
_selectedUserIdLabel.Text = userProfile.UserId.ToString();
|
||||||
_selectedUserNameEntry.Text = userProfile.Name;
|
_selectedUserNameEntry.Text = userProfile.Name;
|
||||||
|
|
||||||
_deleteButton.Sensitive = userProfile.UserId != AccountManager.DefaultUserId;
|
_deleteButton.Sensitive = userProfile.UserId != AccountManager.DefaultUserId;
|
||||||
|
@ -111,7 +110,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
Gdk.Pixbuf userPicture = (Gdk.Pixbuf)_tableStore.GetValue(selectedIter, 1);
|
Gdk.Pixbuf userPicture = (Gdk.Pixbuf)_tableStore.GetValue(selectedIter, 1);
|
||||||
|
|
||||||
string userName = _tableStore.GetValue(selectedIter, 2).ToString().Split("\n")[0];
|
string userName = _tableStore.GetValue(selectedIter, 2).ToString().Split("\n")[0];
|
||||||
string userId = _tableStore.GetValue(selectedIter, 2).ToString().Split("\n")[1];
|
string userId = _tableStore.GetValue(selectedIter, 2).ToString().Split("\n")[1];
|
||||||
|
|
||||||
// Unselect the first user.
|
// Unselect the first user.
|
||||||
_usersTreeView.Model.GetIterFirst(out TreeIter firstIter);
|
_usersTreeView.Model.GetIterFirst(out TreeIter firstIter);
|
||||||
|
@ -121,9 +120,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
// Set new informations.
|
// Set new informations.
|
||||||
_tableStore.SetValue(selectedIter, 0, true);
|
_tableStore.SetValue(selectedIter, 0, true);
|
||||||
|
|
||||||
_selectedUserImage.Pixbuf = userPicture;
|
_selectedUserImage.Pixbuf = userPicture;
|
||||||
_selectedUserNameEntry.Text = userName;
|
_selectedUserNameEntry.Text = userName;
|
||||||
_selectedUserIdLabel.Text = userId;
|
_selectedUserIdLabel.Text = userId;
|
||||||
_saveProfileNameButton.Sensitive = false;
|
_saveProfileNameButton.Sensitive = false;
|
||||||
|
|
||||||
// Open the selected one.
|
// Open the selected one.
|
||||||
|
@ -178,29 +177,27 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private void ProcessProfileImage(byte[] buffer)
|
private void ProcessProfileImage(byte[] buffer)
|
||||||
{
|
{
|
||||||
using (Image image = Image.Load(buffer))
|
using Image image = Image.Load(buffer);
|
||||||
{
|
|
||||||
image.Mutate(x => x.Resize(256, 256));
|
|
||||||
|
|
||||||
using (MemoryStream streamJpg = MemoryStreamManager.Shared.GetStream())
|
image.Mutate(x => x.Resize(256, 256));
|
||||||
{
|
|
||||||
image.SaveAsJpeg(streamJpg);
|
|
||||||
|
|
||||||
_bufferImageProfile = streamJpg.ToArray();
|
using MemoryStream streamJpg = MemoryStreamManager.Shared.GetStream();
|
||||||
}
|
|
||||||
}
|
image.SaveAsJpeg(streamJpg);
|
||||||
|
|
||||||
|
_bufferImageProfile = streamJpg.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProfileImageFileChooser()
|
private void ProfileImageFileChooser()
|
||||||
{
|
{
|
||||||
FileChooserNative fileChooser = new FileChooserNative("Import Custom Profile Image", this, FileChooserAction.Open, "Import", "Cancel")
|
FileChooserNative fileChooser = new("Import Custom Profile Image", this, FileChooserAction.Open, "Import", "Cancel")
|
||||||
{
|
{
|
||||||
SelectMultiple = false
|
SelectMultiple = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
FileFilter filter = new FileFilter()
|
FileFilter filter = new()
|
||||||
{
|
{
|
||||||
Name = "Custom Profile Images"
|
Name = "Custom Profile Images",
|
||||||
};
|
};
|
||||||
filter.AddPattern("*.jpg");
|
filter.AddPattern("*.jpg");
|
||||||
filter.AddPattern("*.jpeg");
|
filter.AddPattern("*.jpeg");
|
||||||
|
@ -225,10 +222,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Dictionary<int, string> buttons = new Dictionary<int, string>()
|
Dictionary<int, string> buttons = new()
|
||||||
{
|
{
|
||||||
{ 0, "Import Image File" },
|
{ 0, "Import Image File" },
|
||||||
{ 1, "Select Firmware Avatar" }
|
{ 1, "Select Firmware Avatar" },
|
||||||
};
|
};
|
||||||
|
|
||||||
ResponseType responseDialog = GtkDialog.CreateCustomDialog("Profile Image Selection",
|
ResponseType responseDialog = GtkDialog.CreateCustomDialog("Profile Image Selection",
|
||||||
|
@ -242,9 +239,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
else if (responseDialog == (ResponseType)1)
|
else if (responseDialog == (ResponseType)1)
|
||||||
{
|
{
|
||||||
AvatarWindow avatarWindow = new AvatarWindow()
|
AvatarWindow avatarWindow = new()
|
||||||
{
|
{
|
||||||
NewUser = newUser
|
NewUser = newUser,
|
||||||
};
|
};
|
||||||
|
|
||||||
avatarWindow.DeleteEvent += AvatarWindow_DeleteEvent;
|
avatarWindow.DeleteEvent += AvatarWindow_DeleteEvent;
|
||||||
|
|
Reference in a new issue